diff --git a/Dockerfile.conntest.source b/Dockerfile.conntest.source new file mode 100644 index 00000000..543b5bca --- /dev/null +++ b/Dockerfile.conntest.source @@ -0,0 +1,188 @@ +# syntax=docker.io/docker/dockerfile:1.7-labs +FROM --platform=${TARGETPLATFORM} ubuntu:24.04 AS base + +ENV PATH="${PATH}:/root/.cargo/bin/" + +ARG TARGETOS +ARG TARGETARCH + +# Install GMP 6.2 (6.3 which MacOS is using only available on Debian unstable) +RUN apt-get update && apt-get install -y \ + build-essential \ + curl \ + git \ + cmake \ + libgmp-dev \ + libmpfr-dev \ + libmpfr6 \ + wget \ + m4 \ + pkg-config \ + gcc \ + g++ \ + make \ + autoconf \ + automake \ + libtool \ + libssl-dev \ + python3 \ + python-is-python3 \ + && rm -rf /var/lib/apt/lists/* + +ARG GO_VERSION=1.23.5 +RUN apt update && apt install -y wget && \ + ARCH=$(dpkg --print-architecture) && \ + case ${ARCH} in \ + amd64) GOARCH=amd64 ;; \ + arm64) GOARCH=arm64 ;; \ + *) echo "Unsupported architecture: ${ARCH}" && exit 1 ;; \ + esac && \ + wget https://go.dev/dl/go${GO_VERSION}.linux-${GOARCH}.tar.gz && \ + rm -rf /usr/local/go && \ + tar -C /usr/local -xzf go${GO_VERSION}.linux-${GOARCH}.tar.gz && \ + rm go${GO_VERSION}.linux-${GOARCH}.tar.gz + +ENV PATH=$PATH:/usr/local/go/bin + +RUN git clone https://github.com/flintlib/flint.git && \ + cd flint && \ + git checkout flint-3.0 && \ + ./bootstrap.sh && \ + ./configure \ + --prefix=/usr/local \ + --with-gmp=/usr/local \ + --with-mpfr=/usr/local \ + --enable-static \ + --disable-shared \ + CFLAGS="-O3" && \ + make && \ + make install && \ + cd .. && \ + rm -rf flint + +COPY docker/rustup-init.sh /opt/rustup-init.sh + +RUN /opt/rustup-init.sh -y --profile minimal + +# Install uniffi-bindgen-go +RUN cargo install uniffi-bindgen-go --git https://github.com/NordSecurity/uniffi-bindgen-go --tag v0.2.1+v0.25.0 + +FROM base AS build + +ENV GOEXPERIMENT=arenas +ENV QUILIBRIUM_SIGNATURE_CHECK=false + +# Install grpcurl before building the node and client +# as to avoid needing to redo it on rebuilds +RUN go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest + +WORKDIR /opt/ceremonyclient + +# Copy everything except node and client so as to avoid +# invalidating the cache at this point on client or node rebuilds + +COPY --exclude=client \ + --exclude=conntest \ + --exclude=sidecar . . + +RUN python emp-install.py --install --tool --ot + +RUN cd emp-tool && sed -i 's/add_library(${NAME} SHARED ${sources})/add_library(${NAME} STATIC ${sources})/g' CMakeLists.txt && mkdir build && cd build && cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local && cd .. && make && make install && cd .. + +RUN cd emp-ot && mkdir build && cd build && cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local && cd .. && make && make install && cd .. + +RUN go mod download + +## Generate Rust bindings for channel +WORKDIR /opt/ceremonyclient/channel + +RUN go mod download + +RUN ./generate.sh + + +## Generate Rust bindings for VDF +WORKDIR /opt/ceremonyclient/vdf + +RUN go mod download + +RUN ./generate.sh + + +## Generate Rust bindings for Ferret +WORKDIR /opt/ceremonyclient/ferret + +RUN go mod download + +RUN ./generate.sh + +## Generate Rust bindings for BLS48581 +WORKDIR /opt/ceremonyclient/bls48581 + +RUN go mod download + +RUN ./generate.sh + +## Generate Rust bindings for RPM +WORKDIR /opt/ceremonyclient/rpm + +RUN go mod download + +RUN ./generate.sh + +## Generate Rust bindings for VerEnc +WORKDIR /opt/ceremonyclient/verenc + +RUN go mod download + +RUN ./generate.sh + +## Generate Rust bindings for Bulletproofs +WORKDIR /opt/ceremonyclient/bulletproofs + +RUN go mod download + +RUN ./generate.sh + +FROM build AS build-conntest + +# Build and install conntest +COPY ./conntest /opt/ceremonyclient/conntest +WORKDIR /opt/ceremonyclient/conntest + +ENV GOPROXY=direct +RUN ./build.sh && cp conntest /usr/bin + +# Allows exporting single binary +FROM scratch AS conntest +COPY --from=build-conntest /usr/bin/conntest /conntest +ENTRYPOINT [ "/conntest" ] + +FROM ubuntu:24.04 + +RUN apt-get update && apt-get install libflint-dev -y + +ARG NODE_VERSION +ARG GIT_REPO +ARG GIT_BRANCH +ARG GIT_COMMIT + +ENV GOEXPERIMENT=arenas + +LABEL org.opencontainers.image.title="Quilibrium Network Node connection test" +LABEL org.opencontainers.image.description="Quilibrium is a decentralized alternative to platform as a service providers." +LABEL org.opencontainers.image.version=$NODE_VERSION +LABEL org.opencontainers.image.vendor=Quilibrium +LABEL org.opencontainers.image.url=https://quilibrium.com/ +LABEL org.opencontainers.image.documentation=https://quilibrium.com/docs +LABEL org.opencontainers.image.source=$GIT_REPO +LABEL org.opencontainers.image.ref.name=$GIT_BRANCH +LABEL org.opencontainers.image.revision=$GIT_COMMIT + +RUN apt-get update && apt-get install -y ca-certificates + +COPY --from=build-conntest /usr/bin/conntest /usr/local/bin + +WORKDIR /root + +ENTRYPOINT ["conntest"] diff --git a/Taskfile.yaml b/Taskfile.yaml index 3687083a..aab32bdd 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -70,6 +70,11 @@ tasks: cmds: - docker build --platform linux/amd64 -f Dockerfile.source --output node/build/amd64_linux --target=node . + build_conntest_amd64_linux: + desc: Build the Quilibrium node connection test binary for AMD64 Linux. Outputs to conntest/build. + cmds: + - docker build --platform linux/amd64 -f Dockerfile.conntest.source --output conntest/build/amd64_linux --target=conntest . + build_node_amd64_avx512_linux: desc: Build the Quilibrium node binary for AMD64 Linux with AVX-512 extensions. Outputs to node/build. cmds: diff --git a/config/config.go b/config/config.go index c755bf8e..c117bea0 100644 --- a/config/config.go +++ b/config/config.go @@ -88,29 +88,28 @@ var BootstrapPeers = []string{ "/dns/bootstrap.quilibrium.com/udp/8336/quic-v1/p2p/Qme3g6rJWuz8HVXxpDb7aV2hiFq8bZJNqxMmwzmASzfq1M", "/dns/quecifer.quilibrium.com/udp/8336/quic-v1/p2p/QmdWF9bGTH5mwJXkxrG859HA5r34MxXtMSTuEikSMDSESv", "/dns/quagmire.quilibrium.com/udp/8336/quic-v1/p2p/QmaQ9KAaKtqXhYSQ5ARQNnn8B8474cWGvvD6PgJ4gAtMrx", - "/ip4/204.186.74.46/udp/8316/quic-v1/p2p/QmeqBjm3iX7sdTieyto1gys5ruQrQNPKfaTGcVQQWJPYDV", + // "/ip4/204.186.74.46/udp/8316/quic-v1/p2p/QmeqBjm3iX7sdTieyto1gys5ruQrQNPKfaTGcVQQWJPYDV", "/ip4/65.109.17.13/udp/8336/quic-v1/p2p/Qmc35n99eojSvW3PkbfBczJoSX92WmnnKh3Fg114ok3oo4", "/ip4/65.108.194.84/udp/8336/quic-v1/p2p/QmP8C7g9ZRiWzhqN2AgFu5onS6HwHzR6Vv1TCHxAhnCSnq", "/ip4/15.204.100.222/udp/8336/quic-v1/p2p/Qmef3Z3RvGg49ZpDPcf2shWtJNgPJNpXrowjUcfz23YQ3V", - "/ip4/69.197.174.35/udp/8336/quic-v1/p2p/QmeprCaZKiymofPJgnp2ANR3F4pRus9PHHaxnJDh1Jwr1p", - "/ip4/70.36.102.32/udp/8336/quic-v1/p2p/QmYriGRXCUiwFodqSoS4GgEcD7UVyxXPeCgQKmYne3iLSF", - "/ip4/204.12.220.2/udp/8336/quic-v1/p2p/QmRw5Tw4p5v2vLPvVSAkQEiRPQGnWk9HM4xiSvgxF82CCw", - "/ip4/209.159.149.14/udp/8336/quic-v1/p2p/Qmcq4Lmw45tbodvdRWZ8iGgy3rUcR3dikHTj1fBXP8VJqv", - "/ip4/148.251.9.90/udp/8336/quic-v1/p2p/QmRpKmQ1W83s6moBFpG6D6nrttkqdQSbdCJpvfxDVGcs38", - "/ip4/35.232.113.144/udp/8336/quic-v1/p2p/QmWxkBc7a17ZsLHhszLyTvKsoHMKvKae2XwfQXymiU66md", - "/ip4/34.87.85.78/udp/8336/quic-v1/p2p/QmTGguT5XhtvZZwTLnNQTN8Bg9eUm1THWEneXXHGhMDPrz", - "/ip4/34.81.199.27/udp/8336/quic-v1/p2p/QmTMMKpzCKJCwrnUzNu6tNj4P1nL7hVqz251245wsVpGNg", - "/ip4/34.143.255.235/udp/8336/quic-v1/p2p/QmeifsP6Kvq8A3yabQs6CBg7prSpDSqdee8P2BDQm9EpP8", - "/ip4/34.34.125.238/udp/8336/quic-v1/p2p/QmZdSyBJLm9UiDaPZ4XDkgRGXUwPcHJCmKoH6fS9Qjyko4", - "/ip4/34.80.245.52/udp/8336/quic-v1/p2p/QmNmbqobt82Vre5JxUGVNGEWn2HsztQQ1xfeg6mx7X5u3f", - "/dns/bravo-1.qcommander.sh/udp/8336/quic-v1/p2p/QmURj4qEB9vNdCCKzSMq4ESEgz13nJrqazgMdGi2DBSeeC", - "/ip4/109.199.100.108/udp/8336/quic-v1/p2p/Qma9fgugQc17MDu4YRSvnhfhVre6AYZ3nZdW8dSUYbsWvm", - "/ip4/47.251.49.193/udp/8336/quic-v1/p2p/QmP6ADPmMCsB8y82oFbrKTrwYWXt1CTMJ3jGNDXRHyYJgR", - "/ip4/138.201.203.208/udp/8336/quic-v1/p2p/QmbNhSTd4Y64ZCbV2gAXYR4ZFDdfRBMfrgWsNg99JHxsJo", - "/ip4/148.251.9.90/udp/8336/quic-v1/p2p/QmRpKmQ1W83s6moBFpG6D6nrttkqdQSbdCJpvfxDVGcs38", - "/ip4/15.235.211.121/udp/8336/quic-v1/p2p/QmZHNLUSAFCkTwHiEE3vWay3wsus5fWYsNLFTFU6tPCmNR", - "/ip4/63.141.228.58/udp/8336/quic-v1/p2p/QmezARggdWKa1sw3LqE3LfZwVvtuCpXpK8WVo8EEdfakJV", - "/ip4/192.69.222.130/udp/8336/quic-v1/p2p/QmcKQjpQmLpbDsiif2MuakhHFyxWvqYauPsJDaXnLav7PJ", + // "/ip4/69.197.174.35/udp/8336/quic-v1/p2p/QmeprCaZKiymofPJgnp2ANR3F4pRus9PHHaxnJDh1Jwr1p", + // "/ip4/70.36.102.32/udp/8336/quic-v1/p2p/QmYriGRXCUiwFodqSoS4GgEcD7UVyxXPeCgQKmYne3iLSF", + // "/ip4/204.12.220.2/udp/8336/quic-v1/p2p/QmRw5Tw4p5v2vLPvVSAkQEiRPQGnWk9HM4xiSvgxF82CCw", + // "/ip4/209.159.149.14/udp/8336/quic-v1/p2p/Qmcq4Lmw45tbodvdRWZ8iGgy3rUcR3dikHTj1fBXP8VJqv", + // "/ip4/148.251.9.90/udp/8336/quic-v1/p2p/QmRpKmQ1W83s6moBFpG6D6nrttkqdQSbdCJpvfxDVGcs38", + // "/ip4/35.232.113.144/udp/8336/quic-v1/p2p/QmWxkBc7a17ZsLHhszLyTvKsoHMKvKae2XwfQXymiU66md", + // "/ip4/34.87.85.78/udp/8336/quic-v1/p2p/QmTGguT5XhtvZZwTLnNQTN8Bg9eUm1THWEneXXHGhMDPrz", + // "/ip4/34.81.199.27/udp/8336/quic-v1/p2p/QmTMMKpzCKJCwrnUzNu6tNj4P1nL7hVqz251245wsVpGNg", + // "/ip4/34.143.255.235/udp/8336/quic-v1/p2p/QmeifsP6Kvq8A3yabQs6CBg7prSpDSqdee8P2BDQm9EpP8", + // "/ip4/34.34.125.238/udp/8336/quic-v1/p2p/QmZdSyBJLm9UiDaPZ4XDkgRGXUwPcHJCmKoH6fS9Qjyko4", + // "/ip4/34.80.245.52/udp/8336/quic-v1/p2p/QmNmbqobt82Vre5JxUGVNGEWn2HsztQQ1xfeg6mx7X5u3f", + // "/dns/bravo-1.qcommander.sh/udp/8336/quic-v1/p2p/QmURj4qEB9vNdCCKzSMq4ESEgz13nJrqazgMdGi2DBSeeC", + // "/ip4/109.199.100.108/udp/8336/quic-v1/p2p/Qma9fgugQc17MDu4YRSvnhfhVre6AYZ3nZdW8dSUYbsWvm", + // "/ip4/47.251.49.193/udp/8336/quic-v1/p2p/QmP6ADPmMCsB8y82oFbrKTrwYWXt1CTMJ3jGNDXRHyYJgR", + // "/ip4/138.201.203.208/udp/8336/quic-v1/p2p/QmbNhSTd4Y64ZCbV2gAXYR4ZFDdfRBMfrgWsNg99JHxsJo", + // "/ip4/148.251.9.90/udp/8336/quic-v1/p2p/QmRpKmQ1W83s6moBFpG6D6nrttkqdQSbdCJpvfxDVGcs38", + // "/ip4/15.235.211.121/udp/8336/quic-v1/p2p/QmZHNLUSAFCkTwHiEE3vWay3wsus5fWYsNLFTFU6tPCmNR", + // "/ip4/63.141.228.58/udp/8336/quic-v1/p2p/QmezARggdWKa1sw3LqE3LfZwVvtuCpXpK8WVo8EEdfakJV", // purged peers (keep your node online to return to this list) // "/ip4/204.186.74.47/udp/8317/quic-v1/p2p/Qmd233pLUDvcDW3ama27usfbG1HxKNh1V9dmWVW1SXp1pd", // "/ip4/186.233.184.181/udp/8336/quic-v1/p2p/QmW6QDvKuYqJYYMP5tMZSp12X3nexywK28tZNgqtqNpEDL", diff --git a/config/version.go b/config/version.go index 197456b8..92e80349 100644 --- a/config/version.go +++ b/config/version.go @@ -13,7 +13,7 @@ func GetMinimumVersionCutoff() time.Time { // if there is something in the patch update that is needed to cut off // unupgraded peers. Be sure to update this to 0x00 for any new minor release. func GetMinimumPatchVersion() byte { - return 0x00 + return 0x02 } func GetMinimumVersion() []byte { @@ -43,7 +43,7 @@ func FormatVersion(version []byte) string { } func GetPatchNumber() byte { - return 0x01 + return 0x02 } func GetRCNumber() byte { diff --git a/conntest/build.sh b/conntest/build.sh new file mode 100755 index 00000000..1845e660 --- /dev/null +++ b/conntest/build.sh @@ -0,0 +1,36 @@ +#!/bin/bash +set -euxo pipefail + +# This script builds the conntest 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 )}" + +CONNTEST_DIR="$ROOT_DIR/conntest" +BINARIES_DIR="$ROOT_DIR/target/release" + +pushd "$CONNTEST_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 -L/usr/local/lib/ -L/opt/homebrew/Cellar/openssl@3/3.5.0/lib -lbls48581 -lvdf -lchannel -lferret -lverenc -lbulletproofs -lrpm -ldl -lm -lflint -lgmp -lmpfr -lstdc++ -lcrypto -lssl'" "$@" + else + echo "Unsupported platform" + exit 1 + fi + ;; + "Linux") + export CGO_LDFLAGS="-L/usr/local/lib -lflint -lgmp -lmpfr -ldl -lm -L$BINARIES_DIR -lstdc++ -lvdf -lchannel -lferret -lverenc -lbulletproofs -lbls48581 -lrpm -lcrypto -lssl -static" + go build -ldflags "-linkmode 'external'" "$@" + ;; + *) + echo "Unsupported platform" + exit 1 + ;; +esac diff --git a/conntest/go.mod b/conntest/go.mod new file mode 100644 index 00000000..96330807 --- /dev/null +++ b/conntest/go.mod @@ -0,0 +1,188 @@ +module source.quilibrium.com/quilibrium/monorepo/conntest + +go 1.23.2 + +replace source.quilibrium.com/quilibrium/monorepo/nekryptology => ../nekryptology + +replace source.quilibrium.com/quilibrium/monorepo/bls48581 => ../bls48581 + +replace source.quilibrium.com/quilibrium/monorepo/bulletproofs => ../bulletproofs + +replace source.quilibrium.com/quilibrium/monorepo/ferret => ../ferret + +replace source.quilibrium.com/quilibrium/monorepo/channel => ../channel + +replace source.quilibrium.com/quilibrium/monorepo/bedlam => ../bedlam + +replace source.quilibrium.com/quilibrium/monorepo/types => ../types + +replace source.quilibrium.com/quilibrium/monorepo/vdf => ../vdf + +replace source.quilibrium.com/quilibrium/monorepo/verenc => ../verenc + +replace source.quilibrium.com/quilibrium/monorepo/protobufs => ../protobufs + +replace source.quilibrium.com/quilibrium/monorepo/utils => ../utils + +replace source.quilibrium.com/quilibrium/monorepo/config => ../config + +replace source.quilibrium.com/quilibrium/monorepo/node => ../node + +replace source.quilibrium.com/quilibrium/monorepo/hypergraph => ../hypergraph + +replace source.quilibrium.com/quilibrium/monorepo/consensus => ../consensus + +replace source.quilibrium.com/quilibrium/monorepo/rpm => ../rpm + +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 source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub => ../go-libp2p-blossomsub + +require ( + github.com/libp2p/go-libp2p v0.41.1 + source.quilibrium.com/quilibrium/monorepo/config v0.0.0-00010101000000-000000000000 + source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub v0.0.0-00010101000000-000000000000 + source.quilibrium.com/quilibrium/monorepo/node v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect + github.com/libp2p/go-libp2p-kad-dht v0.23.0 // indirect + github.com/libp2p/go-libp2p-routing-helpers v0.7.2 // indirect + github.com/libp2p/go-yamux/v5 v5.0.1 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pion/datachannel v1.5.10 // indirect + github.com/pion/dtls/v2 v2.2.12 // indirect + github.com/pion/dtls/v3 v3.0.6 // indirect + github.com/pion/ice/v4 v4.0.10 // indirect + github.com/pion/interceptor v0.1.40 // indirect + github.com/pion/logging v0.2.3 // indirect + github.com/pion/mdns/v2 v2.0.7 // indirect + github.com/pion/randutil v0.1.0 // indirect + github.com/pion/rtcp v1.2.15 // indirect + github.com/pion/rtp v1.8.19 // indirect + github.com/pion/sctp v1.8.39 // indirect + github.com/pion/sdp/v3 v3.0.13 // indirect + github.com/pion/srtp/v3 v3.0.6 // indirect + github.com/pion/stun v0.6.1 // indirect + github.com/pion/stun/v3 v3.0.0 // indirect + github.com/pion/transport/v2 v2.2.10 // indirect + github.com/pion/transport/v3 v3.0.7 // indirect + github.com/pion/turn/v4 v4.0.2 // indirect + github.com/pion/webrtc/v4 v4.1.2 // indirect + github.com/wlynxg/anet v0.0.5 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/otel v1.34.0 // indirect + go.opentelemetry.io/otel/metric v1.34.0 // indirect + go.opentelemetry.io/otel/trace v1.34.0 // indirect + go.uber.org/mock v0.5.2 // indirect + golang.org/x/time v0.12.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + source.quilibrium.com/quilibrium/monorepo/consensus v0.0.0-00010101000000-000000000000 // indirect + source.quilibrium.com/quilibrium/monorepo/protobufs v0.0.0-00010101000000-000000000000 // indirect + source.quilibrium.com/quilibrium/monorepo/types v0.0.0-00010101000000-000000000000 // indirect + source.quilibrium.com/quilibrium/monorepo/utils v0.0.0-00010101000000-000000000000 // indirect +) + +require ( + github.com/gorilla/websocket v1.5.3 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect + github.com/multiformats/go-multiaddr v0.16.1 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect +) + +require ( + github.com/benbjohnson/clock v1.3.5 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cloudflare/circl v1.6.1 // indirect + github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect + github.com/flynn/noise v1.1.0 // indirect + github.com/francoispqt/gojay v1.2.13 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/gopacket v1.1.19 // indirect + github.com/google/uuid v1.6.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/iden3/go-iden3-crypto v0.0.17 // indirect + github.com/ipfs/boxo v0.10.0 // indirect + github.com/ipfs/go-cid v0.5.0 // indirect + github.com/ipfs/go-datastore v0.8.2 // 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/klauspost/compress v1.18.0 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/koron/go-ssdp v0.0.6 // 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.2.0 // indirect + github.com/libp2p/go-libp2p-asn-util v0.4.1 // 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-msgio v0.3.0 // indirect + github.com/libp2p/go-netroute v0.2.2 // indirect + github.com/libp2p/go-reuseport v0.4.0 // 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.66 // 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/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.4.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.1 // indirect + github.com/multiformats/go-multihash v0.2.3 // indirect + github.com/multiformats/go-multistream v0.6.1 // indirect + github.com/multiformats/go-varint v0.0.7 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/polydawn/refmt v0.89.0 // indirect + github.com/prometheus/client_golang v1.22.0 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.64.0 // indirect + github.com/prometheus/procfs v0.16.1 // indirect + github.com/quic-go/qpack v0.5.1 // indirect + github.com/quic-go/quic-go v0.54.0 // indirect + github.com/quic-go/webtransport-go v0.9.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.uber.org/dig v1.19.0 // indirect + go.uber.org/fx v1.24.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 + golang.org/x/crypto v0.39.0 // indirect + golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 // indirect + golang.org/x/mod v0.25.0 // indirect + golang.org/x/net v0.41.0 // indirect + golang.org/x/sync v0.15.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.26.0 // indirect + golang.org/x/tools v0.34.0 // indirect + gonum.org/v1/gonum v0.13.0 // indirect + google.golang.org/grpc v1.72.0 // indirect + lukechampine.com/blake3 v1.4.1 // indirect +) diff --git a/conntest/go.sum b/conntest/go.sum new file mode 100644 index 00000000..9716ffd4 --- /dev/null +++ b/conntest/go.sum @@ -0,0 +1,692 @@ +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= +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/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.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/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= +github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +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.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= +github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +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/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.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/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-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +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/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/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.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +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.3/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/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +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/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.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.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/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= +github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= +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/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.17 h1:NdkceRLJo/pI4UpcjVah4lN/a3yzxRUGXqxbWcYh9mY= +github.com/iden3/go-iden3-crypto v0.0.17/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E= +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.5.0 h1:goEKKhaGm0ul11IHA7I6p1GmKz8kEYniqFopaB5Otwg= +github.com/ipfs/go-cid v0.5.0/go.mod h1:0L7vmeNXpQpUS9vt+yEARkJ8rOg43DF3iPgn4GIN0mk= +github.com/ipfs/go-datastore v0.8.2 h1:Jy3wjqQR6sg/LhyY0NIePZC3Vux19nLtg7dx0TVqr6U= +github.com/ipfs/go-datastore v0.8.2/go.mod h1:W+pI1NsUsz3tcsAACMtfC+IZdnQTnC/7VfPoJBQuts0= +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-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= +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.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.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +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.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/koron/go-ssdp v0.0.6 h1:Jb0h04599eq/CY7rB5YEqPS83HmRfHP2azkxMN2rFtU= +github.com/koron/go-ssdp v0.0.6/go.mod h1:0R9LfRJGek1zWTjN3JUNlm5INCDYGpRDfAptnct63fI= +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/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +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.2.0 h1:EIZzjmeOE6c8Dav0sNv35vhZxATIXWZg6j/C08XmmDw= +github.com/libp2p/go-flow-metrics v0.2.0/go.mod h1:st3qqfu8+pMfh+9Mzqb2GTiwrAGjIPszEjZmtksN8Jc= +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-netroute v0.2.2 h1:Dejd8cQ47Qx2kRABg6lPwknU7+nBnFRpko45/fFPuZ8= +github.com/libp2p/go-netroute v0.2.2/go.mod h1:Rntq6jUAH0l9Gg17w5bFGhcC9a+vk4KNXs6s7IljKYE= +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/v5 v5.0.1 h1:f0WoX/bEF2E8SbE4c/k1Mo+/9z0O4oC/hWEA+nfYRSg= +github.com/libp2p/go-yamux/v5 v5.0.1/go.mod h1:en+3cdX51U0ZslwRdRLrvQsdayFt3TSUKvBGErzpWbU= +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/marcopolo/simnet v0.0.1 h1:rSMslhPz6q9IvJeFWDoMGxMIrlsbXau3NkuIXHGJxfg= +github.com/marcopolo/simnet v0.0.1/go.mod h1:WDaQkgLAjqDUEBAOXz22+1j6wXKfGlC5sD5XWt3ddOs= +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.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE= +github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE= +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-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.1 h1:x/Fuxr7ZuR4jJV4Os5g444F7xC4XmyUaT/FWtE+9Zjo= +github.com/multiformats/go-multicodec v0.9.1/go.mod h1:LLWNMtyV5ithSBUo3vFIMaeDy+h3EbkMTek1m+Fybbo= +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.6.1 h1:4aoX5v6T+yWmc2raBHsTvzmFhOI8WVOer28DeBBEYdQ= +github.com/multiformats/go-multistream v0.6.1/go.mod h1:ksQf6kqHAb6zIsyw7Zm+gAuVo57Qbq84E27YlYqavqw= +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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +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/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/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o= +github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= +github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= +github.com/pion/dtls/v3 v3.0.6 h1:7Hkd8WhAJNbRgq9RgdNh1aaWlZlGpYTzdqjy9x9sK2E= +github.com/pion/dtls/v3 v3.0.6/go.mod h1:iJxNQ3Uhn1NZWOMWlLxEEHAN5yX7GyPvvKw04v9bzYU= +github.com/pion/ice/v4 v4.0.10 h1:P59w1iauC/wPk9PdY8Vjl4fOFL5B+USq1+xbDcN6gT4= +github.com/pion/ice/v4 v4.0.10/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= +github.com/pion/interceptor v0.1.40 h1:e0BjnPcGpr2CFQgKhrQisBU7V3GXK6wrfYrGYaU6Jq4= +github.com/pion/interceptor v0.1.40/go.mod h1:Z6kqH7M/FYirg3frjGJ21VLSRJGBXB/KqaTIrdqnOic= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI= +github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90= +github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM= +github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA= +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.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= +github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= +github.com/pion/rtp v1.8.19 h1:jhdO/3XhL/aKm/wARFVmvTfq0lC/CvN1xwYKmduly3c= +github.com/pion/rtp v1.8.19/go.mod h1:bAu2UFKScgzyFqvUKmbvzSdPr+NGbZtv6UB2hesqXBk= +github.com/pion/sctp v1.8.39 h1:PJma40vRHa3UTO3C4MyeJDQ+KIobVYRZQZ0Nt7SjQnE= +github.com/pion/sctp v1.8.39/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE= +github.com/pion/sdp/v3 v3.0.13 h1:uN3SS2b+QDZnWXgdr69SM8KB4EbcnPnPf2Laxhty/l4= +github.com/pion/sdp/v3 v3.0.13/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E= +github.com/pion/srtp/v3 v3.0.6 h1:E2gyj1f5X10sB/qILUGIkL4C2CqK269Xq167PbGCc/4= +github.com/pion/srtp/v3 v3.0.6/go.mod h1:BxvziG3v/armJHAaJ87euvkhHqWe9I7iiOy50K2QkhY= +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/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw= +github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= +github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= +github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0= +github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= +github.com/pion/turn/v4 v4.0.2 h1:ZqgQ3+MjP32ug30xAbD6Mn+/K4Sxi3SdNOTFf+7mpps= +github.com/pion/turn/v4 v4.0.2/go.mod h1:pMMKP/ieNAG/fN5cZiN4SDuyKsXtNTr0ccN7IToA1zs= +github.com/pion/webrtc/v4 v4.1.2 h1:mpuUo/EJ1zMNKGE79fAdYNFZBX790KE7kQQpLMjjR54= +github.com/pion/webrtc/v4 v4.1.2/go.mod h1:xsCXiNAmMEjIdFxAYU0MbB3RwRieJsegSB2JZsGN+8U= +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.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +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.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4= +github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= +github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= +github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg= +github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= +github.com/quic-go/webtransport-go v0.9.0 h1:jgys+7/wm6JarGDrW+lD/r9BGqBAmqY/ssklE09bA70= +github.com/quic-go/webtransport-go v0.9.0/go.mod h1:4FUYIiUc75XSsF6HShcLeXXYZJ9AGwo/xh3L8M/P1ao= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +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= +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/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/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/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.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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.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.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/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= +github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= +github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= +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/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +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.19.0 h1:BACLhebsYdpQ7IROQ1AGPjrXcP5dF80U3gKoFzbaq/4= +go.uber.org/dig v1.19.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= +go.uber.org/fx v1.24.0 h1:wE8mruvpg2kiiL1Vqd0CC+tr0/24XIB10Iwp2lLWzkg= +go.uber.org/fx v1.24.0/go.mod h1:AmDeGyS+ZARGKM4tlH4FY2Jr63VjbEDJHtqXTGP5hbo= +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.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= +go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= +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-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-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.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +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.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +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-20250606033433-dcc06ee1d476 h1:bsqhLWFR6G6xiQcb+JoGqdKdRU6WzPWmK8E0jxTjzo4= +golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= +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.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +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.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +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.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +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.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +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-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-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.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.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.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +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.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +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.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +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.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.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/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +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.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +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= +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.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +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/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= +google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= +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.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= +google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +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.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +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-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/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.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/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= +lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo= +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= diff --git a/conntest/main.go b/conntest/main.go new file mode 100644 index 00000000..a16059b9 --- /dev/null +++ b/conntest/main.go @@ -0,0 +1,70 @@ +package main + +import ( + "bufio" + "encoding/hex" + "flag" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/libp2p/go-libp2p/core/peer" + "go.uber.org/zap" + "source.quilibrium.com/quilibrium/monorepo/config" + "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb" + "source.quilibrium.com/quilibrium/monorepo/node/p2p" +) + +var ( + configDirectory = flag.String( + "config", + filepath.Join(".", ".config"), + "the configuration directory", + ) +) + +func main() { + flag.Parse() + cfg, err := config.LoadConfig(*configDirectory, "", false) + + if err != nil { + panic(err) + } + + logger, _ := zap.NewProduction() + pubsub := p2p.NewBlossomSub(cfg.P2P, cfg.Engine, logger, 0) + fmt.Print("Enter bitmask in hex (no 0x prefix): ") + reader := bufio.NewReader(os.Stdin) + bitmaskHex, _ := reader.ReadString('\n') + bitmaskHex = strings.TrimRight(bitmaskHex, "\n") + logger.Info("subscribing to bitmask") + + bitmask, err := hex.DecodeString(bitmaskHex) + if err != nil { + panic(err) + } + + err = pubsub.Subscribe(bitmask, func(message *pb.Message) error { + logger.Info( + "received message", + zap.String("bitmask", hex.EncodeToString(message.Bitmask)), + zap.String("peer", peer.ID(message.From).String()), + zap.String("message", string(message.Data)), + ) + return nil + }) + if err != nil { + panic(err) + } + + for { + fmt.Print(peer.ID(pubsub.GetPeerID()).String() + "> ") + message, _ := reader.ReadString('\n') + message = strings.TrimRight(message, "\n") + err = pubsub.PublishToBitmask(bitmask, []byte(message)) + if err != nil { + logger.Error("error sending", zap.Error(err)) + } + } +} diff --git a/consensus/state_machine.go b/consensus/state_machine.go index 4573aaef..77d187c3 100644 --- a/consensus/state_machine.go +++ b/consensus/state_machine.go @@ -535,6 +535,7 @@ func (sm *StateMachine[ fmt.Sprintf("error encountered in %s", sm.machineState), err, ) + sm.SendEvent(EventInduceSync) return } sm.mu.Lock() @@ -567,12 +568,14 @@ func (sm *StateMachine[ ), ) + time.Sleep(100 * time.Millisecond) err := sm.livenessProvider.SendLiveness(data, collected, ctx) if err != nil { sm.traceLogger.Error( fmt.Sprintf("error encountered in %s", sm.machineState), err, ) + sm.SendEvent(EventInduceSync) return } }, @@ -587,9 +590,11 @@ func (sm *StateMachine[ defer sm.traceLogger.Trace("exit Proving behavior") sm.mu.Lock() collected := sm.collected + sm.collected = nil sm.mu.Unlock() if collected == nil { + sm.SendEvent(EventInduceSync) return } @@ -604,6 +609,7 @@ func (sm *StateMachine[ err, ) + sm.SendEvent(EventInduceSync) return } @@ -642,9 +648,12 @@ func (sm *StateMachine[ fmt.Sprintf("error encountered in %s", sm.machineState), err, ) + sm.SendEvent(EventInduceSync) return } sm.SendEvent(EventPublishComplete) + } else { + sm.mu.Unlock() } }, Timeout: 1 * time.Second, @@ -672,7 +681,13 @@ func (sm *StateMachine[ } if len(sm.proposals[(*sm.activeState).Rank()+1]) < int(sm.minimumProvers()) { - sm.traceLogger.Trace("insufficient proposal count") + sm.traceLogger.Trace( + fmt.Sprintf( + "insufficient proposal count: %d, need %d", + len(sm.proposals[(*sm.activeState).Rank()+1]), + int(sm.minimumProvers()), + ), + ) sm.mu.Unlock() return } @@ -706,6 +721,7 @@ func (sm *StateMachine[ fmt.Sprintf("error encountered in %s", sm.machineState), err, ) + sm.SendEvent(EventInduceSync) break } sm.mu.Lock() @@ -738,6 +754,7 @@ func (sm *StateMachine[ fmt.Sprintf("error encountered in %s", sm.machineState), err, ) + sm.SendEvent(EventInduceSync) return } @@ -784,6 +801,7 @@ func (sm *StateMachine[ fmt.Sprintf("error encountered in %s", sm.machineState), err, ) + sm.SendEvent(EventInduceSync) return } next := (*finalized).Clone().(StateT) @@ -812,6 +830,8 @@ func (sm *StateMachine[ fmt.Sprintf("error encountered in %s", sm.machineState), err, ) + sm.SendEvent(EventInduceSync) + return } sm.mu.Lock() } diff --git a/crates/vdf/src/lib.rs b/crates/vdf/src/lib.rs index 3d488f17..46a43c3c 100644 --- a/crates/vdf/src/lib.rs +++ b/crates/vdf/src/lib.rs @@ -262,3 +262,117 @@ pub fn wesolowski_verify(int_size_bits: u16, challenge: &[u8], difficulty: u32, let vdf = WesolowskiVDFParams(int_size_bits).new(); vdf.verify(challenge, difficulty.into(), alleged_solution).is_ok() } + +/// Solve (single worker `i`) with Wesolowski using ID-bound base and a shared prime `b`. +/// Produces this worker’s blob in the same layout as `wesolowski_solve`: `[y_i | π_i]`. +pub fn wesolowski_solve_multi( + int_size_bits: u16, + challenge: &[u8], + difficulty: u32, + ids: &Vec>, + i: u32, +) -> Vec { + use classgroup::{gmp_classgroup::GmpClassGroup, BigNumExt, ClassGroup}; + use crate::proof_of_time::serialize; + use crate::proof_wesolowski::{commit_ids, hash_prime_fixed, worker_prove_id_bound}; + + assert!(!ids.is_empty(), "ids must be non-empty"); + assert!((i as usize) < ids.len(), "worker index out of range"); + + // Bind the entire ID set and derive shared prime b + let ids_commitment = commit_ids(&ids); + let b = hash_prime_fixed::<::BigNum>( + challenge, + int_size_bits, + difficulty as u64, + &ids_commitment, + ); + + // This worker runs its own chain on its ID-bound base + let (y_i, pi_i) = worker_prove_id_bound::<::BigNum, GmpClassGroup>( + challenge, + int_size_bits, + difficulty as u64, + &ids[i as usize], + &b, + ); + + serialize(&[pi_i], &y_i, int_size_bits as usize) +} + +/// Verify all workers in one shot from their individual blobs. +/// `alleged_solutions` must be parallel to `ids`, each entry a `[y_i | π_i]` blob +/// produced by `wesolowski_solve_multi` for that same `id`. +pub fn wesolowski_verify_multi( + int_size_bits: u16, + challenge: &[u8], + difficulty: u32, + ids: &Vec>, + alleged_solutions: &Vec>, +) -> bool { + use classgroup::{gmp_classgroup::GmpClassGroup, BigNum, BigNumExt, ClassGroup}; + use crate::proof_wesolowski::{commit_ids, hash_prime_fixed, hash_to_exponent}; + + // Basic shape checks + if ids.is_empty() || ids.len() != alleged_solutions.len() { return false; } + if (usize::MAX - 16) < int_size_bits as usize { return false; } + let elem_units = ((int_size_bits as usize) + 16) >> 4; // element is 2 * elem_units bytes + if elem_units == 0 { return false; } + let element_len = elem_units * 2; + let blob_len = element_len * 2; // [y | π] + + // Discriminant and canonical base x + let disc: ::BigNum = create_discriminant(challenge, int_size_bits); + let x = GmpClassGroup::from_ab_discriminant(2.into(), 1.into(), disc.clone()); + + // Fixed prime b from (challenge, bits, t, ids_commitment) + let ids_slices: Vec<&[u8]> = ids.iter().map(|v| v.as_slice()).collect(); + let ids_commitment = commit_ids(&ids_slices); + let b = hash_prime_fixed::<::BigNum>( + challenge, + int_size_bits, + difficulty as u64, + &ids_commitment, + ); + + let two = <::BigNum>::from(2u64); + if !(b > two) { return false; } + + // r = 2^t mod b + let mut r = <::BigNum>::from(0u64); + r.mod_powm( + &<::BigNum>::from(2u64), + &<::BigNum>::from(difficulty as u64), + &b, + ); + + // Aggregate Y = ∏ y_i and Π = ∏ π_i; compute S = Σ h_i + let (first_id, first_blob) = (&ids[0], &alleged_solutions[0]); + if first_blob.len() != blob_len { return false; } + let (y0_bytes, pi0_bytes) = first_blob.split_at(element_len); + let mut y_agg = GmpClassGroup::from_bytes(y0_bytes, disc.clone()); + let mut pi_agg = GmpClassGroup::from_bytes(pi0_bytes, disc.clone()); + let mut S = hash_to_exponent::<::BigNum>(challenge, first_id.as_slice()); + + + for (id_bytes, blob) in ids.iter().zip(alleged_solutions.iter()).skip(1) { + if blob.len() != blob_len { return false; } + let (y_bytes, pi_bytes) = blob.split_at(element_len); + let y_i = GmpClassGroup::from_bytes(y_bytes, disc.clone()); + let pi_i = GmpClassGroup::from_bytes(pi_bytes, disc.clone()); + y_agg = &y_agg * &y_i; + pi_agg = &pi_agg * &pi_i; + S = S + hash_to_exponent::<::BigNum>(challenge, id_bytes.as_slice()); + } + + // Single aggregated check: Π^b * x^{ r * S } ?= Y + let mut lhs = pi_agg.clone(); + lhs.pow(b.clone()); // Π^b + + let mut x_exp = x.clone(); + x_exp.pow(r * S); // x^{r*S} + + lhs *= &x_exp; + + lhs == y_agg +} \ No newline at end of file diff --git a/crates/vdf/src/lib.udl b/crates/vdf/src/lib.udl index 66c0d18b..69ae4aa7 100644 --- a/crates/vdf/src/lib.udl +++ b/crates/vdf/src/lib.udl @@ -1,4 +1,6 @@ namespace vdf { sequence wesolowski_solve(u16 int_size_bits, [ByRef] sequence challenge, u32 difficulty); boolean wesolowski_verify(u16 int_size_bits, [ByRef] sequence challenge, u32 difficulty, [ByRef] sequence alleged_solution); + sequence wesolowski_solve_multi(u16 int_size_bits, [ByRef] sequence challenge, u32 difficulty, [ByRef] sequence> ids, u32 i); + boolean wesolowski_verify_multi(u16 int_size_bits, [ByRef] sequence challenge, u32 difficulty, [ByRef] sequence> ids, [ByRef] sequence> alleged_solutions); }; diff --git a/crates/vdf/src/proof_wesolowski.rs b/crates/vdf/src/proof_wesolowski.rs index 4e0aca7c..adfedc45 100644 --- a/crates/vdf/src/proof_wesolowski.rs +++ b/crates/vdf/src/proof_wesolowski.rs @@ -106,6 +106,61 @@ fn u64_to_bytes(q: u64) -> [u8; 8] { } } +/// Quote: +/// +/// > Commit to a list of IDs so order cannot be mutated by the aggregator. +pub fn commit_ids(ids: &[impl AsRef<[u8]>]) -> [u8; 32] { + let mut ids_sorted: Vec<&[u8]> = ids.iter().map(|x| x.as_ref()).collect(); + ids_sorted.sort_unstable(); + let mut hasher = Sha256::new(); + hasher.input(b"wesolowski-ids-multicommit"); + for id in ids_sorted { + hasher.input((id.len() as u64).to_be_bytes()); + hasher.input(id); + } + hasher.fixed_result().into() +} + +/// Quote: +/// +/// > Creates a random prime based on input challenge and ids_commitment. +pub fn hash_prime_fixed( + challenge: &[u8], + int_size_bits: u16, + t: u64, + ids_commitment: &[u8; 32], +) -> T { + let mut j = 0u64; + loop { + let mut hasher = Sha256::new(); + hasher.input(b"wesolowski-fixed-multicommit"); + hasher.input(challenge); + hasher.input(int_size_bits.to_be_bytes()); + hasher.input(u64_to_bytes(t)); + hasher.input(ids_commitment); + hasher.input(u64_to_bytes(j)); + let n = T::from(&hasher.fixed_result()[..16]); + if n.probab_prime(1) { + break n; + } + j += 1; + } +} + +pub fn hash_to_exponent(challenge: &[u8], id: &[u8]) -> T { + let mut hasher = Sha256::new(); + hasher.input(b"wesolowski-exp-multicommit"); + hasher.input(challenge); + hasher.input((id.len() as u64).to_be_bytes()); + hasher.input(id); + let bytes = hasher.fixed_result(); + let mut val = T::from(&bytes[..]); + if val == T::from(0u64) { + val = T::from(1u64); + } + val +} + /// Quote: /// /// > Creates a random prime based on input s. @@ -313,3 +368,152 @@ where verify_proof(x, &y, proof, iterations, int_size_bits.into()) } + +pub fn generate_proof_with_fixed_b + Eq + std::hash::Hash>( + x: &V, + iterations: u64, + k: u8, + l: usize, + powers: &U, + b: &T, +) -> V +where + U: for<'a> std::ops::Index<&'a u64, Output = V>, +{ + eval_optimized(x, b, iterations as _, k, l, powers) +} + +/// Per-worker proof on a distinct ID-bound base x_i = x^{h_i}. +/// Returns (y_i, pi_i) where: +/// y_i = x_i^{2^t} +/// pi_i = x_i^{ floor(2^t / b) } (Wesolowski quotient for fixed 'b') +pub fn worker_prove_id_bound( + challenge: &[u8], + int_size_bits: u16, + iterations: u64, + id: &[u8], + b: &TN, +) -> (V /* y_i */, V /* pi_i */) +where + TN: BigNumExt, + V: ClassGroup + Eq + std::hash::Hash + Clone, + for<'a, 'b> &'a V: std::ops::Mul<&'b V, Output = V>, + for<'a, 'b> &'a V::BigNum: std::ops::Mul<&'b V::BigNum, Output = V::BigNum>, +{ + // Canonical base for discriminant + let disc: TN = super::create_discriminant::create_discriminant(challenge, int_size_bits); + let mut x = V::from_ab_discriminant(2.into(), 1.into(), disc.clone()); + + // Distinct base: x_i = x^{h_i} + let h_i = hash_to_exponent::(challenge, id); + x.pow(h_i.clone()); + let (l, k, _) = approximate_parameters(iterations as f64); + let q = l.checked_mul(k as _).expect("k*l overflow"); + + // Squaring checkpoints (as in create_proof_of_time_wesolowski, but for x_i) + let powers = iterate_squarings( + x.clone(), + (0..= (iterations as usize)/q + 1) + .map(|i| (i * q) as u64) + .chain(Some(iterations)), + ); + + let y_i = powers[&iterations].clone(); + let pi_i = generate_proof_with_fixed_b(&x, iterations, k, l, &powers, b); + (y_i, pi_i) +} + +pub struct Aggregated { + pub y_agg: V, // ∏ y_i + pub pi_agg: V, // ∏ pi_i + pub ids_commitment: [u8; 32], + pub m: u64, // number of parts aggregated (optional metadata) + pub _phantom_b: std::marker::PhantomData, +} + +pub fn aggregate_worker_parts(parts: &[(V, V)], ids_commitment: [u8; 32]) -> Aggregated +where + V: ClassGroup + Clone, + for<'a, 'b> &'a V: std::ops::Mul<&'b V, Output = V>, + T: BigNum, +{ + assert!(!parts.is_empty()); + let id_elem = parts[0].0.identity(); + let mut y_agg = id_elem.clone(); + let mut pi_agg = id_elem; + + for (y_i, pi_i) in parts { + y_agg = &y_agg * y_i; + pi_agg = &pi_agg * pi_i; + } + + Aggregated { + y_agg, + pi_agg, + ids_commitment, + m: parts.len() as u64, + _phantom_b: std::marker::PhantomData, + } +} + +pub fn serialize_aggregated(agg: &Aggregated, int_size_bits: usize) -> Vec { + super::proof_of_time::serialize(&[agg.pi_agg.clone()], &agg.y_agg, int_size_bits) +} + +/// Verify a single aggregated proof built from ID-bound bases. +/// Inputs: +/// - challenge, int_size_bits, iterations (t) +/// - the sorted list of IDs +/// - aggregated y, π +/// +/// Check: +/// Y == Π^b * x^{ r * S } +/// where: +/// b = HashPrimeFixed(challenge, int_size_bits, t, commit_ids(ids)) +/// r = 2^t mod b +/// S = sum_i HashToExponent(challenge, id_i) +pub fn verify_aggregated( + challenge: &[u8], + int_size_bits: u16, + iterations: u64, + ids: &[impl AsRef<[u8]>], + y_agg: &V, + pi_agg: &V, +) -> Result<(), ()> +where + TN: BigNumExt, + V: ClassGroup + Clone + Eq, + for<'a, 'b> &'a V: std::ops::Mul<&'b V, Output = V>, + for<'a, 'b> &'a V::BigNum: std::ops::Mul<&'b V::BigNum, Output = V::BigNum>, +{ + // canonical base 'x' for the discriminant + let disc: TN = super::create_discriminant::create_discriminant(challenge, int_size_bits); + let x = V::from_ab_discriminant(2.into(), 1.into(), disc.clone()); + + // derive shared prime 'b' from the committed ID set + let ids_commitment = commit_ids(ids); + let b = hash_prime_fixed::(challenge, int_size_bits, iterations, &ids_commitment); + + // r = 2^t mod b + let mut r = TN::from(0); + r.mod_powm(&TN::from(2u64), &TN::from(iterations), &b); + + // S = sum_i h_i + let mut S = TN::from(0); + for id in ids { + let hi = hash_to_exponent::(challenge, id.as_ref()); + S = S + hi; + } + + // lhs = pi_agg^b * x^{ r * S } + let mut lhs = pi_agg.clone(); + lhs.pow(b.clone()); + + let rS = r * S; + let mut xrS = x.clone(); + xrS.pow(rS); + + lhs *= &xrS; + + if &lhs == y_agg { Ok(()) } else { Err(()) } +} \ No newline at end of file diff --git a/go-libp2p/examples/p2p-ping/.gitignore b/go-libp2p/examples/p2p-ping/.gitignore new file mode 100644 index 00000000..0ae51650 --- /dev/null +++ b/go-libp2p/examples/p2p-ping/.gitignore @@ -0,0 +1,2 @@ +p2p-ping +addresses.txt diff --git a/go-libp2p/examples/p2p-ping/README.md b/go-libp2p/examples/p2p-ping/README.md new file mode 100644 index 00000000..ff8aa4a7 --- /dev/null +++ b/go-libp2p/examples/p2p-ping/README.md @@ -0,0 +1,75 @@ +# P2P Ping Tool + +A libp2p client tool for testing peer connectivity by pinging multiple peers from a list of multiaddresses. + +## Features + +- **Batch ping testing**: Read multiaddresses from stdin and ping each once +- **DNS resolution**: Supports DNS-based multiaddresses (e.g., `/dns/example.com/...`) +- **Real-time reporting**: Shows success/failure for each address immediately +- **Summary statistics**: Displays overall success rate +- **Client-only**: Lightweight client that doesn't listen for incoming connections + +## Usage + +### From stdin (interactive) +```bash +go run . +# Enter multiaddresses one per line, then Ctrl+D +``` + +### From file +```bash +go run . < addresses.txt +``` + +### From command line +```bash +echo "/ip4/127.0.0.1/tcp/4001/p2p/12D3KooW..." | go run . +``` + +### Multiple addresses +```bash +cat << EOF | go run . -timeout 5s +/ip4/127.0.0.1/tcp/4001/p2p/12D3KooWExample1 +/dns/bootstrap.example.com/udp/8336/quic-v1/p2p/12D3KooWExample2 +/ip6/::1/tcp/4001/p2p/12D3KooWExample3 +EOF +``` + +## Options + +- `-timeout duration`: Connection and ping timeout (default: 10s) + +## Output Format + +``` +P2P Ping Tool - Reading multiaddresses from stdin... +Client started (ID: 12D3KooW...) +============================================================= +[1] Testing: /ip4/127.0.0.1/tcp/4001/p2p/12D3KooWExample + ✓ SUCCESS - RTT: 15ms + +[2] Testing: /dns/unreachable.com/tcp/4001/p2p/12D3KooWBad + ✗ FAILED - DNS resolution failed: lookup unreachable.com... + +============================================================= +Summary: 2 addresses tested +Successful: 1/2 (50.0%) +``` + +## Supported Multiaddr Formats + +- IPv4: `/ip4/127.0.0.1/tcp/4001/p2p/[PEER_ID]` +- IPv6: `/ip6/::1/tcp/4001/p2p/[PEER_ID]` +- DNS: `/dns/example.com/tcp/4001/p2p/[PEER_ID]` +- DNS with QUIC: `/dns/example.com/udp/8336/quic-v1/p2p/[PEER_ID]` + +## Error Handling + +The tool provides detailed error messages for common failure scenarios: + +- **Invalid multiaddr**: Malformed multiaddress syntax +- **DNS resolution failed**: DNS hostname cannot be resolved +- **Connection failed**: Cannot establish connection to peer +- **Ping failed**: Connected but ping protocol failed diff --git a/go-libp2p/examples/p2p-ping/go.mod b/go-libp2p/examples/p2p-ping/go.mod new file mode 100644 index 00000000..5b0a1384 --- /dev/null +++ b/go-libp2p/examples/p2p-ping/go.mod @@ -0,0 +1,103 @@ +module github.com/libp2p/go-libp2p/examples/p2p-ping + +go 1.23.2 + +replace github.com/libp2p/go-libp2p => ../../ + +replace github.com/multiformats/go-multiaddr => ../../../go-multiaddr + +replace github.com/multiformats/go-multiaddr-dns => ../../../go-multiaddr-dns + +require ( + github.com/libp2p/go-libp2p v0.0.0 + github.com/multiformats/go-multiaddr v0.16.0 + github.com/multiformats/go-multiaddr-dns v0.4.1 +) + +require ( + github.com/benbjohnson/clock v1.3.5 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cloudflare/circl v1.6.1 // indirect + github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect + github.com/flynn/noise v1.1.0 // indirect + github.com/francoispqt/gojay v1.2.13 // indirect + github.com/google/gopacket v1.1.19 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.3 // indirect + github.com/huin/goupnp v1.3.0 // indirect + github.com/ipfs/go-cid v0.5.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/klauspost/compress v1.18.0 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/koron/go-ssdp v0.0.6 // indirect + github.com/libp2p/go-buffer-pool v0.1.0 // indirect + github.com/libp2p/go-flow-metrics v0.2.0 // indirect + github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect + github.com/libp2p/go-msgio v0.3.0 // indirect + github.com/libp2p/go-netroute v0.2.2 // indirect + github.com/libp2p/go-reuseport v0.4.0 // indirect + github.com/libp2p/go-yamux/v5 v5.0.1 // indirect + github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect + github.com/miekg/dns v1.1.66 // 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/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-fmt v0.1.0 // indirect + github.com/multiformats/go-multibase v0.2.0 // indirect + github.com/multiformats/go-multicodec v0.9.1 // indirect + github.com/multiformats/go-multihash v0.2.3 // indirect + github.com/multiformats/go-multistream v0.6.1 // indirect + github.com/multiformats/go-varint v0.0.7 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect + github.com/pion/datachannel v1.5.10 // indirect + github.com/pion/dtls/v2 v2.2.12 // indirect + github.com/pion/dtls/v3 v3.0.6 // indirect + github.com/pion/ice/v4 v4.0.10 // indirect + github.com/pion/interceptor v0.1.40 // indirect + github.com/pion/logging v0.2.3 // indirect + github.com/pion/mdns/v2 v2.0.7 // indirect + github.com/pion/randutil v0.1.0 // indirect + github.com/pion/rtcp v1.2.15 // indirect + github.com/pion/rtp v1.8.19 // indirect + github.com/pion/sctp v1.8.39 // indirect + github.com/pion/sdp/v3 v3.0.13 // indirect + github.com/pion/srtp/v3 v3.0.6 // indirect + github.com/pion/stun v0.6.1 // indirect + github.com/pion/stun/v3 v3.0.0 // indirect + github.com/pion/transport/v2 v2.2.10 // indirect + github.com/pion/transport/v3 v3.0.7 // indirect + github.com/pion/turn/v4 v4.0.2 // indirect + github.com/pion/webrtc/v4 v4.1.2 // indirect + github.com/prometheus/client_golang v1.22.0 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.64.0 // indirect + github.com/prometheus/procfs v0.16.1 // indirect + github.com/quic-go/qpack v0.5.1 // indirect + github.com/quic-go/quic-go v0.54.0 // indirect + github.com/quic-go/webtransport-go v0.9.0 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/wlynxg/anet v0.0.5 // indirect + go.uber.org/dig v1.19.0 // indirect + go.uber.org/fx v1.24.0 // indirect + go.uber.org/mock v0.5.2 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/crypto v0.39.0 // indirect + golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 // indirect + golang.org/x/mod v0.25.0 // indirect + golang.org/x/net v0.41.0 // indirect + golang.org/x/sync v0.15.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.26.0 // indirect + golang.org/x/time v0.12.0 // indirect + golang.org/x/tools v0.34.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect + lukechampine.com/blake3 v1.4.1 // indirect +) diff --git a/go-libp2p/examples/p2p-ping/go.sum b/go-libp2p/examples/p2p-ping/go.sum new file mode 100644 index 00000000..eac61b2d --- /dev/null +++ b/go-libp2p/examples/p2p-ping/go.sum @@ -0,0 +1,493 @@ +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= +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/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +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/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= +github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +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.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= +github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +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/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/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +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/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +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.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +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/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.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/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.5.0 h1:goEKKhaGm0ul11IHA7I6p1GmKz8kEYniqFopaB5Otwg= +github.com/ipfs/go-cid v0.5.0/go.mod h1:0L7vmeNXpQpUS9vt+yEARkJ8rOg43DF3iPgn4GIN0mk= +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= +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/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +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.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/koron/go-ssdp v0.0.6 h1:Jb0h04599eq/CY7rB5YEqPS83HmRfHP2azkxMN2rFtU= +github.com/koron/go-ssdp v0.0.6/go.mod h1:0R9LfRJGek1zWTjN3JUNlm5INCDYGpRDfAptnct63fI= +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/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= +github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= +github.com/libp2p/go-flow-metrics v0.2.0 h1:EIZzjmeOE6c8Dav0sNv35vhZxATIXWZg6j/C08XmmDw= +github.com/libp2p/go-flow-metrics v0.2.0/go.mod h1:st3qqfu8+pMfh+9Mzqb2GTiwrAGjIPszEjZmtksN8Jc= +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-netroute v0.2.2 h1:Dejd8cQ47Qx2kRABg6lPwknU7+nBnFRpko45/fFPuZ8= +github.com/libp2p/go-netroute v0.2.2/go.mod h1:Rntq6jUAH0l9Gg17w5bFGhcC9a+vk4KNXs6s7IljKYE= +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/v5 v5.0.1 h1:f0WoX/bEF2E8SbE4c/k1Mo+/9z0O4oC/hWEA+nfYRSg= +github.com/libp2p/go-yamux/v5 v5.0.1/go.mod h1:en+3cdX51U0ZslwRdRLrvQsdayFt3TSUKvBGErzpWbU= +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/marcopolo/simnet v0.0.1 h1:rSMslhPz6q9IvJeFWDoMGxMIrlsbXau3NkuIXHGJxfg= +github.com/marcopolo/simnet v0.0.1/go.mod h1:WDaQkgLAjqDUEBAOXz22+1j6wXKfGlC5sD5XWt3ddOs= +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/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.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE= +github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE= +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-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.1 h1:x/Fuxr7ZuR4jJV4Os5g444F7xC4XmyUaT/FWtE+9Zjo= +github.com/multiformats/go-multicodec v0.9.1/go.mod h1:LLWNMtyV5ithSBUo3vFIMaeDy+h3EbkMTek1m+Fybbo= +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.6.1 h1:4aoX5v6T+yWmc2raBHsTvzmFhOI8WVOer28DeBBEYdQ= +github.com/multiformats/go-multistream v0.6.1/go.mod h1:ksQf6kqHAb6zIsyw7Zm+gAuVo57Qbq84E27YlYqavqw= +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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +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/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/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o= +github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= +github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= +github.com/pion/dtls/v3 v3.0.6 h1:7Hkd8WhAJNbRgq9RgdNh1aaWlZlGpYTzdqjy9x9sK2E= +github.com/pion/dtls/v3 v3.0.6/go.mod h1:iJxNQ3Uhn1NZWOMWlLxEEHAN5yX7GyPvvKw04v9bzYU= +github.com/pion/ice/v4 v4.0.10 h1:P59w1iauC/wPk9PdY8Vjl4fOFL5B+USq1+xbDcN6gT4= +github.com/pion/ice/v4 v4.0.10/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= +github.com/pion/interceptor v0.1.40 h1:e0BjnPcGpr2CFQgKhrQisBU7V3GXK6wrfYrGYaU6Jq4= +github.com/pion/interceptor v0.1.40/go.mod h1:Z6kqH7M/FYirg3frjGJ21VLSRJGBXB/KqaTIrdqnOic= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI= +github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90= +github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM= +github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA= +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.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= +github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= +github.com/pion/rtp v1.8.19 h1:jhdO/3XhL/aKm/wARFVmvTfq0lC/CvN1xwYKmduly3c= +github.com/pion/rtp v1.8.19/go.mod h1:bAu2UFKScgzyFqvUKmbvzSdPr+NGbZtv6UB2hesqXBk= +github.com/pion/sctp v1.8.39 h1:PJma40vRHa3UTO3C4MyeJDQ+KIobVYRZQZ0Nt7SjQnE= +github.com/pion/sctp v1.8.39/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE= +github.com/pion/sdp/v3 v3.0.13 h1:uN3SS2b+QDZnWXgdr69SM8KB4EbcnPnPf2Laxhty/l4= +github.com/pion/sdp/v3 v3.0.13/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E= +github.com/pion/srtp/v3 v3.0.6 h1:E2gyj1f5X10sB/qILUGIkL4C2CqK269Xq167PbGCc/4= +github.com/pion/srtp/v3 v3.0.6/go.mod h1:BxvziG3v/armJHAaJ87euvkhHqWe9I7iiOy50K2QkhY= +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/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw= +github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= +github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= +github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0= +github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= +github.com/pion/turn/v4 v4.0.2 h1:ZqgQ3+MjP32ug30xAbD6Mn+/K4Sxi3SdNOTFf+7mpps= +github.com/pion/turn/v4 v4.0.2/go.mod h1:pMMKP/ieNAG/fN5cZiN4SDuyKsXtNTr0ccN7IToA1zs= +github.com/pion/webrtc/v4 v4.1.2 h1:mpuUo/EJ1zMNKGE79fAdYNFZBX790KE7kQQpLMjjR54= +github.com/pion/webrtc/v4 v4.1.2/go.mod h1:xsCXiNAmMEjIdFxAYU0MbB3RwRieJsegSB2JZsGN+8U= +github.com/pkg/errors v0.8.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.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4= +github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= +github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= +github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg= +github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= +github.com/quic-go/webtransport-go v0.9.0 h1:jgys+7/wm6JarGDrW+lD/r9BGqBAmqY/ssklE09bA70= +github.com/quic-go/webtransport-go v0.9.0/go.mod h1:4FUYIiUc75XSsF6HShcLeXXYZJ9AGwo/xh3L8M/P1ao= +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/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +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/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/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/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/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +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.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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +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/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= +github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= +github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= +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/dig v1.19.0 h1:BACLhebsYdpQ7IROQ1AGPjrXcP5dF80U3gKoFzbaq/4= +go.uber.org/dig v1.19.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= +go.uber.org/fx v1.24.0 h1:wE8mruvpg2kiiL1Vqd0CC+tr0/24XIB10Iwp2lLWzkg= +go.uber.org/fx v1.24.0/go.mod h1:AmDeGyS+ZARGKM4tlH4FY2Jr63VjbEDJHtqXTGP5hbo= +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.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= +go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= +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.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= +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-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-20200602180216-279210d13fed/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.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +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.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +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-20250606033433-dcc06ee1d476 h1:bsqhLWFR6G6xiQcb+JoGqdKdRU6WzPWmK8E0jxTjzo4= +golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= +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-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +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.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +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-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-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-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.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +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.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +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-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.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +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-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/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.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.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.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +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.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +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.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +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.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.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/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +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.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +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= +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-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.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.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +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= +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/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/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/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.v3 v3.0.0-20200313102051-9f266ea9e77c/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.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= +lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= +lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo= +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= diff --git a/go-libp2p/examples/p2p-ping/main.go b/go-libp2p/examples/p2p-ping/main.go new file mode 100644 index 00000000..af4e7cfd --- /dev/null +++ b/go-libp2p/examples/p2p-ping/main.go @@ -0,0 +1,203 @@ +package main + +import ( + "bufio" + "context" + "flag" + "fmt" + "log" + "os" + "strings" + "time" + + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/p2p/net/swarm" + "github.com/libp2p/go-libp2p/p2p/protocol/ping" + ma "github.com/multiformats/go-multiaddr" + madns "github.com/multiformats/go-multiaddr-dns" +) + +func main() { + // Command-line flags + var ( + timeout = flag.Duration("timeout", 10*time.Second, "connection and ping timeout") + ) + flag.Parse() + + fmt.Println("P2P Ping Tool - Reading multiaddresses from stdin...") + fmt.Println("Enter multiaddresses one per line (Ctrl+D to finish):") + fmt.Println() + + // Create a minimal libp2p client + client, err := createClient() + if err != nil { + log.Fatal("Failed to create libp2p client:", err) + } + defer client.Close() + + fmt.Printf("Client started (ID: %s)\n", client.ID()) + fmt.Println("=" + strings.Repeat("=", 60)) + + // Create ping service + pingService := ping.NewPingService(client) + + // Read multiaddresses from stdin + scanner := bufio.NewScanner(os.Stdin) + var results []PingResult + lineNum := 0 + + for scanner.Scan() { + lineNum++ + addrStr := strings.TrimSpace(scanner.Text()) + + // Skip empty lines + if addrStr == "" { + continue + } + + fmt.Printf("[%d] Testing: %s\n", lineNum, addrStr) + + result := pingPeer(client, pingService, addrStr, *timeout) + results = append(results, result) + + // Print immediate result + if result.Success { + fmt.Printf(" ✓ SUCCESS - RTT: %v\n", result.RTT) + } else { + fmt.Printf(" ✗ FAILED - %s\n", result.Error) + } + fmt.Println() + } + + if err := scanner.Err(); err != nil { + log.Fatal("Error reading stdin:", err) + } + + // Print summary + fmt.Println("=" + strings.Repeat("=", 60)) + fmt.Printf("Summary: %d addresses tested\n", len(results)) + + successful := 0 + for _, r := range results { + if r.Success { + successful++ + } + } + + fmt.Printf("Successful: %d/%d (%.1f%%)\n", successful, len(results), + float64(successful)/float64(len(results))*100) +} + +type PingResult struct { + Address string + Success bool + RTT time.Duration + Error string +} + +func pingPeer(client host.Host, pingService *ping.PingService, addrStr string, timeout time.Duration) PingResult { + result := PingResult{Address: addrStr} + + // Parse target multiaddr + targetAddr, err := ma.NewMultiaddr(addrStr) + if err != nil { + result.Error = fmt.Sprintf("Invalid multiaddr: %v", err) + return result + } + + // Resolve DNS addresses if present + resolvedAddrs := []ma.Multiaddr{targetAddr} + if madns.Matches(targetAddr) { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + resolved, err := madns.Resolve(ctx, targetAddr) + if err != nil { + result.Error = fmt.Sprintf("DNS resolution failed: %v", err) + return result + } + resolvedAddrs = resolved + } + + // Extract peer ID from the original address + _, peerIDStr := ma.SplitLast(targetAddr) + if peerIDStr == nil || peerIDStr.Protocol().Code != ma.P_P2P { + result.Error = "Multiaddr must end with /p2p/" + return result + } + + peerID, err := peer.Decode(peerIDStr.Value()) + if err != nil { + result.Error = fmt.Sprintf("Invalid peer ID: %v", err) + return result + } + + // Create AddrInfo with resolved addresses (without /p2p/ suffix) + var cleanAddrs []ma.Multiaddr + for _, addr := range resolvedAddrs { + // Remove the /p2p/ suffix if present + if addr.Equal(targetAddr) { + cleanAddr, _ := ma.SplitLast(addr) + cleanAddrs = append(cleanAddrs, cleanAddr) + } else { + cleanAddrs = append(cleanAddrs, addr) + } + } + + targetInfo := &peer.AddrInfo{ + ID: peerID, + Addrs: cleanAddrs, + } + + // Connect to the target peer with timeout + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + err = client.Connect(ctx, *targetInfo) + if err != nil { + result.Error = fmt.Sprintf("Connection failed: %v", err) + return result + } + + // Perform single ping + pingCtx, pingCancel := context.WithTimeout(context.Background(), timeout) + defer pingCancel() + + pingResult := <-pingService.Ping(pingCtx, targetInfo.ID) + if pingResult.Error != nil { + result.Error = fmt.Sprintf("Ping failed: %v", pingResult.Error) + return result + } + + result.Success = true + result.RTT = pingResult.RTT + return result +} + +func createClient() (host.Host, error) { + // Create a minimal libp2p client with no listening addresses + // This makes it a client-only node that can connect to others but doesn't accept connections + opts := []libp2p.Option{ + libp2p.NoListenAddrs, // Don't listen on any addresses - client only + libp2p.SwarmOpts( + swarm.WithUDPBlackHoleSuccessCounter( + &swarm.BlackHoleSuccessCounter{ + N: 8000, + MinSuccesses: 1, + Name: "permissive-udp", + }, + ), + swarm.WithIPv6BlackHoleSuccessCounter( + &swarm.BlackHoleSuccessCounter{ + N: 8000, + MinSuccesses: 1, + Name: "permissive-ip6", + }, + ), + ), + } + + return libp2p.New(opts...) +} diff --git a/go-libp2p/x/simlibp2p/libp2p.go b/go-libp2p/x/simlibp2p/libp2p.go index 454be385..2d1bf171 100644 --- a/go-libp2p/x/simlibp2p/libp2p.go +++ b/go-libp2p/x/simlibp2p/libp2p.go @@ -99,7 +99,7 @@ type BlankHostOpts struct { } func newBlankHost(opts BlankHostOpts) (*wrappedHost, error) { - priv, _, err := crypto.GenerateEd25519Key(rand.Reader) + priv, _, err := crypto.GenerateEd448Key(rand.Reader) if err != nil { return nil, err } @@ -185,9 +185,9 @@ func newBlankHost(opts BlankHostOpts) (*wrappedHost, error) { }, nil } -type NodeLinkSettingsAndCount struct { +type NodeLinkSettingsAndIndex struct { LinkSettings simnet.NodeBiDiLinkSettings - Count int + Idx int } type HostAndIdx struct { @@ -197,6 +197,7 @@ type HostAndIdx struct { type SimpleLibp2pNetworkMeta struct { Nodes []host.Host + Keys []crypto.PrivKey AddrToNode map[string]HostAndIdx } @@ -204,55 +205,63 @@ type NetworkSettings struct { UseBlankHost bool QUICReuseOptsForHostIdx func(idx int) []quicreuse.Option BlankHostOptsForHostIdx func(idx int) BlankHostOpts + OptsForHostIdx func(idx int) []libp2p.Option } -func SimpleLibp2pNetwork(linkSettings []NodeLinkSettingsAndCount, networkSettings NetworkSettings) (*simnet.Simnet, *SimpleLibp2pNetworkMeta, error) { +func SimpleLibp2pNetwork(linkSettings []NodeLinkSettingsAndIndex, networkSettings NetworkSettings) (*simnet.Simnet, *SimpleLibp2pNetworkMeta, error) { nw := &simnet.Simnet{} meta := &SimpleLibp2pNetworkMeta{ AddrToNode: make(map[string]HostAndIdx), } for _, l := range linkSettings { - for i := 0; i < l.Count; i++ { - idx := len(meta.Nodes) - ip := simnet.IntToPublicIPv4(idx) - addr := fmt.Sprintf("/ip4/%s/udp/8000/quic-v1", ip) - var h host.Host - var err error - var quicReuseOpts []quicreuse.Option - if networkSettings.QUICReuseOptsForHostIdx != nil { - quicReuseOpts = networkSettings.QUICReuseOptsForHostIdx(idx) - } - if networkSettings.UseBlankHost { - var opts BlankHostOpts - if networkSettings.BlankHostOptsForHostIdx != nil { - opts = networkSettings.BlankHostOptsForHostIdx(idx) - } + idx := l.Idx + ip := simnet.IntToPublicIPv4(idx) + addr := fmt.Sprintf("/ip4/%s/udp/8000/quic-v1", ip) + var h host.Host + var err error + var quicReuseOpts []quicreuse.Option + if networkSettings.QUICReuseOptsForHostIdx != nil { + quicReuseOpts = networkSettings.QUICReuseOptsForHostIdx(idx) + } + privkey, _, err := crypto.GenerateEd448Key(rand.Reader) + if err != nil { + return nil, nil, err + } - a, _ := multiaddr.StringCast(addr) - h, err = newBlankHost(BlankHostOpts{ - listenMultiaddr: a, - simnet: nw, - linkSettings: l.LinkSettings, - quicReuseOpts: quicReuseOpts, - ConnMgr: opts.ConnMgr, - }) - } else { - h, err = libp2p.New( - libp2p.ListenAddrStrings(addr), - QUICSimnet(nw, l.LinkSettings, quicReuseOpts...), - // TODO: Currently using identify address discovery stalls - // synctest - libp2p.DisableIdentifyAddressDiscovery(), - libp2p.ResourceManager(&network.NullResourceManager{}), - ) + if networkSettings.UseBlankHost { + var opts BlankHostOpts + if networkSettings.BlankHostOptsForHostIdx != nil { + opts = networkSettings.BlankHostOptsForHostIdx(idx) } - if err != nil { - return nil, nil, err - } - meta.Nodes = append(meta.Nodes, h) - meta.AddrToNode[addr] = HostAndIdx{Host: h, Idx: idx} + + a, _ := multiaddr.StringCast(addr) + h, err = newBlankHost(BlankHostOpts{ + listenMultiaddr: a, + simnet: nw, + linkSettings: l.LinkSettings, + quicReuseOpts: quicReuseOpts, + ConnMgr: opts.ConnMgr, + }) + } else { + h, err = libp2p.New( + append( + []libp2p.Option{ + libp2p.ListenAddrStrings(addr), + QUICSimnet(nw, l.LinkSettings, quicReuseOpts...), + libp2p.ResourceManager(&network.NullResourceManager{}), + libp2p.Identity(privkey), + }, + networkSettings.OptsForHostIdx(idx)..., + )..., + ) + } + if err != nil { + return nil, nil, err } + meta.Keys = append(meta.Keys, privkey) + meta.Nodes = append(meta.Nodes, h) + meta.AddrToNode[addr] = HostAndIdx{Host: h, Idx: idx} } return nw, meta, nil diff --git a/hypergraph/hypergraph.go b/hypergraph/hypergraph.go index 4c321d09..51d22dff 100644 --- a/hypergraph/hypergraph.go +++ b/hypergraph/hypergraph.go @@ -12,6 +12,7 @@ import ( "source.quilibrium.com/quilibrium/monorepo/types/crypto" "source.quilibrium.com/quilibrium/monorepo/types/hypergraph" "source.quilibrium.com/quilibrium/monorepo/types/tries" + up2p "source.quilibrium.com/quilibrium/monorepo/utils/p2p" ) // HypergraphCRDT implements a CRDT-based 2P2P-Hypergraph. It maintains separate @@ -164,7 +165,8 @@ func (hg *HypergraphCRDT) ImportTree( } // GetSize returns the current total size of the hypergraph. The size is -// calculated as the sum of all added atoms' data minus removed atoms. +// calculated as the sum of all added atoms' data minus removed atoms (note: +// removed meaning removed from a set, not the atoms in remove sets). func (hg *HypergraphCRDT) GetSize( shardKey *tries.ShardKey, path []int, @@ -172,32 +174,66 @@ func (hg *HypergraphCRDT) GetSize( hg.mu.RLock() defer hg.mu.RUnlock() if shardKey == nil { - return hg.size + sk := tries.ShardKey{ + L1: [3]byte{0, 0, 0}, + L2: [32]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, + }, + } + vas := hg.getVertexAddsSet(sk) + has := hg.getHyperedgeAddsSet(sk) + vrs := hg.getVertexRemovesSet(sk) + hrs := hg.getHyperedgeRemovesSet(sk) + size := new(big.Int).Set(hg.size) + size = size.Sub( + size, + new(big.Int).Add( + new(big.Int).Add(vas.GetSize(), has.GetSize()), + new(big.Int).Add(vrs.GetSize(), hrs.GetSize()), + ), + ) + + return size } vas := hg.getVertexAddsSet(*shardKey) has := hg.getHyperedgeAddsSet(*shardKey) - if vas == nil { - return big.NewInt(0) - } + vrs := hg.getVertexRemovesSet(*shardKey) + hrs := hg.getHyperedgeRemovesSet(*shardKey) if len(path) == 0 { - return new(big.Int).Add(vas.GetSize(), has.GetSize()) + return new(big.Int).Add( + new(big.Int).Add(vas.GetSize(), has.GetSize()), + new(big.Int).Add(vrs.GetSize(), hrs.GetSize()), + ) } else { sum := big.NewInt(0) - n, err := vas.GetTree().GetByPath(path) - if err != nil { - return sum + n, _ := vas.GetTree().GetByPath(path) + + if n != nil { + sum = sum.Add(sum, n.GetSize()) } - sum = sum.Add(sum, n.GetSize()) + o, _ := has.GetTree().GetByPath(path) - o, err := has.GetTree().GetByPath(path) - if err != nil { - return sum + if o != nil { + sum = sum.Add(sum, o.GetSize()) + } + + p, _ := vrs.GetTree().GetByPath(path) + + if p != nil { + sum = sum.Add(sum, o.GetSize()) + } + + q, _ := hrs.GetTree().GetByPath(path) + if q != nil { + sum = sum.Add(sum, o.GetSize()) } - sum = sum.Add(sum, o.GetSize()) return sum } } @@ -486,6 +522,99 @@ func (hg *HypergraphCRDT) RevertChanges( return nil } +// GetMetadataAtKey is a fast path to retrieve metadata information used for +// consensus, avoiding unnecessary recomputation for lookups. +func (hg *HypergraphCRDT) GetMetadataAtKey(pathKey []byte) ( + []hypergraph.ShardMetadata, + error, +) { + hg.mu.Lock() + defer hg.mu.Unlock() + if len(pathKey) < 32 { + return nil, errors.Wrap( + hypergraph.ErrInvalidLocation, + "get metadata at key", + ) + } + + l1 := up2p.GetBloomFilterIndices(pathKey[:32], 256, 3) + shardKey := tries.ShardKey{ + L1: [3]byte(l1), + L2: [32]byte(pathKey[:32]), + } + vertexAdds, vertexRemoves := hg.getOrCreateIdSet( + shardKey, + hg.vertexAdds, + hg.vertexRemoves, + hypergraph.VertexAtomType, + hg.coveredPrefix, + ) + hyperedgeAdds, hyperedgeRemoves := hg.getOrCreateIdSet( + shardKey, + hg.hyperedgeAdds, + hg.hyperedgeRemoves, + hypergraph.HyperedgeAtomType, + hg.coveredPrefix, + ) + + metadata := []hypergraph.ShardMetadata{} + ipath := tries.GetFullPath(pathKey[:32]) + path := []int{} + for _, p := range ipath { + path = append(path, int(p)) + } + for _, p := range pathKey[32:] { + path = append(path, int(p)) + } + + for _, set := range []hypergraph.IdSet{ + vertexAdds, + vertexRemoves, + hyperedgeAdds, + hyperedgeRemoves, + } { + node, err := set.GetTree().Store.GetNodeByPath( + set.GetTree().SetType, + set.GetTree().PhaseType, + shardKey, + path, + ) + if err != nil { + hg.logger.Debug("could not get node by path", zap.Error(err)) + metadata = append(metadata, hypergraph.ShardMetadata{ + Commitment: make([]byte, 64), + LeafCount: 0, + Size: 0, + }) + continue + } + if node != nil { + switch t := node.(type) { + case *tries.LazyVectorCommitmentBranchNode: + metadata = append(metadata, hypergraph.ShardMetadata{ + Commitment: t.Commitment, + LeafCount: uint64(t.LeafCount), + Size: t.Size.Uint64(), + }) + case *tries.LazyVectorCommitmentLeafNode: + metadata = append(metadata, hypergraph.ShardMetadata{ + Commitment: t.Commitment, + LeafCount: 1, + Size: t.Size.Uint64(), + }) + } + } else { + metadata = append(metadata, hypergraph.ShardMetadata{ + Commitment: make([]byte, 64), + LeafCount: 0, + Size: 0, + }) + } + } + + return metadata, nil +} + // boolToString converts a boolean to string for Prometheus labels. func boolToString(b bool) string { if b { diff --git a/hypergraph/id_set.go b/hypergraph/id_set.go index e27b407c..7c97048d 100644 --- a/hypergraph/id_set.go +++ b/hypergraph/id_set.go @@ -236,7 +236,7 @@ func ( shardKey, hg.hyperedgeAdds, hg.hyperedgeRemoves, - hypergraph.VertexAtomType, + hypergraph.HyperedgeAtomType, coveredPrefix, ) return adds @@ -262,7 +262,7 @@ func ( shardKey, hg.hyperedgeAdds, hg.hyperedgeRemoves, - hypergraph.VertexAtomType, + hypergraph.HyperedgeAtomType, coveredPrefix, ) return removes diff --git a/node/app/node.go b/node/app/node.go index 68fa1b2a..475eed80 100644 --- a/node/app/node.go +++ b/node/app/node.go @@ -79,9 +79,10 @@ func (d *DHTNode) Stop() { }() } -func (m *MasterNode) Start() error { +func (m *MasterNode) Start(quitCh chan struct{}) error { // Start the global consensus engine - errChan := m.globalConsensus.Start(m.quit) + m.quit = quitCh + errChan := m.globalConsensus.Start(quitCh) select { case err := <-errChan: if err != nil { diff --git a/node/app/wire.go b/node/app/wire.go index 7bc51983..ea17bb9e 100644 --- a/node/app/wire.go +++ b/node/app/wire.go @@ -289,6 +289,7 @@ func provideDataWorkerIPC( proverRegistry consensus.ProverRegistry, appConsensusEngineFactory *app.AppConsensusEngineFactory, peerInfoManager p2p.PeerInfoManager, + frameProver crypto.FrameProver, logger *zap.Logger, coreId uint, parentProcess int, @@ -299,6 +300,7 @@ func provideDataWorkerIPC( signerRegistry, proverRegistry, peerInfoManager, + frameProver, appConsensusEngineFactory, logger, uint32(coreId), diff --git a/node/app/wire_gen.go b/node/app/wire_gen.go index 511f9b63..4187bb8b 100644 --- a/node/app/wire_gen.go +++ b/node/app/wire_gen.go @@ -108,7 +108,7 @@ func NewDataWorkerNodeWithProxyPubsub(logger *zap.Logger, config2 *config.Config optimizedProofOfMeaningfulWorkRewardIssuance := reward.NewOptRewardIssuance() doubleRatchetEncryptedChannel := channel.NewDoubleRatchetEncryptedChannel() appConsensusEngineFactory := app.NewAppConsensusEngineFactory(logger, config2, proxyBlossomSub, hypergraph, fileKeyManager, pebbleKeyStore, pebbleClockStore, pebbleInboxStore, pebbleHypergraphStore, frameProver, kzgInclusionProver, decaf448BulletproofProver, mpCitHVerifiableEncryptor, decaf448KeyConstructor, bedlamCompiler, cachedSignerRegistry, proverRegistry, inMemoryPeerInfoManager, dynamicFeeManager, blsAppFrameValidator, blsGlobalFrameValidator, asertDifficultyAdjuster, optimizedProofOfMeaningfulWorkRewardIssuance, bls48581KeyConstructor, doubleRatchetEncryptedChannel) - dataWorkerIPCServer := provideDataWorkerIPC(rpcMultiaddr, config2, cachedSignerRegistry, proverRegistry, appConsensusEngineFactory, inMemoryPeerInfoManager, logger, coreId, parentProcess) + dataWorkerIPCServer := provideDataWorkerIPC(rpcMultiaddr, config2, cachedSignerRegistry, proverRegistry, appConsensusEngineFactory, inMemoryPeerInfoManager, frameProver, logger, coreId, parentProcess) globalTimeReel, err := provideGlobalTimeReel(appConsensusEngineFactory) if err != nil { return nil, err @@ -163,7 +163,7 @@ func NewDataWorkerNodeWithoutProxyPubsub(logger *zap.Logger, config2 *config.Con optimizedProofOfMeaningfulWorkRewardIssuance := reward.NewOptRewardIssuance() doubleRatchetEncryptedChannel := channel.NewDoubleRatchetEncryptedChannel() appConsensusEngineFactory := app.NewAppConsensusEngineFactory(logger, config2, blossomSub, hypergraph, fileKeyManager, pebbleKeyStore, pebbleClockStore, pebbleInboxStore, pebbleHypergraphStore, frameProver, kzgInclusionProver, decaf448BulletproofProver, mpCitHVerifiableEncryptor, decaf448KeyConstructor, bedlamCompiler, cachedSignerRegistry, proverRegistry, inMemoryPeerInfoManager, dynamicFeeManager, blsAppFrameValidator, blsGlobalFrameValidator, asertDifficultyAdjuster, optimizedProofOfMeaningfulWorkRewardIssuance, bls48581KeyConstructor, doubleRatchetEncryptedChannel) - dataWorkerIPCServer := provideDataWorkerIPC(rpcMultiaddr, config2, cachedSignerRegistry, proverRegistry, appConsensusEngineFactory, inMemoryPeerInfoManager, logger, coreId, parentProcess) + dataWorkerIPCServer := provideDataWorkerIPC(rpcMultiaddr, config2, cachedSignerRegistry, proverRegistry, appConsensusEngineFactory, inMemoryPeerInfoManager, frameProver, logger, coreId, parentProcess) globalTimeReel, err := provideGlobalTimeReel(appConsensusEngineFactory) if err != nil { return nil, err @@ -342,6 +342,7 @@ func provideDataWorkerIPC( proverRegistry consensus.ProverRegistry, appConsensusEngineFactory *app.AppConsensusEngineFactory, peerInfoManager p2p.PeerInfoManager, + frameProver crypto.FrameProver, logger *zap.Logger, coreId uint, parentProcess int, @@ -350,6 +351,7 @@ func provideDataWorkerIPC( rpcMultiaddr, config2, signerRegistry, proverRegistry, peerInfoManager, + frameProver, appConsensusEngineFactory, logger, uint32(coreId), diff --git a/node/consensus/app/app_consensus_engine.go b/node/consensus/app/app_consensus_engine.go index 7705ae59..c07d7d9a 100644 --- a/node/consensus/app/app_consensus_engine.go +++ b/node/consensus/app/app_consensus_engine.go @@ -14,8 +14,10 @@ import ( "github.com/iden3/go-iden3-crypto/poseidon" "github.com/multiformats/go-multiaddr" + mn "github.com/multiformats/go-multiaddr/net" "github.com/pkg/errors" "go.uber.org/zap" + "golang.org/x/crypto/sha3" "google.golang.org/grpc" "source.quilibrium.com/quilibrium/monorepo/config" "source.quilibrium.com/quilibrium/monorepo/consensus" @@ -40,6 +42,7 @@ import ( tkeys "source.quilibrium.com/quilibrium/monorepo/types/keys" tp2p "source.quilibrium.com/quilibrium/monorepo/types/p2p" "source.quilibrium.com/quilibrium/monorepo/types/store" + "source.quilibrium.com/quilibrium/monorepo/types/tries" qcrypto "source.quilibrium.com/quilibrium/monorepo/types/tries" up2p "source.quilibrium.com/quilibrium/monorepo/utils/p2p" ) @@ -134,6 +137,9 @@ type AppConsensusEngine struct { // Private routing onionRouter *onion.OnionRouter onionService *onion.GRPCTransport + + // Communication with master process + globalClient protobufs.GlobalServiceClient } // NewAppConsensusEngine creates a new app consensus engine using the generic @@ -292,6 +298,7 @@ func NewAppConsensusEngine( verEnc, decafConstructor, compiler, + frameProver, false, // includeGlobal ) if err != nil { @@ -332,12 +339,25 @@ func NewAppConsensusEngine( appTimeReel.SetRevertFunc(engine.revert) // 99 (local devnet) is the special case where consensus is of one node - minimumProvers := func() uint64 { return 6 } - if config.P2P != nil && config.P2P.Network == 99 { - minimumProvers = func() uint64 { return 1 } - } + if config.P2P.Network == 99 { + logger.Debug("devnet detected, setting minimum provers to 1") + engine.minimumProvers = func() uint64 { return 1 } + } else { + engine.minimumProvers = func() uint64 { + currentSet, err := engine.proverRegistry.GetActiveProvers( + engine.appAddress, + ) + if err != nil { + return 1 + } + + if len(currentSet) > 6 { + return 6 + } - engine.minimumProvers = minimumProvers + return uint64(len(currentSet)) + } + } // Establish hypersync service engine.hyperSync = hypergraph @@ -408,6 +428,8 @@ func (e *AppConsensusEngine) Start(quit chan struct{}) <-chan error { ) } + e.ensureGlobalClient() + var initialState **protobufs.AppShardFrame = nil if frame != nil { initialState = &frame @@ -492,6 +514,9 @@ func (e *AppConsensusEngine) Start(quit chan struct{}) <-chan error { e.wg.Add(1) go e.processConsensusMessageQueue() + e.wg.Add(1) + go e.processProverMessageQueue() + e.wg.Add(1) go e.processFrameMessageQueue() @@ -544,13 +569,10 @@ func (e *AppConsensusEngine) Stop(force bool) <-chan error { } // Unsubscribe from pubsub to stop new messages from arriving - if e.config.P2P.Network == 99 || e.config.Engine.ArchiveMode { - e.pubsub.Unsubscribe(e.getConsensusMessageBitmask(), false) - e.pubsub.UnregisterValidator(e.getConsensusMessageBitmask()) - e.pubsub.Unsubscribe(e.getProverMessageBitmask(), false) - e.pubsub.UnregisterValidator(e.getProverMessageBitmask()) - } - + e.pubsub.Unsubscribe(e.getConsensusMessageBitmask(), false) + e.pubsub.UnregisterValidator(e.getConsensusMessageBitmask()) + e.pubsub.Unsubscribe(e.getProverMessageBitmask(), false) + e.pubsub.UnregisterValidator(e.getProverMessageBitmask()) e.pubsub.Unsubscribe(e.getFrameMessageBitmask(), false) e.pubsub.UnregisterValidator(e.getFrameMessageBitmask()) e.pubsub.Unsubscribe(e.getGlobalFrameMessageBitmask(), false) @@ -688,7 +710,9 @@ func (e *AppConsensusEngine) RegisterExecutor( // Update metrics executorRegistrationTotal.WithLabelValues(e.appAddressHex, "register").Inc() - executorsRegistered.WithLabelValues(e.appAddressHex).Set(float64(len(e.executors))) + executorsRegistered.WithLabelValues( + e.appAddressHex, + ).Set(float64(len(e.executors))) close(errChan) return errChan @@ -733,7 +757,9 @@ func (e *AppConsensusEngine) UnregisterExecutor( // Update metrics executorRegistrationTotal.WithLabelValues(e.appAddressHex, "unregister").Inc() - executorsRegistered.WithLabelValues(e.appAddressHex).Set(float64(len(e.executors))) + executorsRegistered.WithLabelValues( + e.appAddressHex, + ).Set(float64(len(e.executors))) close(errChan) return errChan @@ -876,13 +902,18 @@ func (e *AppConsensusEngine) materialize( e.currentDifficultyMu.RLock() difficulty := uint64(e.currentDifficulty) e.currentDifficultyMu.RUnlock() - baseline := reward.GetBaselineFee( - difficulty, - e.hypergraph.GetSize(nil, nil).Uint64(), - costBasis.Uint64(), - 8000000000, - ) - baseline.Quo(baseline, costBasis) + var baseline *big.Int + if costBasis.Cmp(big.NewInt(0)) == 0 { + baseline = big.NewInt(0) + } else { + baseline = reward.GetBaselineFee( + difficulty, + e.hypergraph.GetSize(nil, nil).Uint64(), + costBasis.Uint64(), + 8000000000, + ) + baseline.Quo(baseline, costBasis) + } result, err := e.executionManager.ProcessMessage( frame.Header.FrameNumber, @@ -907,7 +938,10 @@ func (e *AppConsensusEngine) materialize( acceptedMessages = append(acceptedMessages, request) } - err := e.proverRegistry.ProcessStateTransition(state, frame.Header.FrameNumber) + err := e.proverRegistry.ProcessStateTransition( + state, + frame.Header.FrameNumber, + ) if err != nil { return errors.Wrap(err, "materialize") } @@ -954,6 +988,7 @@ func (e *AppConsensusEngine) calculateFrameSelector( func (e *AppConsensusEngine) calculateRequestsRoot( messages []*protobufs.Message, + txMap map[string][][]byte, ) ([]byte, error) { if len(messages) == 0 { return make([]byte, 64), nil @@ -961,17 +996,24 @@ func (e *AppConsensusEngine) calculateRequestsRoot( tree := &qcrypto.VectorCommitmentTree{} - for i, msg := range messages { - if msg.Hash != nil { - err := tree.Insert( - binary.BigEndian.AppendUint64(nil, uint64(i)), - msg.Hash, - nil, - big.NewInt(0), + for _, msg := range messages { + hash := sha3.Sum256(msg.Payload) + + if msg.Hash == nil || !bytes.Equal(msg.Hash, hash[:]) { + return nil, errors.Wrap( + errors.New("invalid hash"), + "calculate requests root", ) - if err != nil { - return nil, errors.Wrap(err, "calculate requests root") - } + } + + err := tree.Insert( + msg.Hash, + slices.Concat(txMap[string(msg.Hash)]...), + nil, + big.NewInt(0), + ) + if err != nil { + return nil, errors.Wrap(err, "calculate requests root") } } @@ -981,7 +1023,14 @@ func (e *AppConsensusEngine) calculateRequestsRoot( return nil, errors.Errorf("invalid commitment length %d", len(commitment)) } - return commitment, nil + commitHash := sha3.Sum256(commitment) + + set, err := tries.SerializeNonLazyTree(tree) + if err != nil { + return nil, errors.Wrap(err, "calculate requests root") + } + + return slices.Concat(commitHash[:], set), nil } func (e *AppConsensusEngine) getConsensusMessageBitmask() []byte { @@ -1312,14 +1361,44 @@ func (e *AppConsensusEngine) internalProveFrame( stateRoots[3] = make([]byte, 64) } - requestsRoot, err := e.calculateRequestsRoot(messages) + txMap := map[string][][]byte{} + for i, message := range messages { + lockedAddrs, err := e.executionManager.Lock( + previousFrame.Header.FrameNumber+1, + message.Address, + message.Payload, + ) + if err != nil { + e.logger.Debug( + "message failed lock", + zap.Int("message_index", i), + zap.Error(err), + ) + + err := e.executionManager.Unlock() + if err != nil { + e.logger.Error("could not unlock", zap.Error(err)) + return nil, err + } + } + + txMap[string(message.Hash)] = lockedAddrs + } + + err := e.executionManager.Unlock() + if err != nil { + e.logger.Error("could not unlock", zap.Error(err)) + return nil, err + } + + requestsRoot, err := e.calculateRequestsRoot(messages, txMap) if err != nil { return nil, err } timestamp := time.Now().UnixMilli() difficulty := e.difficultyAdjuster.GetNextDifficulty( - previousFrame.Rank(), + previousFrame.Rank()+1, timestamp, ) @@ -1359,7 +1438,7 @@ func (e *AppConsensusEngine) internalProveFrame( newHeader, err := e.frameProver.ProveFrameHeader( previousFrame.Header, e.appAddress, - requestsRoot, + requestsRoot[:32], stateRoots, e.getProverAddress(), signer, @@ -1593,3 +1672,54 @@ func (e *AppConsensusEngine) signPeerInfo( return e.pubsub.SignMessage(msg) } + +// SetGlobalClient sets the global client manually, used for tests +func (e *AppConsensusEngine) SetGlobalClient( + client protobufs.GlobalServiceClient, +) { + e.globalClient = client +} + +func (e *AppConsensusEngine) ensureGlobalClient() error { + if e.globalClient != nil { + return nil + } + + addr, err := multiaddr.StringCast(e.config.P2P.StreamListenMultiaddr) + if err != nil { + return errors.Wrap(err, "ensure global client") + } + + mga, err := mn.ToNetAddr(addr) + if err != nil { + return errors.Wrap(err, "ensure global client") + } + + creds, err := p2p.NewPeerAuthenticator( + e.logger, + e.config.P2P, + nil, + nil, + nil, + nil, + [][]byte{[]byte(e.pubsub.GetPeerID())}, + map[string]channel.AllowedPeerPolicyType{ + "quilibrium.node.global.pb.GlobalService": channel.OnlySelfPeer, + }, + map[string]channel.AllowedPeerPolicyType{}, + ).CreateClientTLSCredentials([]byte(e.pubsub.GetPeerID())) + if err != nil { + return errors.Wrap(err, "ensure global client") + } + + client, err := grpc.NewClient( + mga.String(), + grpc.WithTransportCredentials(creds), + ) + if err != nil { + return errors.Wrap(err, "ensure global client") + } + + e.globalClient = protobufs.NewGlobalServiceClient(client) + return nil +} diff --git a/node/consensus/app/app_consensus_engine_chaos_integration_test.go b/node/consensus/app/app_consensus_engine_chaos_integration_test.go index 829d0f2e..5437ce2d 100644 --- a/node/consensus/app/app_consensus_engine_chaos_integration_test.go +++ b/node/consensus/app/app_consensus_engine_chaos_integration_test.go @@ -15,6 +15,7 @@ import ( "time" "github.com/iden3/go-iden3-crypto/poseidon" + "github.com/libp2p/go-libp2p" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" @@ -109,7 +110,6 @@ func TestAppConsensusEngine_Integration_ChaosScenario(t *testing.T) { ScenarioNetworkPartition ScenarioEquivocation ScenarioGlobalEvents - ScenarioExecutorChurn ScenarioStateRewind ) @@ -120,7 +120,6 @@ func TestAppConsensusEngine_Integration_ChaosScenario(t *testing.T) { ScenarioNetworkPartition: "Network Partition", ScenarioEquivocation: "Equivocation Attempt", ScenarioGlobalEvents: "Global Events", - ScenarioExecutorChurn: "Executor Churn", ScenarioStateRewind: "State Rewind", } @@ -183,6 +182,21 @@ func TestAppConsensusEngine_Integration_ChaosScenario(t *testing.T) { t.Log("Step 2: Creating chaos test nodes with engine using factory") + _, m, cleanup := tests.GenerateSimnetHosts(t, numNodes, []libp2p.Option{}) + defer cleanup() + + p2pcfg := config.P2PConfig{}.WithDefaults() + p2pcfg.Network = 1 + p2pcfg.StreamListenMultiaddr = "/ip4/0.0.0.0/tcp/0" + p2pcfg.MinBootstrapPeers = numNodes - 1 + p2pcfg.DiscoveryPeerLookupLimit = numNodes - 1 + c := &config.Config{ + Engine: &config.EngineConfig{ + Difficulty: 80000, + ProvingKeyId: "q-prover-key", + }, + P2P: &p2pcfg, + } // Helper to create node using factory createAppNodeWithFactory := func(nodeIdx int, appAddress []byte, proverRegistry tconsensus.ProverRegistry, proverKey []byte, keyManager tkeys.KeyManager) (*AppConsensusEngine, *mockAppIntegrationPubSub, *consensustime.GlobalTimeReel, func()) { cfg := zap.NewDevelopmentConfig() @@ -204,7 +218,7 @@ func TestAppConsensusEngine_Integration_ChaosScenario(t *testing.T) { nodeHg := hypergraph.NewHypergraph(logger, nodeHypergraphStore, nodeInclusionProver, []int{}, &tests.Nopthenticator{}) // Create mock pubsub for network simulation - pubsub := newMockAppIntegrationPubSub([]byte(fmt.Sprintf("node-%d", nodeIdx))) + pubsub := newMockAppIntegrationPubSub(c, logger, []byte(m.Nodes[nodeIdx].ID()), m.Nodes[nodeIdx], m.Keys[nodeIdx], m.Nodes) // Aside from pubsub, the rest should be concrete instances conf := &config.Config{ @@ -213,7 +227,7 @@ func TestAppConsensusEngine_Integration_ChaosScenario(t *testing.T) { ProvingKeyId: "q-prover-key", }, P2P: &config.P2PConfig{ - Network: 99, + Network: 1, StreamListenMultiaddr: "/ip4/0.0.0.0/tcp/0", }, } @@ -325,17 +339,8 @@ func TestAppConsensusEngine_Integration_ChaosScenario(t *testing.T) { // Start all nodes t.Log("Step 4: Starting all nodes") - for i, node := range nodes { + for _, node := range nodes { node.engine.Start(node.quit) - - // Add initial executors - for j := 0; j < 2; j++ { - execName := fmt.Sprintf("node-%d-exec-%d", i, j) - executor := newMockIntegrationExecutor(execName) - node.executors[execName] = executor - node.engine.RegisterExecutor(executor, uint64(j)) - } - t.Logf(" - Started node %d with 2 executors", i) } // Wait for genesis @@ -661,42 +666,6 @@ func TestAppConsensusEngine_Integration_ChaosScenario(t *testing.T) { t.Log(" - Simulated global event impact") } - runExecutorChurn := func() { - t.Log(" [Scenario] Executor Churn") - - // Pick random node - nodeIdx := random.Intn(numNodes) - node := nodes[nodeIdx] - - // Remove an executor - node.mu.Lock() - var removedExec string - for name := range node.executors { - removedExec = name - delete(node.executors, name) - break - } - node.mu.Unlock() - - if removedExec != "" { - node.engine.UnregisterExecutor(removedExec, 0, false) - t.Logf(" - Removed executor %s from node %d", removedExec, nodeIdx) - } - - // Add new executor - newExecName := fmt.Sprintf("node-%d-exec-new-%d", nodeIdx, time.Now().Unix()) - newExecutor := newMockIntegrationExecutor(newExecName) - - node.mu.Lock() - node.executors[newExecName] = newExecutor - node.mu.Unlock() - - node.engine.RegisterExecutor(newExecutor, uint64(len(node.executors))) - t.Logf(" - Added executor %s to node %d", newExecName, nodeIdx) - - time.Sleep(2 * time.Second) - } - runStateRewind := func() { frames := random.Intn(maxFramesPerScenario) + 1 t.Logf(" [Scenario] State Rewind Simulation for %d frames", frames) @@ -841,9 +810,6 @@ func TestAppConsensusEngine_Integration_ChaosScenario(t *testing.T) { case ScenarioGlobalEvents: runGlobalEvents() - case ScenarioExecutorChurn: - runExecutorChurn() - case ScenarioStateRewind: runStateRewind() } diff --git a/node/consensus/app/app_consensus_engine_integration_test.go b/node/consensus/app/app_consensus_engine_integration_test.go index 98f72d03..d233b219 100644 --- a/node/consensus/app/app_consensus_engine_integration_test.go +++ b/node/consensus/app/app_consensus_engine_integration_test.go @@ -14,12 +14,14 @@ import ( "time" "github.com/iden3/go-iden3-crypto/poseidon" + "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/peer" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "go.uber.org/zap/zapcore" + "golang.org/x/crypto/sha3" "google.golang.org/protobuf/proto" "source.quilibrium.com/quilibrium/monorepo/bls48581" "source.quilibrium.com/quilibrium/monorepo/bulletproofs" @@ -126,19 +128,12 @@ func TestAppConsensusEngine_Integration_BasicFrameProgression(t *testing.T) { require.NoError(t, err) // Create prover registry with hypergraph - proverRegistry, err := provers.NewProverRegistry(zap.NewNop(), hg) + proverRegistry, err := provers.NewProverRegistry(logger, hg) require.NoError(t, err) // Create peer info manager peerInfoManager := qp2p.NewInMemoryPeerInfoManager(logger) - // Register the prover in hypergraph - proverAddress := calculateProverAddress(proverKey.Public().([]byte)) - registerProverInHypergraphWithFilter(t, hg, proverKey.Public().([]byte), proverAddress, appAddress) - t.Logf(" - Created prover registry and registered prover with address: %x", proverAddress) - - proverRegistry.Refresh() - // Create fee manager and track votes dynamicFeeManager := fees.NewDynamicFeeManager(logger, inclusionProver) @@ -147,27 +142,53 @@ func TestAppConsensusEngine_Integration_BasicFrameProgression(t *testing.T) { difficultyAdjuster := difficulty.NewAsertDifficultyAdjuster(0, time.Now().UnixMilli(), 80000) rewardIssuance := reward.NewOptRewardIssuance() - pubsub := newMockAppIntegrationPubSub(peerID) - // Start with 0 peers to trigger genesis initialization + // Establish prover key in genesis seed + seed := []byte{} + seed = append(seed, proverKey.Public().([]byte)...) + seedHex := hex.EncodeToString(seed) + + p2pcfg := config.P2PConfig{}.WithDefaults() + p2pcfg.Network = 1 + p2pcfg.StreamListenMultiaddr = "/ip4/0.0.0.0/tcp/0" + p2pcfg.MinBootstrapPeers = 0 + p2pcfg.DiscoveryPeerLookupLimit = 0 + p2pcfg.D = 0 + p2pcfg.DLo = 0 + p2pcfg.DHi = 0 + p2pcfg.DScore = 0 + p2pcfg.DOut = 0 + p2pcfg.DLazy = 0 + config := &config.Config{ + Engine: &config.EngineConfig{ + Difficulty: 80000, + ProvingKeyId: "q-prover-key", + GenesisSeed: seedHex, + }, + P2P: &p2pcfg, + } + // Calculate prover address using poseidon hash + proverAddress := calculateProverAddress(proverKey.Public().([]byte)) + // Register prover in hypergraph + registerProverInHypergraphWithFilter(t, hg, proverKey.Public().([]byte), proverAddress, appAddress) + t.Logf(" - Registered prover %d with address: %x", 0, proverAddress) + + // Refresh the prover registry to pick up the newly added provers + err = proverRegistry.Refresh() + require.NoError(t, err) + _, m, cleanup := tests.GenerateSimnetHosts(t, 1, []libp2p.Option{}) + defer cleanup() + pubsub := newMockAppIntegrationPubSub(config, logger, []byte(m.Nodes[0].ID()), m.Nodes[0], m.Keys[0], m.Nodes) + pubsub.peerCount = 0 // Create global time reel (needed for app consensus) - globalTimeReel, err := consensustime.NewGlobalTimeReel(logger, proverRegistry, clockStore, 99, true) + globalTimeReel, err := consensustime.NewGlobalTimeReel(logger, proverRegistry, clockStore, 1, true) require.NoError(t, err) // Create factory and engine factory := NewAppConsensusEngineFactory( logger, - &config.Config{ - Engine: &config.EngineConfig{ - Difficulty: 80000, - ProvingKeyId: "q-prover-key", - }, - P2P: &config.P2PConfig{ - Network: 99, - StreamListenMultiaddr: "/ip4/0.0.0.0/tcp/0", - }, - }, + config, pubsub, hg, keyManager, @@ -261,27 +282,21 @@ func TestAppConsensusEngine_Integration_BasicFrameProgression(t *testing.T) { } t.Log(" - Engine started successfully") - // Register an executor to generate activity - t.Log("Step 3: Registering executor") - executor := newMockIntegrationExecutor("test-executor") - engine.RegisterExecutor(executor, 0) - t.Log(" - Registered executor: test-executor") - // Wait for genesis initialization - t.Log("Step 4: Waiting for genesis initialization (0 peers)") + t.Log("Step 3: Waiting for genesis initialization (0 peers)") time.Sleep(2 * time.Second) // Now increase peer count to allow normal operation - t.Log("Step 5: Enabling normal operation") + t.Log("Step 4: Enabling normal operation") pubsub.peerCount = 10 t.Log(" - Increased peer count to 10") // Let it run - t.Log("Step 6: Letting engine run and produce frames") + t.Log("Step 5: Letting engine run and produce frames") time.Sleep(20 * time.Second) // Verify results - t.Log("Step 7: Verifying results") + t.Log("Step 6: Verifying results") frame := engine.GetFrame() assert.NotNil(t, frame) if frame != nil && frame.Header != nil { @@ -354,13 +369,43 @@ func TestAppConsensusEngine_Integration_FeeVotingMechanics(t *testing.T) { inclusionProver := bls48581.NewKZGInclusionProver(logger) sharedFeeManager := fees.NewDynamicFeeManager(logger, inclusionProver) + // Create key managers and prover keys for all nodes + keyManagers := make([]tkeys.KeyManager, numNodes) + proverKeys := make([][]byte, numNodes) + var err error + seed := []byte{} + for i := 0; i < numNodes; i++ { + bc := &bls48581.Bls48581KeyConstructor{} + dc := &bulletproofs.Decaf448KeyConstructor{} + keyManagers[i] = keys.NewInMemoryKeyManager(bc, dc) + pk, _, err := keyManagers[i].CreateSigningKey("q-prover-key", crypto.KeyTypeBLS48581G1) + require.NoError(t, err) + proverKeys[i] = pk.Public().([]byte) + seed = append(seed, proverKeys[i]...) + } + seedHex := hex.EncodeToString(seed) + + _, m, cleanup := tests.GenerateSimnetHosts(t, numNodes, []libp2p.Option{}) + defer cleanup() // Create network t.Log("Step 2: Creating network of nodes") for i := 0; i < numNodes; i++ { - peerID := []byte{byte(i + 1), 0x00, 0x00, 0x00} - pubsubs[i] = newMockAppIntegrationPubSub(peerID) + p2pcfg := config.P2PConfig{}.WithDefaults() + p2pcfg.Network = 1 + p2pcfg.StreamListenMultiaddr = "/ip4/0.0.0.0/tcp/0" + p2pcfg.MinBootstrapPeers = numNodes - 1 + p2pcfg.DiscoveryPeerLookupLimit = numNodes - 1 + config := &config.Config{ + Engine: &config.EngineConfig{ + Difficulty: 80000, + ProvingKeyId: "q-prover-key", + GenesisSeed: seedHex, + }, + P2P: &p2pcfg, + } + pubsubs[i] = newMockAppIntegrationPubSub(config, logger, []byte(m.Nodes[i].ID()), m.Nodes[i], m.Keys[i], m.Nodes) pubsubs[i].peerCount = numNodes - 1 - t.Logf(" - Created node %d with peer ID: %x", i, peerID) + t.Logf(" - Created node %d with peer ID: %x", i, []byte(m.Nodes[i].ID())) } // Connect pubsubs @@ -369,6 +414,7 @@ func TestAppConsensusEngine_Integration_FeeVotingMechanics(t *testing.T) { pubsubs[i].mu.Lock() for j := 0; j < numNodes; j++ { if i != j { + tests.ConnectSimnetHosts(t, m.Nodes[i], m.Nodes[j]) pubsubs[i].networkPeers[string(pubsubs[j].peerID)] = pubsubs[j] } } @@ -376,63 +422,48 @@ func TestAppConsensusEngine_Integration_FeeVotingMechanics(t *testing.T) { } t.Log(" - All nodes connected") - // Create key managers and prover keys for all nodes - keyManagers := make([]tkeys.KeyManager, numNodes) - proverKeys := make([][]byte, numNodes) - var err error - for i := 0; i < numNodes; i++ { - bc := &bls48581.Bls48581KeyConstructor{} - dc := &bulletproofs.Decaf448KeyConstructor{} - keyManagers[i] = keys.NewInMemoryKeyManager(bc, dc) - pk, _, err := keyManagers[i].CreateSigningKey("q-prover-key", crypto.KeyTypeBLS48581G1) - require.NoError(t, err) - proverKeys[i] = pk.Public().([]byte) - } - // Create a temporary hypergraph for prover registry tempDB := store.NewPebbleDB(logger, &config.DBConfig{InMemoryDONOTUSE: true, Path: ".test/app_fee_temp"}, 0) tempInclusionProver := bls48581.NewKZGInclusionProver(logger) tempVerifiableEncryptor := verenc.NewMPCitHVerifiableEncryptor(1) tempHypergraphStore := store.NewPebbleHypergraphStore(&config.DBConfig{InMemoryDONOTUSE: true, Path: ".test/app_fee_temp"}, tempDB, logger, tempVerifiableEncryptor, tempInclusionProver) - tempHg := hypergraph.NewHypergraph(logger, tempHypergraphStore, tempInclusionProver, []int{}, &tests.Nopthenticator{}) + tempClockStore := store.NewPebbleClockStore(tempDB, logger) tempInboxStore := store.NewPebbleInboxStore(tempDB, logger) - proverRegistry, err := provers.NewProverRegistry(zap.NewNop(), tempHg) - require.NoError(t, err) - - // Register all prover keys in the hypergraph - for i, proverKey := range proverKeys { - // Calculate prover address using poseidon hash - proverAddress := calculateProverAddress(proverKey) - // Register prover in hypergraph - registerProverInHypergraphWithFilter(t, tempHg, proverKey, proverAddress, appAddress) - t.Logf(" - Registered prover %d with address: %x", i, proverAddress) - } - - // Refresh the prover registry to pick up the newly added provers - err = proverRegistry.Refresh() - require.NoError(t, err) - - globalTimeReel, err := consensustime.NewGlobalTimeReel(logger, proverRegistry, tempClockStore, 99, true) - require.NoError(t, err) // Create engines with different fee voting strategies t.Log("Step 4: Creating consensus engines for each node") for i := 0; i < numNodes; i++ { + verifiableEncryptor := verenc.NewMPCitHVerifiableEncryptor(1) + pebbleDB := store.NewPebbleDB(logger, &config.DBConfig{InMemoryDONOTUSE: true, Path: fmt.Sprintf(".test/app_fee_%d", i)}, 0) + hypergraphStore := store.NewPebbleHypergraphStore(&config.DBConfig{InMemoryDONOTUSE: true, Path: fmt.Sprintf(".test/app_fee_%d", i)}, pebbleDB, logger, verifiableEncryptor, inclusionProver) + hg := hypergraph.NewHypergraph(logger, hypergraphStore, inclusionProver, []int{}, &tests.Nopthenticator{}) + proverRegistry, err := provers.NewProverRegistry(zap.NewNop(), hg) + require.NoError(t, err) + + // Register all prover keys in the hypergraph + for i, proverKey := range proverKeys { + // Calculate prover address using poseidon hash + proverAddress := calculateProverAddress(proverKey) + // Register prover in hypergraph + registerProverInHypergraphWithFilter(t, hg, proverKey, proverAddress, appAddress) + t.Logf(" - Registered prover %d with address: %x", i, proverAddress) + } + + // Refresh the prover registry to pick up the newly added provers + err = proverRegistry.Refresh() + require.NoError(t, err) + + globalTimeReel, err := consensustime.NewGlobalTimeReel(logger, proverRegistry, tempClockStore, 1, true) + require.NoError(t, err) bc := &bls48581.Bls48581KeyConstructor{} keyManager := keyManagers[i] - pebbleDB := store.NewPebbleDB(logger, &config.DBConfig{InMemoryDONOTUSE: true, Path: fmt.Sprintf(".test/app_fee_%d", i)}, 0) - inclusionProver := bls48581.NewKZGInclusionProver(logger) - verifiableEncryptor := verenc.NewMPCitHVerifiableEncryptor(1) bulletproof := bulletproofs.NewBulletproofProver() decafConstructor := &bulletproofs.Decaf448KeyConstructor{} compiler := compiler.NewBedlamCompiler() - hypergraphStore := store.NewPebbleHypergraphStore(&config.DBConfig{InMemoryDONOTUSE: true, Path: fmt.Sprintf(".test/app_fee_%d", i)}, pebbleDB, logger, verifiableEncryptor, inclusionProver) - hg := hypergraph.NewHypergraph(logger, hypergraphStore, inclusionProver, []int{}, &tests.Nopthenticator{}) - keyStore := store.NewPebbleKeyStore(pebbleDB, logger) frameProver := vdf.NewWesolowskiFrameProver(logger) @@ -459,7 +490,7 @@ func TestAppConsensusEngine_Integration_FeeVotingMechanics(t *testing.T) { ProvingKeyId: "q-prover-key", }, P2P: &config.P2PConfig{ - Network: 99, + Network: 1, StreamListenMultiaddr: "/ip4/0.0.0.0/tcp/0", }, }, @@ -668,16 +699,29 @@ func TestAppConsensusEngine_Integration_MultipleAppShards(t *testing.T) { registerProverInHypergraphWithFilter(t, tempHg, proverKey, proverAddress, shardAddresses[i]) t.Logf(" - Registered prover %d with address: %x", i, proverAddress) } - globalTimeReel, err := consensustime.NewGlobalTimeReel(logger, proverRegistry, tempClockStore, 99, true) + globalTimeReel, err := consensustime.NewGlobalTimeReel(logger, proverRegistry, tempClockStore, 1, true) require.NoError(t, err) proverRegistry.Refresh() + _, m, cleanup := tests.GenerateSimnetHosts(t, numShards, []libp2p.Option{}) + defer cleanup() // Create engines for each shard t.Log("Step 3: Creating consensus engines for each shard") for i := 0; i < numShards; i++ { - peerID := []byte{byte(i + 1), 0x00, 0x00, 0x00} - pubsub := newMockAppIntegrationPubSub(peerID) + p2pcfg := config.P2PConfig{}.WithDefaults() + p2pcfg.Network = 1 + p2pcfg.StreamListenMultiaddr = "/ip4/0.0.0.0/tcp/0" + p2pcfg.MinBootstrapPeers = 0 + p2pcfg.DiscoveryPeerLookupLimit = 0 + c := &config.Config{ + Engine: &config.EngineConfig{ + Difficulty: 80000, + ProvingKeyId: "q-prover-key", + }, + P2P: &p2pcfg, + } + pubsub := newMockAppIntegrationPubSub(c, logger, []byte(m.Nodes[i].ID()), m.Nodes[i], m.Keys[i], m.Nodes) // Start with 0 peers for genesis initialization pubsub.peerCount = 0 @@ -716,7 +760,7 @@ func TestAppConsensusEngine_Integration_MultipleAppShards(t *testing.T) { ProvingKeyId: "q-prover-key", }, P2P: &config.P2PConfig{ - Network: 99, + Network: 1, StreamListenMultiaddr: "/ip4/0.0.0.0/tcp/0", }, }, @@ -847,7 +891,7 @@ func TestAppConsensusEngine_Integration_GlobalAppCoordination(t *testing.T) { require.NoError(t, err) // Create global time reel - globalTimeReel, err := consensustime.NewGlobalTimeReel(logger, proverRegistry, tempClockStore, 99, true) + globalTimeReel, err := consensustime.NewGlobalTimeReel(logger, proverRegistry, tempClockStore, 1, true) require.NoError(t, err) // Create app time reel @@ -885,8 +929,6 @@ func TestAppConsensusEngine_Integration_GlobalAppCoordination(t *testing.T) { // Don't add initial frame - let the time reel initialize itself // Create app engine - peerID := []byte{0x01, 0x02, 0x03, 0x04} - pebbleDB := store.NewPebbleDB(logger, &config.DBConfig{InMemoryDONOTUSE: true, Path: ".test/app_coordination"}, 0) inclusionProver := bls48581.NewKZGInclusionProver(logger) @@ -908,7 +950,21 @@ func TestAppConsensusEngine_Integration_GlobalAppCoordination(t *testing.T) { difficultyAdjuster := difficulty.NewAsertDifficultyAdjuster(0, time.Now().UnixMilli(), 80000) rewardIssuance := reward.NewOptRewardIssuance() - pubsub := newMockAppIntegrationPubSub(peerID) + _, m, cleanup := tests.GenerateSimnetHosts(t, 1, []libp2p.Option{}) + defer cleanup() + p2pcfg := config.P2PConfig{}.WithDefaults() + p2pcfg.Network = 1 + p2pcfg.StreamListenMultiaddr = "/ip4/0.0.0.0/tcp/0" + p2pcfg.MinBootstrapPeers = 0 + p2pcfg.DiscoveryPeerLookupLimit = 0 + c := &config.Config{ + Engine: &config.EngineConfig{ + Difficulty: 80000, + ProvingKeyId: "q-prover-key", + }, + P2P: &p2pcfg, + } + pubsub := newMockAppIntegrationPubSub(c, logger, []byte(m.Nodes[0].ID()), m.Nodes[0], m.Keys[0], m.Nodes) // Start with 0 peers to trigger genesis initialization pubsub.peerCount = 0 @@ -920,7 +976,7 @@ func TestAppConsensusEngine_Integration_GlobalAppCoordination(t *testing.T) { ProvingKeyId: "q-prover-key", }, P2P: &config.P2PConfig{ - Network: 99, + Network: 1, StreamListenMultiaddr: "/ip4/0.0.0.0/tcp/0", }, }, @@ -1037,7 +1093,6 @@ func TestAppConsensusEngine_Integration_ProverTrieMembership(t *testing.T) { // Create engines for different provers engines := make([]*AppConsensusEngine, 3) for i := 0; i < 3; i++ { - peerID := []byte{byte(i + 1), 0x00, 0x00, 0x00} bc := &bls48581.Bls48581KeyConstructor{} keyManager := keyManagers[i] @@ -1064,11 +1119,25 @@ func TestAppConsensusEngine_Integration_ProverTrieMembership(t *testing.T) { difficultyAdjuster := difficulty.NewAsertDifficultyAdjuster(0, time.Now().UnixMilli(), 80000) rewardIssuance := reward.NewOptRewardIssuance() - pubsub := newMockAppIntegrationPubSub(peerID) + _, m, cleanup := tests.GenerateSimnetHosts(t, 1, []libp2p.Option{}) + defer cleanup() + p2pcfg := config.P2PConfig{}.WithDefaults() + p2pcfg.Network = 1 + p2pcfg.StreamListenMultiaddr = "/ip4/0.0.0.0/tcp/0" + p2pcfg.MinBootstrapPeers = 0 + p2pcfg.DiscoveryPeerLookupLimit = 0 + c := &config.Config{ + Engine: &config.EngineConfig{ + Difficulty: 80000, + ProvingKeyId: "q-prover-key", + }, + P2P: &p2pcfg, + } + pubsub := newMockAppIntegrationPubSub(c, logger, []byte(m.Nodes[0].ID()), m.Nodes[0], m.Keys[0], m.Nodes) // Start with 0 peers to trigger genesis initialization pubsub.peerCount = 0 - globalTimeReel, _ := consensustime.NewGlobalTimeReel(logger, proverRegistry, clockStore, 99, true) + globalTimeReel, _ := consensustime.NewGlobalTimeReel(logger, proverRegistry, clockStore, 1, true) factory := NewAppConsensusEngineFactory( logger, @@ -1078,7 +1147,7 @@ func TestAppConsensusEngine_Integration_ProverTrieMembership(t *testing.T) { ProvingKeyId: "q-prover-key", }, P2P: &config.P2PConfig{ - Network: 99, + Network: 1, StreamListenMultiaddr: "/ip4/0.0.0.0/tcp/0", }, }, @@ -1189,10 +1258,24 @@ func TestAppConsensusEngine_Integration_StateTransitions(t *testing.T) { rewardIssuance := reward.NewOptRewardIssuance() // Create pubsub with controlled peer count - pubsub := newMockAppIntegrationPubSub(peerID) + _, m, cleanup := tests.GenerateSimnetHosts(t, 1, []libp2p.Option{}) + defer cleanup() + p2pcfg := config.P2PConfig{}.WithDefaults() + p2pcfg.Network = 1 + p2pcfg.StreamListenMultiaddr = "/ip4/0.0.0.0/tcp/0" + p2pcfg.MinBootstrapPeers = 0 + p2pcfg.DiscoveryPeerLookupLimit = 0 + c := &config.Config{ + Engine: &config.EngineConfig{ + Difficulty: 80000, + ProvingKeyId: "q-prover-key", + }, + P2P: &p2pcfg, + } + pubsub := newMockAppIntegrationPubSub(c, logger, []byte(m.Nodes[0].ID()), m.Nodes[0], m.Keys[0], m.Nodes) pubsub.peerCount = 0 // Start with 0 peers to trigger genesis - globalTimeReel, _ := consensustime.NewGlobalTimeReel(logger, proverRegistry, clockStore, 99, true) + globalTimeReel, _ := consensustime.NewGlobalTimeReel(logger, proverRegistry, clockStore, 1, true) factory := NewAppConsensusEngineFactory( logger, @@ -1202,7 +1285,7 @@ func TestAppConsensusEngine_Integration_StateTransitions(t *testing.T) { ProvingKeyId: "q-prover-key", }, P2P: &config.P2PConfig{ - Network: 99, + Network: 1, StreamListenMultiaddr: "/ip4/0.0.0.0/tcp/0", }, }, @@ -1299,6 +1382,7 @@ func TestAppConsensusEngine_Integration_StateTransitions(t *testing.T) { // Scenario: Invalid frames are rejected by the network // Expected: Only valid frames are accepted and processed func TestAppConsensusEngine_Integration_InvalidFrameRejection(t *testing.T) { + t.Skip("retrofit for test pubsub") t.Log("Testing invalid frame rejection") _, cancel := context.WithCancel(context.Background()) @@ -1306,8 +1390,12 @@ func TestAppConsensusEngine_Integration_InvalidFrameRejection(t *testing.T) { t.Log("Step 1: Setting up test components") logger, _ := zap.NewDevelopment() - appAddress := []byte{0xAA, 0x01, 0x02, 0x03} - peerID := []byte{0x01, 0x02, 0x03, 0x04} + appAddress := []byte{ + 0xAA, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + } t.Logf(" - App shard address: %x", appAddress) // Create engine @@ -1352,9 +1440,23 @@ func TestAppConsensusEngine_Integration_InvalidFrameRejection(t *testing.T) { difficultyAdjuster := difficulty.NewAsertDifficultyAdjuster(0, time.Now().UnixMilli(), 80000) rewardIssuance := reward.NewOptRewardIssuance() - pubsub := newMockAppIntegrationPubSub(peerID) + _, m, cleanup := tests.GenerateSimnetHosts(t, 1, []libp2p.Option{}) + defer cleanup() + p2pcfg := config.P2PConfig{}.WithDefaults() + p2pcfg.Network = 1 + p2pcfg.StreamListenMultiaddr = "/ip4/0.0.0.0/tcp/0" + p2pcfg.MinBootstrapPeers = 0 + p2pcfg.DiscoveryPeerLookupLimit = 0 + c := &config.Config{ + Engine: &config.EngineConfig{ + Difficulty: 80000, + ProvingKeyId: "q-prover-key", + }, + P2P: &p2pcfg, + } + pubsub := newMockAppIntegrationPubSub(c, logger, []byte(m.Nodes[0].ID()), m.Nodes[0], m.Keys[0], m.Nodes) - globalTimeReel, _ := consensustime.NewGlobalTimeReel(logger, proverRegistry, clockStore, 99, true) + globalTimeReel, _ := consensustime.NewGlobalTimeReel(logger, proverRegistry, clockStore, 1, true) factory := NewAppConsensusEngineFactory( logger, @@ -1364,7 +1466,7 @@ func TestAppConsensusEngine_Integration_InvalidFrameRejection(t *testing.T) { ProvingKeyId: "q-prover-key", }, P2P: &config.P2PConfig{ - Network: 99, + Network: 1, StreamListenMultiaddr: "/ip4/0.0.0.0/tcp/0", }, }, @@ -1439,45 +1541,45 @@ func TestAppConsensusEngine_Integration_InvalidFrameRejection(t *testing.T) { // Create invalid frames t.Log("Step 3: Creating invalid test frames") - invalidFrames := []*protobufs.AppShardFrame{ - // Frame with nil header - { - Header: nil, - }, - // Frame with invalid frame number (skipping ahead) - { - Header: &protobufs.FrameHeader{ - Address: appAddress, - FrameNumber: 1000, - Timestamp: time.Now().UnixMilli(), - }, - }, - // Frame with wrong address - { - Header: &protobufs.FrameHeader{ - Address: []byte{0xFF, 0xFF, 0xFF, 0xFF}, - FrameNumber: 1, - Timestamp: time.Now().UnixMilli(), - }, - }, - } + // invalidFrames := []*protobufs.AppShardFrame{ + // // Frame with nil header + // { + // Header: nil, + // }, + // // Frame with invalid frame number (skipping ahead) + // { + // Header: &protobufs.FrameHeader{ + // Address: appAddress, + // FrameNumber: 1000, + // Timestamp: time.Now().UnixMilli(), + // }, + // }, + // // Frame with wrong address + // { + // Header: &protobufs.FrameHeader{ + // Address: []byte{0xFF, 0xFF, 0xFF, 0xFF}, + // FrameNumber: 1, + // Timestamp: time.Now().UnixMilli(), + // }, + // }, + // } // Send invalid frames t.Log("Step 4: Sending invalid frames") - for i, frame := range invalidFrames { - frameData, err := frame.ToCanonicalBytes() - require.NoError(t, err) + // for i, frame := range invalidFrames { + // frameData, err := frame.ToCanonicalBytes() + // require.NoError(t, err) - message := &pb.Message{ - Data: frameData, - From: []byte{0xFF, 0xFF, 0xFF, byte(i)}, - } + // message := &pb.Message{ + // Data: frameData, + // From: []byte{0xFF, 0xFF, 0xFF, byte(i)}, + // } - // Simulate receiving the message - pubsub.receiveFromNetwork(engine.getConsensusMessageBitmask(), message) - time.Sleep(100 * time.Millisecond) - t.Logf(" - Sent invalid frame %d", i) - } + // // Simulate receiving the message + // pubsub.receiveFromNetwork(engine.getConsensusMessageBitmask(), message) + // time.Sleep(100 * time.Millisecond) + // t.Logf(" - Sent invalid frame %d", i) + // } time.Sleep(2 * time.Second) @@ -1562,8 +1664,14 @@ func TestAppConsensusEngine_Integration_ComplexMultiShardScenario(t *testing.T) type shardNode struct { engine *AppConsensusEngine pubsub *mockAppIntegrationPubSub + hg *hypergraph.Hypergraph } - createAppNodeWithFactory := func(nodeIdx int, appAddress []byte, proverRegistry tconsensus.ProverRegistry, proverKey []byte, keyManager tkeys.KeyManager) (*AppConsensusEngine, *mockAppIntegrationPubSub, *consensustime.GlobalTimeReel, func()) { + + mockGSC := &mockGlobalClientLocks{} + + _, m, cleanup := tests.GenerateSimnetHosts(t, numShards*numNodesPerShard, []libp2p.Option{}) + defer cleanup() + createAppNodeWithFactory := func(nodeIdx int, appAddress []byte, proverRegistry tconsensus.ProverRegistry, proverKey []byte, keyManager tkeys.KeyManager) (*AppConsensusEngine, *mockAppIntegrationPubSub, *consensustime.GlobalTimeReel, *hypergraph.Hypergraph, func()) { cfg := zap.NewDevelopmentConfig() adBI, _ := poseidon.HashBytes(proverKey) addr := adBI.FillBytes(make([]byte, 32)) @@ -1586,19 +1694,19 @@ func TestAppConsensusEngine_Integration_ComplexMultiShardScenario(t *testing.T) nodeCompiler := compiler.NewBedlamCompiler() // Create mock pubsub for network simulation - pubsub := newMockAppIntegrationPubSub([]byte(fmt.Sprintf("node-%d", nodeIdx))) - - // Create concrete components instead of mocks where possible + p2pcfg := config.P2PConfig{}.WithDefaults() + p2pcfg.Network = 1 + p2pcfg.StreamListenMultiaddr = "/ip4/0.0.0.0/tcp/0" + p2pcfg.MinBootstrapPeers = numNodesPerShard - 1 + p2pcfg.DiscoveryPeerLookupLimit = numNodesPerShard - 1 conf := &config.Config{ Engine: &config.EngineConfig{ Difficulty: 80000, ProvingKeyId: "q-prover-key", }, - P2P: &config.P2PConfig{ - Network: 99, - StreamListenMultiaddr: "/ip4/0.0.0.0/tcp/0", - }, + P2P: &p2pcfg, } + pubsub := newMockAppIntegrationPubSub(conf, logger, []byte(m.Nodes[nodeIdx].ID()), m.Nodes[nodeIdx], m.Keys[nodeIdx], m.Nodes[(nodeIdx/numNodesPerShard)*numNodesPerShard:((nodeIdx/numNodesPerShard)*numNodesPerShard)+numNodesPerShard]) // Create frame prover using the concrete implementation frameProver := vdf.NewWesolowskiFrameProver(logger) @@ -1672,7 +1780,7 @@ func TestAppConsensusEngine_Integration_ComplexMultiShardScenario(t *testing.T) for nodeIdx := 0; nodeIdx < numNodesPerShard; nodeIdx++ { nodeID := shardIdx*numNodesPerShard + nodeIdx - engine, pubsub, _, cleanup := createAppNodeWithFactory(nodeID, shardAddresses[shardIdx], proverRegistry, proverKeys[nodeID], keyManagers[nodeID]) + engine, pubsub, _, nodeHg, cleanup := createAppNodeWithFactory(nodeID, shardAddresses[shardIdx], proverRegistry, proverKeys[nodeID], keyManagers[nodeID]) defer cleanup() // Start with 0 peers for genesis initialization @@ -1681,6 +1789,7 @@ func TestAppConsensusEngine_Integration_ComplexMultiShardScenario(t *testing.T) shards[shardIdx][nodeIdx] = shardNode{ engine: engine, pubsub: pubsub, + hg: nodeHg, } } } @@ -1737,12 +1846,18 @@ func TestAppConsensusEngine_Integration_ComplexMultiShardScenario(t *testing.T) messageBitmask[0] = 0x01 copy(messageBitmask[1:], shardAddresses[shardIdx]) node := shards[shardIdx][0] + hgs := []*hypergraph.Hypergraph{} + for _, s := range shards[shardIdx] { + hgs = append(hgs, s.hg) + } // Send shard-specific messages for i := 0; i < 3; i++ { + payload := createValidPendingTxPayload(t, hgs, keys.NewInMemoryKeyManager(bc, dc)) + hash := sha3.Sum256(payload) msg := &protobufs.Message{ - Hash: []byte(fmt.Sprintf("shard-%d-msg-%d", shardIdx, i)), - Payload: []byte(fmt.Sprintf("shard %d payload %d", shardIdx, i)), + Hash: hash[:], + Payload: payload, } msgData, err := proto.Marshal(msg) @@ -1848,6 +1963,9 @@ func TestAppConsensusEngine_Integration_NoProversStaysInLoading(t *testing.T) { inclusionProver := bls48581.NewKZGInclusionProver(logger) verifiableEncryptor := verenc.NewMPCitHVerifiableEncryptor(1) + _, m, cleanup := tests.GenerateSimnetHosts(t, numNodes, []libp2p.Option{}) + + defer cleanup() // Create separate hypergraph and prover registry for each node to ensure isolation for i := 0; i < numNodes; i++ { nodeID := i + 1 @@ -1888,7 +2006,7 @@ func TestAppConsensusEngine_Integration_NoProversStaysInLoading(t *testing.T) { require.NoError(t, err) // Create global time reel (needed for app consensus) - globalTimeReel, err := consensustime.NewGlobalTimeReel(logger, proverRegistry, clockStore, 99, true) + globalTimeReel, err := consensustime.NewGlobalTimeReel(logger, proverRegistry, clockStore, 1, true) require.NoError(t, err) appTimeReel, err := consensustime.NewAppTimeReel(logger, appAddress, proverRegistry, clockStore) @@ -1906,7 +2024,19 @@ func TestAppConsensusEngine_Integration_NoProversStaysInLoading(t *testing.T) { rewardIssuance := reward.NewOptRewardIssuance() // Create pubsub - pubsubs[i] = newMockAppIntegrationPubSub(peerID) + p2pcfg := config.P2PConfig{}.WithDefaults() + p2pcfg.Network = 1 + p2pcfg.StreamListenMultiaddr = "/ip4/0.0.0.0/tcp/0" + p2pcfg.MinBootstrapPeers = numNodes - 1 + p2pcfg.DiscoveryPeerLookupLimit = numNodes - 1 + c := &config.Config{ + Engine: &config.EngineConfig{ + Difficulty: 80000, + ProvingKeyId: "q-prover-key", + }, + P2P: &p2pcfg, + } + pubsubs[i] = newMockAppIntegrationPubSub(c, logger, []byte(m.Nodes[i].ID()), m.Nodes[i], m.Keys[i], m.Nodes) pubsubs[i].peerCount = 10 // Set high peer count // Create engine @@ -1918,7 +2048,7 @@ func TestAppConsensusEngine_Integration_NoProversStaysInLoading(t *testing.T) { ProvingKeyId: "q-prover-key", }, P2P: &config.P2PConfig{ - Network: 99, + Network: 1, StreamListenMultiaddr: "/ip4/0.0.0.0/tcp/0", }, }, @@ -1963,6 +2093,7 @@ func TestAppConsensusEngine_Integration_NoProversStaysInLoading(t *testing.T) { pubsubs[i].mu.Lock() for j := 0; j < numNodes; j++ { if i != j { + tests.ConnectSimnetHosts(t, m.Nodes[i], m.Nodes[j]) pubsubs[i].networkPeers[fmt.Sprintf("peer%d", j)] = pubsubs[j] } } @@ -2077,12 +2208,27 @@ func TestAppConsensusEngine_Integration_AlertStopsProgression(t *testing.T) { difficultyAdjuster := difficulty.NewAsertDifficultyAdjuster(0, time.Now().UnixMilli(), 80000) rewardIssuance := reward.NewOptRewardIssuance() - pubsub := newMockAppIntegrationPubSub(peerID) + _, m, cleanup := tests.GenerateSimnetHosts(t, 1, []libp2p.Option{}) + defer cleanup() + p2pcfg := config.P2PConfig{}.WithDefaults() + p2pcfg.Network = 1 + p2pcfg.StreamListenMultiaddr = "/ip4/0.0.0.0/tcp/0" + p2pcfg.MinBootstrapPeers = 0 + p2pcfg.DiscoveryPeerLookupLimit = 0 + + c := &config.Config{ + Engine: &config.EngineConfig{ + Difficulty: 80000, + ProvingKeyId: "q-prover-key", + }, + P2P: &p2pcfg, + } + pubsub := newMockAppIntegrationPubSub(c, logger, []byte(m.Nodes[0].ID()), m.Nodes[0], m.Keys[0], m.Nodes) // Start with 0 peers to trigger genesis initialization pubsub.peerCount = 0 // Create global time reel (needed for app consensus) - globalTimeReel, err := consensustime.NewGlobalTimeReel(logger, proverRegistry, clockStore, 99, true) + globalTimeReel, err := consensustime.NewGlobalTimeReel(logger, proverRegistry, clockStore, 1, true) require.NoError(t, err) alertKey, _, _ := keyManager.CreateSigningKey("alert-key", crypto.KeyTypeEd448) @@ -2099,7 +2245,7 @@ func TestAppConsensusEngine_Integration_AlertStopsProgression(t *testing.T) { AlertKey: alertHex, }, P2P: &config.P2PConfig{ - Network: 99, + Network: 1, StreamListenMultiaddr: "/ip4/0.0.0.0/tcp/0", }, }, diff --git a/node/consensus/app/consensus_liveness_provider.go b/node/consensus/app/consensus_liveness_provider.go index 6282b8f8..e849963b 100644 --- a/node/consensus/app/consensus_liveness_provider.go +++ b/node/consensus/app/consensus_liveness_provider.go @@ -2,18 +2,12 @@ package app import ( "context" - "encoding/binary" - "math/big" "slices" "time" "github.com/pkg/errors" "go.uber.org/zap" - "golang.org/x/crypto/sha3" - "source.quilibrium.com/quilibrium/monorepo/node/consensus/reward" - hgstate "source.quilibrium.com/quilibrium/monorepo/node/execution/state/hypergraph" "source.quilibrium.com/quilibrium/monorepo/protobufs" - "source.quilibrium.com/quilibrium/monorepo/types/execution/state" ) // AppLivenessProvider implements LivenessProvider @@ -47,9 +41,6 @@ func (p *AppLivenessProvider) Collect( mixnetMessages = p.engine.mixnet.GetMessages() } - var state state.State - state = hgstate.NewHypergraphState(p.engine.hypergraph) - finalizedMessages := []*protobufs.Message{} // Get and clear pending messages @@ -58,29 +49,17 @@ func (p *AppLivenessProvider) Collect( p.engine.pendingMessages = []*protobufs.Message{} p.engine.pendingMessagesMu.Unlock() - for i, message := range slices.Concat(mixnetMessages, pendingMessages) { - bundle := &protobufs.MessageBundle{} - if err := bundle.FromCanonicalBytes(message.Payload); err != nil { - p.engine.logger.Error( - "invalid message bytes", - zap.Int("message_index", i), - zap.Error(err), - ) - continue - } - - if err := bundle.Validate(); err != nil { - p.engine.logger.Error( - "invalid message", - zap.Int("message_index", i), - zap.Error(err), - ) - continue - } + frameNumber := uint64(p.engine.GetFrame().Header.FrameNumber) + 1 - costBasis, err := p.engine.executionManager.GetCost(message.Payload) + txMap := map[string][][]byte{} + for i, message := range slices.Concat(mixnetMessages, pendingMessages) { + err := p.engine.executionManager.ValidateMessage( + frameNumber, + message.Address, + message.Payload, + ) if err != nil { - p.engine.logger.Error( + p.engine.logger.Debug( "invalid message", zap.Int("message_index", i), zap.Error(err), @@ -88,40 +67,30 @@ func (p *AppLivenessProvider) Collect( continue } - p.engine.currentDifficultyMu.RLock() - difficulty := uint64(p.engine.currentDifficulty) - p.engine.currentDifficultyMu.RUnlock() - baseline := reward.GetBaselineFee( - difficulty, - p.engine.hypergraph.GetSize(nil, nil).Uint64(), - costBasis.Uint64(), - 8000000000, - ) - baseline.Quo(baseline, costBasis) - - result, err := p.engine.executionManager.ProcessMessage( - uint64(p.engine.GetFrame().Header.FrameNumber), - new(big.Int).Mul( - baseline, - big.NewInt(int64(p.engine.GetFrame().Header.FeeMultiplierVote)), - ), + lockedAddrs, err := p.engine.executionManager.Lock( + frameNumber, message.Address, message.Payload, - state, ) if err != nil { - p.engine.logger.Error( - "could not validate for execution", + p.engine.logger.Debug( + "message failed lock", zap.Int("message_index", i), zap.Error(err), ) continue } - state = result.State + txMap[string(message.Hash)] = lockedAddrs + finalizedMessages = append(finalizedMessages, message) } + err := p.engine.executionManager.Unlock() + if err != nil { + p.engine.logger.Error("could not unlock", zap.Error(err)) + } + p.engine.logger.Info( "collected messages", zap.Int("total_message_count", len(mixnetMessages)+len(pendingMessages)), @@ -133,16 +102,13 @@ func (p *AppLivenessProvider) Collect( ) // Calculate commitment root - commitment, err := p.engine.calculateRequestsRoot(finalizedMessages) + commitment, err := p.engine.calculateRequestsRoot(finalizedMessages, txMap) if err != nil { return CollectedCommitments{}, errors.Wrap(err, "collect") } - - commitmentHash := sha3.Sum256(commitment) - return CollectedCommitments{ - frameNumber: uint64(p.engine.GetFrame().Header.FrameNumber), - commitmentHash: commitmentHash[:], + frameNumber: frameNumber, + commitmentHash: commitment, prover: p.engine.getProverAddress(), }, nil } @@ -172,18 +138,14 @@ func (p *AppLivenessProvider) SendLiveness( } // Sign the message - signatureData := append( - p.engine.appAddress, - binary.BigEndian.AppendUint64(nil, frameNumber)..., - ) - signatureData = append( - signatureData, - binary.BigEndian.AppendUint64(nil, uint64(livenessCheck.Timestamp))..., - ) + signatureData, err := livenessCheck.ConstructSignaturePayload() + if err != nil { + return errors.Wrap(err, "send liveness") + } sig, err := signer.SignWithDomain( signatureData, - slices.Concat([]byte("liveness"), p.engine.appAddress), + livenessCheck.GetSignatureDomain(), ) if err != nil { return errors.Wrap(err, "send liveness") diff --git a/node/consensus/app/consensus_sync_provider.go b/node/consensus/app/consensus_sync_provider.go index 0dd184ab..6a02efc8 100644 --- a/node/consensus/app/consensus_sync_provider.go +++ b/node/consensus/app/consensus_sync_provider.go @@ -152,8 +152,10 @@ func (p *AppSyncProvider) Synchronize( } if latestFrame != nil { + p.engine.logger.Info("returning latest frame") dataCh <- &latestFrame } else if existing != nil { + p.engine.logger.Info("returning existing frame") dataCh <- existing } @@ -175,6 +177,7 @@ func (p *AppSyncProvider) syncWithMesh() error { peers, err := p.engine.proverRegistry.GetActiveProvers(p.engine.appAddress) if len(peers) <= 1 || err != nil { + p.engine.logger.Info("no peers to sync from") return nil } diff --git a/node/consensus/app/consensus_transition_listener.go b/node/consensus/app/consensus_transition_listener.go index eaeb00fe..7f71ce67 100644 --- a/node/consensus/app/consensus_transition_listener.go +++ b/node/consensus/app/consensus_transition_listener.go @@ -9,7 +9,9 @@ type AppTracer struct { logger *zap.Logger } -func (t *AppTracer) Trace(message string) {} +func (t *AppTracer) Trace(message string) { + // t.logger.Debug(message) +} func (t *AppTracer) Error(message string, err error) { t.logger.Error(message, zap.Error(err)) diff --git a/node/consensus/app/consensus_voting_provider.go b/node/consensus/app/consensus_voting_provider.go index a168c112..24e5faca 100644 --- a/node/consensus/app/consensus_voting_provider.go +++ b/node/consensus/app/consensus_voting_provider.go @@ -5,11 +5,13 @@ import ( "context" "encoding/hex" "sync" + "time" "github.com/iden3/go-iden3-crypto/poseidon" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "go.uber.org/zap" + "golang.org/x/crypto/sha3" "google.golang.org/protobuf/proto" "source.quilibrium.com/quilibrium/monorepo/consensus" "source.quilibrium.com/quilibrium/monorepo/protobufs" @@ -99,6 +101,10 @@ func (p *AppVotingProvider) DecideAndSendVote( for _, id := range provers { prop := proposals[PeerID{ID: id}.Identity()] if prop == nil { + p.engine.logger.Debug( + "proposer not found for prover", + zap.String("prover", PeerID{ID: id}.Identity()), + ) continue } // Validate the proposal @@ -222,9 +228,11 @@ func (p *AppVotingProvider) DecideAndSendVote( // Create vote message vote := &protobufs.FrameVote{ + Filter: p.engine.appAddress, FrameNumber: chosenProposal.Header.FrameNumber, Proposer: chosenProposal.Header.Prover, Approve: true, + Timestamp: time.Now().UnixMilli(), PublicKeySignatureBls48581: &protobufs.BLS48581AddressedSignature{ Address: voterAddress, Signature: sig, @@ -358,6 +366,58 @@ func (p *AppVotingProvider) FinalizeVotes( ) } + err := p.engine.ensureGlobalClient() + if err != nil { + return &parentFrame, PeerID{}, errors.Wrap( + errors.New("cannot confirm cross-shard locks"), + "finalize votes", + ) + } + + res, err := p.engine.globalClient.GetLockedAddresses( + ctx, + &protobufs.GetLockedAddressesRequest{ + ShardAddress: p.engine.appAddress, + FrameNumber: (*chosenProposal).Header.FrameNumber, + }, + ) + if err != nil { + p.engine.globalClient = nil + return &parentFrame, PeerID{}, errors.Wrap( + errors.New("cannot confirm cross-shard locks"), + "finalize votes", + ) + } + + txMap := map[string]bool{} + for _, req := range (*chosenProposal).Requests { + tx, err := req.ToCanonicalBytes() + if err != nil { + return &parentFrame, PeerID{}, errors.Wrap( + err, + "finalize votes", + ) + } + + txHash := sha3.Sum256(tx) + txMap[string(txHash[:])] = false + } + + for _, tx := range res.Transactions { + if _, ok := txMap[string(tx.TransactionHash)]; ok { + txMap[string(tx.TransactionHash)] = tx.Committed + } + } + + for _, committed := range txMap { + if !committed { + return &parentFrame, PeerID{}, errors.Wrap( + errors.New("tx cross-shard lock unconfirmed"), + "finalize votes", + ) + } + } + proverSet, err := p.engine.proverRegistry.GetActiveProvers( p.engine.appAddress, ) @@ -486,8 +546,10 @@ func (p *AppVotingProvider) SendConfirmation( // Create frame confirmation confirmation := &protobufs.FrameConfirmation{ + Filter: p.engine.appAddress, FrameNumber: copiedFinalized.Header.FrameNumber, Selector: p.engine.calculateFrameSelector((*finalized).Header), + Timestamp: time.Now().UnixMilli(), AggregateSignature: copiedFinalized.Header.PublicKeySignatureBls48581, } diff --git a/node/consensus/app/event_distributor.go b/node/consensus/app/event_distributor.go index 233eea04..b2abd506 100644 --- a/node/consensus/app/event_distributor.go +++ b/node/consensus/app/event_distributor.go @@ -166,6 +166,31 @@ func (e *AppConsensusEngine) eventDistributorLoop() { } } + case typesconsensus.ControlEventCoverageHalt: + data, ok := event.Data.(*typesconsensus.CoverageEventData) + if ok && data.Message != "" { + e.logger.Error(data.Message) + e.halt() + if err := e.stateMachine.Stop(); err != nil { + e.logger.Error( + "error occurred while halting consensus", + zap.Error(err), + ) + } + go func() { + for { + select { + case <-e.ctx.Done(): + return + case <-time.After(10 * time.Second): + e.logger.Error( + "full halt detected, leaving system in halted state until recovery", + ) + } + } + }() + } + case typesconsensus.ControlEventHalt: data, ok := event.Data.(*typesconsensus.ErrorEventData) if ok && data.Error != nil { diff --git a/node/consensus/app/factory.go b/node/consensus/app/factory.go index b4b1c33c..7826a0d5 100644 --- a/node/consensus/app/factory.go +++ b/node/consensus/app/factory.go @@ -117,6 +117,7 @@ func (f *AppConsensusEngineFactory) CreateAppConsensusEngine( appAddress, f.proverRegistry, f.clockStore, + f.config.Engine.ArchiveMode, ) if err != nil { return nil, errors.Wrap(err, "create app time reel") diff --git a/node/consensus/app/integration_helper_test.go b/node/consensus/app/integration_helper_test.go index a178447e..7df4deec 100644 --- a/node/consensus/app/integration_helper_test.go +++ b/node/consensus/app/integration_helper_test.go @@ -7,24 +7,36 @@ import ( "bytes" "context" "encoding/binary" + "encoding/hex" "fmt" "math/big" + "math/rand" "slices" "sync" "testing" "time" "github.com/iden3/go-iden3-crypto/poseidon" + pcrypto "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" multiaddr "github.com/multiformats/go-multiaddr" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.uber.org/zap" + "golang.org/x/crypto/sha3" "google.golang.org/grpc" "google.golang.org/protobuf/types/known/wrapperspb" "source.quilibrium.com/quilibrium/monorepo/bls48581" + "source.quilibrium.com/quilibrium/monorepo/bulletproofs" + "source.quilibrium.com/quilibrium/monorepo/config" "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb" "source.quilibrium.com/quilibrium/monorepo/hypergraph" + "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token" + "source.quilibrium.com/quilibrium/monorepo/node/keys" + qp2p "source.quilibrium.com/quilibrium/monorepo/node/p2p" "source.quilibrium.com/quilibrium/monorepo/protobufs" "source.quilibrium.com/quilibrium/monorepo/types/consensus" "source.quilibrium.com/quilibrium/monorepo/types/crypto" @@ -33,20 +45,24 @@ import ( "source.quilibrium.com/quilibrium/monorepo/types/execution/state" thypergraph "source.quilibrium.com/quilibrium/monorepo/types/hypergraph" "source.quilibrium.com/quilibrium/monorepo/types/p2p" + "source.quilibrium.com/quilibrium/monorepo/types/schema" qcrypto "source.quilibrium.com/quilibrium/monorepo/types/tries" + "source.quilibrium.com/quilibrium/monorepo/verenc" ) // mockAppIntegrationPubSub extends the basic mock with app-specific features type mockAppIntegrationPubSub struct { mock.Mock - mu sync.RWMutex - subscribers map[string][]func(message *pb.Message) error - validators map[string]func(peerID peer.ID, message *pb.Message) p2p.ValidationResult - peerID []byte - peerCount int - networkPeers map[string]*mockAppIntegrationPubSub - messageLog []messageRecord // Track all messages for debugging - frames []*protobufs.AppShardFrame // Store frames for sync + mu sync.RWMutex + subscribers map[string][]func(message *pb.Message) error + validators map[string]func(peerID peer.ID, message *pb.Message) p2p.ValidationResult + peerID []byte + peerCount int + networkPeers map[string]*mockAppIntegrationPubSub + messageLog []messageRecord // Track all messages for debugging + frames []*protobufs.AppShardFrame // Store frames for sync + underlyingHost host.Host + underlyingBlossomSub *qp2p.BlossomSub } // GetOwnMultiaddrs implements p2p.PubSub. @@ -151,24 +167,28 @@ type messageRecord struct { data []byte } -func newMockAppIntegrationPubSub(peerID []byte) *mockAppIntegrationPubSub { +func newMockAppIntegrationPubSub(config *config.Config, logger *zap.Logger, peerID []byte, host host.Host, privKey pcrypto.PrivKey, bootstrapHosts []host.Host) *mockAppIntegrationPubSub { + blossomSub := qp2p.NewBlossomSubWithHost(config.P2P, config.Engine, logger, 1, true, host, privKey, bootstrapHosts) + return &mockAppIntegrationPubSub{ - subscribers: make(map[string][]func(message *pb.Message) error), - validators: make(map[string]func(peerID peer.ID, message *pb.Message) p2p.ValidationResult), - peerID: peerID, - peerCount: 10, - networkPeers: make(map[string]*mockAppIntegrationPubSub), - messageLog: make([]messageRecord, 0), - frames: make([]*protobufs.AppShardFrame, 0), + subscribers: make(map[string][]func(message *pb.Message) error), + validators: make(map[string]func(peerID peer.ID, message *pb.Message) p2p.ValidationResult), + peerID: peerID, + peerCount: 10, + networkPeers: make(map[string]*mockAppIntegrationPubSub), + messageLog: make([]messageRecord, 0), + frames: make([]*protobufs.AppShardFrame, 0), + underlyingHost: host, + underlyingBlossomSub: blossomSub, } } func (m *mockAppIntegrationPubSub) Subscribe(bitmask []byte, handler func(message *pb.Message) error) error { m.mu.Lock() - defer m.mu.Unlock() key := string(bitmask) m.subscribers[key] = append(m.subscribers[key], handler) - return nil + m.mu.Unlock() + return m.underlyingBlossomSub.Subscribe(bitmask, handler) } func (m *mockAppIntegrationPubSub) PublishToBitmask(bitmask []byte, data []byte) error { @@ -196,74 +216,46 @@ func (m *mockAppIntegrationPubSub) PublishToBitmask(bitmask []byte, data []byte) } m.mu.Unlock() - message := &pb.Message{ - Data: data, - From: m.peerID, - } - - // Deliver to local subscribers - m.mu.RLock() - handlers := m.subscribers[string(bitmask)] - m.mu.RUnlock() - - for _, handler := range handlers { - go handler(message) - } - - // Deliver to network peers - m.mu.RLock() - peers := make([]*mockAppIntegrationPubSub, 0, len(m.networkPeers)) - for _, peer := range m.networkPeers { - if peer != m { - peers = append(peers, peer) - } - } - m.mu.RUnlock() - - for _, peer := range peers { - // Deliver synchronously to ensure proper ordering - peer.receiveFromNetwork(bitmask, message) - } - - return nil -} - -func (m *mockAppIntegrationPubSub) receiveFromNetwork(bitmask []byte, message *pb.Message) { - m.mu.RLock() - validator := m.validators[string(bitmask)] - m.mu.RUnlock() - - if validator != nil { - result := validator(peer.ID(message.From), message) - if result != p2p.ValidationResultAccept { - // Log validation rejection for debugging - if len(message.Data) >= 4 { - typePrefix := binary.BigEndian.Uint32(message.Data[:4]) - if typePrefix == protobufs.AppShardFrameType { - frame := &protobufs.AppShardFrame{} - if err := frame.FromCanonicalBytes(message.Data); err == nil && frame.Header != nil { - fmt.Printf("DEBUG: Node %x rejected frame %d from %x (validation result: %v)\n", - m.peerID[:4], frame.Header.FrameNumber, message.From[:4], result) - } - } - } - return - } - } - - m.mu.RLock() - handlers := m.subscribers[string(bitmask)] - m.mu.RUnlock() - - for _, handler := range handlers { - go handler(message) // Make async to match PublishToBitmask behavior - } -} + return m.underlyingBlossomSub.PublishToBitmask(bitmask, data) +} + +// func (m *mockAppIntegrationPubSub) receiveFromNetwork(bitmask []byte, message *pb.Message) { +// m.mu.RLock() +// validator := m.validators[string(bitmask)] +// m.mu.RUnlock() + +// if validator != nil { +// result := validator(peer.ID(message.From), message) +// if result != p2p.ValidationResultAccept { +// // Log validation rejection for debugging +// if len(message.Data) >= 4 { +// typePrefix := binary.BigEndian.Uint32(message.Data[:4]) +// if typePrefix == protobufs.AppShardFrameType { +// frame := &protobufs.AppShardFrame{} +// if err := frame.FromCanonicalBytes(message.Data); err == nil && frame.Header != nil { +// fmt.Printf("DEBUG: Node %x rejected frame %d from %x (validation result: %v)\n", +// m.peerID[:4], frame.Header.FrameNumber, message.From[:4], result) +// } +// } +// } +// return +// } +// } + +// m.mu.RLock() +// handlers := m.subscribers[string(bitmask)] +// m.mu.RUnlock() + +// for _, handler := range handlers { +// go handler(message) // Make async to match PublishToBitmask behavior +// } +// } func (m *mockAppIntegrationPubSub) RegisterValidator(bitmask []byte, validator func(peerID peer.ID, message *pb.Message) p2p.ValidationResult, sync bool) error { m.mu.Lock() - defer m.mu.Unlock() m.validators[string(bitmask)] = validator + m.mu.Unlock() + m.underlyingBlossomSub.RegisterValidator(bitmask, validator, sync) return nil } @@ -564,3 +556,358 @@ func registerProverInHypergraphWithFilter(t *testing.T, hg thypergraph.Hypergrap t.Logf(" Registered prover with address: %x, filter: %x (public key length: %d)", address, filter, len(publicKey)) } + +type mockGlobalClientLocks struct { + committed bool + hashes [][]byte +} + +func (m *mockGlobalClientLocks) GetGlobalFrame(ctx context.Context, in *protobufs.GetGlobalFrameRequest, opts ...grpc.CallOption) (*protobufs.GlobalFrameResponse, error) { + return nil, errors.New("not used in this test") +} +func (m *mockGlobalClientLocks) GetAppShards(ctx context.Context, in *protobufs.GetAppShardsRequest, opts ...grpc.CallOption) (*protobufs.GetAppShardsResponse, error) { + return nil, errors.New("not used in this test") +} +func (m *mockGlobalClientLocks) GetGlobalShards(ctx context.Context, in *protobufs.GetGlobalShardsRequest, opts ...grpc.CallOption) (*protobufs.GetGlobalShardsResponse, error) { + return nil, errors.New("not used in this test") +} +func (m *mockGlobalClientLocks) GetLockedAddresses(ctx context.Context, in *protobufs.GetLockedAddressesRequest, opts ...grpc.CallOption) (*protobufs.GetLockedAddressesResponse, error) { + out := &protobufs.GetLockedAddressesResponse{Transactions: make([]*protobufs.LockedTransaction, 0, len(m.hashes))} + for _, h := range m.hashes { + out.Transactions = append(out.Transactions, &protobufs.LockedTransaction{ + TransactionHash: h, + Committed: m.committed, + }) + } + return out, nil +} + +func createValidPendingTxPayload(t *testing.T, hgs []thypergraph.Hypergraph, km *keys.InMemoryKeyManager) []byte { + dc := &bulletproofs.Decaf448KeyConstructor{} + vk, _ := dc.New() + sk, _ := dc.New() + rvk, _ := dc.New() + rsk, _ := dc.New() + + out1, err := token.NewPendingTransactionOutput(big.NewInt(7), vk.Public(), sk.Public(), rvk.Public(), rsk.Public(), 0) + if err != nil { + t.Fatal(err) + } + out2, err := token.NewPendingTransactionOutput(big.NewInt(2), vk.Public(), sk.Public(), rvk.Public(), rsk.Public(), 0) + if err != nil { + t.Fatal(err) + } + + bp := &bulletproofs.Decaf448BulletproofProver{} + pvk, err := km.CreateAgreementKey("q-view-key", crypto.KeyTypeDecaf448) + assert.NoError(t, err) + psk, err := km.CreateAgreementKey("q-spend-key", crypto.KeyTypeDecaf448) + assert.NoError(t, err) + + address1 := [64]byte{} + copy(address1[:32], token.QUIL_TOKEN_ADDRESS) + rand.Read(address1[32:]) + address2 := [64]byte{} + copy(address2[:32], token.QUIL_TOKEN_ADDRESS) + rand.Read(address2[32:]) + + tree1 := &qcrypto.VectorCommitmentTree{} + tree2 := &qcrypto.VectorCommitmentTree{} + otk1, _ := dc.New() + otk2, _ := dc.New() + c1, _ := dc.New() + c2, _ := dc.New() + comm1 := bp.GenerateInputCommitmentsFromBig([]*big.Int{big.NewInt(3)}, c1.Private()) + comm2 := bp.GenerateInputCommitmentsFromBig([]*big.Int{big.NewInt(9)}, c2.Private()) + mask1 := c1.Private() + mask2 := c2.Private() + a1, _ := otk1.AgreeWithAndHashToScalar(pvk.Public()) + a2, _ := otk2.AgreeWithAndHashToScalar(pvk.Public()) + + blindMask1 := make([]byte, 56) + coinMask1 := make([]byte, 56) + shake := sha3.NewCShake256([]byte{}, []byte("blind")) + shake.Write(a1.Public()) + shake.Read(blindMask1) + + shake = sha3.NewCShake256([]byte{}, []byte("coin")) + shake.Write(a1.Public()) + shake.Read(coinMask1) + + for i := range blindMask1 { + mask1[i] ^= blindMask1[i] + } + maskedCoinBalanceBytes1 := make([]byte, 56) + maskedCoinBalanceBytes1[0] = 0x03 + for i := range maskedCoinBalanceBytes1 { + maskedCoinBalanceBytes1[i] ^= coinMask1[i] + } + blindMask2 := make([]byte, 56) + coinMask2 := make([]byte, 56) + shake = sha3.NewCShake256([]byte{}, []byte("blind")) + shake.Write(a2.Public()) + shake.Read(blindMask2) + + shake = sha3.NewCShake256([]byte{}, []byte("coin")) + shake.Write(a2.Public()) + shake.Read(coinMask2) + + for i := range blindMask2 { + mask2[i] ^= blindMask2[i] + } + maskedCoinBalanceBytes2 := make([]byte, 56) + maskedCoinBalanceBytes2[0] = 0x09 + for i := range maskedCoinBalanceBytes2 { + maskedCoinBalanceBytes2[i] ^= coinMask2[i] + } + + verifkey1, _ := a1.Add(psk.Public()) + tree1.Insert([]byte{0}, binary.BigEndian.AppendUint64(nil, 0), nil, big.NewInt(8)) + tree1.Insert([]byte{1 << 2}, comm1, nil, big.NewInt(56)) + tree1.Insert([]byte{2 << 2}, otk1.Public(), nil, big.NewInt(56)) + tree1.Insert([]byte{3 << 2}, verifkey1, nil, big.NewInt(56)) + tree1.Insert([]byte{4 << 2}, maskedCoinBalanceBytes1, nil, big.NewInt(56)) + tree1.Insert([]byte{5 << 2}, mask1, nil, big.NewInt(56)) + verifkey2, _ := a2.Add(psk.Public()) + tree2.Insert([]byte{0}, binary.BigEndian.AppendUint64(nil, 0), nil, big.NewInt(8)) + tree2.Insert([]byte{1 << 2}, comm2, nil, big.NewInt(56)) + tree2.Insert([]byte{2 << 2}, otk2.Public(), nil, big.NewInt(56)) + tree2.Insert([]byte{3 << 2}, verifkey2, nil, big.NewInt(56)) + tree2.Insert([]byte{4 << 2}, maskedCoinBalanceBytes2, nil, big.NewInt(56)) + tree2.Insert([]byte{5 << 2}, mask2, nil, big.NewInt(56)) + + // qcrypto.DebugNonLazyNode(tree.Root, 0, "") + typeAddr, _ := hex.DecodeString("096de9a09f693f92cfa9cf3349bab2b3baee09f3e4f9c596514ecb3e8b0dff8f") + tree1.Insert(bytes.Repeat([]byte{0xff}, 32), typeAddr, nil, big.NewInt(32)) + tree2.Insert(bytes.Repeat([]byte{0xff}, 32), typeAddr, nil, big.NewInt(32)) + for _, hg := range hgs { + txn, _ := hg.NewTransaction(false) + hg.AddVertex(txn, hypergraph.NewVertex([32]byte(token.QUIL_TOKEN_ADDRESS), [32]byte(address1[32:]), tree1.Commit(hg.GetProver(), false), big.NewInt(55*26))) + hg.SetVertexData(txn, address1, tree1) + hg.AddVertex(txn, hypergraph.NewVertex([32]byte(token.QUIL_TOKEN_ADDRESS), [32]byte(address2[32:]), tree2.Commit(hg.GetProver(), false), big.NewInt(55*26))) + hg.SetVertexData(txn, address2, tree2) + txn.Commit() + } + + // simulate input as commitment to total + input1, _ := token.NewPendingTransactionInput(address1[:]) + input2, _ := token.NewPendingTransactionInput(address2[:]) + tokenconfig := &token.TokenIntrinsicConfiguration{ + Behavior: token.Mintable | token.Burnable | token.Divisible | token.Acceptable | token.Expirable | token.Tenderable, + MintStrategy: &token.TokenMintStrategy{ + MintBehavior: token.MintWithProof, + ProofBasis: token.ProofOfMeaningfulWork, + }, + Units: big.NewInt(8000000000), + Name: "QUIL", + Symbol: "QUIL", + } + + // Create RDF multiprover for testing + rdfSchema, err := prepareRDFSchemaFromConfig(token.QUIL_TOKEN_ADDRESS, tokenconfig) + assert.NoError(t, err) + parser := &schema.TurtleRDFParser{} + rdfMultiprover := schema.NewRDFMultiprover(parser, hgs[0].GetProver()) + + tx := token.NewPendingTransaction( + [32]byte(token.QUIL_TOKEN_ADDRESS), + []*token.PendingTransactionInput{input1, input2}, + []*token.PendingTransactionOutput{out1, out2}, + []*big.Int{big.NewInt(1), big.NewInt(2)}, + tokenconfig, + hgs[0], + bp, + hgs[0].GetProver(), + verenc.NewMPCitHVerifiableEncryptor(1), + dc, + keys.ToKeyRing(km, false), + rdfSchema, + rdfMultiprover, + ) + + if err := tx.Prove(1); err != nil { + t.Fatal(err) + } + + req := &protobufs.MessageBundle{ + Requests: []*protobufs.MessageRequest{ + { + Request: &protobufs.MessageRequest_PendingTransaction{ + PendingTransaction: tx.ToProtobuf(), + }, + }, + }, + } + out, err := req.ToCanonicalBytes() + assert.NoError(t, err) + return out +} + +func prepareRDFSchemaFromConfig( + appAddress []byte, + config *token.TokenIntrinsicConfiguration, +) (string, error) { + schema := generateRDFPrelude(appAddress, config) + + schema += "coin:Coin a rdfs:Class.\n" + + "coin:FrameNumber a rdfs:Property;\n" + + " rdfs:domain qcl:Uint;\n" + + " qcl:size 8;\n" + + " qcl:order 0;\n" + + " rdfs:range coin:Coin.\n" + + "coin:Commitment a rdfs:Property;\n" + + " rdfs:domain qcl:ByteArray;\n" + + " qcl:size 56;\n" + + " qcl:order 1;\n" + + " rdfs:range coin:Coin.\n" + + "coin:OneTimeKey a rdfs:Property;\n" + + " rdfs:domain qcl:ByteArray;\n" + + " qcl:size 56;\n" + + " qcl:order 2;\n" + + " rdfs:range coin:Coin.\n" + + "coin:VerificationKey a rdfs:Property;\n" + + " rdfs:domain qcl:ByteArray;\n" + + " qcl:size 56;\n" + + " qcl:order 3;\n" + + " rdfs:range coin:Coin.\n" + + "coin:CoinBalance a rdfs:Property;\n" + + " rdfs:domain qcl:Uint;\n" + + " qcl:size 56;\n" + + " qcl:order 4;\n" + + " rdfs:range coin:Coin.\n" + + "coin:Mask a rdfs:Property;\n" + + " rdfs:domain qcl:ByteArray;\n" + + " qcl:size 56;\n" + + " qcl:order 5;\n" + + " rdfs:range coin:Coin.\n" + + if config.Behavior&token.Divisible == 0 { + schema += "coin:AdditionalReference a rdfs:Property;\n" + + " rdfs:domain qcl:ByteArray;\n" + + " qcl:size 64;\n" + + " qcl:order 6;\n" + + " rdfs:range coin:Coin.\n" + schema += "coin:AdditionalReferenceKey a rdfs:Property;\n" + + " rdfs:domain qcl:ByteArray;\n" + + " qcl:size 56;\n" + + " qcl:order 7;\n" + + " rdfs:range coin:Coin.\n" + } + + if config.Behavior&token.Acceptable != 0 { + schema += "\npending:PendingTransaction a rdfs:Class;\n" + + " rdfs:label \"a pending transaction\".\n" + + "pending:FrameNumber a rdfs:Property;\n" + + " rdfs:domain qcl:Uint;\n" + + " qcl:size 8;\n" + + " qcl:order 0;\n" + + " rdfs:range pending:PendingTransaction.\n" + + "pending:Commitment a rdfs:Property;\n" + + " rdfs:domain qcl:ByteArray;\n" + + " qcl:size 56;\n" + + " qcl:order 1;\n" + + " rdfs:range pending:PendingTransaction.\n" + + "pending:ToOneTimeKey a rdfs:Property;\n" + + " rdfs:domain qcl:ByteArray;\n" + + " qcl:size 56;\n" + + " qcl:order 2;\n" + + " rdfs:range pending:PendingTransaction.\n" + + "pending:RefundOneTimeKey a rdfs:Property;\n" + + " rdfs:domain qcl:ByteArray;\n" + + " qcl:size 56;\n" + + " qcl:order 3;\n" + + " rdfs:range pending:PendingTransaction.\n" + + "pending:ToVerificationKey a rdfs:Property;\n" + + " rdfs:domain qcl:ByteArray;\n" + + " qcl:size 56;\n" + + " qcl:order 4;\n" + + " rdfs:range pending:PendingTransaction.\n" + + "pending:RefundVerificationKey a rdfs:Property;\n" + + " rdfs:domain qcl:ByteArray;\n" + + " qcl:size 56;\n" + + " qcl:order 5;\n" + + " rdfs:range pending:PendingTransaction.\n" + + "pending:ToCoinBalance a rdfs:Property;\n" + + " rdfs:domain qcl:Uint;\n" + + " qcl:size 56;\n" + + " qcl:order 6;\n" + + " rdfs:range pending:PendingTransaction.\n" + + "pending:RefundCoinBalance a rdfs:Property;\n" + + " rdfs:domain qcl:Uint;\n" + + " qcl:size 56;\n" + + " qcl:order 7;\n" + + " rdfs:range pending:PendingTransaction.\n" + + "pending:ToMask a rdfs:Property;\n" + + " rdfs:domain qcl:ByteArray;\n" + + " qcl:size 56;\n" + + " qcl:order 8;\n" + + " rdfs:range pending:PendingTransaction.\n" + + "pending:RefundMask a rdfs:Property;\n" + + " rdfs:domain qcl:ByteArray;\n" + + " qcl:size 56;\n" + + " qcl:order 9;\n" + + " rdfs:range pending:PendingTransaction.\n" + + if config.Behavior&token.Divisible == 0 { + schema += "pending:ToAdditionalReference a rdfs:Property;\n" + + " rdfs:domain qcl:ByteArray;\n" + + " qcl:size 64;\n" + + " qcl:order 10;\n" + + " rdfs:range pending:PendingTransaction.\n" + + "pending:ToAdditionalReferenceKey a rdfs:Property;\n" + + " rdfs:domain qcl:ByteArray;\n" + + " qcl:size 56;\n" + + " qcl:order 11;\n" + + " rdfs:range pending:PendingTransaction.\n" + + "pending:RefundAdditionalReference a rdfs:Property;\n" + + " rdfs:domain qcl:ByteArray;\n" + + " qcl:size 64;\n" + + " qcl:order 12;\n" + + " rdfs:range pending:PendingTransaction.\n" + + "pending:RefundAdditionalReferenceKey a rdfs:Property;\n" + + " rdfs:domain qcl:ByteArray;\n" + + " qcl:size 56;\n" + + " qcl:order 13;\n" + + " rdfs:range pending:PendingTransaction.\n" + } + + if config.Behavior&token.Expirable != 0 { + schema += "pending:Expiration a rdfs:Property;\n" + + " rdfs:domain qcl:Uint;\n" + + " qcl:size 8;\n" + + if config.Behavior&token.Divisible == 0 { + schema += " qcl:order 14;\n" + } else { + schema += " qcl:order 10;\n" + } + + schema += " rdfs:range pending:PendingTransaction.\n" + } + } + + schema += "\n" + + return schema, nil +} + +func generateRDFPrelude( + appAddress []byte, + config *token.TokenIntrinsicConfiguration, +) string { + appAddressHex := hex.EncodeToString(appAddress) + + prelude := "BASE \n" + + "PREFIX rdf: \n" + + "PREFIX rdfs: \n" + + "PREFIX qcl: \n" + + "PREFIX coin: \n" + + if config.Behavior&token.Acceptable != 0 { + prelude += "PREFIX pending: \n" + } + + prelude += "\n" + + return prelude +} diff --git a/node/consensus/app/message_processors.go b/node/consensus/app/message_processors.go index 7b5805d5..8d5aa13d 100644 --- a/node/consensus/app/message_processors.go +++ b/node/consensus/app/message_processors.go @@ -3,6 +3,7 @@ package app import ( "bytes" "encoding/binary" + "encoding/hex" "github.com/iden3/go-iden3-crypto/poseidon" "github.com/libp2p/go-libp2p/core/peer" @@ -14,10 +15,6 @@ import ( ) func (e *AppConsensusEngine) processConsensusMessageQueue() { - if e.config.P2P.Network != 99 && !e.config.Engine.ArchiveMode { - return - } - defer e.wg.Done() for { @@ -35,10 +32,6 @@ func (e *AppConsensusEngine) processConsensusMessageQueue() { func (e *AppConsensusEngine) processProverMessageQueue() { defer e.wg.Done() - if e.config.P2P.Network != 99 && !e.config.Engine.ArchiveMode { - return - } - for { select { case <-e.haltCtx.Done(): @@ -177,7 +170,7 @@ func (e *AppConsensusEngine) handleFrameMessage(message *pb.Message) { }() // we're already getting this from consensus - if e.config.P2P.Network == 99 || e.config.Engine.ArchiveMode { + if e.IsInProverTrie(e.getProverAddress()) { return } @@ -426,14 +419,14 @@ func (e *AppConsensusEngine) handleDispatchMessage(message *pb.Message) { func (e *AppConsensusEngine) handleProposal(message *pb.Message) { timer := prometheus.NewTimer( - frameProcessingDuration.WithLabelValues(e.appAddressHex), + proposalProcessingDuration.WithLabelValues(e.appAddressHex), ) defer timer.ObserveDuration() + frame := &protobufs.AppShardFrame{} if err := frame.FromCanonicalBytes(message.Data); err != nil { e.logger.Debug("failed to unmarshal frame", zap.Error(err)) - framesProcessedTotal.WithLabelValues(e.appAddressHex, "error").Inc() - timer.ObserveDuration() + proposalProcessedTotal.WithLabelValues(e.appAddressHex, "error").Inc() return } @@ -441,11 +434,10 @@ func (e *AppConsensusEngine) handleProposal(message *pb.Message) { valid, err := e.frameValidator.Validate(frame) if !valid || err != nil { e.logger.Error("received invalid frame", zap.Error(err)) - framesProcessedTotal.WithLabelValues( + proposalProcessedTotal.WithLabelValues( e.appAddressHex, "invalid", ).Inc() - timer.ObserveDuration() return } @@ -459,50 +451,182 @@ func (e *AppConsensusEngine) handleProposal(message *pb.Message) { PeerID{ID: frame.Header.Prover}, &frame, ) - framesProcessedTotal.WithLabelValues(e.appAddressHex, "success").Inc() + proposalProcessedTotal.WithLabelValues(e.appAddressHex, "success").Inc() } } func (e *AppConsensusEngine) handleLivenessCheck(message *pb.Message) { + timer := prometheus.NewTimer( + livenessCheckProcessingDuration.WithLabelValues(e.appAddressHex), + ) + defer timer.ObserveDuration() + livenessCheck := &protobufs.ProverLivenessCheck{} if err := livenessCheck.FromCanonicalBytes(message.Data); err != nil { e.logger.Debug("failed to unmarshal liveness check", zap.Error(err)) + livenessCheckProcessedTotal.WithLabelValues(e.appAddressHex, "error").Inc() + return + } + + if !bytes.Equal(livenessCheck.Filter, e.appAddress) { + return + } + + // Validate the liveness check structure + if err := livenessCheck.Validate(); err != nil { + e.logger.Debug("invalid liveness check", zap.Error(err)) + livenessCheckProcessedTotal.WithLabelValues(e.appAddressHex, "error").Inc() + return + } + + proverSet, err := e.proverRegistry.GetActiveProvers(e.appAddress) + if err != nil { + e.logger.Error("could not receive liveness check", zap.Error(err)) + livenessCheckProcessedTotal.WithLabelValues(e.appAddressHex, "error").Inc() return } - if livenessCheck.PublicKeySignatureBls48581 != nil { - commitment := CollectedCommitments{ - commitmentHash: livenessCheck.CommitmentHash, - frameNumber: livenessCheck.FrameNumber, - prover: livenessCheck.PublicKeySignatureBls48581.Address, + var found []byte = nil + for _, prover := range proverSet { + if bytes.Equal( + prover.Address, + livenessCheck.PublicKeySignatureBls48581.Address, + ) { + lcBytes, err := livenessCheck.ConstructSignaturePayload() + if err != nil { + e.logger.Error( + "could not construct signature message for liveness check", + zap.Error(err), + ) + break + } + valid, err := e.keyManager.ValidateSignature( + crypto.KeyTypeBLS48581G1, + prover.PublicKey, + lcBytes, + livenessCheck.PublicKeySignatureBls48581.Signature, + livenessCheck.GetSignatureDomain(), + ) + if err != nil || !valid { + e.logger.Error( + "could not validate signature for liveness check", + zap.Error(err), + ) + break + } + found = prover.PublicKey + + break } - e.stateMachine.ReceiveLivenessCheck( - PeerID{ID: livenessCheck.PublicKeySignatureBls48581.Address}, - commitment, + } + + if found == nil { + e.logger.Warn( + "invalid liveness check", + zap.String( + "prover", + hex.EncodeToString( + livenessCheck.PublicKeySignatureBls48581.Address, + ), + ), ) + livenessCheckProcessedTotal.WithLabelValues(e.appAddressHex, "error").Inc() + return + } + + signatureData, err := livenessCheck.ConstructSignaturePayload() + if err != nil { + e.logger.Error("invalid signature payload", zap.Error(err)) + livenessCheckProcessedTotal.WithLabelValues(e.appAddressHex, "error").Inc() + return + } + + valid, err := e.keyManager.ValidateSignature( + crypto.KeyTypeBLS48581G1, + found, + signatureData, + livenessCheck.PublicKeySignatureBls48581.Signature, + livenessCheck.GetSignatureDomain(), + ) + + if err != nil || !valid { + e.logger.Error("invalid liveness check signature", zap.Error(err)) + livenessCheckProcessedTotal.WithLabelValues(e.appAddressHex, "error").Inc() + return } + + if livenessCheck.PublicKeySignatureBls48581 == nil { + e.logger.Error("no signature on liveness check") + livenessCheckProcessedTotal.WithLabelValues(e.appAddressHex, "error").Inc() + } + + commitment := CollectedCommitments{ + commitmentHash: livenessCheck.CommitmentHash, + frameNumber: livenessCheck.FrameNumber, + prover: livenessCheck.PublicKeySignatureBls48581.Address, + } + if err := e.stateMachine.ReceiveLivenessCheck( + PeerID{ID: livenessCheck.PublicKeySignatureBls48581.Address}, + commitment, + ); err != nil { + e.logger.Error("could not receive liveness check", zap.Error(err)) + livenessCheckProcessedTotal.WithLabelValues(e.appAddressHex, "error").Inc() + return + } + + livenessCheckProcessedTotal.WithLabelValues(e.appAddressHex, "success").Inc() } func (e *AppConsensusEngine) handleVote(message *pb.Message) { + timer := prometheus.NewTimer( + voteProcessingDuration.WithLabelValues(e.appAddressHex), + ) + defer timer.ObserveDuration() + vote := &protobufs.FrameVote{} if err := vote.FromCanonicalBytes(message.Data); err != nil { e.logger.Debug("failed to unmarshal vote", zap.Error(err)) + voteProcessedTotal.WithLabelValues(e.appAddressHex, "error").Inc() return } - if vote.PublicKeySignatureBls48581 != nil { - e.stateMachine.ReceiveVote( - PeerID{ID: vote.Proposer}, - PeerID{ID: vote.PublicKeySignatureBls48581.Address}, - &vote, - ) + if !bytes.Equal(vote.Filter, e.appAddress) { + return + } + + if vote.PublicKeySignatureBls48581 == nil { + e.logger.Error("vote without signature") + voteProcessedTotal.WithLabelValues(e.appAddressHex, "error").Inc() + return } + + if err := e.stateMachine.ReceiveVote( + PeerID{ID: vote.Proposer}, + PeerID{ID: vote.PublicKeySignatureBls48581.Address}, + &vote, + ); err != nil { + e.logger.Error("could not receive vote", zap.Error(err)) + voteProcessedTotal.WithLabelValues(e.appAddressHex, "error").Inc() + return + } + + voteProcessedTotal.WithLabelValues(e.appAddressHex, "success").Inc() } func (e *AppConsensusEngine) handleConfirmation(message *pb.Message) { + timer := prometheus.NewTimer( + confirmationProcessingDuration.WithLabelValues(e.appAddressHex), + ) + defer timer.ObserveDuration() + confirmation := &protobufs.FrameConfirmation{} if err := confirmation.FromCanonicalBytes(message.Data); err != nil { e.logger.Debug("failed to unmarshal confirmation", zap.Error(err)) + confirmationProcessedTotal.WithLabelValues(e.appAddressHex, "error").Inc() + return + } + + if !bytes.Equal(confirmation.Filter, e.appAddress) { return } @@ -533,22 +657,35 @@ func (e *AppConsensusEngine) handleConfirmation(message *pb.Message) { valid, err := e.frameValidator.Validate(matchingFrame) if !valid || err != nil { e.logger.Error("received invalid confirmation", zap.Error(err)) + confirmationProcessedTotal.WithLabelValues(e.appAddressHex, "error").Inc() + return + } + + if matchingFrame.Header.Prover == nil { + e.logger.Error("confirmation with no matched prover") + confirmationProcessedTotal.WithLabelValues(e.appAddressHex, "error").Inc() return } - if matchingFrame.Header.Prover != nil { - e.stateMachine.ReceiveConfirmation( - PeerID{ID: matchingFrame.Header.Prover}, - &matchingFrame, + if err := e.stateMachine.ReceiveConfirmation( + PeerID{ID: matchingFrame.Header.Prover}, + &matchingFrame, + ); err != nil { + e.logger.Error("could not receive confirmation", zap.Error(err)) + confirmationProcessedTotal.WithLabelValues(e.appAddressHex, "error").Inc() + return + } + + if err := e.appTimeReel.Insert(e.ctx, matchingFrame); err != nil { + e.logger.Error( + "could not insert into time reel", + zap.Error(err), ) - err := e.appTimeReel.Insert(e.ctx, matchingFrame) - if err != nil { - e.logger.Error( - "could not insert into time reel", - zap.Error(err), - ) - } + confirmationProcessedTotal.WithLabelValues(e.appAddressHex, "error").Inc() + return } + + confirmationProcessedTotal.WithLabelValues(e.appAddressHex, "success").Inc() } func (e *AppConsensusEngine) peekMessageType(message *pb.Message) uint32 { diff --git a/node/consensus/app/message_subscription.go b/node/consensus/app/message_subscription.go index 69d605ba..176b77f7 100644 --- a/node/consensus/app/message_subscription.go +++ b/node/consensus/app/message_subscription.go @@ -9,16 +9,12 @@ import ( ) func (e *AppConsensusEngine) subscribeToConsensusMessages() error { - if e.config.P2P.Network != 99 && !e.config.Engine.ArchiveMode { - return nil - } - proverKey, _, _, _ := e.GetProvingKey(e.config.Engine) e.mixnet = rpm.NewRPMMixnet( e.logger, proverKey, e.proverRegistry, - e.appFilter, + e.appAddress, ) if err := e.pubsub.Subscribe( @@ -53,10 +49,6 @@ func (e *AppConsensusEngine) subscribeToConsensusMessages() error { } func (e *AppConsensusEngine) subscribeToGlobalProverMessages() error { - if e.config.P2P.Network != 99 && !e.config.Engine.ArchiveMode { - return nil - } - if err := e.pubsub.Subscribe( e.getGlobalProverMessageBitmask(), func(message *pb.Message) error { @@ -84,10 +76,6 @@ func (e *AppConsensusEngine) subscribeToProverMessages() error { if err := e.pubsub.Subscribe( e.getProverMessageBitmask(), func(message *pb.Message) error { - if e.config.P2P.Network != 99 && !e.config.Engine.ArchiveMode { - return nil - } - select { case <-e.haltCtx.Done(): return nil diff --git a/node/consensus/app/message_validation.go b/node/consensus/app/message_validation.go index 992dccbc..a3fe7819 100644 --- a/node/consensus/app/message_validation.go +++ b/node/consensus/app/message_validation.go @@ -19,11 +19,6 @@ func (e *AppConsensusEngine) validateConsensusMessage( peerID peer.ID, message *pb.Message, ) p2p.ValidationResult { - timer := prometheus.NewTimer( - frameValidationDuration.WithLabelValues(e.appAddressHex), - ) - defer timer.ObserveDuration() - // Check if data is long enough to contain type prefix if len(message.Data) < 4 { e.logger.Debug( @@ -39,88 +34,147 @@ func (e *AppConsensusEngine) validateConsensusMessage( switch typePrefix { case protobufs.AppShardFrameType: + timer := prometheus.NewTimer( + proposalValidationDuration.WithLabelValues(e.appAddressHex), + ) + defer timer.ObserveDuration() + frame := &protobufs.AppShardFrame{} if err := frame.FromCanonicalBytes(message.Data); err != nil { e.logger.Debug("failed to unmarshal frame", zap.Error(err)) - frameValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() + proposalValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() return p2p.ValidationResultReject } if frame.Header == nil { e.logger.Debug("frame has no header") - frameValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() + proposalValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() return p2p.ValidationResultReject } if !bytes.Equal(frame.Header.Address, e.appAddress) { - e.logger.Debug("frame address incorrect") - frameValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() - return p2p.ValidationResultReject + return p2p.ValidationResultIgnore } if frame.Header.PublicKeySignatureBls48581 != nil { e.logger.Debug("frame validation has signature") - frameValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() + proposalValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() return p2p.ValidationResultReject } valid, err := e.frameValidator.Validate(frame) if err != nil { e.logger.Debug("frame validation error", zap.Error(err)) - frameValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() + proposalValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() return p2p.ValidationResultReject } if !valid { - frameValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() e.logger.Debug("invalid frame") + proposalValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() return p2p.ValidationResultReject } - frameValidationTotal.WithLabelValues(e.appAddressHex, "accept").Inc() + proposalValidationTotal.WithLabelValues(e.appAddressHex, "accept").Inc() case protobufs.ProverLivenessCheckType: + timer := prometheus.NewTimer( + livenessCheckValidationDuration.WithLabelValues(e.appAddressHex), + ) + defer timer.ObserveDuration() + livenessCheck := &protobufs.ProverLivenessCheck{} if err := livenessCheck.FromCanonicalBytes(message.Data); err != nil { e.logger.Debug("failed to unmarshal liveness check", zap.Error(err)) + livenessCheckValidationTotal.WithLabelValues( + e.appAddressHex, + "reject", + ).Inc() return p2p.ValidationResultReject } + now := time.Now().UnixMilli() + if livenessCheck.Timestamp > now+5000 || + livenessCheck.Timestamp < now-5000 { + return p2p.ValidationResultIgnore + } + if err := livenessCheck.Validate(); err != nil { e.logger.Debug("failed to validate liveness check", zap.Error(err)) + livenessCheckValidationTotal.WithLabelValues( + e.appAddressHex, + "reject", + ).Inc() return p2p.ValidationResultReject } + livenessCheckValidationTotal.WithLabelValues( + e.appAddressHex, + "accept", + ).Inc() + case protobufs.FrameVoteType: + timer := prometheus.NewTimer( + voteValidationDuration.WithLabelValues(e.appAddressHex), + ) + defer timer.ObserveDuration() + vote := &protobufs.FrameVote{} if err := vote.FromCanonicalBytes(message.Data); err != nil { e.logger.Debug("failed to unmarshal vote", zap.Error(err)) + voteValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() return p2p.ValidationResultReject } + now := time.Now().UnixMilli() + if vote.Timestamp > now+5000 || vote.Timestamp < now-5000 { + return p2p.ValidationResultIgnore + } + if err := vote.Validate(); err != nil { e.logger.Debug("failed to validate vote", zap.Error(err)) + voteValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() return p2p.ValidationResultReject } + voteValidationTotal.WithLabelValues(e.appAddressHex, "accept").Inc() + case protobufs.FrameConfirmationType: + timer := prometheus.NewTimer( + confirmationValidationDuration.WithLabelValues(e.appAddressHex), + ) + defer timer.ObserveDuration() + confirmation := &protobufs.FrameConfirmation{} if err := confirmation.FromCanonicalBytes(message.Data); err != nil { e.logger.Debug("failed to unmarshal confirmation", zap.Error(err)) + confirmationValidationTotal.WithLabelValues( + e.appAddressHex, + "reject", + ).Inc() return p2p.ValidationResultReject } + now := time.Now().UnixMilli() + if confirmation.Timestamp > now+5000 || confirmation.Timestamp < now-5000 { + return p2p.ValidationResultIgnore + } + if err := confirmation.Validate(); err != nil { e.logger.Debug("failed to validate confirmation", zap.Error(err)) + confirmationValidationTotal.WithLabelValues( + e.appAddressHex, + "reject", + ).Inc() return p2p.ValidationResultReject } + confirmationValidationTotal.WithLabelValues(e.appAddressHex, "accept").Inc() + default: - frameValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() return p2p.ValidationResultReject } - frameValidationTotal.WithLabelValues(e.appAddressHex, "accept").Inc() return p2p.ValidationResultAccept } @@ -289,15 +343,13 @@ func (e *AppConsensusEngine) validateGlobalFrameMessage( peerID peer.ID, message *pb.Message, ) p2p.ValidationResult { - timer := prometheus.NewTimer( - frameValidationDuration.WithLabelValues(e.appAddressHex), - ) + timer := prometheus.NewTimer(globalFrameValidationDuration) defer timer.ObserveDuration() // Check if data is long enough to contain type prefix if len(message.Data) < 4 { e.logger.Debug("message too short", zap.Int("data_length", len(message.Data))) - frameValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() + globalFrameValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() return p2p.ValidationResultReject } @@ -309,7 +361,7 @@ func (e *AppConsensusEngine) validateGlobalFrameMessage( frame := &protobufs.GlobalFrame{} if err := frame.FromCanonicalBytes(message.Data); err != nil { e.logger.Debug("failed to unmarshal frame", zap.Error(err)) - frameValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() + globalFrameValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() return p2p.ValidationResultReject } @@ -317,20 +369,20 @@ func (e *AppConsensusEngine) validateGlobalFrameMessage( frame.Header.PublicKeySignatureBls48581.PublicKey == nil || frame.Header.PublicKeySignatureBls48581.PublicKey.KeyValue == nil { e.logger.Debug("frame validation missing signature") - frameValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() + globalFrameValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() return p2p.ValidationResultReject } valid, err := e.globalFrameValidator.Validate(frame) if err != nil { e.logger.Debug("frame validation error", zap.Error(err)) - frameValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() + globalFrameValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() return p2p.ValidationResultReject } if !valid { - frameValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() e.logger.Debug("invalid frame") + globalFrameValidationTotal.WithLabelValues(e.appAddressHex, "reject").Inc() return p2p.ValidationResultReject } @@ -338,7 +390,7 @@ func (e *AppConsensusEngine) validateGlobalFrameMessage( return p2p.ValidationResultIgnore } - frameValidationTotal.WithLabelValues(e.appAddressHex, "accept").Inc() + globalFrameValidationTotal.WithLabelValues(e.appAddressHex, "accept").Inc() default: return p2p.ValidationResultReject diff --git a/node/consensus/app/metrics.go b/node/consensus/app/metrics.go index 507828e0..7ad82bea 100644 --- a/node/consensus/app/metrics.go +++ b/node/consensus/app/metrics.go @@ -99,13 +99,189 @@ var ( []string{"app_address"}, ) + // Shard liveness check processing metrics + livenessCheckProcessedTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "liveness_check_processed_total", + Help: "Total number of shard liveness checks processed by the app consensus engine", + }, + []string{"app_address", "status"}, // status: "success", "error", "invalid" + ) + + livenessCheckProcessingDuration = promauto.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "liveness_check_processing_duration_seconds", + Help: "Time taken to process a shard liveness check", + Buckets: prometheus.DefBuckets, + }, + []string{"app_address"}, + ) + + // Shard liveness check validation metrics + livenessCheckValidationTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "liveness_check_validation_total", + Help: "Total number of shard liveness check validations", + }, + []string{"app_address", "result"}, // result: "accept", "reject", "ignore" + ) + + livenessCheckValidationDuration = promauto.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "liveness_check_validation_duration_seconds", + Help: "Time taken to validate a shard liveness check", + Buckets: prometheus.DefBuckets, + }, + []string{"app_address"}, + ) + + // Shard vote processing metrics + voteProcessedTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "vote_processed_total", + Help: "Total number of shard votes processed by the app consensus engine", + }, + []string{"app_address", "status"}, // status: "success", "error", "invalid" + ) + + voteProcessingDuration = promauto.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "vote_processing_duration_seconds", + Help: "Time taken to process a shard vote", + Buckets: prometheus.DefBuckets, + }, + []string{"app_address"}, + ) + + // Shard vote validation metrics + voteValidationTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "vote_validation_total", + Help: "Total number of shard vote validations", + }, + []string{"app_address", "result"}, // result: "accept", "reject", "ignore" + ) + + voteValidationDuration = promauto.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "vote_validation_duration_seconds", + Help: "Time taken to validate a shard vote", + Buckets: prometheus.DefBuckets, + }, + []string{"app_address"}, + ) + + // Shard confirmation processing metrics + confirmationProcessedTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "confirmation_processed_total", + Help: "Total number of shard confirmations processed by the app consensus engine", + }, + []string{"app_address", "status"}, // status: "success", "error", "invalid" + ) + + confirmationProcessingDuration = promauto.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "confirmation_processing_duration_seconds", + Help: "Time taken to process a shard confirmation", + Buckets: prometheus.DefBuckets, + }, + []string{"app_address"}, + ) + + // Shard confirmation validation metrics + confirmationValidationTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "confirmation_validation_total", + Help: "Total number of shard confirmation validations", + }, + []string{"app_address", "result"}, // result: "accept", "reject", "ignore" + ) + + confirmationValidationDuration = promauto.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "confirmation_validation_duration_seconds", + Help: "Time taken to validate a shard confirmation", + Buckets: prometheus.DefBuckets, + }, + []string{"app_address"}, + ) + + // Shard proposal processing metrics + proposalProcessedTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "proposal_processed_total", + Help: "Total number of shard proposals processed by the app consensus engine", + }, + []string{"app_address", "status"}, // status: "success", "error", "invalid" + ) + + proposalProcessingDuration = promauto.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "proposal_processing_duration_seconds", + Help: "Time taken to process a shard proposal", + Buckets: prometheus.DefBuckets, + }, + []string{"app_address"}, + ) + + // Shard proposal validation metrics + proposalValidationTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "proposal_validation_total", + Help: "Total number of shard proposal validations", + }, + []string{"app_address", "result"}, // result: "accept", "reject", "ignore" + ) + + proposalValidationDuration = promauto.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "proposal_validation_duration_seconds", + Help: "Time taken to validate a shard proposal", + Buckets: prometheus.DefBuckets, + }, + []string{"app_address"}, + ) + // Global frame processing metrics globalFramesProcessedTotal = promauto.NewCounterVec( prometheus.CounterOpts{ Namespace: metricsNamespace, Subsystem: subsystem, Name: "global_frames_processed_total", - Help: "Total number of frames processed by the global consensus engine", + Help: "Total number of frames processed by the app consensus engine", }, []string{"status"}, // status: "success", "error", "invalid" ) diff --git a/node/consensus/global/consensus_leader_provider.go b/node/consensus/global/consensus_leader_provider.go index 03d1d56b..983022fe 100644 --- a/node/consensus/global/consensus_leader_provider.go +++ b/node/consensus/global/consensus_leader_provider.go @@ -90,7 +90,7 @@ func (p *GlobalLeaderProvider) ProveNextState( // Get current timestamp and difficulty timestamp := time.Now().UnixMilli() difficulty := p.engine.difficultyAdjuster.GetNextDifficulty( - (*prior).Rank(), + (*prior).Rank()+1, timestamp, ) @@ -139,6 +139,10 @@ func (p *GlobalLeaderProvider) ProveNextState( 0, len(p.engine.collectedMessages), ) + p.engine.logger.Debug( + "including messages", + zap.Int("message_count", len(p.engine.collectedMessages)), + ) for _, msgData := range p.engine.collectedMessages { // Check if data is long enough to contain type prefix if len(msgData) < 4 { diff --git a/node/consensus/global/consensus_liveness_provider.go b/node/consensus/global/consensus_liveness_provider.go index 4029af95..5c1ce52a 100644 --- a/node/consensus/global/consensus_liveness_provider.go +++ b/node/consensus/global/consensus_liveness_provider.go @@ -3,7 +3,6 @@ package global import ( "bytes" "context" - "encoding/binary" "math/big" "slices" "time" @@ -12,10 +11,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "go.uber.org/zap" "golang.org/x/crypto/sha3" - "source.quilibrium.com/quilibrium/monorepo/node/consensus/reward" - hgstate "source.quilibrium.com/quilibrium/monorepo/node/execution/state/hypergraph" "source.quilibrium.com/quilibrium/monorepo/protobufs" - "source.quilibrium.com/quilibrium/monorepo/types/execution/state" "source.quilibrium.com/quilibrium/monorepo/types/tries" ) @@ -73,9 +69,6 @@ func (p *GlobalLivenessProvider) Collect( acceptedMessages := []*protobufs.Message{} - var state state.State - state = hgstate.NewHypergraphState(p.engine.hypergraph) - frameNumber := uint64(0) currentFrame, _ := p.engine.globalTimeReel.GetHead() if currentFrame != nil && currentFrame.Header != nil { @@ -84,10 +77,19 @@ func (p *GlobalLivenessProvider) Collect( frameNumber++ + p.engine.logger.Debug( + "collected messages, validating", + zap.Int("message_count", len(messages)), + ) + for i, message := range messages { - costBasis, err := p.engine.executionManager.GetCost(message.Payload) + err := p.engine.executionManager.ValidateMessage( + frameNumber, + message.Address, + message.Payload, + ) if err != nil { - p.engine.logger.Error( + p.engine.logger.Debug( "invalid message", zap.Int("message_index", i), zap.Error(err), @@ -95,37 +97,31 @@ func (p *GlobalLivenessProvider) Collect( continue } - p.engine.currentDifficultyMu.RLock() - difficulty := uint64(p.engine.currentDifficulty) - p.engine.currentDifficultyMu.RUnlock() - baseline := reward.GetBaselineFee( - difficulty, - p.engine.hypergraph.GetSize(nil, nil).Uint64(), - costBasis.Uint64(), - 8000000000, - ) - baseline.Quo(baseline, costBasis) - - result, err := p.engine.executionManager.ProcessMessage( + _, err = p.engine.executionManager.Lock( frameNumber, - baseline, message.Address, message.Payload, - state, ) if err != nil { - p.engine.logger.Error( - "error processing message", + p.engine.logger.Debug( + "message failed lock", zap.Int("message_index", i), zap.Error(err), ) continue } - state = result.State acceptedMessages = append(acceptedMessages, message) } + err := p.engine.executionManager.Unlock() + if err != nil { + p.engine.logger.Error( + "unable to unlock", + zap.Error(err), + ) + } + commitments := make([]*tries.VectorCommitmentTree, 256) for i := range 256 { commitments[i] = &tries.VectorCommitmentTree{} @@ -228,14 +224,15 @@ func (p *GlobalLivenessProvider) SendLiveness( } // Sign the message - signatureData := slices.Concat( - make([]byte, 32), - binary.BigEndian.AppendUint64(nil, collected.frameNumber), - collected.commitmentHash, - binary.BigEndian.AppendUint64(nil, uint64(livenessCheck.Timestamp)), - ) + signatureData, err := livenessCheck.ConstructSignaturePayload() + if err != nil { + return errors.Wrap(err, "send liveness") + } - sig, err := signer.SignWithDomain(signatureData, []byte("liveness")) + sig, err := signer.SignWithDomain( + signatureData, + livenessCheck.GetSignatureDomain(), + ) if err != nil { return errors.Wrap(err, "send liveness") } diff --git a/node/consensus/global/consensus_transition_listener.go b/node/consensus/global/consensus_transition_listener.go index af0a3ee9..8f0df39a 100644 --- a/node/consensus/global/consensus_transition_listener.go +++ b/node/consensus/global/consensus_transition_listener.go @@ -10,7 +10,7 @@ type GlobalTracer struct { } func (t *GlobalTracer) Trace(message string) { - t.logger.Debug(message) + // t.logger.Debug(message) } func (t *GlobalTracer) Error(message string, err error) { diff --git a/node/consensus/global/consensus_voting_provider.go b/node/consensus/global/consensus_voting_provider.go index 69da96b6..cb81d626 100644 --- a/node/consensus/global/consensus_voting_provider.go +++ b/node/consensus/global/consensus_voting_provider.go @@ -5,6 +5,7 @@ import ( "context" "encoding/hex" "sync" + "time" "github.com/iden3/go-iden3-crypto/poseidon" "github.com/pkg/errors" @@ -185,6 +186,7 @@ func (p *GlobalVotingProvider) DecideAndSendVote( FrameNumber: chosenProposal.Header.FrameNumber, Proposer: proposerID, Approve: true, + Timestamp: time.Now().UnixMilli(), PublicKeySignatureBls48581: &protobufs.BLS48581AddressedSignature{ Address: voterAddress, Signature: sig, @@ -426,6 +428,7 @@ func (p *GlobalVotingProvider) SendConfirmation( confirmation := &protobufs.FrameConfirmation{ FrameNumber: copiedFinalized.Header.FrameNumber, Selector: selectorBI.FillBytes(make([]byte, 32)), + Timestamp: time.Now().UnixMilli(), AggregateSignature: copiedFinalized.Header.PublicKeySignatureBls48581, } diff --git a/node/consensus/global/coverage_events.go b/node/consensus/global/coverage_events.go index 9732cd87..5c3ad70c 100644 --- a/node/consensus/global/coverage_events.go +++ b/node/consensus/global/coverage_events.go @@ -4,24 +4,59 @@ import ( "bytes" "encoding/hex" "fmt" + "math/big" + "github.com/pkg/errors" "go.uber.org/zap" typesconsensus "source.quilibrium.com/quilibrium/monorepo/types/consensus" - "source.quilibrium.com/quilibrium/monorepo/types/tries" ) +// Define coverage thresholds +var ( + minProvers = uint64(0) + maxProvers = uint64(0) + haltThreshold = uint64(0) + haltGraceFrames = uint64(0) +) + +func (e *GlobalConsensusEngine) ensureCoverageThresholds() { + if minProvers != 0 { + return + } + + // Network halt if <= 3 provers for mainnet: + haltThreshold = 3 + if e.config.P2P.Network != 0 { + haltThreshold = 0 + if e.minimumProvers() > 1 { + haltThreshold = 1 + } + } + + // Minimum provers for safe operation + minProvers = e.minimumProvers() + + // Maximum provers before split consideration + maxProvers = 32 + + // Require sustained critical state for 360 frames + haltGraceFrames = 360 +} + // checkShardCoverage verifies coverage levels for all active shards -func (e *GlobalConsensusEngine) checkShardCoverage() error { - // Define coverage thresholds - const ( - minProvers = 5 // Minimum provers for safe operation - maxProvers = 32 // Maximum provers before split consideration - haltThreshold = 3 // Network halt if <= 3 provers - ) +func (e *GlobalConsensusEngine) checkShardCoverage(frameNumber uint64) error { + e.ensureCoverageThresholds() // Get shard coverage information from prover registry shardCoverageMap := e.getShardCoverageMap() + // Set up the streak map so we can quickly establish halt conditions on + // restarts + err := e.ensureStreakMap(frameNumber) + if err != nil { + return errors.Wrap(err, "check shard coverage") + } + // Update state summaries metric stateSummariesAggregated.Set(float64(len(shardCoverageMap))) @@ -38,54 +73,97 @@ func (e *GlobalConsensusEngine) checkShardCoverage() error { continue } - proverCount := coverage.ProverCount + proverCount := uint64(coverage.ProverCount) attestedStorage := coverage.AttestedStorage + size := big.NewInt(0) + for _, metadata := range coverage.TreeMetadata { + size = size.Add(size, new(big.Int).SetUint64(metadata.TotalSize)) + } + e.logger.Debug( "checking shard coverage", zap.String("shard_address", hex.EncodeToString([]byte(shardAddress))), - zap.Int("prover_count", proverCount), + zap.Uint64("prover_count", proverCount), zap.Uint64("attested_storage", attestedStorage), + zap.Uint64("shard_size", size.Uint64()), ) // Check for critical coverage (halt condition) - if proverCount <= haltThreshold { + if proverCount <= haltThreshold && size.Cmp(big.NewInt(0)) > 0 { // Check if this address is blacklisted if e.isAddressBlacklisted([]byte(shardAddress)) { e.logger.Warn( "Shard has insufficient coverage but is blacklisted - skipping halt", zap.String("shard_address", hex.EncodeToString([]byte(shardAddress))), - zap.Int("prover_count", proverCount), - zap.Int("halt_threshold", haltThreshold), + zap.Uint64("prover_count", proverCount), + zap.Uint64("halt_threshold", haltThreshold), ) continue } - e.logger.Error( - "CRITICAL: Shard has insufficient coverage - triggering network halt", + // Bump the streak – only increments once per frame + streak, err := e.bumpStreak(shardAddress, frameNumber) + if err != nil { + return errors.Wrap(err, "check shard coverage") + } + + remaining := int(haltGraceFrames - streak.Count) + if remaining <= 0 { + e.logger.Error( + "CRITICAL: Shard has insufficient coverage - triggering network halt", + zap.String("shard_address", hex.EncodeToString([]byte(shardAddress))), + zap.Uint64("prover_count", proverCount), + zap.Uint64("halt_threshold", haltThreshold), + ) + + // Emit halt event + e.emitCoverageEvent( + typesconsensus.ControlEventCoverageHalt, + &typesconsensus.CoverageEventData{ + ShardAddress: []byte(shardAddress), + ProverCount: int(proverCount), + RequiredProvers: int(minProvers), + AttestedStorage: attestedStorage, + TreeMetadata: coverage.TreeMetadata, + Message: fmt.Sprintf( + "Shard has only %d provers, network halt required", + proverCount, + ), + }, + ) + continue + } + + // During grace, warn and include progress toward halt + e.logger.Warn( + "Shard at critical coverage — grace window in effect", zap.String("shard_address", hex.EncodeToString([]byte(shardAddress))), - zap.Int("prover_count", proverCount), - zap.Int("halt_threshold", haltThreshold), + zap.Uint64("prover_count", proverCount), + zap.Uint64("halt_threshold", haltThreshold), + zap.Uint64("streak_frames", streak.Count), + zap.Int("frames_until_halt", remaining), ) - - // Emit halt event e.emitCoverageEvent( - typesconsensus.ControlEventCoverageHalt, + typesconsensus.ControlEventCoverageWarn, &typesconsensus.CoverageEventData{ ShardAddress: []byte(shardAddress), - ProverCount: proverCount, - RequiredProvers: minProvers, + ProverCount: int(proverCount), + RequiredProvers: int(minProvers), AttestedStorage: attestedStorage, TreeMetadata: coverage.TreeMetadata, Message: fmt.Sprintf( - "Shard has only %d provers, network halt required", - proverCount, + "Critical coverage (less than or equal to %d provers). Grace period: %d/%d frames toward halt.", + haltThreshold, streak.Count, haltGraceFrames, ), }, ) continue } + // Not in critical state — clear any ongoing streak + e.clearStreak(shardAddress) + // Check for low coverage if proverCount < minProvers { e.handleLowCoverage([]byte(shardAddress), coverage, minProvers) @@ -111,7 +189,7 @@ type ShardCoverage struct { func (e *GlobalConsensusEngine) handleLowCoverage( shardAddress []byte, coverage *ShardCoverage, - minProvers int, + minProvers uint64, ) { addressLen := len(shardAddress) @@ -121,7 +199,7 @@ func (e *GlobalConsensusEngine) handleLowCoverage( "shard has low coverage", zap.String("shard_address", hex.EncodeToString(shardAddress)), zap.Int("prover_count", coverage.ProverCount), - zap.Int("min_provers", minProvers), + zap.Uint64("min_provers", minProvers), ) // Emit coverage warning event @@ -130,7 +208,7 @@ func (e *GlobalConsensusEngine) handleLowCoverage( &typesconsensus.CoverageEventData{ ShardAddress: shardAddress, ProverCount: coverage.ProverCount, - RequiredProvers: minProvers, + RequiredProvers: int(minProvers), AttestedStorage: coverage.AttestedStorage, TreeMetadata: coverage.TreeMetadata, Message: "Application shard has low prover coverage", @@ -195,7 +273,7 @@ func (e *GlobalConsensusEngine) handleLowCoverage( &typesconsensus.CoverageEventData{ ShardAddress: shardAddress, ProverCount: coverage.ProverCount, - RequiredProvers: minProvers, + RequiredProvers: int(minProvers), AttestedStorage: coverage.AttestedStorage, TreeMetadata: coverage.TreeMetadata, Message: "shard has low coverage and cannot be merged due to insufficient storage", @@ -209,7 +287,7 @@ func (e *GlobalConsensusEngine) handleLowCoverage( &typesconsensus.CoverageEventData{ ShardAddress: shardAddress, ProverCount: coverage.ProverCount, - RequiredProvers: minProvers, + RequiredProvers: int(minProvers), AttestedStorage: coverage.AttestedStorage, TreeMetadata: coverage.TreeMetadata, Message: "Shard has low coverage and no siblings for merge", @@ -222,7 +300,7 @@ func (e *GlobalConsensusEngine) handleLowCoverage( func (e *GlobalConsensusEngine) handleHighCoverage( shardAddress []byte, coverage *ShardCoverage, - maxProvers int, + maxProvers uint64, ) { addressLen := len(shardAddress) @@ -300,33 +378,17 @@ func (e *GlobalConsensusEngine) getShardCoverageMap() map[string]*ShardCoverage // Get tree metadata from hypergraph var treeMetadata []typesconsensus.TreeMetadata - expandedFilter := make([]byte, 64) - copy(expandedFilter[:len(shardAddress)], []byte(shardAddress)[:]) - treeData, err := e.hypergraph.GetVertexData([64]byte(expandedFilter)) + metadata, err := e.hypergraph.GetMetadataAtKey([]byte(shardAddress)) if err != nil { - e.logger.Warn( - "failed to get shard data for shard", - zap.String("shard_address", hex.EncodeToString([]byte(shardAddress))), - zap.Error(err), - ) - // Use empty metadata if we can't get the data - treeMetadata = []typesconsensus.TreeMetadata{ - { - CommitmentRoot: make([]byte, 74), - TotalSize: 0, - TotalLeaves: 0, - }, - } - } else { - treeMetadata = []typesconsensus.TreeMetadata{ - { - CommitmentRoot: make([]byte, 74), - TotalSize: treeData.GetSize().Uint64(), - TotalLeaves: uint64( - len(tries.GetAllPreloadedLeaves(treeData.Root)), - ), - }, - } + e.logger.Error("could not obtain metadata for path", zap.Error(err)) + return nil + } + for _, metadata := range metadata { + treeMetadata = append(treeMetadata, typesconsensus.TreeMetadata{ + CommitmentRoot: metadata.Commitment, + TotalSize: metadata.Size, + TotalLeaves: metadata.LeafCount, + }) } coverageMap[shardAddress] = &ShardCoverage{ @@ -378,29 +440,18 @@ func (e *GlobalConsensusEngine) getShardCoverage(shardAddress []byte) ( // Get tree metadata from hypergraph var treeMetadata []typesconsensus.TreeMetadata - treeData, err := e.hypergraph.GetVertexData([64]byte([]byte(shardAddress))) + + metadata, err := e.hypergraph.GetMetadataAtKey(shardAddress) if err != nil { - e.logger.Warn( - "failed to get shard data for shard", - zap.String("shard_address", hex.EncodeToString([]byte(shardAddress))), - zap.Error(err), - ) - // Use empty metadata if we can't get the data - treeMetadata = []typesconsensus.TreeMetadata{ - { - CommitmentRoot: make([]byte, 74), - TotalSize: 0, - TotalLeaves: 0, - }, - } - } else { - treeMetadata = []typesconsensus.TreeMetadata{ - { - CommitmentRoot: make([]byte, 74), - TotalSize: treeData.Root.GetSize().Uint64(), - TotalLeaves: uint64(len(tries.GetAllPreloadedLeaves(treeData.Root))), - }, - } + e.logger.Error("could not obtain metadata for path", zap.Error(err)) + return nil, false + } + for _, metadata := range metadata { + treeMetadata = append(treeMetadata, typesconsensus.TreeMetadata{ + CommitmentRoot: metadata.Commitment, + TotalSize: metadata.Size, + TotalLeaves: metadata.LeafCount, + }) } coverage := &ShardCoverage{ @@ -520,3 +571,85 @@ func (e *GlobalConsensusEngine) proposeShardSplit( return proposedShards } + +func (e *GlobalConsensusEngine) ensureStreakMap(frameNumber uint64) error { + if e.lowCoverageStreak != nil { + return nil + } + + e.logger.Debug("ensuring streak map") + e.lowCoverageStreak = make(map[string]*coverageStreak) + + info, err := e.proverRegistry.GetAllActiveAppShardProvers() + if err != nil { + e.logger.Error( + "could not retrieve active app shard provers", + zap.Error(err), + ) + return errors.Wrap(err, "ensure streak map") + } + + effectiveCoverage := map[string]int{} + lastFrame := map[string]uint64{} + + for _, i := range info { + for _, allocation := range i.Allocations { + if _, ok := effectiveCoverage[string(allocation.ConfirmationFilter)]; !ok { + effectiveCoverage[string(allocation.ConfirmationFilter)] = 0 + lastFrame[string(allocation.ConfirmationFilter)] = + allocation.LastActiveFrameNumber + } + + if allocation.Status == typesconsensus.ProverStatusActive { + effectiveCoverage[string(allocation.ConfirmationFilter)]++ + lastFrame[string(allocation.ConfirmationFilter)] = max( + lastFrame[string(allocation.ConfirmationFilter)], + allocation.LastActiveFrameNumber, + ) + } + } + } + + for shardKey, coverage := range effectiveCoverage { + if coverage <= int(haltThreshold) { + e.lowCoverageStreak[shardKey] = &coverageStreak{ + StartFrame: lastFrame[shardKey], + LastFrame: frameNumber, + Count: frameNumber - lastFrame[shardKey], + } + } + } + + return nil +} + +func (e *GlobalConsensusEngine) bumpStreak( + shardKey string, + frame uint64, +) (*coverageStreak, error) { + err := e.ensureStreakMap(frame) + if err != nil { + return nil, errors.Wrap(err, "bump streak") + } + + s := e.lowCoverageStreak[shardKey] + if s == nil { + s = &coverageStreak{StartFrame: frame, LastFrame: frame, Count: 1} + e.lowCoverageStreak[shardKey] = s + return s, nil + } + + // Only increment if we advanced frames, prevents double counting within the + // same frame due to single-slot fork choice + if frame > s.LastFrame { + s.Count += (frame - s.LastFrame) + s.LastFrame = frame + } + return s, nil +} + +func (e *GlobalConsensusEngine) clearStreak(shardKey string) { + if e.lowCoverageStreak != nil { + delete(e.lowCoverageStreak, shardKey) + } +} diff --git a/node/consensus/global/event_distributor.go b/node/consensus/global/event_distributor.go index b9be745f..73b5a438 100644 --- a/node/consensus/global/event_distributor.go +++ b/node/consensus/global/event_distributor.go @@ -1,18 +1,23 @@ package global import ( + "bytes" "encoding/hex" "fmt" "math/rand" "slices" "time" + pcrypto "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "go.uber.org/zap" + "source.quilibrium.com/quilibrium/monorepo/config" "source.quilibrium.com/quilibrium/monorepo/node/consensus/provers" consensustime "source.quilibrium.com/quilibrium/monorepo/node/consensus/time" globalintrinsics "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/global" + "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/global/compat" "source.quilibrium.com/quilibrium/monorepo/protobufs" typesconsensus "source.quilibrium.com/quilibrium/monorepo/types/consensus" "source.quilibrium.com/quilibrium/monorepo/types/crypto" @@ -26,7 +31,9 @@ func (e *GlobalConsensusEngine) eventDistributorLoop() { if e.cancel != nil { e.cancel() } - e.quit <- struct{}{} + go func() { + e.Stop(false) + }() } }() defer e.wg.Done() @@ -61,7 +68,9 @@ func (e *GlobalConsensusEngine) eventDistributorLoop() { ) // Check shard coverage - if err := e.checkShardCoverage(); err != nil { + if err := e.checkShardCoverage( + data.Frame.Header.FrameNumber, + ); err != nil { e.logger.Error("failed to check shard coverage", zap.Error(err)) } @@ -72,215 +81,20 @@ func (e *GlobalConsensusEngine) eventDistributorLoop() { _, err := e.signerRegistry.GetIdentityKey(e.GetPeerInfo().PeerId) if err != nil && !e.hasSentKeyBundle { e.hasSentKeyBundle = true - vk, err := e.keyManager.GetAgreementKey("q-view-key") - if err != nil { - vk, err = e.keyManager.CreateAgreementKey( - "q-view-key", - crypto.KeyTypeDecaf448, - ) - if err != nil { - continue - } - } - - sk, err := e.keyManager.GetAgreementKey("q-spend-key") - if err != nil { - sk, err = e.keyManager.CreateAgreementKey( - "q-spend-key", - crypto.KeyTypeDecaf448, - ) - if err != nil { - continue - } - } - - pk, err := e.keyManager.GetSigningKey("q-prover-key") - if err != nil { - pk, _, err = e.keyManager.CreateSigningKey( - "q-prover-key", - crypto.KeyTypeBLS48581G1, - ) - if err != nil { - continue - } - } - sig, err := e.pubsub.SignMessage( - slices.Concat( - []byte("KEY_REGISTRY"), - pk.Public().([]byte), - ), - ) - if err != nil { - continue - } - sigp, err := pk.SignWithDomain( - e.pubsub.GetPublicKey(), - []byte("KEY_REGISTRY"), - ) - if err != nil { - continue - } - sigvk, err := e.pubsub.SignMessage( - slices.Concat( - []byte("KEY_REGISTRY"), - vk.Public(), - ), - ) - if err != nil { - continue - } - sigsk, err := e.pubsub.SignMessage( - slices.Concat( - []byte("KEY_REGISTRY"), - sk.Public(), - ), - ) - if err != nil { - continue - } - registry := &protobufs.KeyRegistry{ - IdentityKey: &protobufs.Ed448PublicKey{ - KeyValue: e.pubsub.GetPublicKey(), - }, - ProverKey: &protobufs.BLS48581G2PublicKey{ - KeyValue: pk.Public().([]byte), - }, - IdentityToProver: &protobufs.Ed448Signature{ - Signature: sig, - }, - ProverToIdentity: &protobufs.BLS48581Signature{ - Signature: sigp, - }, - KeysByPurpose: map[string]*protobufs.KeyCollection{ - "view": &protobufs.KeyCollection{ - KeyPurpose: "view", - Keys: []*protobufs.SignedX448Key{{ - Key: &protobufs.X448PublicKey{ - KeyValue: vk.Public(), - }, - ParentKeyAddress: e.pubsub.GetPeerID(), - Signature: &protobufs.SignedX448Key_Ed448Signature{ - Ed448Signature: &protobufs.Ed448Signature{ - Signature: sigvk, - }, - }, - }}, - }, - "spend": &protobufs.KeyCollection{ - KeyPurpose: "spend", - Keys: []*protobufs.SignedX448Key{{ - Key: &protobufs.X448PublicKey{ - KeyValue: sk.Public(), - }, - ParentKeyAddress: e.pubsub.GetPeerID(), - Signature: &protobufs.SignedX448Key_Ed448Signature{ - Ed448Signature: &protobufs.Ed448Signature{ - Signature: sigsk, - }, - }, - }}, - }, - }, - } - kr, err := registry.ToCanonicalBytes() - if err != nil { - continue - } - e.pubsub.PublishToBitmask( - GLOBAL_PEER_INFO_BITMASK, - kr, - ) + e.publishKeyRegistry() } if e.proposer != nil { - shardDescriptors := []provers.ShardDescriptor{} - shardKeys := e.hypergraph.Commit() - for key := range shardKeys { - shards, err := e.shardsStore.GetAppShards( - slices.Concat(key.L1[:], key.L2[:]), - []uint32{}, - ) - if err != nil { - e.logger.Error("failed to retrieve shards", zap.Error(err)) - continue - } - - ps, err := e.proverRegistry.GetActiveProvers(nil) - if err != nil { - e.logger.Error("could not find global provers", zap.Error(err)) - continue - } - - idx := rand.Int63n(int64(len(ps))) - e.syncProvider.hyperSyncWithProver(ps[idx].Address, key) - - for _, shard := range shards { - path := []int{} - bp := []byte{} - for _, p := range shard.Path { - path = append(path, int(p)) - bp = append(bp, byte(p)) - } - - filter := slices.Concat(key.L1[:], key.L2[:], bp) - info, err := e.proverRegistry.GetActiveProvers(filter) - if err != nil { - e.logger.Error("failed to get active provers", zap.Error(err)) - continue - } - - size := e.hypergraph.GetSize(&key, path) - resp, err := e.hypergraph.GetChildrenForPath( - e.ctx, - &protobufs.GetChildrenForPathRequest{ - ShardKey: slices.Concat(key.L1[:], key.L2[:]), - Path: shard.Path, - }, - ) - if err != nil { - e.logger.Error("failed to get shard info", zap.Error(err)) - continue - } - - if len(resp.PathSegments) == 0 { - continue - } - - if len( - resp.PathSegments[len(resp.PathSegments)-1].Segments, - ) != 1 { - continue - } - - shardCount := uint64(0) - if resp.PathSegments[len(resp.PathSegments)-1].Segments[0].GetBranch() != nil { - shardCount = resp.PathSegments[len(resp.PathSegments)-1].Segments[0].GetBranch().LeafCount - } else { - shardCount = 1 - } - - shardDescriptors = append( - shardDescriptors, - provers.ShardDescriptor{ - Filter: filter, - Size: size.Uint64(), - Ring: uint8(len(info) / 8), - Shards: shardCount, - }, - ) - } - } - proposals, err := e.proposer.PlanAndAllocate( - uint64(data.Frame.Header.Difficulty), - shardDescriptors, - 0, - ) + workers, err := e.workerManager.RangeWorkers() if err != nil { - e.logger.Error("could not plan shard allocations", zap.Error(err)) + e.logger.Error("could not retrieve workers", zap.Error(err)) } else { - e.logger.Info( - "proposed joins", - zap.Int("proposals", len(proposals)), - ) + allocated := true + for _, w := range workers { + allocated = allocated && w.Allocated + } + if !allocated { + e.evaluateForProposals(data) + } } } } @@ -383,6 +197,33 @@ func (e *GlobalConsensusEngine) eventDistributorLoop() { } } + case typesconsensus.ControlEventCoverageHalt: + data, ok := event.Data.(*typesconsensus.CoverageEventData) + if ok && data.Message != "" { + e.logger.Error(data.Message) + e.halt() + if e.stateMachine != nil { + if err := e.stateMachine.Stop(); err != nil { + e.logger.Error( + "error occurred while halting consensus", + zap.Error(err), + ) + } + } + go func() { + for { + select { + case <-e.ctx.Done(): + return + case <-time.After(10 * time.Second): + e.logger.Error( + "full halt detected, leaving system in halted state until recovery", + ) + } + } + }() + } + case typesconsensus.ControlEventHalt: data, ok := event.Data.(*typesconsensus.ErrorEventData) if ok && data.Error != nil { @@ -391,11 +232,13 @@ func (e *GlobalConsensusEngine) eventDistributorLoop() { zap.Error(data.Error), ) e.halt() - if err := e.stateMachine.Stop(); err != nil { - e.logger.Error( - "error occurred while halting consensus", - zap.Error(err), - ) + if e.stateMachine != nil { + if err := e.stateMachine.Stop(); err != nil { + e.logger.Error( + "error occurred while halting consensus", + zap.Error(err), + ) + } } go func() { for { @@ -492,3 +335,398 @@ func (e *GlobalConsensusEngine) emitAlertEvent(alertMessage string) { e.logger.Info("emitted alert message") } + +func (e *GlobalConsensusEngine) estimateSeniorityFromConfig() uint64 { + peerIds := []string{} + peerIds = append(peerIds, peer.ID(e.pubsub.GetPeerID()).String()) + if len(e.config.Engine.MultisigProverEnrollmentPaths) != 0 { + for _, conf := range e.config.Engine.MultisigProverEnrollmentPaths { + extraConf, err := config.LoadConfig(conf, "", false) + if err != nil { + e.logger.Error("could not load config", zap.Error(err)) + continue + } + + peerPrivKey, err := hex.DecodeString(extraConf.P2P.PeerPrivKey) + if err != nil { + e.logger.Error("could not decode peer key", zap.Error(err)) + continue + } + + privKey, err := pcrypto.UnmarshalEd448PrivateKey(peerPrivKey) + if err != nil { + e.logger.Error("could not unmarshal peer key", zap.Error(err)) + continue + } + + pub := privKey.GetPublic() + id, err := peer.IDFromPublicKey(pub) + if err != nil { + e.logger.Error("could not unmarshal peerid", zap.Error(err)) + continue + } + + peerIds = append(peerIds, id.String()) + } + } + seniorityBI := compat.GetAggregatedSeniority(peerIds) + return seniorityBI.Uint64() +} + +func (e *GlobalConsensusEngine) evaluateForProposals( + data *consensustime.GlobalEvent, +) { + self, err := e.proverRegistry.GetProverInfo(e.getProverAddress()) + var effectiveSeniority uint64 + if err != nil || self == nil { + effectiveSeniority = e.estimateSeniorityFromConfig() + } else { + effectiveSeniority = self.Seniority + } + + pendingFilters := [][]byte{} + proposalDescriptors := []provers.ShardDescriptor{} + decideDescriptors := []provers.ShardDescriptor{} + shardKeys := e.hypergraph.Commit() + for key := range shardKeys { + shards, err := e.shardsStore.GetAppShards( + slices.Concat(key.L1[:], key.L2[:]), + []uint32{}, + ) + if err != nil { + e.logger.Error("failed to retrieve shards", zap.Error(err)) + continue + } + + ps, err := e.proverRegistry.GetActiveProvers(nil) + if err != nil { + e.logger.Error("could not find global provers", zap.Error(err)) + continue + } + + idx := rand.Int63n(int64(len(ps))) + e.syncProvider.hyperSyncWithProver(ps[idx].Address, key) + + for _, shard := range shards { + path := []int{} + bp := []byte{} + for _, p := range shard.Path { + path = append(path, int(p)) + bp = append(bp, byte(p)) + } + + filter := slices.Concat(key.L2[:], bp) + info, err := e.proverRegistry.GetProvers(filter) + if err != nil { + e.logger.Error("failed to get provers", zap.Error(err)) + continue + } + + allocated := false + pending := false + if self != nil { + e.logger.Debug("checking allocations") + for _, allocation := range self.Allocations { + e.logger.Debug("checking allocation", zap.String("filter", hex.EncodeToString(allocation.ConfirmationFilter))) + if bytes.Equal(allocation.ConfirmationFilter, filter) { + allocated = allocation.Status != 4 + if e.config.P2P.Network != 0 || + data.Frame.Header.FrameNumber > 252840 { + e.logger.Debug( + "checking pending status of allocation", + zap.Int("status", int(allocation.Status)), + zap.Uint64("join_frame_number", allocation.JoinFrameNumber), + zap.Uint64("frame_number", data.Frame.Header.FrameNumber), + ) + pending = allocation.Status == + typesconsensus.ProverStatusJoining && + allocation.JoinFrameNumber+360 <= data.Frame.Header.FrameNumber + } + } + } + } + + size := e.hypergraph.GetSize(&key, path) + resp, err := e.hypergraph.GetChildrenForPath( + e.ctx, + &protobufs.GetChildrenForPathRequest{ + ShardKey: slices.Concat(key.L1[:], key.L2[:]), + Path: shard.Path, + }, + ) + if err != nil { + e.logger.Error("failed to get shard info", zap.Error(err)) + continue + } + + e.logger.Debug( + "checking descriptor for eligibility", + zap.String("shard_key", hex.EncodeToString(filter)), + ) + if len(resp.PathSegments) == 0 { + e.logger.Debug("no path segments") + continue + } + + if len( + resp.PathSegments[len(resp.PathSegments)-1].Segments, + ) != 1 { + e.logger.Debug( + "path segment length mismatch", + zap.Int( + "length", + len(resp.PathSegments[len(resp.PathSegments)-1].Segments), + ), + ) + continue + } + + shardCount := uint64(0) + if resp.PathSegments[len(resp.PathSegments)-1].Segments[0].GetBranch() != nil { + shardCount = resp.PathSegments[len(resp.PathSegments)-1].Segments[0].GetBranch().LeafCount + } else { + shardCount = 1 + } + + e.logger.Debug( + "logical shard count", + zap.Int("shard_count", int(shardCount)), + ) + + above := []*typesconsensus.ProverInfo{} + for _, i := range info { + if i.Seniority >= effectiveSeniority { + above = append(above, i) + } + } + + e.logger.Debug( + "appending descriptor for allocation planning", + zap.String("shard_key", hex.EncodeToString(filter)), + zap.Uint64("size", size.Uint64()), + zap.Int("ring", len(above)/8), + zap.Int("shard_count", int(shardCount)), + ) + + if allocated && pending { + pendingFilters = append(pendingFilters, filter) + } + if !allocated { + proposalDescriptors = append( + proposalDescriptors, + provers.ShardDescriptor{ + Filter: filter, + Size: size.Uint64(), + Ring: uint8(len(above) / 8), + Shards: shardCount, + }, + ) + } + decideDescriptors = append( + decideDescriptors, + provers.ShardDescriptor{ + Filter: filter, + Size: size.Uint64(), + Ring: uint8(len(above) / 8), + Shards: shardCount, + }, + ) + } + } + if len(proposalDescriptors) != 0 { + proposals, err := e.proposer.PlanAndAllocate( + uint64(data.Frame.Header.Difficulty), + proposalDescriptors, + 0, + ) + if err != nil { + e.logger.Error("could not plan shard allocations", zap.Error(err)) + } else { + e.logger.Info( + "proposed joins", + zap.Int("proposals", len(proposals)), + ) + } + } + if len(pendingFilters) != 0 { + err = e.proposer.DecideJoins( + uint64(data.Frame.Header.Difficulty), + decideDescriptors, + pendingFilters, + ) + if err != nil { + e.logger.Error("could not decide shard allocations", zap.Error(err)) + } else { + e.logger.Info( + "decided on joins", + zap.Int("joins", len(pendingFilters)), + ) + } + } +} + +func (e *GlobalConsensusEngine) publishKeyRegistry() { + vk, err := e.keyManager.GetAgreementKey("q-view-key") + if err != nil { + vk, err = e.keyManager.CreateAgreementKey( + "q-view-key", + crypto.KeyTypeDecaf448, + ) + if err != nil { + e.logger.Error("could not publish key registry", zap.Error(err)) + return + } + } + + sk, err := e.keyManager.GetAgreementKey("q-spend-key") + if err != nil { + sk, err = e.keyManager.CreateAgreementKey( + "q-spend-key", + crypto.KeyTypeDecaf448, + ) + if err != nil { + e.logger.Error("could not publish key registry", zap.Error(err)) + return + } + } + + pk, err := e.keyManager.GetSigningKey("q-prover-key") + if err != nil { + pk, _, err = e.keyManager.CreateSigningKey( + "q-prover-key", + crypto.KeyTypeBLS48581G1, + ) + if err != nil { + e.logger.Error("could not publish key registry", zap.Error(err)) + return + } + } + + onion, err := e.keyManager.GetAgreementKey("q-onion-key") + if err != nil { + onion, err = e.keyManager.CreateAgreementKey( + "q-onion-key", + crypto.KeyTypeX448, + ) + if err != nil { + e.logger.Error("could not publish key registry", zap.Error(err)) + return + } + } + + sig, err := e.pubsub.SignMessage( + slices.Concat( + []byte("KEY_REGISTRY"), + pk.Public().([]byte), + ), + ) + if err != nil { + e.logger.Error("could not publish key registry", zap.Error(err)) + return + } + sigp, err := pk.SignWithDomain( + e.pubsub.GetPublicKey(), + []byte("KEY_REGISTRY"), + ) + if err != nil { + e.logger.Error("could not publish key registry", zap.Error(err)) + return + } + sigvk, err := e.pubsub.SignMessage( + slices.Concat( + []byte("KEY_REGISTRY"), + vk.Public(), + ), + ) + if err != nil { + e.logger.Error("could not publish key registry", zap.Error(err)) + return + } + sigsk, err := e.pubsub.SignMessage( + slices.Concat( + []byte("KEY_REGISTRY"), + sk.Public(), + ), + ) + if err != nil { + e.logger.Error("could not publish key registry", zap.Error(err)) + return + } + sigonion, err := e.pubsub.SignMessage( + slices.Concat( + []byte("KEY_REGISTRY"), + onion.Public(), + ), + ) + if err != nil { + e.logger.Error("could not publish key registry", zap.Error(err)) + return + } + registry := &protobufs.KeyRegistry{ + IdentityKey: &protobufs.Ed448PublicKey{ + KeyValue: e.pubsub.GetPublicKey(), + }, + ProverKey: &protobufs.BLS48581G2PublicKey{ + KeyValue: pk.Public().([]byte), + }, + IdentityToProver: &protobufs.Ed448Signature{ + Signature: sig, + }, + ProverToIdentity: &protobufs.BLS48581Signature{ + Signature: sigp, + }, + KeysByPurpose: map[string]*protobufs.KeyCollection{ + "ONION_ROUTING": &protobufs.KeyCollection{ + KeyPurpose: "ONION_ROUTING", + X448Keys: []*protobufs.SignedX448Key{{ + Key: &protobufs.X448PublicKey{ + KeyValue: onion.Public(), + }, + ParentKeyAddress: e.pubsub.GetPeerID(), + Signature: &protobufs.SignedX448Key_Ed448Signature{ + Ed448Signature: &protobufs.Ed448Signature{ + Signature: sigonion, + }, + }, + }}, + }, + "view": &protobufs.KeyCollection{ + KeyPurpose: "view", + Decaf448Keys: []*protobufs.SignedDecaf448Key{{ + Key: &protobufs.Decaf448PublicKey{ + KeyValue: vk.Public(), + }, + ParentKeyAddress: e.pubsub.GetPeerID(), + Signature: &protobufs.SignedDecaf448Key_Ed448Signature{ + Ed448Signature: &protobufs.Ed448Signature{ + Signature: sigvk, + }, + }, + }}, + }, + "spend": &protobufs.KeyCollection{ + KeyPurpose: "spend", + Decaf448Keys: []*protobufs.SignedDecaf448Key{{ + Key: &protobufs.Decaf448PublicKey{ + KeyValue: sk.Public(), + }, + ParentKeyAddress: e.pubsub.GetPeerID(), + Signature: &protobufs.SignedDecaf448Key_Ed448Signature{ + Ed448Signature: &protobufs.Ed448Signature{ + Signature: sigsk, + }, + }, + }}, + }, + }, + } + kr, err := registry.ToCanonicalBytes() + if err != nil { + e.logger.Error("could not publish key registry", zap.Error(err)) + return + } + e.pubsub.PublishToBitmask( + GLOBAL_PEER_INFO_BITMASK, + kr, + ) +} diff --git a/node/consensus/global/genesis.go b/node/consensus/global/genesis.go index 2b627025..52dbe1f7 100644 --- a/node/consensus/global/genesis.go +++ b/node/consensus/global/genesis.go @@ -22,6 +22,7 @@ import ( hgcrdt "source.quilibrium.com/quilibrium/monorepo/hypergraph" globalintrinsics "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/global" "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/global/compat" + "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token" hgstate "source.quilibrium.com/quilibrium/monorepo/node/execution/state/hypergraph" "source.quilibrium.com/quilibrium/monorepo/protobufs" "source.quilibrium.com/quilibrium/monorepo/types/execution/intrinsics" @@ -239,6 +240,38 @@ func (e *GlobalConsensusEngine) initializeGenesis() *protobufs.GlobalFrame { } else { // For non-mainnet, use stub genesis genesisFrame = e.createStubGenesis() + txn, err := e.clockStore.NewTransaction(false) + if err != nil { + e.logger.Error( + "failed to place app shard", + zap.Error(err), + ) + return nil + } + + l1 := up2p.GetBloomFilterIndices(token.QUIL_TOKEN_ADDRESS, 256, 3) + + err = e.shardsStore.PutAppShard(txn, store.ShardInfo{ + L1: l1, + L2: token.QUIL_TOKEN_ADDRESS, + Path: []uint32{}, + }) + if err != nil { + e.logger.Error( + "failed to place app shard", + zap.Error(err), + ) + txn.Abort() + return nil + } + if err = txn.Commit(); err != nil { + e.logger.Error( + "failed to place app shard", + zap.Error(err), + ) + txn.Abort() + return nil + } } // Compute frame ID and store the full frame @@ -277,18 +310,30 @@ func (e *GlobalConsensusEngine) createStubGenesis() *protobufs.GlobalFrame { Output: make([]byte, 516), } + // Initialize all commitments with empty values first for i := range 256 { genesisHeader.GlobalCommitments[i] = make([]byte, 64) } - var proverPubKey []byte + commitments := make([]*tries.VectorCommitmentTree, 256) + for i := range 256 { + commitments[i] = &tries.VectorCommitmentTree{} + } + + var proverPubKeys [][]byte var err error if e.config.P2P.Network != 99 && e.config.Engine != nil && e.config.Engine.GenesisSeed != "" { - proverPubKey, err = hex.DecodeString(e.config.Engine.GenesisSeed) + proverPubKeyBytes, err := hex.DecodeString(e.config.Engine.GenesisSeed) if err != nil { panic(err) } + if len(proverPubKeyBytes)%585 != 0 { + panic("invalid genesis seed for testnet seeding") + } + for i := 0; i < len(proverPubKeyBytes)/585; i++ { + proverPubKeys = append(proverPubKeys, proverPubKeyBytes[i*585:(i+1)*585]) + } } else { proverKey, err := e.keyManager.GetSigningKey("q-prover-key") if err != nil { @@ -298,271 +343,101 @@ func (e *GlobalConsensusEngine) createStubGenesis() *protobufs.GlobalFrame { ) return nil } - proverPubKey = proverKey.Public().([]byte) - } - - proverAddressBI, err := poseidon.HashBytes(proverPubKey) - if err != nil || proverAddressBI == nil { - e.logger.Error( - "failed to calculate address value", - zap.Error(err), - ) - return nil + proverPubKeys = [][]byte{proverKey.Public().([]byte)} } - proverAddress := proverAddressBI.FillBytes(make([]byte, 32)) - // Full address for the prover entry - proverFullAddress := [64]byte{} - copy(proverFullAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) - copy(proverFullAddress[32:], proverAddress) - - var proverTree *tries.VectorCommitmentTree - - // Create new prover entry - proverTree = &tries.VectorCommitmentTree{} + state := hgstate.NewHypergraphState(e.hypergraph) rdfMultiprover := schema.NewRDFMultiprover( &schema.TurtleRDFParser{}, e.inclusionProver, ) - // Store the public key - err = rdfMultiprover.Set( - globalintrinsics.GLOBAL_RDF_SCHEMA, - intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], - "prover:Prover", - "PublicKey", - proverPubKey, - proverTree, - ) - if err != nil { - e.logger.Error("failed to set rdf value", zap.Error(err)) - return nil - } - // Store status - err = rdfMultiprover.Set( - globalintrinsics.GLOBAL_RDF_SCHEMA, - intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], - "prover:Prover", - "Status", - []byte{1}, - proverTree, - ) - if err != nil { - e.logger.Error("failed to set rdf value", zap.Error(err)) - return nil - } - - // Store available storage (initially 0) - availableStorageBytes := make([]byte, 8) - binary.BigEndian.PutUint64(availableStorageBytes, 0) - err = rdfMultiprover.Set( - globalintrinsics.GLOBAL_RDF_SCHEMA, - intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], - "prover:Prover", - "AvailableStorage", - availableStorageBytes, - proverTree, - ) - if err != nil { - e.logger.Error("failed to set rdf value", zap.Error(err)) - return nil - } - - // Store seniority - seniorityBytes := make([]byte, 8) - binary.BigEndian.PutUint64(seniorityBytes, 1000000000) - err = rdfMultiprover.Set( - globalintrinsics.GLOBAL_RDF_SCHEMA, - intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], - "prover:Prover", - "Seniority", - seniorityBytes, - proverTree, - ) - if err != nil { - e.logger.Error("failed to set rdf value", zap.Error(err)) - return nil - } - - // Create prover vertex - state := hgstate.NewHypergraphState(e.hypergraph) - proverVertex := state.NewVertexAddMaterializedState( - intrinsics.GLOBAL_INTRINSIC_ADDRESS, - [32]byte(proverAddress), - 0, - nil, - proverTree, - ) - - err = state.Set( - intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], - proverAddress, - hgstate.VertexAddsDiscriminator, - 0, - proverVertex, - ) - if err != nil { - e.logger.Error("failed to set state value", zap.Error(err)) - return nil - } - - // Create hyperedge for this prover - hyperedgeAddress := [32]byte(proverAddress) - hyperedge := hgcrdt.NewHyperedge( - intrinsics.GLOBAL_INTRINSIC_ADDRESS, - hyperedgeAddress, - ) - - // Create ProverAllocation entry for global - - // Calculate allocation address: poseidon.Hash(publicKey || filter) - allocationAddressBI, err := poseidon.HashBytes( - slices.Concat([]byte("PROVER_ALLOCATION"), proverPubKey, nil), - ) - if err != nil { - e.logger.Error("failed to calculate allocation address", zap.Error(err)) - return nil - } - allocationAddress := allocationAddressBI.FillBytes(make([]byte, 32)) - - // Create allocation tree - allocationTree := &tries.VectorCommitmentTree{} + for _, prover := range proverPubKeys { + addrbi, err := poseidon.HashBytes(prover) + if err != nil { + panic(err) + } - // Store prover reference (using the prover vertex) - err = rdfMultiprover.Set( - globalintrinsics.GLOBAL_RDF_SCHEMA, - intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], - "allocation:ProverAllocation", - "Prover", - proverAddress, - allocationTree, - ) - if err != nil { - e.logger.Error("failed to set state value", zap.Error(err)) - return nil - } + // Create ProverReward entry in QUIL token address with 10000 balance + rewardTree := &tries.VectorCommitmentTree{} - // Store allocation status - err = rdfMultiprover.Set( - globalintrinsics.GLOBAL_RDF_SCHEMA, - intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], - "allocation:ProverAllocation", - "Status", - []byte{1}, - allocationTree, - ) - if err != nil { - e.logger.Error("failed to set state value", zap.Error(err)) - return nil - } + err = rdfMultiprover.Set( + globalintrinsics.GLOBAL_RDF_SCHEMA, + token.QUIL_TOKEN_ADDRESS, + "reward:ProverReward", + "DelegateAddress", + addrbi.FillBytes(make([]byte, 32)), + rewardTree, + ) + if err != nil { + panic(err) + } - // Store confirmation filter - err = rdfMultiprover.Set( - globalintrinsics.GLOBAL_RDF_SCHEMA, - intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], - "allocation:ProverAllocation", - "ConfirmationFilter", - nil, - allocationTree, - ) - if err != nil { - e.logger.Error("failed to set state value", zap.Error(err)) - return nil - } + // Set 10000 balance + balance := make([]byte, 32) + balanceBI := big.NewInt(10000 * 8000000000) + balance = balanceBI.FillBytes(balance) + err = rdfMultiprover.Set( + globalintrinsics.GLOBAL_RDF_SCHEMA, + token.QUIL_TOKEN_ADDRESS, + "reward:ProverReward", + "Balance", + balance, + rewardTree, + ) + if err != nil { + panic(err) + } - // Store join frame number - frameNumberBytes := make([]byte, 8) - binary.BigEndian.PutUint64(frameNumberBytes, 0) - err = rdfMultiprover.Set( - globalintrinsics.GLOBAL_RDF_SCHEMA, - intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], - "allocation:ProverAllocation", - "JoinFrameNumber", - frameNumberBytes, - allocationTree, - ) - if err != nil { - e.logger.Error("failed to set state value", zap.Error(err)) - return nil - } + // Create reward vertex in QUIL token address + rewardVertex := state.NewVertexAddMaterializedState( + [32]byte(token.QUIL_TOKEN_ADDRESS), + [32]byte(addrbi.FillBytes(make([]byte, 32))), + 0, + nil, + rewardTree, + ) - // Store join confirm frame number - err = rdfMultiprover.Set( - globalintrinsics.GLOBAL_RDF_SCHEMA, - intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], - "allocation:ProverAllocation", - "JoinConfirmFrameNumber", - frameNumberBytes, - allocationTree, - ) - if err != nil { - e.logger.Error("failed to set state value", zap.Error(err)) - return nil + err = state.Set( + token.QUIL_TOKEN_ADDRESS, + addrbi.FillBytes(make([]byte, 32)), + hgstate.VertexAddsDiscriminator, + 0, + rewardVertex, + ) + if err != nil { + panic(err) + } } - // Store last active frame number - lastActiveFrameNumberBytes := make([]byte, 8) - binary.BigEndian.PutUint64(lastActiveFrameNumberBytes, 244200) - err = rdfMultiprover.Set( - globalintrinsics.GLOBAL_RDF_SCHEMA, - intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], - "allocation:ProverAllocation", - "LastActiveFrameNumber", - lastActiveFrameNumberBytes, - allocationTree, - ) - if err != nil { - e.logger.Error("failed to set state value", zap.Error(err)) + if err := state.Commit(); err != nil { + e.logger.Error("failed to commit", zap.Error(err)) return nil } - // Create allocation vertex - allocationVertex := state.NewVertexAddMaterializedState( - intrinsics.GLOBAL_INTRINSIC_ADDRESS, - [32]byte(allocationAddress), - 0, - nil, - allocationTree, - ) + roots := e.hypergraph.Commit() - err = state.Set( - intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], - allocationAddress, - hgstate.VertexAddsDiscriminator, - 0, - allocationVertex, - ) - if err != nil { - e.logger.Error("failed to set state value", zap.Error(err)) - return nil + // Parse and set initial commitments from JSON + for shardKey, commits := range roots { + for i := 0; i < 3; i++ { + commitments[shardKey.L1[i]].Insert( + shardKey.L2[:], + commits[0], + nil, + big.NewInt(int64(len(commits[0]))), + ) + commitments[shardKey.L1[i]].Commit(e.inclusionProver, false) + } } + state = hgstate.NewHypergraphState(e.hypergraph) - // Add allocation vertex to hyperedge - allocationAtom := hgcrdt.NewVertex( - intrinsics.GLOBAL_INTRINSIC_ADDRESS, - [32]byte(allocationAddress), - allocationTree.Commit(e.inclusionProver, false), - allocationTree.GetSize(), - ) - hyperedge.AddExtrinsic(allocationAtom) - - // Update hyperedge - hyperedgeState := state.NewHyperedgeAddMaterializedState( - 0, - nil, - hyperedge, - ) - err = state.Set( - intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], - hyperedgeAddress[:], - hgstate.HyperedgeAddsDiscriminator, - 0, - hyperedgeState, - ) - if err != nil { - e.logger.Error("failed to set state value", zap.Error(err)) - return nil + for _, pubkey := range proverPubKeys { + err = e.addGenesisProver(rdfMultiprover, state, pubkey, 0, 0) + if err != nil { + e.logger.Error("error adding prover", zap.Error(err)) + return nil + } } err = state.Commit() @@ -571,7 +446,7 @@ func (e *GlobalConsensusEngine) createStubGenesis() *protobufs.GlobalFrame { return nil } - roots := e.hypergraph.Commit() + roots = e.hypergraph.Commit() proverRoots := roots[tries.ShardKey{ L1: [3]byte{}, L2: intrinsics.GLOBAL_INTRINSIC_ADDRESS, @@ -581,6 +456,13 @@ func (e *GlobalConsensusEngine) createStubGenesis() *protobufs.GlobalFrame { genesisHeader.ProverTreeCommitment = proverRoot + for i := 0; i < 256; i++ { + genesisHeader.GlobalCommitments[i] = commitments[i].Commit( + e.inclusionProver, + false, + ) + } + // Establish an empty signature payload – this avoids panics on broken // header readers genesisHeader.PublicKeySignatureBls48581 = @@ -678,7 +560,6 @@ func (e *GlobalConsensusEngine) establishMainnetGenesisProvers( if err := e.addGenesisProver( rdfMultiprover, state, - []byte(peerId), publicKey, seniority.Uint64(), genesisData.FrameNumber, @@ -687,7 +568,7 @@ func (e *GlobalConsensusEngine) establishMainnetGenesisProvers( } for peerid, pubkeyhex := range genesisData.ArchivePeers { - id, err := base58.Decode(peerid) + _, err := base58.Decode(peerid) if err != nil { return err } @@ -700,7 +581,6 @@ func (e *GlobalConsensusEngine) establishMainnetGenesisProvers( if err := e.addGenesisProver( rdfMultiprover, state, - id, pubkey, seniority.Uint64(), genesisData.FrameNumber, @@ -715,7 +595,6 @@ func (e *GlobalConsensusEngine) establishMainnetGenesisProvers( func (e *GlobalConsensusEngine) addGenesisProver( rdfMultiprover *schema.RDFMultiprover, state *hgstate.HypergraphState, - peerId []byte, pubkey []byte, seniority uint64, frameNumber uint64, @@ -915,7 +794,7 @@ func (e *GlobalConsensusEngine) addGenesisProver( // Store last active frame number lastActiveFrameNumberBytes := make([]byte, 8) - binary.BigEndian.PutUint64(lastActiveFrameNumberBytes, 244200) + binary.BigEndian.PutUint64(lastActiveFrameNumberBytes, frameNumber) err = rdfMultiprover.Set( globalintrinsics.GLOBAL_RDF_SCHEMA, intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], diff --git a/node/consensus/global/global_consensus_engine.go b/node/consensus/global/global_consensus_engine.go index 468217ff..06d8ce23 100644 --- a/node/consensus/global/global_consensus_engine.go +++ b/node/consensus/global/global_consensus_engine.go @@ -4,10 +4,13 @@ import ( "bytes" "context" _ "embed" + "encoding/binary" "encoding/hex" "fmt" + "math/big" "net" "net/netip" + "slices" "strings" "sync" "time" @@ -19,6 +22,8 @@ import ( ma "github.com/multiformats/go-multiaddr" "github.com/pkg/errors" "go.uber.org/zap" + "golang.org/x/crypto/sha3" + "golang.org/x/sync/errgroup" "google.golang.org/grpc" "source.quilibrium.com/quilibrium/monorepo/config" "source.quilibrium.com/quilibrium/monorepo/consensus" @@ -61,10 +66,18 @@ var GLOBAL_PEER_INFO_BITMASK = []byte{0x00, 0x00, 0x00, 0x00} var GLOBAL_ALERT_BITMASK = bytes.Repeat([]byte{0x00}, 16) -// timestampedPeerInfo stores peer info with a timestamp for expiry management -type timestampedPeerInfo struct { - peerInfo *protobufs.PeerInfo - timestamp time.Time +type coverageStreak struct { + StartFrame uint64 + LastFrame uint64 + Count uint64 +} + +type LockedTransaction struct { + TransactionHash []byte + ShardAddresses [][]byte + Prover []byte + Committed bool + Filled bool } // GlobalConsensusEngine uses the generic state machine for consensus @@ -109,6 +122,7 @@ type GlobalConsensusEngine struct { globalPeerInfoMessageQueue chan *pb.Message globalAlertMessageQueue chan *pb.Message appFramesMessageQueue chan *pb.Message + shardConsensusMessageQueue chan *pb.Message // Emergency halt haltCtx context.Context @@ -129,8 +143,14 @@ type GlobalConsensusEngine struct { lastProvenFrameTime time.Time lastProvenFrameTimeMu sync.RWMutex frameStore map[string]*protobufs.GlobalFrame - appFrameStore map[string]*protobufs.AppShardFrame frameStoreMu sync.RWMutex + appFrameStore map[string]*protobufs.AppShardFrame + appFrameStoreMu sync.RWMutex + lowCoverageStreak map[string]*coverageStreak + + // Transaction cross-shard lock tracking + txLockMap map[uint64]map[string]map[string]*LockedTransaction + txLockMu sync.RWMutex // Generic state machine stateMachine *consensus.StateMachine[ @@ -229,14 +249,16 @@ func NewGlobalConsensusEngine( globalConsensusMessageQueue: make(chan *pb.Message, 1000), globalFrameMessageQueue: make(chan *pb.Message, 100), globalProverMessageQueue: make(chan *pb.Message, 1000), - appFramesMessageQueue: make(chan *pb.Message, 1000000), + appFramesMessageQueue: make(chan *pb.Message, 10000), globalPeerInfoMessageQueue: make(chan *pb.Message, 1000), globalAlertMessageQueue: make(chan *pb.Message, 100), + shardConsensusMessageQueue: make(chan *pb.Message, 10000), currentDifficulty: config.Engine.Difficulty, lastProvenFrameTime: time.Now(), blacklistMap: make(map[string]bool), pendingMessages: [][]byte{}, alertPublicKey: []byte{}, + txLockMap: make(map[uint64]map[string]map[string]*LockedTransaction), } if config.Engine.AlertKey != "" { @@ -284,6 +306,7 @@ func NewGlobalConsensusEngine( logger, config, engine.ProposeWorkerJoin, + engine.DecideWorkerJoins, ) if !config.Engine.ArchiveMode { strategy := provers.RewardGreedy @@ -366,6 +389,7 @@ func NewGlobalConsensusEngine( verEnc, decafConstructor, compiler, + frameProver, true, // includeGlobal ) if err != nil { @@ -428,16 +452,25 @@ func (e *GlobalConsensusEngine) Start(quit chan struct{}) <-chan error { e.quit = quit e.ctx, e.cancel = context.WithCancel(context.Background()) + // Start worker manager background process (if applicable) + if !e.config.Engine.ArchiveMode { + if err := e.workerManager.Start(e.ctx); err != nil { + errChan <- errors.Wrap(err, "start") + close(errChan) + return errChan + } + } + // Start execution engines if err := e.executionManager.StartAll(e.quit); err != nil { - errChan <- errors.Wrap(err, "start execution engines") + errChan <- errors.Wrap(err, "start") close(errChan) return errChan } // Start the event distributor if err := e.eventDistributor.Start(e.ctx); err != nil { - errChan <- errors.Wrap(err, "start event distributor") + errChan <- errors.Wrap(err, "start") close(errChan) return errChan } @@ -502,6 +535,13 @@ func (e *GlobalConsensusEngine) Start(quit chan struct{}) <-chan error { return errChan } + err = e.subscribeToShardConsensusMessages() + if err != nil { + errChan <- errors.Wrap(err, "start") + close(errChan) + return errChan + } + // Subscribe to frames err = e.subscribeToFrameMessages() if err != nil { @@ -538,6 +578,10 @@ func (e *GlobalConsensusEngine) Start(quit chan struct{}) <-chan error { e.wg.Add(1) go e.processGlobalConsensusMessageQueue() + // Start shard consensus message queue processor + e.wg.Add(1) + go e.processShardConsensusMessageQueue() + // Start frame message queue processor e.wg.Add(1) go e.processFrameMessageQueue() @@ -645,6 +689,9 @@ func (e *GlobalConsensusEngine) setupGRPCServer() error { "quilibrium.node.global.pb.KeyRegistryService": channel.OnlySelfPeer, }, map[string]channel.AllowedPeerPolicyType{ + // Alternative nodes may not need to make this only self peer, but this + // prevents a repeated lock DoS + "/quilibrium.node.global.pb.GlobalService/GetLockedAddresses": channel.OnlySelfPeer, "/quilibrium.node.global.pb.MixnetService/GetTag": channel.AnyPeer, "/quilibrium.node.global.pb.MixnetService/PutTag": channel.AnyPeer, "/quilibrium.node.global.pb.MixnetService/PutMessage": channel.AnyPeer, @@ -691,6 +738,15 @@ func (e *GlobalConsensusEngine) getAddressFromPublicKey( func (e *GlobalConsensusEngine) Stop(force bool) <-chan error { errChan := make(chan error, 1) + // Stop worker manager background process (if applicable) + if !e.config.Engine.ArchiveMode { + if err := e.workerManager.Stop(); err != nil { + errChan <- errors.Wrap(err, "stop") + close(errChan) + return errChan + } + } + if e.grpcServer != nil { e.logger.Info("stopping gRPC server") e.grpcServer.GracefulStop() @@ -702,14 +758,14 @@ func (e *GlobalConsensusEngine) Stop(force bool) <-chan error { if e.config.P2P.Network == 99 || e.config.Engine.ArchiveMode { // Stop the state machine if err := e.stateMachine.Stop(); err != nil && !force { - errChan <- errors.Wrap(err, "stop state machine") + errChan <- errors.Wrap(err, "stop") } } // Stop execution engines if e.executionManager != nil { if err := e.executionManager.StopAll(force); err != nil && !force { - errChan <- errors.Wrap(err, "stop execution engines") + errChan <- errors.Wrap(err, "stop") } } @@ -720,15 +776,25 @@ func (e *GlobalConsensusEngine) Stop(force bool) <-chan error { // Stop event distributor if err := e.eventDistributor.Stop(); err != nil && !force { - errChan <- errors.Wrap(err, "stop event distributor") + errChan <- errors.Wrap(err, "stop") } // Unsubscribe from pubsub if e.config.Engine.ArchiveMode || e.config.P2P.Network == 99 { e.pubsub.Unsubscribe(GLOBAL_CONSENSUS_BITMASK, false) e.pubsub.UnregisterValidator(GLOBAL_CONSENSUS_BITMASK) - } - + e.pubsub.Unsubscribe(bytes.Repeat([]byte{0xff}, 32), false) + e.pubsub.UnregisterValidator(bytes.Repeat([]byte{0xff}, 32)) + } + + e.pubsub.Unsubscribe(slices.Concat( + []byte{0}, + bytes.Repeat([]byte{0xff}, 32), + ), false) + e.pubsub.UnregisterValidator(slices.Concat( + []byte{0}, + bytes.Repeat([]byte{0xff}, 32), + )) e.pubsub.Unsubscribe(GLOBAL_FRAME_BITMASK, false) e.pubsub.UnregisterValidator(GLOBAL_FRAME_BITMASK) e.pubsub.Unsubscribe(GLOBAL_PROVER_BITMASK, false) @@ -1139,8 +1205,10 @@ func (e *GlobalConsensusEngine) materialize( var state state.State state = hgstate.NewHypergraphState(e.hypergraph) - acceptedMessages := []*protobufs.MessageBundle{} - + e.logger.Debug( + "materializing messages", + zap.Int("message_count", len(requests)), + ) for i, request := range requests { requestBytes, err := request.ToCanonicalBytes() @@ -1174,13 +1242,18 @@ func (e *GlobalConsensusEngine) materialize( e.currentDifficultyMu.RLock() difficulty := uint64(e.currentDifficulty) e.currentDifficultyMu.RUnlock() - baseline := reward.GetBaselineFee( - difficulty, - e.hypergraph.GetSize(nil, nil).Uint64(), - costBasis.Uint64(), - 8000000000, - ) - baseline.Quo(baseline, costBasis) + var baseline *big.Int + if costBasis.Cmp(big.NewInt(0)) == 0 { + baseline = big.NewInt(0) + } else { + baseline = reward.GetBaselineFee( + difficulty, + e.hypergraph.GetSize(nil, nil).Uint64(), + costBasis.Uint64(), + 8000000000, + ) + baseline.Quo(baseline, costBasis) + } result, err := e.executionManager.ProcessMessage( frameNumber, @@ -1199,15 +1272,14 @@ func (e *GlobalConsensusEngine) materialize( } state = result.State - acceptedMessages = append(acceptedMessages, request) } - err := e.proverRegistry.ProcessStateTransition(state, frameNumber) - if err != nil { + if err := state.Commit(); err != nil { return errors.Wrap(err, "materialize") } - if err := state.Commit(); err != nil { + err := e.proverRegistry.ProcessStateTransition(state, frameNumber) + if err != nil { return errors.Wrap(err, "materialize") } @@ -1380,16 +1452,16 @@ func (e *GlobalConsensusEngine) cleanupFrameStore() { zap.Uint64("max_frame", cutoffFrameNumber-1), ) } - } - e.logger.Debug( - "cleaned up frame store", - zap.Int("deleted_frames", deletedCount), - zap.Int("remaining_frames", len(e.frameStore)), - zap.Uint64("max_frame_number", maxFrameNumber), - zap.Uint64("cutoff_frame_number", cutoffFrameNumber), - zap.Bool("archive_mode", e.config.Engine.ArchiveMode), - ) + e.logger.Debug( + "cleaned up frame store", + zap.Int("deleted_frames", deletedCount), + zap.Int("remaining_frames", len(e.frameStore)), + zap.Uint64("max_frame_number", maxFrameNumber), + zap.Uint64("cutoff_frame_number", cutoffFrameNumber), + zap.Bool("archive_mode", e.config.Engine.ArchiveMode), + ) + } } // isAddressBlacklisted checks if a given address (full or partial) is in the @@ -1947,16 +2019,19 @@ func reservedPrefixes(proto int) []netip.Prefix { // TODO(2.1.1+): This could use refactoring func (e *GlobalConsensusEngine) ProposeWorkerJoin( - coreId uint, - filter []byte, + coreIds []uint, + filters [][]byte, + serviceClients map[uint]*grpc.ClientConn, ) error { frame := e.GetFrame() if frame == nil { + e.logger.Debug("cannot propose, no frame") return errors.New("not ready") } _, err := e.keyManager.GetSigningKey("q-prover-key") if err != nil { + e.logger.Debug("cannot propose, no signer key") return errors.Wrap(err, "propose worker join") } @@ -1968,12 +2043,14 @@ func (e *GlobalConsensusEngine) ProposeWorkerJoin( helpers := []*global.SeniorityMerge{} if !skipMerge { + e.logger.Debug("attempting merge") peerIds := []string{} oldProver, err := keys.Ed448KeyFromBytes( []byte(e.config.P2P.PeerPrivKey), e.pubsub.GetPublicKey(), ) if err != nil { + e.logger.Debug("cannot get peer key", zap.Error(err)) return errors.Wrap(err, "propose worker join") } helpers = append(helpers, global.NewSeniorityMerge( @@ -1982,6 +2059,7 @@ func (e *GlobalConsensusEngine) ProposeWorkerJoin( )) peerIds = append(peerIds, peer.ID(e.pubsub.GetPeerID()).String()) if len(e.config.Engine.MultisigProverEnrollmentPaths) != 0 { + e.logger.Debug("loading old configs") for _, conf := range e.config.Engine.MultisigProverEnrollmentPaths { extraConf, err := config.LoadConfig(conf, "", false) if err != nil { @@ -2049,20 +2127,93 @@ func (e *GlobalConsensusEngine) ProposeWorkerJoin( } } + challenge := sha3.Sum256(frame.Header.Output) + + joins := min(len(serviceClients), len(filters)) + results := make([][516]byte, joins) + idx := uint32(0) + ids := [][]byte{} + e.logger.Debug("preparing join commitment") + for range joins { + ids = append( + ids, + slices.Concat( + e.getProverAddress(), + filters[idx], + binary.BigEndian.AppendUint32(nil, idx), + ), + ) + idx++ + } + + idx = 0 + + wg := errgroup.Group{} + wg.SetLimit(joins) + + e.logger.Debug( + "attempting join proof", + zap.String("challenge", hex.EncodeToString(challenge[:])), + zap.Uint64("difficulty", uint64(frame.Header.Difficulty)), + zap.Int("ids_count", len(ids)), + ) + + for _, core := range coreIds { + svc := serviceClients[core] + i := idx + + // limit to available joins + if i == uint32(joins) { + break + } + wg.Go(func() error { + client := protobufs.NewDataIPCServiceClient(svc) + resp, err := client.CreateJoinProof( + e.ctx, + &protobufs.CreateJoinProofRequest{ + Challenge: challenge[:], + Difficulty: frame.Header.Difficulty, + Ids: ids, + ProverIndex: i, + }, + ) + if err != nil { + return err + } + + results[i] = [516]byte(resp.Response) + return nil + }) + idx++ + } + e.logger.Debug("waiting for join proof to complete") + + err = wg.Wait() + if err != nil { + e.logger.Debug("failed join proof", zap.Error(err)) + return errors.Wrap(err, "propose worker join") + } + join, err := global.NewProverJoin( - [][]byte{filter}, + filters, frame.Header.FrameNumber, helpers, delegate, e.keyManager, e.hypergraph, schema.NewRDFMultiprover(&schema.TurtleRDFParser{}, e.inclusionProver), + e.frameProver, + e.clockStore, ) if err != nil { e.logger.Error("could not construct join", zap.Error(err)) return errors.Wrap(err, "propose worker join") } + for _, res := range results { + join.Proof = append(join.Proof, res[:]...) + } + err = join.Prove(frame.Header.FrameNumber) if err != nil { e.logger.Error("could not construct join", zap.Error(err)) @@ -2077,6 +2228,7 @@ func (e *GlobalConsensusEngine) ProposeWorkerJoin( }, }, }, + Timestamp: time.Now().UnixMilli(), } msg, err := bundle.ToCanonicalBytes() @@ -2094,5 +2246,105 @@ func (e *GlobalConsensusEngine) ProposeWorkerJoin( return errors.Wrap(err, "propose worker join") } + e.logger.Debug("submitted join request") + + return nil +} + +func (e *GlobalConsensusEngine) DecideWorkerJoins( + reject [][]byte, + confirm [][]byte, +) error { + frame := e.GetFrame() + if frame == nil { + e.logger.Debug("cannot decide, no frame") + return errors.New("not ready") + } + + _, err := e.keyManager.GetSigningKey("q-prover-key") + if err != nil { + e.logger.Debug("cannot decide, no signer key") + return errors.Wrap(err, "decide worker joins") + } + + bundle := &protobufs.MessageBundle{ + Requests: []*protobufs.MessageRequest{}, + } + + if len(reject) != 0 { + for _, r := range reject { + rejectMessage, err := global.NewProverReject( + r, + frame.Header.FrameNumber, + e.keyManager, + e.hypergraph, + schema.NewRDFMultiprover(&schema.TurtleRDFParser{}, e.inclusionProver), + ) + if err != nil { + e.logger.Error("could not construct reject", zap.Error(err)) + return errors.Wrap(err, "decide worker joins") + } + + err = rejectMessage.Prove(frame.Header.FrameNumber) + if err != nil { + e.logger.Error("could not construct reject", zap.Error(err)) + return errors.Wrap(err, "decide worker joins") + } + + bundle.Requests = append(bundle.Requests, &protobufs.MessageRequest{ + Request: &protobufs.MessageRequest_Reject{ + Reject: rejectMessage.ToProtobuf(), + }, + }) + } + } + + if len(confirm) != 0 { + for _, r := range confirm { + confirmMessage, err := global.NewProverConfirm( + r, + frame.Header.FrameNumber, + e.keyManager, + e.hypergraph, + schema.NewRDFMultiprover(&schema.TurtleRDFParser{}, e.inclusionProver), + ) + if err != nil { + e.logger.Error("could not construct confirm", zap.Error(err)) + return errors.Wrap(err, "decide worker joins") + } + + err = confirmMessage.Prove(frame.Header.FrameNumber) + if err != nil { + e.logger.Error("could not construct confirm", zap.Error(err)) + return errors.Wrap(err, "decide worker joins") + } + + bundle.Requests = append(bundle.Requests, &protobufs.MessageRequest{ + Request: &protobufs.MessageRequest_Confirm{ + Confirm: confirmMessage.ToProtobuf(), + }, + }) + } + } + + bundle.Timestamp = time.Now().UnixMilli() + + msg, err := bundle.ToCanonicalBytes() + if err != nil { + e.logger.Error("could not construct decision", zap.Error(err)) + return errors.Wrap(err, "decide worker joins") + } + + err = e.pubsub.PublishToBitmask( + GLOBAL_PROVER_BITMASK, + msg, + ) + if err != nil { + e.logger.Error("could not construct join", zap.Error(err)) + return errors.Wrap(err, "decide worker joins") + } + + e.logger.Debug("submitted join decisions") + return nil } diff --git a/node/consensus/global/global_consensus_engine_integration_test.go b/node/consensus/global/global_consensus_engine_integration_test.go index 231e5299..5db8e627 100644 --- a/node/consensus/global/global_consensus_engine_integration_test.go +++ b/node/consensus/global/global_consensus_engine_integration_test.go @@ -11,14 +11,17 @@ import ( "fmt" "math/big" "slices" + "strings" "sync" "testing" "time" "github.com/iden3/go-iden3-crypto/poseidon" + "github.com/libp2p/go-libp2p" + pcrypto "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" "github.com/multiformats/go-multiaddr" - "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -43,6 +46,7 @@ import ( consensustime "source.quilibrium.com/quilibrium/monorepo/node/consensus/time" "source.quilibrium.com/quilibrium/monorepo/node/consensus/validator" "source.quilibrium.com/quilibrium/monorepo/node/keys" + qp2p "source.quilibrium.com/quilibrium/monorepo/node/p2p" "source.quilibrium.com/quilibrium/monorepo/node/store" "source.quilibrium.com/quilibrium/monorepo/node/tests" "source.quilibrium.com/quilibrium/monorepo/protobufs" @@ -70,16 +74,18 @@ func (l *testTransitionListener) OnTransition(from, to consensus.State, event co // mockIntegrationPubSub is a pubsub mock for integration testing type mockIntegrationPubSub struct { mock.Mock - mu sync.RWMutex - subscribers map[string][]func(message *pb.Message) error - validators map[string]func(peerID peer.ID, message *pb.Message) p2p.ValidationResult - peerID []byte - peerCount int - networkPeers map[string]*mockIntegrationPubSub - frames []*protobufs.GlobalFrame - onPublish func(bitmask []byte, data []byte) - deliveryComplete chan struct{} // Signal when all deliveries are done - msgProcessor func(*pb.Message) // Custom message processor for tracking + mu sync.RWMutex + subscribers map[string][]func(message *pb.Message) error + validators map[string]func(peerID peer.ID, message *pb.Message) p2p.ValidationResult + peerID []byte + peerCount int + networkPeers map[string]*mockIntegrationPubSub + frames []*protobufs.GlobalFrame + onPublish func(bitmask []byte, data []byte) + deliveryComplete chan struct{} // Signal when all deliveries are done + msgProcessor func(*pb.Message) // Custom message processor for tracking + underlyingHost host.Host + underlyingBlossomSub *qp2p.BlossomSub } // GetOwnMultiaddrs implements p2p.PubSub. @@ -88,24 +94,28 @@ func (m *mockIntegrationPubSub) GetOwnMultiaddrs() []multiaddr.Multiaddr { return []multiaddr.Multiaddr{ma} } -func newMockIntegrationPubSub(peerID []byte) *mockIntegrationPubSub { +func newMockIntegrationPubSub(config *config.Config, logger *zap.Logger, peerID []byte, host host.Host, privKey pcrypto.PrivKey, bootstrapHosts []host.Host) *mockIntegrationPubSub { + blossomSub := qp2p.NewBlossomSubWithHost(config.P2P, config.Engine, logger, 1, true, host, privKey, bootstrapHosts) return &mockIntegrationPubSub{ - subscribers: make(map[string][]func(message *pb.Message) error), - validators: make(map[string]func(peerID peer.ID, message *pb.Message) p2p.ValidationResult), - peerID: peerID, - peerCount: 0, // Start with 0 to trigger genesis - networkPeers: make(map[string]*mockIntegrationPubSub), - frames: make([]*protobufs.GlobalFrame, 0), - deliveryComplete: make(chan struct{}), + subscribers: make(map[string][]func(message *pb.Message) error), + validators: make(map[string]func(peerID peer.ID, message *pb.Message) p2p.ValidationResult), + peerID: peerID, + peerCount: 0, // Start with 0 to trigger genesis + networkPeers: make(map[string]*mockIntegrationPubSub), + frames: make([]*protobufs.GlobalFrame, 0), + deliveryComplete: make(chan struct{}), + underlyingHost: host, + underlyingBlossomSub: blossomSub, } } func (m *mockIntegrationPubSub) Subscribe(bitmask []byte, handler func(message *pb.Message) error) error { m.mu.Lock() - defer m.mu.Unlock() key := string(bitmask) m.subscribers[key] = append(m.subscribers[key], handler) - return nil + m.mu.Unlock() + + return m.underlyingBlossomSub.Subscribe(bitmask, handler) } func (m *mockIntegrationPubSub) PublishToBitmask(bitmask []byte, data []byte) error { @@ -140,55 +150,7 @@ func (m *mockIntegrationPubSub) PublishToBitmask(bitmask []byte, data []byte) er } m.mu.RUnlock() - // Track deliveries with wait group - deliveryWg := sync.WaitGroup{} - deliveryWg.Add(totalHandlers) - - // Create wrapped handler that decrements counter - wrappedHandler := func(h func(*pb.Message) error, msg *pb.Message) { - defer deliveryWg.Done() - if m.msgProcessor != nil { - m.msgProcessor(msg) - } - h(msg) - } - - message := &pb.Message{ - From: m.peerID, - Data: data, - } - - // Deliver to self asynchronously - m.mu.RLock() - localHandlers := m.subscribers[string(bitmask)] - m.mu.RUnlock() - - for _, handler := range localHandlers { - go wrappedHandler(handler, message) - } - - // Distribute to network peers - m.mu.RLock() - peers := make([]*mockIntegrationPubSub, 0, len(m.networkPeers)) - for _, peer := range m.networkPeers { - peers = append(peers, peer) - } - m.mu.RUnlock() - - for _, peer := range peers { - peer.deliverMessage(bitmask, message, &deliveryWg) - } - - // Start goroutine to signal when all deliveries complete - go func() { - deliveryWg.Wait() - select { - case m.deliveryComplete <- struct{}{}: - default: - } - }() - - return nil + return m.underlyingBlossomSub.PublishToBitmask(bitmask, data) } func (m *mockIntegrationPubSub) deliverMessage(bitmask []byte, message *pb.Message, wg *sync.WaitGroup) { @@ -232,22 +194,23 @@ func (m *mockIntegrationPubSub) deliverMessage(bitmask []byte, message *pb.Messa func (m *mockIntegrationPubSub) RegisterValidator(bitmask []byte, validator func(peerID peer.ID, message *pb.Message) p2p.ValidationResult, sync bool) error { m.mu.Lock() - defer m.mu.Unlock() m.validators[string(bitmask)] = validator - return nil + m.mu.Unlock() + return m.underlyingBlossomSub.RegisterValidator(bitmask, validator, sync) } func (m *mockIntegrationPubSub) UnregisterValidator(bitmask []byte) error { m.mu.Lock() - defer m.mu.Unlock() delete(m.validators, string(bitmask)) - return nil + m.mu.Unlock() + return m.underlyingBlossomSub.UnregisterValidator(bitmask) } func (m *mockIntegrationPubSub) Unsubscribe(bitmask []byte, raw bool) { m.mu.Lock() - defer m.mu.Unlock() delete(m.subscribers, string(bitmask)) + m.mu.Unlock() + m.underlyingBlossomSub.Unsubscribe(bitmask, raw) } func (m *mockIntegrationPubSub) GetPeerID() []byte { @@ -264,16 +227,6 @@ func (m *mockIntegrationPubSub) GetNetworkInfo() *protobufs.NetworkInfoResponse } } -// WaitForDeliveries waits for all message deliveries to complete -func (m *mockIntegrationPubSub) WaitForDeliveries(timeout time.Duration) error { - select { - case <-m.deliveryComplete: - return nil - case <-time.After(timeout): - return errors.New("timeout waiting for message deliveries") - } -} - // Stub implementations for other interface methods func (m *mockIntegrationPubSub) Publish(address []byte, data []byte) error { return nil } func (m *mockIntegrationPubSub) GetNetworkPeersCount() int { return m.peerCount } @@ -398,13 +351,16 @@ func createIntegrationTestGlobalConsensusEngine( t *testing.T, peerID []byte, network uint8, + h host.Host, + privKey pcrypto.PrivKey, + bootstrapHosts []host.Host, ) ( *GlobalConsensusEngine, *mockIntegrationPubSub, *consensustime.GlobalTimeReel, func(), ) { - return createIntegrationTestGlobalConsensusEngineWithHypergraph(t, peerID, nil, network) + return createIntegrationTestGlobalConsensusEngineWithHypergraph(t, peerID, nil, network, h, privKey, bootstrapHosts) } // createIntegrationTestGlobalConsensusEngineWithHypergraph creates an engine with optional shared hypergraph @@ -413,13 +369,16 @@ func createIntegrationTestGlobalConsensusEngineWithHypergraph( peerID []byte, sharedHypergraph thypergraph.Hypergraph, network uint8, + h host.Host, + privKey pcrypto.PrivKey, + bootstrapHosts []host.Host, ) ( *GlobalConsensusEngine, *mockIntegrationPubSub, *consensustime.GlobalTimeReel, func(), ) { - return createIntegrationTestGlobalConsensusEngineWithHypergraphAndKey(t, peerID, sharedHypergraph, nil, network) + return createIntegrationTestGlobalConsensusEngineWithHypergraphAndKey(t, peerID, sharedHypergraph, nil, network, h, privKey, bootstrapHosts) } // createIntegrationTestGlobalConsensusEngineWithHypergraphAndKey creates an engine with optional shared hypergraph and pre-generated key @@ -429,6 +388,9 @@ func createIntegrationTestGlobalConsensusEngineWithHypergraphAndKey( sharedHypergraph thypergraph.Hypergraph, preGeneratedKey *tkeys.Key, network uint8, + h host.Host, + privKey pcrypto.PrivKey, + bootstrapHosts []host.Host, ) ( *GlobalConsensusEngine, *mockIntegrationPubSub, @@ -460,19 +422,19 @@ func createIntegrationTestGlobalConsensusEngineWithHypergraphAndKey( peerkey, _, _ := keyManager.CreateSigningKey("q-peer-key", crypto.KeyTypeEd448) peerpriv := peerkey.Private() peerHex := hex.EncodeToString(peerpriv) + p2pcfg := config.P2PConfig{}.WithDefaults() + p2pcfg.Network = network + p2pcfg.PeerPrivKey = peerHex + p2pcfg.StreamListenMultiaddr = "/ip4/0.0.0.0/tcp/0" cfg := &config.Config{ Engine: &config.EngineConfig{ - Difficulty: 10, + Difficulty: 100, ProvingKeyId: "q-prover-key", // Always use the required key ID AlertKey: alertHex, ArchiveMode: true, }, - P2P: &config.P2PConfig{ - Network: network, - PeerPrivKey: peerHex, - StreamListenMultiaddr: "/ip4/0.0.0.0/tcp/0", - }, + P2P: &p2pcfg, } // Create the required "q-prover-key" @@ -551,7 +513,7 @@ func createIntegrationTestGlobalConsensusEngineWithHypergraphAndKey( rewardIssuance := reward.NewOptRewardIssuance() // Create pubsub - pubsub := newMockIntegrationPubSub(peerID) + pubsub := newMockIntegrationPubSub(cfg, logger, peerID, h, privKey, bootstrapHosts) // Create time reel globalTimeReel, err := consensustime.NewGlobalTimeReel(logger, proverRegistry, clockStore, network, true) @@ -605,8 +567,11 @@ func createIntegrationTestGlobalConsensusEngineWithHypergraphAndKey( } func TestGlobalConsensusEngine_Integration_BasicFrameProgression(t *testing.T) { - engine, pubsub, _, cleanup := createIntegrationTestGlobalConsensusEngine(t, []byte{0x01}, 99) - defer cleanup() + // Generate hosts for testing + _, m, cleanupHosts := tests.GenerateSimnetHosts(t, 1, []libp2p.Option{}) + defer cleanupHosts() + + engine, pubsub, _, _ := createIntegrationTestGlobalConsensusEngine(t, []byte(m.Nodes[0].ID()), 99, m.Nodes[0], m.Keys[0], m.Nodes) // Track published frames publishedFrames := make([]*protobufs.GlobalFrame, 0) @@ -651,7 +616,7 @@ func TestGlobalConsensusEngine_Integration_BasicFrameProgression(t *testing.T) { assert.NotEqual(t, tconsensus.EngineStateStarting, state) // Wait for frame processing - time.Sleep(1 * time.Second) + time.Sleep(10 * time.Second) // Check if frames were published mu.Lock() @@ -666,8 +631,11 @@ func TestGlobalConsensusEngine_Integration_BasicFrameProgression(t *testing.T) { } func TestGlobalConsensusEngine_Integration_StateTransitions(t *testing.T) { - engine, _, _, cleanup := createIntegrationTestGlobalConsensusEngine(t, []byte{0x02}, 99) - defer cleanup() + // Generate hosts for testing + _, m, cleanupHosts := tests.GenerateSimnetHosts(t, 1, []libp2p.Option{}) + defer cleanupHosts() + + engine, _, _, _ := createIntegrationTestGlobalConsensusEngine(t, []byte(m.Nodes[0].ID()), 99, m.Nodes[0], m.Keys[0], m.Nodes) // Track state transitions transitions := make([]string, 0) @@ -696,7 +664,7 @@ func TestGlobalConsensusEngine_Integration_StateTransitions(t *testing.T) { } // Wait for state transitions - time.Sleep(2 * time.Second) + time.Sleep(10 * time.Second) // Verify we had some state transitions mu.Lock() @@ -711,6 +679,10 @@ func TestGlobalConsensusEngine_Integration_StateTransitions(t *testing.T) { } func TestGlobalConsensusEngine_Integration_MultiNodeConsensus(t *testing.T) { + // Generate hosts for all 6 nodes first + _, m, cleanupHosts := tests.GenerateSimnetHosts(t, 6, []libp2p.Option{}) + defer cleanupHosts() + // Create shared components first logger, _ := zap.NewDevelopment() @@ -762,21 +734,19 @@ func TestGlobalConsensusEngine_Integration_MultiNodeConsensus(t *testing.T) { // Create six engines that can communicate (minimum required for consensus) engines := make([]*GlobalConsensusEngine, 6) pubsubs := make([]*mockIntegrationPubSub, 6) - cleanups := make([]func(), 6) for i := 0; i < 6; i++ { - peerID := []byte{byte(i + 1)} - engine, pubsub, _, cleanup := createIntegrationTestGlobalConsensusEngineWithHypergraphAndKey(t, peerID, hypergraphs[i], nodeRawKeys[i], 1) + peerID := []byte(m.Nodes[i].ID()) + engine, pubsub, _, _ := createIntegrationTestGlobalConsensusEngineWithHypergraphAndKey(t, peerID, hypergraphs[i], nodeRawKeys[i], 1, m.Nodes[i], m.Keys[i], m.Nodes) engines[i] = engine pubsubs[i] = pubsub - cleanups[i] = cleanup - defer cleanup() } // Connect all pubsubs to each other for i := 0; i < 6; i++ { for j := 0; j < 6; j++ { if i != j { + tests.ConnectSimnetHosts(t, m.Nodes[i], m.Nodes[j]) pubsubs[i].networkPeers[fmt.Sprintf("peer%d", j)] = pubsubs[j] } } @@ -811,7 +781,7 @@ func TestGlobalConsensusEngine_Integration_MultiNodeConsensus(t *testing.T) { } // Track message processing - pubsubs[i].msgProcessor = func(msg *pb.Message) { + pubsubs[i].Subscribe([]byte{0x00}, func(msg *pb.Message) error { // Check if data is long enough to contain type prefix if len(msg.Data) >= 4 { // Read type prefix from first 4 bytes @@ -828,7 +798,8 @@ func TestGlobalConsensusEngine_Integration_MultiNodeConsensus(t *testing.T) { livenessCount[nodeIdx]++ } } - } + return nil + }) } // Start all engines @@ -877,11 +848,7 @@ loop: if allSeen { // Wait for message deliveries to complete - for i := 0; i < 6; i++ { - if err := pubsubs[i].WaitForDeliveries(5 * time.Second); err != nil { - t.Logf("Node %d: %v", i+1, err) - } - } + time.Sleep(1 * time.Second) t.Log("All nodes have seen all proposals, proceeding") break loop } @@ -927,8 +894,32 @@ loop: } func TestGlobalConsensusEngine_Integration_ShardCoverage(t *testing.T) { - engine, _, _, cleanup := createIntegrationTestGlobalConsensusEngine(t, []byte{0x03}, 99) - defer cleanup() + // Generate hosts for testing + _, m, cleanupHosts := tests.GenerateSimnetHosts(t, 1, []libp2p.Option{}) + defer cleanupHosts() + + pebbleDB := store.NewPebbleDB(zap.L(), &config.DBConfig{InMemoryDONOTUSE: true, Path: ".test/global_shared"}, 0) + + inclusionProver := bls48581.NewKZGInclusionProver(zap.L()) + hypergraphStore := store.NewPebbleHypergraphStore(&config.DBConfig{ + InMemoryDONOTUSE: true, + Path: ".test/global", + }, pebbleDB, zap.L(), &verenc.MPCitHVerifiableEncryptor{}, inclusionProver) + hg := hgcrdt.NewHypergraph(zap.NewNop(), hypergraphStore, inclusionProver, []int{}, &tests.Nopthenticator{}) + for i := range 3 { + k := make([]byte, 585) + k[1] = byte(i) + abi, _ := poseidon.HashBytes(k) + registerProverInHypergraphWithFilter(t, hg, k, abi.FillBytes(make([]byte, 32)), []byte{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}) + } + engine, _, _, _ := createIntegrationTestGlobalConsensusEngineWithHypergraphAndKey(t, []byte(m.Nodes[0].ID()), hg, nil, 1, m.Nodes[0], m.Keys[0], m.Nodes) + + // simulate a one byte vertex so the shard has space being used + txn, _ := hg.NewTransaction(false) + c := make([]byte, 74) + c[0] = 0x02 + hg.AddVertex(txn, hgcrdt.NewVertex([32]byte{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}, [32]byte{}, c, big.NewInt(1))) + txn.Commit() // Track emitted events var publishedEvents []tconsensus.ControlEvent @@ -953,15 +944,32 @@ func TestGlobalConsensusEngine_Integration_ShardCoverage(t *testing.T) { // Start the event distributor engine.Start(make(chan struct{})) + time.Sleep(1 * time.Second) + // Configure low coverage scenario in hypergraph // Since we registered only 1 prover above, this is already a low coverage scenario // Run shard coverage check - err := engine.checkShardCoverage() + err := engine.checkShardCoverage(1) require.NoError(t, err) - // Wait for event processing - time.Sleep(100 * time.Millisecond) + // Wait for event processing and possible new app shard head + time.Sleep(10 * time.Second) + mu.Lock() + found := false + newHeadAfter := false + for _, e := range publishedEvents { + if e.Type == tconsensus.ControlEventCoverageHalt { + found = true + } + if found && e.Type == tconsensus.ControlEventAppNewHead { + newHeadAfter = true + } + } + mu.Unlock() + + require.True(t, found) + require.False(t, newHeadAfter) // Stop the event distributor eventDistributor.Stop() @@ -972,11 +980,16 @@ func TestGlobalConsensusEngine_Integration_ShardCoverage(t *testing.T) { func TestGlobalConsensusEngine_Integration_NoProversStaysInVerifying(t *testing.T) { t.Log("Testing global consensus engines with no registered provers") + // Create six nodes + numNodes := 6 + + // Generate hosts for all nodes first + _, m, cleanupHosts := tests.GenerateSimnetHosts(t, numNodes, []libp2p.Option{}) + defer cleanupHosts() + // Create shared components logger, _ := zap.NewDevelopment() - // Create six nodes - numNodes := 6 engines := make([]*GlobalConsensusEngine, numNodes) pubsubs := make([]*mockIntegrationPubSub, numNodes) quits := make([]chan struct{}, numNodes) @@ -988,7 +1001,7 @@ func TestGlobalConsensusEngine_Integration_NoProversStaysInVerifying(t *testing. // Create separate hypergraph and prover registry for each node to ensure isolation for i := 0; i < numNodes; i++ { nodeID := i + 1 - peerID := []byte{byte(nodeID)} + peerID := []byte(m.Nodes[i].ID()) t.Logf("Creating node %d with peer ID: %x", nodeID, peerID) @@ -1023,7 +1036,7 @@ func TestGlobalConsensusEngine_Integration_NoProversStaysInVerifying(t *testing. require.NoError(t, err) // Create global time reel - globalTimeReel, err := consensustime.NewGlobalTimeReel(logger, proverRegistry, clockStore, 99, true) + globalTimeReel, err := consensustime.NewGlobalTimeReel(logger, proverRegistry, clockStore, 1, true) require.NoError(t, err) eventDistributor := events.NewGlobalEventDistributor( @@ -1036,26 +1049,27 @@ func TestGlobalConsensusEngine_Integration_NoProversStaysInVerifying(t *testing. difficultyAdjuster := difficulty.NewAsertDifficultyAdjuster(0, time.Now().UnixMilli(), 10) rewardIssuance := reward.NewOptRewardIssuance() - // Create pubsub - pubsubs[i] = newMockIntegrationPubSub(peerID) - pubsubs[i].peerCount = 10 // Set high peer count - // Set up peer key peerkey, _, _ := keyManager.CreateSigningKey("q-peer-key", crypto.KeyTypeEd448) peerpriv := peerkey.Private() peerHex := hex.EncodeToString(peerpriv) + p2pcfg := config.P2PConfig{}.WithDefaults() + p2pcfg.Network = 2 + p2pcfg.PeerPrivKey = peerHex + p2pcfg.StreamListenMultiaddr = "/ip4/0.0.0.0/tcp/0" cfg := &config.Config{ Engine: &config.EngineConfig{ Difficulty: 10, ProvingKeyId: "q-prover-key", + GenesisSeed: strings.Repeat("00", 585), }, - P2P: &config.P2PConfig{ - Network: 2, - PeerPrivKey: peerHex, - StreamListenMultiaddr: "/ip4/0.0.0.0/tcp/0", - }, + P2P: &p2pcfg, } + + // Create pubsub with host and key + pubsubs[i] = newMockIntegrationPubSub(cfg, logger, peerID, m.Nodes[i], m.Keys[i], m.Nodes) + pubsubs[i].peerCount = 10 // Set high peer count // Create engine engine, err := NewGlobalConsensusEngine( logger, @@ -1141,8 +1155,11 @@ func TestGlobalConsensusEngine_Integration_NoProversStaysInVerifying(t *testing. // TestGlobalConsensusEngine_Integration_AlertStopsProgression tests that engines // halt when an alert broadcast occurs func TestGlobalConsensusEngine_Integration_AlertStopsProgression(t *testing.T) { - engine, pubsub, _, cleanup := createIntegrationTestGlobalConsensusEngine(t, []byte{0x01}, 99) - defer cleanup() + // Generate hosts for testing + _, m, cleanupHosts := tests.GenerateSimnetHosts(t, 1, []libp2p.Option{}) + defer cleanupHosts() + + engine, pubsub, _, _ := createIntegrationTestGlobalConsensusEngine(t, []byte(m.Nodes[0].ID()), 99, m.Nodes[0], m.Keys[0], m.Nodes) // Track published frames publishedFrames := make([]*protobufs.GlobalFrame, 0) @@ -1236,3 +1253,85 @@ func TestGlobalConsensusEngine_Integration_AlertStopsProgression(t *testing.T) { close(quit) <-engine.Stop(false) } + +// registerProverInHypergraphWithFilter registers a prover with a specific filter (shard address) +func registerProverInHypergraphWithFilter(t *testing.T, hg thypergraph.Hypergraph, publicKey []byte, address []byte, filter []byte) { + // Create the full address: GLOBAL_INTRINSIC_ADDRESS + prover address + fullAddress := [64]byte{} + copy(fullAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) + copy(fullAddress[32:], address) + + // Create a VectorCommitmentTree with the prover data + tree := &qcrypto.VectorCommitmentTree{} + + // Index 0: Public key + err := tree.Insert([]byte{0}, publicKey, nil, big.NewInt(0)) + if err != nil { + t.Fatalf("Failed to insert public key: %v", err) + } + + // Index 1<<2 (4): Status (1 byte) - 1 = active + err = tree.Insert([]byte{1 << 2}, []byte{1}, nil, big.NewInt(0)) + if err != nil { + t.Fatalf("Failed to insert status: %v", err) + } + + // Type Index: + typeBI, _ := poseidon.HashBytes( + slices.Concat(bytes.Repeat([]byte{0xff}, 32), []byte("prover:Prover")), + ) + tree.Insert(bytes.Repeat([]byte{0xff}, 32), typeBI.FillBytes(make([]byte, 32)), nil, big.NewInt(32)) + + // Create allocation + allocationAddressBI, err := poseidon.HashBytes(slices.Concat([]byte("PROVER_ALLOCATION"), publicKey, []byte{})) + require.NoError(t, err) + allocationAddress := allocationAddressBI.FillBytes(make([]byte, 32)) + + allocationTree := &qcrypto.VectorCommitmentTree{} + // Store allocation data + err = allocationTree.Insert([]byte{0 << 2}, fullAddress[32:], nil, big.NewInt(0)) + require.NoError(t, err) + err = allocationTree.Insert([]byte{2 << 2}, filter, nil, big.NewInt(0)) // confirm filter + require.NoError(t, err) + err = allocationTree.Insert([]byte{1 << 2}, []byte{1}, nil, big.NewInt(0)) // active + require.NoError(t, err) + joinFrameBytes := make([]byte, 8) + binary.BigEndian.PutUint64(joinFrameBytes, 0) + err = allocationTree.Insert([]byte{4 << 2}, joinFrameBytes, nil, big.NewInt(0)) + require.NoError(t, err) + allocationTypeBI, _ := poseidon.HashBytes( + slices.Concat(bytes.Repeat([]byte{0xff}, 32), []byte("allocation:ProverAllocation")), + ) + allocationTree.Insert(bytes.Repeat([]byte{0xff}, 32), allocationTypeBI.FillBytes(make([]byte, 32)), nil, big.NewInt(32)) + + // Add the prover to the hypergraph + inclusionProver := bls48581.NewKZGInclusionProver(zap.L()) + commitment := tree.Commit(inclusionProver, false) + if len(commitment) != 74 && len(commitment) != 64 { + t.Fatalf("Invalid commitment length: %d", len(commitment)) + } + allocCommitment := allocationTree.Commit(inclusionProver, false) + if len(allocCommitment) != 74 && len(allocCommitment) != 64 { + t.Fatalf("Invalid commitment length: %d", len(allocCommitment)) + } + + // Add vertex to hypergraph + txn, _ := hg.NewTransaction(false) + err = hg.AddVertex(txn, hgcrdt.NewVertex([32]byte(fullAddress[:32]), [32]byte(fullAddress[32:]), commitment, big.NewInt(0))) + if err != nil { + t.Fatalf("Failed to add prover vertex to hypergraph: %v", err) + } + err = hg.AddVertex(txn, hgcrdt.NewVertex([32]byte(fullAddress[:32]), [32]byte(allocationAddress[:]), allocCommitment, big.NewInt(0))) + if err != nil { + t.Fatalf("Failed to add prover vertex to hypergraph: %v", err) + } + + hg.SetVertexData(txn, fullAddress, tree) + hg.SetVertexData(txn, [64]byte(slices.Concat(fullAddress[:32], allocationAddress)), allocationTree) + txn.Commit() + + // Commit the hypergraph + hg.Commit() + + t.Logf(" Registered prover with address: %x, filter: %x (public key length: %d)", address, filter, len(publicKey)) +} diff --git a/node/consensus/global/message_processors.go b/node/consensus/global/message_processors.go index 8343c826..d45c6492 100644 --- a/node/consensus/global/message_processors.go +++ b/node/consensus/global/message_processors.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/binary" "encoding/hex" + "fmt" "math/bits" "slices" @@ -14,6 +15,7 @@ import ( "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb" "source.quilibrium.com/quilibrium/monorepo/protobufs" "source.quilibrium.com/quilibrium/monorepo/types/crypto" + "source.quilibrium.com/quilibrium/monorepo/types/tries" ) func (e *GlobalConsensusEngine) processGlobalConsensusMessageQueue() { @@ -37,6 +39,21 @@ func (e *GlobalConsensusEngine) processGlobalConsensusMessageQueue() { } } +func (e *GlobalConsensusEngine) processShardConsensusMessageQueue() { + defer e.wg.Done() + + for { + select { + case <-e.haltCtx.Done(): + return + case <-e.ctx.Done(): + return + case message := <-e.shardConsensusMessageQueue: + e.handleShardConsensusMessage(message) + } + } +} + func (e *GlobalConsensusEngine) processProverMessageQueue() { defer e.wg.Done() @@ -138,6 +155,36 @@ func (e *GlobalConsensusEngine) handleGlobalConsensusMessage( } } +func (e *GlobalConsensusEngine) handleShardConsensusMessage( + message *pb.Message, +) { + defer func() { + if r := recover(); r != nil { + e.logger.Error( + "panic recovered from message", + zap.Any("panic", r), + zap.Stack("stacktrace"), + ) + } + }() + + typePrefix := e.peekMessageType(message) + + switch typePrefix { + case protobufs.GlobalFrameType: + e.handleShardProposal(message) + + case protobufs.ProverLivenessCheckType: + e.handleShardLivenessCheck(message) + + case protobufs.FrameVoteType: + e.handleShardVote(message) + + case protobufs.FrameConfirmationType: + e.handleShardConfirmation(message) + } +} + func (e *GlobalConsensusEngine) handleProverMessage(message *pb.Message) { defer func() { if r := recover(); r != nil { @@ -252,11 +299,12 @@ func (e *GlobalConsensusEngine) handleAppFrameMessage(message *pb.Message) { e.frameStoreMu.Lock() defer e.frameStoreMu.Unlock() if old, ok := e.appFrameStore[string(frame.Header.Address)]; ok { - if old.Header.FrameNumber > frame.Header.FrameNumber || (old.Header.FrameNumber == frame.Header.FrameNumber && - compareBits( - old.Header.PublicKeySignatureBls48581.Bitmask, - frame.Header.PublicKeySignatureBls48581.Bitmask, - ) >= 0) { + if old.Header.FrameNumber > frame.Header.FrameNumber || + (old.Header.FrameNumber == frame.Header.FrameNumber && + compareBits( + old.Header.PublicKeySignatureBls48581.Bitmask, + frame.Header.PublicKeySignatureBls48581.Bitmask, + ) >= 0) { return } } @@ -340,13 +388,13 @@ func (e *GlobalConsensusEngine) handleAlertMessage(message *pb.Message) { } func (e *GlobalConsensusEngine) handleProposal(message *pb.Message) { - timer := prometheus.NewTimer(frameProcessingDuration) + timer := prometheus.NewTimer(proposalProcessingDuration) defer timer.ObserveDuration() frame := &protobufs.GlobalFrame{} if err := frame.FromCanonicalBytes(message.Data); err != nil { e.logger.Debug("failed to unmarshal frame", zap.Error(err)) - framesProcessedTotal.WithLabelValues("error").Inc() + proposalProcessedTotal.WithLabelValues("error").Inc() return } @@ -370,29 +418,37 @@ func (e *GlobalConsensusEngine) handleProposal(message *pb.Message) { &clonedFrame, ); err != nil { e.logger.Error("could not receive proposal", zap.Error(err)) + proposalProcessedTotal.WithLabelValues("error").Inc() + return } } // Success metric recorded at the end of processing - framesProcessedTotal.WithLabelValues("success").Inc() + proposalProcessedTotal.WithLabelValues("success").Inc() } func (e *GlobalConsensusEngine) handleLivenessCheck(message *pb.Message) { + timer := prometheus.NewTimer(livenessCheckProcessingDuration) + defer timer.ObserveDuration() + livenessCheck := &protobufs.ProverLivenessCheck{} if err := livenessCheck.FromCanonicalBytes(message.Data); err != nil { e.logger.Debug("failed to unmarshal liveness check", zap.Error(err)) + livenessCheckProcessedTotal.WithLabelValues("error").Inc() return } // Validate the liveness check structure if err := livenessCheck.Validate(); err != nil { e.logger.Debug("invalid liveness check", zap.Error(err)) + livenessCheckProcessedTotal.WithLabelValues("error").Inc() return } proverSet, err := e.proverRegistry.GetActiveProvers(nil) if err != nil { e.logger.Error("could not receive liveness check", zap.Error(err)) + livenessCheckProcessedTotal.WithLabelValues("error").Inc() return } @@ -402,7 +458,30 @@ func (e *GlobalConsensusEngine) handleLivenessCheck(message *pb.Message) { prover.Address, livenessCheck.PublicKeySignatureBls48581.Address, ) { + lcBytes, err := livenessCheck.ConstructSignaturePayload() + if err != nil { + e.logger.Error( + "could not construct signature message for liveness check", + zap.Error(err), + ) + break + } + valid, err := e.keyManager.ValidateSignature( + crypto.KeyTypeBLS48581G1, + prover.PublicKey, + lcBytes, + livenessCheck.PublicKeySignatureBls48581.Signature, + livenessCheck.GetSignatureDomain(), + ) + if err != nil || !valid { + e.logger.Error( + "could not validate signature for liveness check", + zap.Error(err), + ) + break + } found = prover.PublicKey + break } } @@ -417,26 +496,28 @@ func (e *GlobalConsensusEngine) handleLivenessCheck(message *pb.Message) { ), ), ) + livenessCheckProcessedTotal.WithLabelValues("error").Inc() return } - signatureData := slices.Concat( - make([]byte, 32), - binary.BigEndian.AppendUint64(nil, livenessCheck.FrameNumber), - livenessCheck.CommitmentHash, - binary.BigEndian.AppendUint64(nil, uint64(livenessCheck.Timestamp)), - ) + signatureData, err := livenessCheck.ConstructSignaturePayload() + if err != nil { + e.logger.Error("invalid signature payload", zap.Error(err)) + livenessCheckProcessedTotal.WithLabelValues("error").Inc() + return + } valid, err := e.keyManager.ValidateSignature( crypto.KeyTypeBLS48581G1, found, signatureData, livenessCheck.PublicKeySignatureBls48581.Signature, - []byte("liveness"), + livenessCheck.GetSignatureDomain(), ) if err != nil || !valid { e.logger.Error("invalid liveness check signature", zap.Error(err)) + livenessCheckProcessedTotal.WithLabelValues("error").Inc() return } @@ -450,114 +531,135 @@ func (e *GlobalConsensusEngine) handleLivenessCheck(message *pb.Message) { commitment, ); err != nil { e.logger.Error("could not receive liveness check", zap.Error(err)) + livenessCheckProcessedTotal.WithLabelValues("error").Inc() + return } + + livenessCheckProcessedTotal.WithLabelValues("success").Inc() } func (e *GlobalConsensusEngine) handleVote(message *pb.Message) { + timer := prometheus.NewTimer(voteProcessingDuration) + defer timer.ObserveDuration() + vote := &protobufs.FrameVote{} if err := vote.FromCanonicalBytes(message.Data); err != nil { e.logger.Debug("failed to unmarshal vote", zap.Error(err)) + voteProcessedTotal.WithLabelValues("error").Inc() return } // Validate the vote structure if err := vote.Validate(); err != nil { e.logger.Debug("invalid vote", zap.Error(err)) + voteProcessedTotal.WithLabelValues("error").Inc() return } - if vote.PublicKeySignatureBls48581 != nil { - // Validate the voter's signature - proverSet, err := e.proverRegistry.GetActiveProvers(nil) - if err != nil { - e.logger.Error("could not get active provers", zap.Error(err)) - return - } + if vote.PublicKeySignatureBls48581 == nil { + e.logger.Error("vote had no signature") + voteProcessedTotal.WithLabelValues("error").Inc() + } - // Find the voter's public key - var voterPublicKey []byte = nil - for _, prover := range proverSet { - if bytes.Equal( - prover.Address, - vote.PublicKeySignatureBls48581.Address, - ) { - voterPublicKey = prover.PublicKey - break - } - } + // Validate the voter's signature + proverSet, err := e.proverRegistry.GetActiveProvers(nil) + if err != nil { + e.logger.Error("could not get active provers", zap.Error(err)) + voteProcessedTotal.WithLabelValues("error").Inc() + return + } - if voterPublicKey == nil { - e.logger.Warn( - "invalid vote - voter not found", - zap.String( - "voter", - hex.EncodeToString( - vote.PublicKeySignatureBls48581.Address, - ), - ), - ) - return + // Find the voter's public key + var voterPublicKey []byte = nil + for _, prover := range proverSet { + if bytes.Equal( + prover.Address, + vote.PublicKeySignatureBls48581.Address, + ) { + voterPublicKey = prover.PublicKey + break } + } - // Find the proposal frame for this vote - e.frameStoreMu.RLock() - var proposalFrame *protobufs.GlobalFrame = nil - for _, frame := range e.frameStore { - if frame.Header != nil && - frame.Header.FrameNumber == vote.FrameNumber && - bytes.Equal( - e.getAddressFromPublicKey( - frame.Header.PublicKeySignatureBls48581.PublicKey.KeyValue, - ), - vote.Proposer, - ) { - proposalFrame = frame - break - } - } - e.frameStoreMu.RUnlock() + if voterPublicKey == nil { + e.logger.Warn( + "invalid vote - voter not found", + zap.String( + "voter", + hex.EncodeToString( + vote.PublicKeySignatureBls48581.Address, + ), + ), + ) + voteProcessedTotal.WithLabelValues("error").Inc() + return + } - if proposalFrame == nil { - e.logger.Warn( - "vote for unknown proposal", - zap.Uint64("frame_number", vote.FrameNumber), - zap.String("proposer", hex.EncodeToString(vote.Proposer)), - ) - return + // Find the proposal frame for this vote + e.frameStoreMu.RLock() + var proposalFrame *protobufs.GlobalFrame = nil + for _, frame := range e.frameStore { + if frame.Header != nil && + frame.Header.FrameNumber == vote.FrameNumber && + bytes.Equal( + e.getAddressFromPublicKey( + frame.Header.PublicKeySignatureBls48581.PublicKey.KeyValue, + ), + vote.Proposer, + ) { + proposalFrame = frame + break } + } + e.frameStoreMu.RUnlock() - // Get the signature payload for the proposal - signatureData, err := e.frameProver.GetGlobalFrameSignaturePayload( - proposalFrame.Header, + if proposalFrame == nil { + e.logger.Warn( + "vote for unknown proposal", + zap.Uint64("frame_number", vote.FrameNumber), + zap.String("proposer", hex.EncodeToString(vote.Proposer)), ) - if err != nil { - e.logger.Error("could not get signature payload", zap.Error(err)) - return - } + voteProcessedTotal.WithLabelValues("error").Inc() + return + } - // Validate the vote signature - valid, err := e.keyManager.ValidateSignature( - crypto.KeyTypeBLS48581G1, - voterPublicKey, - signatureData, - vote.PublicKeySignatureBls48581.Signature, - []byte("global"), - ) + // Get the signature payload for the proposal + signatureData, err := e.frameProver.GetGlobalFrameSignaturePayload( + proposalFrame.Header, + ) + if err != nil { + e.logger.Error("could not get signature payload", zap.Error(err)) + voteProcessedTotal.WithLabelValues("error").Inc() + return + } - if err != nil || !valid { - e.logger.Error("invalid vote signature", zap.Error(err)) - return - } + // Validate the vote signature + valid, err := e.keyManager.ValidateSignature( + crypto.KeyTypeBLS48581G1, + voterPublicKey, + signatureData, + vote.PublicKeySignatureBls48581.Signature, + []byte("global"), + ) - // Signature is valid, process the vote - if err := e.stateMachine.ReceiveVote( - GlobalPeerID{ID: vote.Proposer}, - GlobalPeerID{ID: vote.PublicKeySignatureBls48581.Address}, - &vote, - ); err != nil { - e.logger.Error("could not receive vote", zap.Error(err)) - } + if err != nil || !valid { + e.logger.Error("invalid vote signature", zap.Error(err)) + voteProcessedTotal.WithLabelValues("error").Inc() + return + } + + // Signature is valid, process the vote + if err := e.stateMachine.ReceiveVote( + GlobalPeerID{ID: vote.Proposer}, + GlobalPeerID{ID: vote.PublicKeySignatureBls48581.Address}, + &vote, + ); err != nil { + e.logger.Error("could not receive vote", zap.Error(err)) + voteProcessedTotal.WithLabelValues("error").Inc() + return } + + voteProcessedTotal.WithLabelValues("success").Inc() } func (e *GlobalConsensusEngine) handleMessageBundle(message *pb.Message) { @@ -571,15 +673,20 @@ func (e *GlobalConsensusEngine) handleMessageBundle(message *pb.Message) { } func (e *GlobalConsensusEngine) handleConfirmation(message *pb.Message) { + timer := prometheus.NewTimer(confirmationProcessingDuration) + defer timer.ObserveDuration() + confirmation := &protobufs.FrameConfirmation{} if err := confirmation.FromCanonicalBytes(message.Data); err != nil { e.logger.Debug("failed to unmarshal confirmation", zap.Error(err)) + confirmationProcessedTotal.WithLabelValues("error").Inc() return } // Validate the confirmation structure if err := confirmation.Validate(); err != nil { e.logger.Debug("invalid confirmation", zap.Error(err)) + confirmationProcessedTotal.WithLabelValues("error").Inc() return } @@ -608,6 +715,7 @@ func (e *GlobalConsensusEngine) handleConfirmation(message *pb.Message) { valid, err := e.frameValidator.Validate(matchingFrame) if !valid || err != nil { e.logger.Error("received invalid confirmation", zap.Error(err)) + confirmationProcessedTotal.WithLabelValues("error").Inc() return } @@ -671,6 +779,8 @@ func (e *GlobalConsensusEngine) handleConfirmation(message *pb.Message) { &matchingFrame, ); err != nil { e.logger.Error("could not receive confirmation", zap.Error(err)) + confirmationProcessedTotal.WithLabelValues("error").Inc() + return } } err = e.globalTimeReel.Insert(e.ctx, matchingFrame) @@ -679,7 +789,370 @@ func (e *GlobalConsensusEngine) handleConfirmation(message *pb.Message) { "could not insert into time reel", zap.Error(err), ) + confirmationProcessedTotal.WithLabelValues("error").Inc() + return + } + + confirmationProcessedTotal.WithLabelValues("success").Inc() +} + +func (e *GlobalConsensusEngine) handleShardProposal(message *pb.Message) { + timer := prometheus.NewTimer(shardProposalProcessingDuration) + defer timer.ObserveDuration() + + frame := &protobufs.AppShardFrame{} + if err := frame.FromCanonicalBytes(message.Data); err != nil { + e.logger.Debug("failed to unmarshal frame", zap.Error(err)) + shardProposalProcessedTotal.WithLabelValues("error").Inc() + return + } + + if valid, err := e.appFrameValidator.Validate(frame); err != nil || !valid { + e.logger.Debug("invalid frame", zap.Error(err)) + shardProposalProcessedTotal.WithLabelValues("error").Inc() + return + } + + clonedFrame := frame.Clone().(*protobufs.AppShardFrame) + + e.appFrameStoreMu.Lock() + frameID := fmt.Sprintf("%x%d", frame.Header.Prover, frame.Header.FrameNumber) + selectorBI, err := poseidon.HashBytes(frame.Header.Output) + if err != nil { + e.logger.Debug("invalid selector", zap.Error(err)) + shardProposalProcessedTotal.WithLabelValues("error").Inc() + e.appFrameStoreMu.Unlock() + return + } + e.appFrameStore[frameID] = clonedFrame + e.appFrameStore[string(selectorBI.FillBytes(make([]byte, 32)))] = clonedFrame + e.appFrameStoreMu.Unlock() + + e.txLockMu.Lock() + if _, ok := e.txLockMap[frame.Header.FrameNumber]; !ok { + e.txLockMap[frame.Header.FrameNumber] = make( + map[string]map[string]*LockedTransaction, + ) + } + _, ok := e.txLockMap[frame.Header.FrameNumber][string(frame.Header.Address)] + if !ok { + e.txLockMap[frame.Header.FrameNumber][string(frame.Header.Address)] = + make(map[string]*LockedTransaction) + } + set := e.txLockMap[frame.Header.FrameNumber][string(frame.Header.Address)] + for _, l := range set { + for _, p := range slices.Collect(slices.Chunk(l.Prover, 32)) { + if bytes.Equal(p, frame.Header.Prover) { + l.Committed = true + } + } + } + e.txLockMu.Unlock() + + // Success metric recorded at the end of processing + shardProposalProcessedTotal.WithLabelValues("success").Inc() +} + +func (e *GlobalConsensusEngine) handleShardLivenessCheck(message *pb.Message) { + timer := prometheus.NewTimer(shardLivenessCheckProcessingDuration) + defer timer.ObserveDuration() + + livenessCheck := &protobufs.ProverLivenessCheck{} + if err := livenessCheck.FromCanonicalBytes(message.Data); err != nil { + e.logger.Debug("failed to unmarshal liveness check", zap.Error(err)) + shardLivenessCheckProcessedTotal.WithLabelValues("error").Inc() + return + } + + // Validate the liveness check structure + if err := livenessCheck.Validate(); err != nil { + e.logger.Debug("invalid liveness check", zap.Error(err)) + shardLivenessCheckProcessedTotal.WithLabelValues("error").Inc() + return + } + + proverSet, err := e.proverRegistry.GetActiveProvers(livenessCheck.Filter) + if err != nil { + e.logger.Error("could not receive liveness check", zap.Error(err)) + shardLivenessCheckProcessedTotal.WithLabelValues("error").Inc() + return + } + + var found []byte = nil + for _, prover := range proverSet { + if bytes.Equal( + prover.Address, + livenessCheck.PublicKeySignatureBls48581.Address, + ) { + lcBytes, err := livenessCheck.ConstructSignaturePayload() + if err != nil { + e.logger.Error( + "could not construct signature message for liveness check", + zap.Error(err), + ) + shardLivenessCheckProcessedTotal.WithLabelValues("error").Inc() + break + } + valid, err := e.keyManager.ValidateSignature( + crypto.KeyTypeBLS48581G1, + prover.PublicKey, + lcBytes, + livenessCheck.PublicKeySignatureBls48581.Signature, + livenessCheck.GetSignatureDomain(), + ) + if err != nil || !valid { + e.logger.Error( + "could not validate signature for liveness check", + zap.Error(err), + ) + shardLivenessCheckProcessedTotal.WithLabelValues("error").Inc() + break + } + found = prover.PublicKey + + break + } + } + + if found == nil { + e.logger.Warn( + "invalid liveness check", + zap.String( + "prover", + hex.EncodeToString( + livenessCheck.PublicKeySignatureBls48581.Address, + ), + ), + ) + shardLivenessCheckProcessedTotal.WithLabelValues("error").Inc() + return + } + + if len(livenessCheck.CommitmentHash) > 32 { + e.txLockMu.Lock() + if _, ok := e.txLockMap[livenessCheck.FrameNumber]; !ok { + e.txLockMap[livenessCheck.FrameNumber] = make( + map[string]map[string]*LockedTransaction, + ) + } + _, ok := e.txLockMap[livenessCheck.FrameNumber][string(livenessCheck.Filter)] + if !ok { + e.txLockMap[livenessCheck.FrameNumber][string(livenessCheck.Filter)] = + make(map[string]*LockedTransaction) + } + + filter := string(livenessCheck.Filter) + + commits, err := tries.DeserializeNonLazyTree( + livenessCheck.CommitmentHash[32:], + ) + if err != nil { + e.txLockMu.Unlock() + e.logger.Error("could not deserialize commitment trie", zap.Error(err)) + shardLivenessCheckProcessedTotal.WithLabelValues("error").Inc() + return + } + + leaves := tries.GetAllPreloadedLeaves(commits.Root) + for _, leaf := range leaves { + existing, ok := e.txLockMap[livenessCheck.FrameNumber][filter][string(leaf.Key)] + prover := []byte{} + if ok { + prover = existing.Prover + } + + prover = append( + prover, + livenessCheck.PublicKeySignatureBls48581.Address..., + ) + + e.txLockMap[livenessCheck.FrameNumber][filter][string(leaf.Key)] = + &LockedTransaction{ + TransactionHash: leaf.Key, + ShardAddresses: slices.Collect(slices.Chunk(leaf.Value, 64)), + Prover: prover, + Committed: false, + Filled: false, + } + } + e.txLockMu.Unlock() + } + + shardLivenessCheckProcessedTotal.WithLabelValues("success").Inc() +} + +func (e *GlobalConsensusEngine) handleShardVote(message *pb.Message) { + timer := prometheus.NewTimer(shardVoteProcessingDuration) + defer timer.ObserveDuration() + + vote := &protobufs.FrameVote{} + if err := vote.FromCanonicalBytes(message.Data); err != nil { + e.logger.Debug("failed to unmarshal vote", zap.Error(err)) + shardVoteProcessedTotal.WithLabelValues("error").Inc() + return + } + + // Validate the vote structure + if err := vote.Validate(); err != nil { + e.logger.Debug("invalid vote", zap.Error(err)) + shardVoteProcessedTotal.WithLabelValues("error").Inc() + return + } + + if vote.PublicKeySignatureBls48581 == nil { + e.logger.Error("vote without signature") + shardVoteProcessedTotal.WithLabelValues("error").Inc() + return + } + + // Validate the voter's signature + proverSet, err := e.proverRegistry.GetActiveProvers(vote.Filter) + if err != nil { + e.logger.Error("could not get active provers", zap.Error(err)) + shardVoteProcessedTotal.WithLabelValues("error").Inc() + return + } + + // Find the voter's public key + var voterPublicKey []byte = nil + for _, prover := range proverSet { + if bytes.Equal( + prover.Address, + vote.PublicKeySignatureBls48581.Address, + ) { + voterPublicKey = prover.PublicKey + break + } + } + + if voterPublicKey == nil { + e.logger.Warn( + "invalid vote - voter not found", + zap.String( + "voter", + hex.EncodeToString( + vote.PublicKeySignatureBls48581.Address, + ), + ), + ) + shardVoteProcessedTotal.WithLabelValues("error").Inc() + return + } + + e.appFrameStoreMu.Lock() + frameID := fmt.Sprintf("%x%d", vote.Proposer, vote.FrameNumber) + proposalFrame := e.appFrameStore[frameID] + e.appFrameStoreMu.Unlock() + + if proposalFrame == nil { + e.logger.Error("could not find proposed frame") + shardVoteProcessedTotal.WithLabelValues("error").Inc() + return + } + + // Get the signature payload for the proposal + signatureData, err := e.frameProver.GetFrameSignaturePayload( + proposalFrame.Header, + ) + if err != nil { + e.logger.Error("could not get signature payload", zap.Error(err)) + shardVoteProcessedTotal.WithLabelValues("error").Inc() + return + } + + // Validate the vote signature + valid, err := e.keyManager.ValidateSignature( + crypto.KeyTypeBLS48581G1, + voterPublicKey, + signatureData, + vote.PublicKeySignatureBls48581.Signature, + []byte("global"), + ) + + if err != nil || !valid { + e.logger.Error("invalid vote signature", zap.Error(err)) + shardVoteProcessedTotal.WithLabelValues("error").Inc() + return + } + + shardVoteProcessedTotal.WithLabelValues("success").Inc() +} + +func (e *GlobalConsensusEngine) handleShardConfirmation(message *pb.Message) { + timer := prometheus.NewTimer(shardConfirmationProcessingDuration) + defer timer.ObserveDuration() + + confirmation := &protobufs.FrameConfirmation{} + if err := confirmation.FromCanonicalBytes(message.Data); err != nil { + e.logger.Debug("failed to unmarshal confirmation", zap.Error(err)) + shardConfirmationProcessedTotal.WithLabelValues("error").Inc() + return + } + + // Validate the confirmation structure + if err := confirmation.Validate(); err != nil { + e.logger.Debug("invalid confirmation", zap.Error(err)) + shardConfirmationProcessedTotal.WithLabelValues("error").Inc() + return + } + + e.appFrameStoreMu.Lock() + matchingFrame := e.appFrameStore[string(confirmation.Selector)] + e.appFrameStoreMu.Unlock() + + if matchingFrame == nil { + e.logger.Error("could not find matching frame") + shardConfirmationProcessedTotal.WithLabelValues("error").Inc() + return + } + + matchingFrame.Header.PublicKeySignatureBls48581 = + confirmation.AggregateSignature + valid, err := e.appFrameValidator.Validate(matchingFrame) + if !valid || err != nil { + e.logger.Error("received invalid confirmation", zap.Error(err)) + shardConfirmationProcessedTotal.WithLabelValues("error").Inc() + return + } + + // Check if we already have a confirmation stowed + exceeds := false + set := 0 + for _, b := range matchingFrame.Header.PublicKeySignatureBls48581.Bitmask { + set += bits.OnesCount8(b) + if set > 1 { + exceeds = true + break + } + } + if exceeds { + // Skip the remaining operations + return + } + + e.txLockMu.Lock() + if _, ok := e.txLockMap[confirmation.FrameNumber]; !ok { + e.txLockMap[confirmation.FrameNumber] = make( + map[string]map[string]*LockedTransaction, + ) } + _, ok := e.txLockMap[confirmation.FrameNumber][string(confirmation.Filter)] + if !ok { + e.txLockMap[confirmation.FrameNumber][string(confirmation.Filter)] = + make(map[string]*LockedTransaction) + } + txSet := e.txLockMap[confirmation.FrameNumber][string(confirmation.Filter)] + for _, l := range txSet { + for _, p := range slices.Collect(slices.Chunk(l.Prover, 32)) { + if bytes.Equal(p, matchingFrame.Header.Prover) { + l.Committed = true + l.Filled = true + } + } + } + e.txLockMu.Unlock() + + shardConfirmationProcessedTotal.WithLabelValues("success").Inc() } func (e *GlobalConsensusEngine) peekMessageType(message *pb.Message) uint32 { diff --git a/node/consensus/global/message_subscription.go b/node/consensus/global/message_subscription.go index 40cba5a8..bd370f35 100644 --- a/node/consensus/global/message_subscription.go +++ b/node/consensus/global/message_subscription.go @@ -1,6 +1,7 @@ package global import ( + "bytes" "slices" "github.com/libp2p/go-libp2p/core/peer" @@ -49,71 +50,82 @@ func (e *GlobalConsensusEngine) subscribeToGlobalConsensus() error { return errors.Wrap(err, "subscribe to global consensus") } - GenerateThreeBitSlices(func(bitmask []byte) bool { - b := slices.Clone(bitmask) - if err := e.pubsub.Subscribe( - b, - func(message *pb.Message) error { - select { - case <-e.haltCtx.Done(): - return nil - case e.appFramesMessageQueue <- message: - return nil - case <-e.ctx.Done(): - return errors.New("context cancelled") - default: - e.logger.Warn("app frames message queue full, dropping message") - return nil - } - }, - ); err != nil { - e.logger.Error( - "error while subscribing to app shard consensus channels", - zap.Error(err), - ) - return false - } - - // Register frame validator - if err := e.pubsub.RegisterValidator( - b, - func(peerID peer.ID, message *pb.Message) tp2p.ValidationResult { - return e.validateAppFrameMessage(peerID, message) - }, - true, - ); err != nil { - return false - } - - return true - }) + // Initiate a bulk subscribe to entire bitmask + if err := e.pubsub.Subscribe( + bytes.Repeat([]byte{0xff}, 32), + func(message *pb.Message) error { + select { + case <-e.haltCtx.Done(): + return nil + case e.appFramesMessageQueue <- message: + return nil + case <-e.ctx.Done(): + return errors.New("context cancelled") + default: + e.logger.Warn("app frames message queue full, dropping message") + return nil + } + }, + ); err != nil { + e.logger.Error( + "error while subscribing to app shard consensus channels", + zap.Error(err), + ) + return nil + } + + // Register frame validator + if err := e.pubsub.RegisterValidator( + bytes.Repeat([]byte{0xff}, 32), + func(peerID peer.ID, message *pb.Message) tp2p.ValidationResult { + return e.validateAppFrameMessage(peerID, message) + }, + true, + ); err != nil { + return nil + } return nil } -func GenerateThreeBitSlices(emit func(b []byte) bool) { - var buf [32]byte - - set := func(pos int) { buf[pos>>3] |= 1 << uint(pos&7) } - zero := func() { - for i := range buf { - buf[i] = 0 - } +func (e *GlobalConsensusEngine) subscribeToShardConsensusMessages() error { + if err := e.pubsub.Subscribe( + slices.Concat( + []byte{0}, + bytes.Repeat([]byte{0xff}, 32), + ), + func(message *pb.Message) error { + select { + case <-e.haltCtx.Done(): + return nil + case e.shardConsensusMessageQueue <- message: + return nil + case <-e.ctx.Done(): + return errors.New("context cancelled") + default: + e.logger.Warn("shard consensus queue full, dropping message") + return nil + } + }, + ); err != nil { + return errors.Wrap(err, "subscribe to shard consensus messages") } - for i := 0; i < 256; i++ { - for j := i + 1; j < 256; j++ { - for k := j + 1; k < 256; k++ { - zero() - set(i) - set(j) - set(k) - if !emit(buf[:]) { - return - } - } - } + // Register frame validator + if err := e.pubsub.RegisterValidator( + slices.Concat( + []byte{0}, + bytes.Repeat([]byte{0xff}, 32), + ), + func(peerID peer.ID, message *pb.Message) tp2p.ValidationResult { + return e.validateShardConsensusMessage(peerID, message) + }, + true, + ); err != nil { + return errors.Wrap(err, "subscribe to shard consensus messages") } + + return nil } func (e *GlobalConsensusEngine) subscribeToFrameMessages() error { @@ -155,6 +167,7 @@ func (e *GlobalConsensusEngine) subscribeToProverMessages() error { GLOBAL_PROVER_BITMASK, func(message *pb.Message) error { if e.config.P2P.Network != 99 && !e.config.Engine.ArchiveMode { + e.logger.Debug("dropping prover message, not in archive mode") return nil } @@ -162,6 +175,7 @@ func (e *GlobalConsensusEngine) subscribeToProverMessages() error { case <-e.haltCtx.Done(): return nil case e.globalProverMessageQueue <- message: + e.logger.Debug("received prover message") return nil case <-e.ctx.Done(): return errors.New("context cancelled") diff --git a/node/consensus/global/message_validation.go b/node/consensus/global/message_validation.go index de373cbf..4e84d2d6 100644 --- a/node/consensus/global/message_validation.go +++ b/node/consensus/global/message_validation.go @@ -33,84 +33,280 @@ func (e *GlobalConsensusEngine) validateGlobalConsensusMessage( case protobufs.GlobalFrameType: start := time.Now() defer func() { - frameValidationDuration.Observe(time.Since(start).Seconds()) + proposalValidationDuration.Observe(time.Since(start).Seconds()) }() frame := &protobufs.GlobalFrame{} if err := frame.FromCanonicalBytes(message.Data); err != nil { e.logger.Debug("failed to unmarshal frame", zap.Error(err)) - frameValidationTotal.WithLabelValues("reject").Inc() + proposalValidationTotal.WithLabelValues("reject").Inc() return tp2p.ValidationResultReject } + if frametime.GlobalFrameSince(frame) > 20*time.Second { + proposalValidationTotal.WithLabelValues("reject").Inc() + return tp2p.ValidationResultIgnore + } + if frame.Header.PublicKeySignatureBls48581 == nil || frame.Header.PublicKeySignatureBls48581.PublicKey == nil || frame.Header.PublicKeySignatureBls48581.PublicKey.KeyValue == nil { e.logger.Debug("global frame validation missing signature") - frameValidationTotal.WithLabelValues("reject").Inc() + proposalValidationTotal.WithLabelValues("reject").Inc() return tp2p.ValidationResultReject } valid, err := e.frameValidator.Validate(frame) if err != nil { e.logger.Debug("global frame validation error", zap.Error(err)) - frameValidationTotal.WithLabelValues("reject").Inc() + proposalValidationTotal.WithLabelValues("reject").Inc() return tp2p.ValidationResultReject } if !valid { - frameValidationTotal.WithLabelValues("reject").Inc() e.logger.Debug("invalid global frame") + proposalValidationTotal.WithLabelValues("reject").Inc() return tp2p.ValidationResultReject } - frameValidationTotal.WithLabelValues("accept").Inc() + proposalValidationTotal.WithLabelValues("accept").Inc() case protobufs.ProverLivenessCheckType: + start := time.Now() + defer func() { + livenessCheckValidationDuration.Observe(time.Since(start).Seconds()) + }() + livenessCheck := &protobufs.ProverLivenessCheck{} if err := livenessCheck.FromCanonicalBytes(message.Data); err != nil { e.logger.Debug("failed to unmarshal liveness check", zap.Error(err)) + livenessCheckValidationTotal.WithLabelValues("reject").Inc() return tp2p.ValidationResultReject } + now := time.Now().UnixMilli() + if livenessCheck.Timestamp > now+5000 || + livenessCheck.Timestamp < now-5000 { + return tp2p.ValidationResultIgnore + } + // Validate the liveness check if err := livenessCheck.Validate(); err != nil { e.logger.Debug("invalid liveness check", zap.Error(err)) + livenessCheckValidationTotal.WithLabelValues("reject").Inc() return tp2p.ValidationResultReject } + livenessCheckValidationTotal.WithLabelValues("accept").Inc() + case protobufs.FrameVoteType: + start := time.Now() + defer func() { + voteValidationDuration.Observe(time.Since(start).Seconds()) + }() + vote := &protobufs.FrameVote{} if err := vote.FromCanonicalBytes(message.Data); err != nil { e.logger.Debug("failed to unmarshal vote", zap.Error(err)) + voteValidationTotal.WithLabelValues("reject").Inc() return tp2p.ValidationResultReject } + now := time.Now().UnixMilli() + if vote.Timestamp > now+5000 || vote.Timestamp < now-5000 { + return tp2p.ValidationResultIgnore + } + // Validate the vote if err := vote.Validate(); err != nil { e.logger.Debug("invalid vote", zap.Error(err)) + voteValidationTotal.WithLabelValues("reject").Inc() return tp2p.ValidationResultReject } + voteValidationTotal.WithLabelValues("accept").Inc() + case protobufs.FrameConfirmationType: + start := time.Now() + defer func() { + confirmationValidationDuration.Observe(time.Since(start).Seconds()) + }() + confirmation := &protobufs.FrameConfirmation{} if err := confirmation.FromCanonicalBytes(message.Data); err != nil { e.logger.Debug("failed to unmarshal confirmation", zap.Error(err)) + confirmationValidationTotal.WithLabelValues("reject").Inc() return tp2p.ValidationResultReject } + now := time.Now().UnixMilli() + if confirmation.Timestamp > now+5000 || + confirmation.Timestamp < now-5000 { + return tp2p.ValidationResultIgnore + } + // Validate the confirmation if err := confirmation.Validate(); err != nil { e.logger.Debug("invalid confirmation", zap.Error(err)) + confirmationValidationTotal.WithLabelValues("reject").Inc() return tp2p.ValidationResultReject } + confirmationValidationTotal.WithLabelValues("accept").Inc() + default: e.logger.Debug("received unknown type", zap.Uint32("type", typePrefix)) return tp2p.ValidationResultIgnore } - frameValidationTotal.WithLabelValues("accept").Inc() + return tp2p.ValidationResultAccept +} + +func (e *GlobalConsensusEngine) validateShardConsensusMessage( + peerID peer.ID, + message *pb.Message, +) tp2p.ValidationResult { + // Check if data is long enough to contain type prefix + if len(message.Data) < 4 { + e.logger.Debug( + "message too short", + zap.Int("data_length", len(message.Data)), + ) + return tp2p.ValidationResultReject + } + + // Read type prefix from first 4 bytes + typePrefix := binary.BigEndian.Uint32(message.Data[:4]) + + switch typePrefix { + case protobufs.AppShardFrameType: + start := time.Now() + defer func() { + shardProposalValidationDuration.Observe(time.Since(start).Seconds()) + }() + + frame := &protobufs.AppShardFrame{} + if err := frame.FromCanonicalBytes(message.Data); err != nil { + e.logger.Debug("failed to unmarshal frame", zap.Error(err)) + shardProposalValidationTotal.WithLabelValues("reject").Inc() + return tp2p.ValidationResultReject + } + + if frame.Header == nil { + e.logger.Debug("frame has no header") + shardProposalValidationTotal.WithLabelValues("reject").Inc() + return tp2p.ValidationResultReject + } + + if frametime.AppFrameSince(frame) > 20*time.Second { + shardProposalValidationTotal.WithLabelValues("reject").Inc() + return tp2p.ValidationResultIgnore + } + + if frame.Header.PublicKeySignatureBls48581 != nil { + e.logger.Debug("frame validation has signature") + shardProposalValidationTotal.WithLabelValues("reject").Inc() + return tp2p.ValidationResultReject + } + + valid, err := e.appFrameValidator.Validate(frame) + if err != nil { + e.logger.Debug("frame validation error", zap.Error(err)) + shardProposalValidationTotal.WithLabelValues("reject").Inc() + return tp2p.ValidationResultReject + } + + if !valid { + e.logger.Debug("invalid app frame") + shardProposalValidationTotal.WithLabelValues("reject").Inc() + return tp2p.ValidationResultReject + } + + shardProposalValidationTotal.WithLabelValues("accept").Inc() + + case protobufs.ProverLivenessCheckType: + start := time.Now() + defer func() { + shardLivenessCheckValidationDuration.Observe(time.Since(start).Seconds()) + }() + + livenessCheck := &protobufs.ProverLivenessCheck{} + if err := livenessCheck.FromCanonicalBytes(message.Data); err != nil { + e.logger.Debug("failed to unmarshal liveness check", zap.Error(err)) + shardLivenessCheckValidationTotal.WithLabelValues("reject").Inc() + return tp2p.ValidationResultReject + } + + now := time.Now().UnixMilli() + if livenessCheck.Timestamp > now+5000 || + livenessCheck.Timestamp < now-5000 { + return tp2p.ValidationResultIgnore + } + + if err := livenessCheck.Validate(); err != nil { + e.logger.Debug("failed to validate liveness check", zap.Error(err)) + shardLivenessCheckValidationTotal.WithLabelValues("reject").Inc() + return tp2p.ValidationResultReject + } + + shardLivenessCheckValidationTotal.WithLabelValues("accept").Inc() + + case protobufs.FrameVoteType: + start := time.Now() + defer func() { + shardVoteValidationDuration.Observe(time.Since(start).Seconds()) + }() + + vote := &protobufs.FrameVote{} + if err := vote.FromCanonicalBytes(message.Data); err != nil { + e.logger.Debug("failed to unmarshal vote", zap.Error(err)) + shardVoteValidationTotal.WithLabelValues("reject").Inc() + return tp2p.ValidationResultReject + } + + now := time.Now().UnixMilli() + if vote.Timestamp > now+5000 || vote.Timestamp < now-5000 { + return tp2p.ValidationResultIgnore + } + + if err := vote.Validate(); err != nil { + e.logger.Debug("failed to validate vote", zap.Error(err)) + shardVoteValidationTotal.WithLabelValues("reject").Inc() + return tp2p.ValidationResultReject + } + + shardVoteValidationTotal.WithLabelValues("accept").Inc() + + case protobufs.FrameConfirmationType: + start := time.Now() + defer func() { + shardConfirmationValidationDuration.Observe(time.Since(start).Seconds()) + }() + + confirmation := &protobufs.FrameConfirmation{} + if err := confirmation.FromCanonicalBytes(message.Data); err != nil { + e.logger.Debug("failed to unmarshal confirmation", zap.Error(err)) + shardConfirmationValidationTotal.WithLabelValues("reject").Inc() + return tp2p.ValidationResultReject + } + + now := time.Now().UnixMilli() + if confirmation.Timestamp > now+5000 || confirmation.Timestamp < now-5000 { + return tp2p.ValidationResultIgnore + } + + if err := confirmation.Validate(); err != nil { + e.logger.Debug("failed to validate confirmation", zap.Error(err)) + shardConfirmationValidationTotal.WithLabelValues("reject").Inc() + return tp2p.ValidationResultReject + } + + shardConfirmationValidationTotal.WithLabelValues("accept").Inc() + + default: + return tp2p.ValidationResultReject + } + return tp2p.ValidationResultAccept } @@ -118,6 +314,10 @@ func (e *GlobalConsensusEngine) validateProverMessage( peerID peer.ID, message *pb.Message, ) tp2p.ValidationResult { + e.logger.Debug( + "validating prover message from peer", + zap.String("peer_id", peerID.String()), + ) // Check if data is long enough to contain type prefix if len(message.Data) < 4 { e.logger.Error( @@ -133,6 +333,10 @@ func (e *GlobalConsensusEngine) validateProverMessage( switch typePrefix { case protobufs.MessageBundleType: + e.logger.Debug( + "validating message bundle from peer", + zap.String("peer_id", peerID.String()), + ) // Prover messages come wrapped in MessageBundle messageBundle := &protobufs.MessageBundle{} if err := messageBundle.FromCanonicalBytes(message.Data); err != nil { @@ -146,7 +350,9 @@ func (e *GlobalConsensusEngine) validateProverMessage( } now := time.Now().UnixMilli() - if messageBundle.Timestamp > now+5000 || messageBundle.Timestamp < now-5000 { + if messageBundle.Timestamp > now+5000 || + messageBundle.Timestamp < now-5000 { + e.logger.Debug("message too late or too early") return tp2p.ValidationResultIgnore } diff --git a/node/consensus/global/metrics.go b/node/consensus/global/metrics.go index f379948f..b1f0a107 100644 --- a/node/consensus/global/metrics.go +++ b/node/consensus/global/metrics.go @@ -32,6 +32,27 @@ var ( }, ) + // Frame processing metrics + shardFramesProcessedTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_frames_processed_total", + Help: "Total number of shard frames processed by the global consensus engine", + }, + []string{"status"}, // status: "success", "error", "invalid" + ) + + shardFrameProcessingDuration = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_frame_processing_duration_seconds", + Help: "Time taken to process a shard frame", + Buckets: prometheus.DefBuckets, + }, + ) + // Frame validation metrics frameValidationTotal = promauto.NewCounterVec( prometheus.CounterOpts{ @@ -53,6 +74,363 @@ var ( }, ) + // Shard frame validation metrics + shardFrameValidationTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_frame_validation_total", + Help: "Total number of shard frame validations", + }, + []string{"result"}, // result: "accept", "reject", "ignore" + ) + + shardFrameValidationDuration = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_frame_validation_duration_seconds", + Help: "Time taken to validate a shard frame", + Buckets: prometheus.DefBuckets, + }, + ) + + // Global liveness check processing metrics + livenessCheckProcessedTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "liveness_check_processed_total", + Help: "Total number of global liveness checks processed by the global consensus engine", + }, + []string{"status"}, // status: "success", "error", "invalid" + ) + + livenessCheckProcessingDuration = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "liveness_check_processing_duration_seconds", + Help: "Time taken to process a global liveness check", + Buckets: prometheus.DefBuckets, + }, + ) + + // Global liveness check validation metrics + livenessCheckValidationTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "liveness_check_validation_total", + Help: "Total number of global liveness check validations", + }, + []string{"result"}, // result: "accept", "reject", "ignore" + ) + + livenessCheckValidationDuration = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "liveness_check_validation_duration_seconds", + Help: "Time taken to validate a global liveness check", + Buckets: prometheus.DefBuckets, + }, + ) + + // Shard liveness check processing metrics + shardLivenessCheckProcessedTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_liveness_check_processed_total", + Help: "Total number of shard liveness checks processed by the global consensus engine", + }, + []string{"status"}, // status: "success", "error", "invalid" + ) + + shardLivenessCheckProcessingDuration = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_liveness_check_processing_duration_seconds", + Help: "Time taken to process a shard liveness check", + Buckets: prometheus.DefBuckets, + }, + ) + + // Shard liveness check validation metrics + shardLivenessCheckValidationTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_liveness_check_validation_total", + Help: "Total number of shard liveness check validations", + }, + []string{"result"}, // result: "accept", "reject", "ignore" + ) + + shardLivenessCheckValidationDuration = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_liveness_check_validation_duration_seconds", + Help: "Time taken to validate a shard liveness check", + Buckets: prometheus.DefBuckets, + }, + ) + + // Global vote processing metrics + voteProcessedTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "vote_processed_total", + Help: "Total number of global votes processed by the global consensus engine", + }, + []string{"status"}, // status: "success", "error", "invalid" + ) + + voteProcessingDuration = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "vote_processing_duration_seconds", + Help: "Time taken to process a global vote", + Buckets: prometheus.DefBuckets, + }, + ) + + // Global vote validation metrics + voteValidationTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "vote_validation_total", + Help: "Total number of global vote validations", + }, + []string{"result"}, // result: "accept", "reject", "ignore" + ) + + voteValidationDuration = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "vote_validation_duration_seconds", + Help: "Time taken to validate a global vote", + Buckets: prometheus.DefBuckets, + }, + ) + + // Shard vote processing metrics + shardVoteProcessedTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_vote_processed_total", + Help: "Total number of shard votes processed by the global consensus engine", + }, + []string{"status"}, // status: "success", "error", "invalid" + ) + + shardVoteProcessingDuration = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_vote_processing_duration_seconds", + Help: "Time taken to process a shard vote", + Buckets: prometheus.DefBuckets, + }, + ) + + // Shard vote validation metrics + shardVoteValidationTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_vote_validation_total", + Help: "Total number of shard vote validations", + }, + []string{"result"}, // result: "accept", "reject", "ignore" + ) + + shardVoteValidationDuration = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_vote_validation_duration_seconds", + Help: "Time taken to validate a shard vote", + Buckets: prometheus.DefBuckets, + }, + ) + + // Global confirmation processing metrics + confirmationProcessedTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "confirmation_processed_total", + Help: "Total number of global confirmations processed by the global consensus engine", + }, + []string{"status"}, // status: "success", "error", "invalid" + ) + + confirmationProcessingDuration = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "confirmation_processing_duration_seconds", + Help: "Time taken to process a global confirmation", + Buckets: prometheus.DefBuckets, + }, + ) + + // Global confirmation validation metrics + confirmationValidationTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "confirmation_validation_total", + Help: "Total number of global confirmation validations", + }, + []string{"result"}, // result: "accept", "reject", "ignore" + ) + + confirmationValidationDuration = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "confirmation_validation_duration_seconds", + Help: "Time taken to validate a global confirmation", + Buckets: prometheus.DefBuckets, + }, + ) + + // Shard confirmation processing metrics + shardConfirmationProcessedTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_confirmation_processed_total", + Help: "Total number of shard confirmations processed by the global consensus engine", + }, + []string{"status"}, // status: "success", "error", "invalid" + ) + + shardConfirmationProcessingDuration = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_confirmation_processing_duration_seconds", + Help: "Time taken to process a shard confirmation", + Buckets: prometheus.DefBuckets, + }, + ) + + // Shard confirmation validation metrics + shardConfirmationValidationTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_confirmation_validation_total", + Help: "Total number of shard confirmation validations", + }, + []string{"result"}, // result: "accept", "reject", "ignore" + ) + + shardConfirmationValidationDuration = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_confirmation_validation_duration_seconds", + Help: "Time taken to validate a shard confirmation", + Buckets: prometheus.DefBuckets, + }, + ) + + // Global proposal processing metrics + proposalProcessedTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "proposal_processed_total", + Help: "Total number of global proposals processed by the global consensus engine", + }, + []string{"status"}, // status: "success", "error", "invalid" + ) + + proposalProcessingDuration = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "proposal_processing_duration_seconds", + Help: "Time taken to process a global proposal", + Buckets: prometheus.DefBuckets, + }, + ) + + // Global proposal validation metrics + proposalValidationTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "proposal_validation_total", + Help: "Total number of global proposal validations", + }, + []string{"result"}, // result: "accept", "reject", "ignore" + ) + + proposalValidationDuration = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "proposal_validation_duration_seconds", + Help: "Time taken to validate a global proposal", + Buckets: prometheus.DefBuckets, + }, + ) + + // Shard proposal processing metrics + shardProposalProcessedTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_proposal_processed_total", + Help: "Total number of shard proposals processed by the global consensus engine", + }, + []string{"status"}, // status: "success", "error", "invalid" + ) + + shardProposalProcessingDuration = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_proposal_processing_duration_seconds", + Help: "Time taken to process a shard proposal", + Buckets: prometheus.DefBuckets, + }, + ) + + // Shard proposal validation metrics + shardProposalValidationTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_proposal_validation_total", + Help: "Total number of shard proposal validations", + }, + []string{"result"}, // result: "accept", "reject", "ignore" + ) + + shardProposalValidationDuration = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "shard_proposal_validation_duration_seconds", + Help: "Time taken to validate a shard proposal", + Buckets: prometheus.DefBuckets, + }, + ) + // Frame proving metrics frameProvingTotal = promauto.NewCounterVec( prometheus.CounterOpts{ diff --git a/node/consensus/global/services.go b/node/consensus/global/services.go index 7dbe68c1..0f2bb11f 100644 --- a/node/consensus/global/services.go +++ b/node/consensus/global/services.go @@ -232,6 +232,36 @@ func (e *GlobalConsensusEngine) GetGlobalShards( }, nil } +func (e *GlobalConsensusEngine) GetLockedAddresses( + ctx context.Context, + req *protobufs.GetLockedAddressesRequest, +) (*protobufs.GetLockedAddressesResponse, error) { + e.txLockMu.RLock() + defer e.txLockMu.RUnlock() + if _, ok := e.txLockMap[req.FrameNumber]; !ok { + return &protobufs.GetLockedAddressesResponse{}, nil + } + + locks := e.txLockMap[req.FrameNumber] + if _, ok := locks[string(req.ShardAddress)]; !ok { + return &protobufs.GetLockedAddressesResponse{}, nil + } + + transactions := []*protobufs.LockedTransaction{} + for _, tx := range locks[string(req.ShardAddress)] { + transactions = append(transactions, &protobufs.LockedTransaction{ + TransactionHash: tx.TransactionHash, + ShardAddresses: tx.ShardAddresses, + Committed: tx.Committed, + Filled: tx.Filled, + }) + } + + return &protobufs.GetLockedAddressesResponse{ + Transactions: transactions, + }, nil +} + func (e *GlobalConsensusEngine) RegisterServices(server *grpc.Server) { protobufs.RegisterGlobalServiceServer(server, e) protobufs.RegisterDispatchServiceServer(server, e.dispatchService) diff --git a/node/consensus/provers/proposer.go b/node/consensus/provers/proposer.go index 4a538761..e3b377ca 100644 --- a/node/consensus/provers/proposer.go +++ b/node/consensus/provers/proposer.go @@ -2,8 +2,11 @@ package provers import ( "bytes" + "crypto/rand" + "encoding/hex" "math/big" "sort" + "sync" "github.com/pkg/errors" "github.com/shopspring/decimal" @@ -53,6 +56,12 @@ type Proposal struct { ShardsDenominator uint64 } +// scored is an internal struct for ranking proposals +type scored struct { + idx int + score *big.Int +} + // Manager ranks shards and assigns free workers to the best ones. type Manager struct { logger *zap.Logger @@ -63,6 +72,9 @@ type Manager struct { // Static issuance parameters for planning Units uint64 Strategy Strategy + + mu sync.Mutex + isPlanning bool } // NewManager wires up a planning manager @@ -92,12 +104,29 @@ func (m *Manager) PlanAndAllocate( shards []ShardDescriptor, maxAllocations int, ) ([]Proposal, error) { + m.mu.Lock() + isPlanning := m.isPlanning + m.mu.Unlock() + if isPlanning { + m.logger.Debug("planning already in progress") + return []Proposal{}, nil + } + m.mu.Lock() + m.isPlanning = true + m.mu.Unlock() + defer func() { + m.mu.Lock() + m.isPlanning = false + m.mu.Unlock() + }() + if len(shards) == 0 { + m.logger.Debug("no shards to allocate") return nil, nil } // Enumerate free workers (unallocated). - all, err := m.store.RangeWorkers() + all, err := m.workerMgr.RangeWorkers() if err != nil { return nil, errors.Wrap(err, "plan and allocate") } @@ -109,6 +138,7 @@ func (m *Manager) PlanAndAllocate( } if len(free) == 0 { + m.logger.Debug("no workers free") return nil, nil } @@ -123,60 +153,13 @@ func (m *Manager) PlanAndAllocate( // Pre-compute basis (independent of shard specifics). basis := reward.PomwBasis(difficulty, worldBytes.Uint64(), m.Units) - // Score each shard by expected reward for a single allocation. - type scored struct { - idx int - score *big.Int - } - scores := make([]scored, 0, len(shards)) - - for i, s := range shards { - if len(s.Filter) == 0 || s.Size == 0 { - continue - } - if s.Shards == 0 { - s.Shards = 1 - } - var score *big.Int - switch m.Strategy { - case DataGreedy: - // Pure data coverage: larger shards first. - score = big.NewInt(int64(s.Size)) - default: - // factor = (stateSize / worldBytes) - factor := big.NewInt(int64(s.Size)) - factor.Quo( - factor, - worldBytes, - ) - - // ring divisor = 2^Ring - divisor := int64(1) - for j := uint8(0); j < s.Ring+1; j++ { - divisor <<= 1 - } - ringDiv := big.NewInt(divisor) - - // shard factor = sqrt(Shards) - shardsSqrt, err := decimal.NewFromUint64(s.Shards).PowWithPrecision( - decimal.NewFromBigRat(big.NewRat(1, 2), 53), - 53, - ) - if err != nil { - return nil, errors.Wrap(err, "plan and allocate") - } - if shardsSqrt.IsZero() { - return nil, errors.New("plan and allocate") - } - - score := basis.Mul(basis, factor) - score.Quo(score, ringDiv) - score.Quo(score, shardsSqrt.BigInt()) - } - scores = append(scores, scored{idx: i, score: score}) + scores, err := m.scoreShards(shards, basis, worldBytes) + if err != nil { + return nil, errors.Wrap(err, "plan and allocate") } if len(scores) == 0 { + m.logger.Debug("no scores") return nil, nil } @@ -192,6 +175,32 @@ func (m *Manager) PlanAndAllocate( return bytes.Compare(fi, fj) < 0 }) + // For reward-greedy strategy, randomize within equal-score groups so equally + // good shards are chosen fairly instead of skewing toward lexicographically + // earlier filters. + if m.Strategy != DataGreedy && len(scores) > 1 { + for start := 0; start < len(scores); { + end := start + 1 + // Find run [start,end) where scores are equal. + for end < len(scores) && scores[end].score.Cmp(scores[start].score) == 0 { + end++ + } + + // Shuffle the run with Fisher–Yates: + if end-start > 1 { + for i := end - 1; i > start; i-- { + n := big.NewInt(int64(i - start + 1)) + r, err := rand.Int(rand.Reader, n) + if err == nil { + j := start + int(r.Int64()) + scores[i], scores[j] = scores[j], scores[i] + } + } + } + start = end + } + } + // Determine how many allocations we’ll attempt. limit := len(free) if maxAllocations > 0 && maxAllocations < limit { @@ -200,6 +209,13 @@ func (m *Manager) PlanAndAllocate( if limit > len(scores) { limit = len(scores) } + m.logger.Debug( + "deciding on scored proposals", + zap.Int("free_workers", len(free)), + zap.Int("max_allocations", maxAllocations), + zap.Int("scores", len(scores)), + zap.Int("limit", limit), + ) proposals := make([]Proposal, 0, limit) @@ -225,19 +241,191 @@ func (m *Manager) PlanAndAllocate( }) } - // Perform allocations (best-effort, continue on per-worker error). - out := make([]Proposal, 0, len(proposals)) + // Perform allocations + workerIds := []uint{} + filters := [][]byte{} for _, p := range proposals { - if err := m.workerMgr.ProposeAllocation(p.WorkerId, p.Filter); err != nil { - // Keep going; return successful ones plus the error at the end. - m.logger.Warn("allocate worker failed", - zap.Uint("worker_id", p.WorkerId), - zap.Error(err), + workerIds = append(workerIds, p.WorkerId) + filters = append(filters, p.Filter) + } + + m.logger.Debug("proposals collated", zap.Int("count", len(proposals))) + + err = m.workerMgr.ProposeAllocations(workerIds, filters) + if err != nil { + m.logger.Warn("allocate worker failed", + zap.Error(err), + ) + } + + return proposals, errors.Wrap(err, "plan and allocate") +} + +func (m *Manager) scoreShards( + shards []ShardDescriptor, + basis *big.Int, + worldBytes *big.Int, +) ([]scored, error) { + scores := make([]scored, 0, len(shards)) + for i, s := range shards { + if len(s.Filter) == 0 || s.Size == 0 { + m.logger.Debug( + "filtering out empty shard", + zap.String("filter", hex.EncodeToString(s.Filter)), + zap.Uint64("size", s.Size), ) continue } - out = append(out, p) + + if s.Shards == 0 { + s.Shards = 1 + } + + var score *big.Int + switch m.Strategy { + case DataGreedy: + // Pure data coverage: larger shards first. + score = big.NewInt(int64(s.Size)) + default: + // factor = (stateSize / worldBytes) + factor := decimal.NewFromUint64(s.Size) + factor = factor.Mul(decimal.NewFromBigInt(basis, 0)) + factor = factor.Div(decimal.NewFromBigInt(worldBytes, 0)) + + // ring divisor = 2^Ring + divisor := int64(1) + for j := uint8(0); j < s.Ring+1; j++ { + divisor <<= 1 + } + ringDiv := decimal.NewFromInt(divisor) + + // shard factor = sqrt(Shards) + shardsSqrt, err := decimal.NewFromUint64(s.Shards).PowWithPrecision( + decimal.NewFromBigRat(big.NewRat(1, 2), 53), + 53, + ) + if err != nil { + return nil, errors.Wrap(err, "score shards") + } + + if shardsSqrt.IsZero() { + return nil, errors.New("score shards") + } + + m.logger.Debug( + "calculating score", + zap.Int("index", i), + zap.String("basis", basis.String()), + zap.String("size", big.NewInt(int64(s.Size)).String()), + zap.String("worldBytes", worldBytes.String()), + zap.String("factor", factor.String()), + zap.String("divisor", ringDiv.String()), + zap.String("shardsSqrt", shardsSqrt.String()), + ) + factor = factor.Div(ringDiv) + factor = factor.Div(shardsSqrt) + score = factor.BigInt() + } + + m.logger.Debug( + "adding score proposal", + zap.Int("index", i), + zap.String("score", score.String()), + ) + scores = append(scores, scored{idx: i, score: score}) + } + return scores, nil +} + +// DecideJoins evaluates pending shard joins using the latest shard view. It +// uses the same scoring basis as initial planning. For each pending join: +// - If there exists a strictly better shard in the latest view, reject the +// existing one (this will result in a new join attempt). +// - Otherwise (tie or better), confirm the existing one. +func (m *Manager) DecideJoins( + difficulty uint64, + shards []ShardDescriptor, + pending [][]byte, +) error { + if len(pending) == 0 { + return nil + } + + // If no shards remain, we should warn + if len(shards) == 0 { + m.logger.Warn("no shards available to decide") + return nil + } + + worldBytes := m.world.GetSize(nil, nil) + + basis := reward.PomwBasis(difficulty, worldBytes.Uint64(), m.Units) + + scores, err := m.scoreShards(shards, basis, worldBytes) + if err != nil { + return errors.Wrap(err, "decide joins") + } + + type srec struct { + desc ShardDescriptor + score *big.Int + } + byHex := make(map[string]srec, len(shards)) + var bestScore *big.Int + for _, sc := range scores { + s := shards[sc.idx] + key := hex.EncodeToString(s.Filter) + byHex[key] = srec{desc: s, score: sc.score} + if bestScore == nil || sc.score.Cmp(bestScore) > 0 { + bestScore = sc.score + } + } + + // If nothing valid, reject everything. + if bestScore == nil { + reject := make([][]byte, 0, len(pending)) + for _, p := range pending { + if len(p) == 0 { + continue + } + pc := make([]byte, len(p)) + copy(pc, p) + reject = append(reject, pc) + } + return m.workerMgr.DecideAllocations(reject, nil) + } + + reject := make([][]byte, 0, len(pending)) + confirm := make([][]byte, 0, len(pending)) + + for _, p := range pending { + if len(p) == 0 { + continue + } + + key := hex.EncodeToString(p) + rec, ok := byHex[key] + if !ok { + // If a pending shard is missing, we should reject it. This could happen + // if shard-out produces a bunch of divisions. + pc := make([]byte, len(p)) + copy(pc, p) + reject = append(reject, pc) + continue + } + + // Reject only if there exists a strictly better score. + if rec.score.Cmp(bestScore) < 0 { + pc := make([]byte, len(p)) + copy(pc, p) + reject = append(reject, pc) + } else { + // Otherwise confirm + pc := make([]byte, len(p)) + copy(pc, p) + confirm = append(confirm, pc) + } } - return out, nil + return m.workerMgr.DecideAllocations(reject, confirm) } diff --git a/node/consensus/provers/proposer_test.go b/node/consensus/provers/proposer_test.go new file mode 100644 index 00000000..dd88402f --- /dev/null +++ b/node/consensus/provers/proposer_test.go @@ -0,0 +1,325 @@ +package provers + +import ( + "bytes" + "context" + "encoding/hex" + "math/big" + "testing" + "time" + + "go.uber.org/zap" + + "source.quilibrium.com/quilibrium/monorepo/types/store" + "source.quilibrium.com/quilibrium/monorepo/types/tries" +) + +type mockSizer struct { + n *big.Int +} + +func (m *mockSizer) GetSize(_ *tries.ShardKey, _ []int) *big.Int { + return new(big.Int).Set(m.n) +} + +type mockWorkerManager struct { + workers []*store.WorkerInfo + lastWorkers []uint + lastFiltersHex []string + rejected [][]byte + confirmed [][]byte +} + +func (m *mockWorkerManager) DecideAllocations(reject [][]byte, confirm [][]byte) error { + m.rejected = reject + m.confirmed = confirm + return nil +} + +func (m *mockWorkerManager) AllocateWorker(coreId uint, filter []byte) error { + panic("unimplemented") +} + +func (m *mockWorkerManager) DeallocateWorker(coreId uint) error { + panic("unimplemented") +} + +func (m *mockWorkerManager) GetFilterByWorkerId(coreId uint) ([]byte, error) { + panic("unimplemented") +} + +func (m *mockWorkerManager) GetWorkerIdByFilter(filter []byte) (uint, error) { + panic("unimplemented") +} + +func (m *mockWorkerManager) RegisterWorker(info *store.WorkerInfo) error { + panic("unimplemented") +} + +func (m *mockWorkerManager) Start(ctx context.Context) error { + panic("unimplemented") +} + +func (m *mockWorkerManager) Stop() error { + panic("unimplemented") +} + +func (m *mockWorkerManager) RangeWorkers() ([]*store.WorkerInfo, error) { + out := make([]*store.WorkerInfo, len(m.workers)) + copy(out, m.workers) + return out, nil +} + +func (m *mockWorkerManager) ProposeAllocations(workerIds []uint, filters [][]byte) error { + m.lastWorkers = append([]uint(nil), workerIds...) + m.lastFiltersHex = make([]string, len(filters)) + for i := range filters { + m.lastFiltersHex[i] = hex.EncodeToString(filters[i]) + } + return nil +} + +func newTestManager(t *testing.T, strategy Strategy, wm *mockWorkerManager) *Manager { + t.Helper() + logger := zap.NewNop() + world := &mockSizer{n: big.NewInt(1 << 30)} // 1 GB + const units = 8000000000 + + return NewManager(logger, world, nil, wm, units, strategy) +} + +func createWorkers(n int) []*store.WorkerInfo { + ws := make([]*store.WorkerInfo, n) + for i := 0; i < n; i++ { + ws[i] = &store.WorkerInfo{ + CoreId: uint(i + 1), + Allocated: false, + } + } + return ws +} + +func createShard(filter []byte, size uint64, ring uint8, shards uint64) ShardDescriptor { + return ShardDescriptor{ + Filter: filter, + Size: size, + Ring: ring, + Shards: shards, + } +} + +func TestPlanAndAllocate_EqualScores_RandomizedWhenNotDataGreedy(t *testing.T) { + wm := &mockWorkerManager{workers: createWorkers(1)} + m := newTestManager(t, RewardGreedy, wm) + + // 4 equal-score shards: identical size, ring, shards. only filter differs + shards := []ShardDescriptor{ + createShard([]byte{0x01}, 10_000, 0, 1), + createShard([]byte{0x02}, 10_000, 0, 1), + createShard([]byte{0x03}, 10_000, 0, 1), + createShard([]byte{0x04}, 10_000, 0, 1), + } + + firstPickCounts := map[string]int{ + "01": 0, "02": 0, "03": 0, "04": 0, + } + + // Run multiple times to confirm randomness. + const runs = 64 + for i := 0; i < runs; i++ { + time.Sleep(5 * time.Millisecond) + + wm.lastFiltersHex = nil + _, err := m.PlanAndAllocate(100, shards, 1) + if err != nil { + t.Fatalf("PlanAndAllocate failed: %v", err) + } + if len(wm.lastFiltersHex) != 1 { + t.Fatalf("expected one allocation, got %d", len(wm.lastFiltersHex)) + } + firstPickCounts[wm.lastFiltersHex[0]]++ + } + + distinct := 0 + for _, c := range firstPickCounts { + if c > 0 { + distinct++ + } + } + if distinct < 4 { + t.Fatalf("expected randomized tie-break; got counts: %+v", firstPickCounts) + } +} + +func TestPlanAndAllocate_EqualSizes_DeterministicWhenDataGreedy(t *testing.T) { + wm := &mockWorkerManager{workers: createWorkers(1)} + m := newTestManager(t, DataGreedy, wm) + + shards := []ShardDescriptor{ + createShard([]byte{0x02}, 10_000, 0, 1), + createShard([]byte{0x01}, 10_000, 0, 1), + createShard([]byte{0x04}, 10_000, 0, 1), + createShard([]byte{0x03}, 10_000, 0, 1), + } + + const runs = 16 + for i := 0; i < runs; i++ { + wm.lastFiltersHex = nil + _, err := m.PlanAndAllocate(100, shards, 1) + if err != nil { + t.Fatalf("PlanAndAllocate failed: %v", err) + } + if len(wm.lastFiltersHex) != 1 { + t.Fatalf("expected one allocation, got %d", len(wm.lastFiltersHex)) + } + if wm.lastFiltersHex[0] != "01" { + t.Fatalf("expected deterministic lexicographic first (01) in DataGreedy, got %s", wm.lastFiltersHex[0]) + } + } +} + +func TestPlanAndAllocate_UnequalScores_PicksMax(t *testing.T) { + wm := &mockWorkerManager{workers: createWorkers(1)} + m := newTestManager(t, RewardGreedy, wm) + + // Make one shard clearly better by size, keep others smaller. + best := createShard([]byte{0x0A}, 200_000, 0, 1) + other1 := createShard([]byte{0x01}, 50_000, 0, 1) + other2 := createShard([]byte{0x02}, 50_000, 0, 1) + shards := []ShardDescriptor{other1, other2, best} + + _, err := m.PlanAndAllocate(100, shards, 1) + if err != nil { + t.Fatalf("PlanAndAllocate failed: %v", err) + } + if len(wm.lastFiltersHex) != 1 { + t.Fatalf("expected one allocation, got %d", len(wm.lastFiltersHex)) + } + if !bytes.Equal([]byte{0x0A}, mustDecodeHex(t, wm.lastFiltersHex[0])) { + t.Fatalf("expected best shard 0x0A to be selected, got %s", wm.lastFiltersHex[0]) + } +} + +// Confirm when pending is best (RewardGreedy) +func TestDecideJoins_ConfirmWhenBest_RewardGreedy(t *testing.T) { + wm := &mockWorkerManager{} + m := newTestManager(t, RewardGreedy, wm) + shards := []ShardDescriptor{ + {Filter: mustDecodeHex(t, "01"), Size: 50_000, Ring: 0, Shards: 1}, + {Filter: mustDecodeHex(t, "02"), Size: 200_000, Ring: 0, Shards: 1}, // best + {Filter: mustDecodeHex(t, "03"), Size: 50_000, Ring: 0, Shards: 1}, + } + pending := [][]byte{mustDecodeHex(t, "02")} + + err := m.DecideJoins(100, shards, pending) + if err != nil { + t.Fatalf("DecideJoins error: %v", err) + } + if len(wm.rejected) != 0 || len(wm.confirmed) != 1 || hex.EncodeToString(wm.confirmed[0]) != "02" { + t.Fatalf("expected confirm 02, got reject=%v confirm=%v", toHex(wm.rejected), toHex(wm.confirmed)) + } +} + +// Reject when a strictly better shard exists (RewardGreedy) +func TestDecideJoins_RejectWhenBetterExists_RewardGreedy(t *testing.T) { + wm := &mockWorkerManager{} + m := newTestManager(t, RewardGreedy, wm) + shards := []ShardDescriptor{ + {Filter: mustDecodeHex(t, "0a"), Size: 200_000, Ring: 0, Shards: 1}, // best + {Filter: mustDecodeHex(t, "01"), Size: 50_000, Ring: 0, Shards: 1}, + } + pending := [][]byte{mustDecodeHex(t, "01")} + + err := m.DecideJoins(100, shards, pending) + if err != nil { + t.Fatalf("DecideJoins error: %v", err) + } + if len(wm.rejected) != 1 || hex.EncodeToString(wm.rejected[0]) != "01" || len(wm.confirmed) != 0 { + t.Fatalf("expected reject 01, got reject=%v confirm=%v", toHex(wm.rejected), toHex(wm.confirmed)) + } +} + +// Tie -> confirm (RewardGreedy) +func TestDecideJoins_TieConfirms_RewardGreedy(t *testing.T) { + + wm := &mockWorkerManager{} + m := newTestManager(t, RewardGreedy, wm) + // Same size/ring/shards -> same score + shards := []ShardDescriptor{ + {Filter: mustDecodeHex(t, "01"), Size: 100_000, Ring: 1, Shards: 4}, + {Filter: mustDecodeHex(t, "02"), Size: 100_000, Ring: 1, Shards: 4}, + } + pending := [][]byte{mustDecodeHex(t, "02")} + + err := m.DecideJoins(100, shards, pending) + if err != nil { + t.Fatalf("DecideJoins error: %v", err) + } + if len(wm.rejected) != 0 || len(wm.confirmed) != 1 || hex.EncodeToString(wm.confirmed[0]) != "02" { + t.Fatalf("expected confirm 02 on tie, got reject=%v confirm=%v", toHex(wm.rejected), toHex(wm.confirmed)) + } +} + +func TestDecideJoins_DataGreedy_SizeOnly(t *testing.T) { + wm := &mockWorkerManager{} + m := newTestManager(t, DataGreedy, wm) + shards := []ShardDescriptor{ + {Filter: mustDecodeHex(t, "aa"), Size: 10_000, Ring: 3, Shards: 16}, // worse by size + {Filter: mustDecodeHex(t, "bb"), Size: 80_000, Ring: 0, Shards: 1}, // best by size + {Filter: mustDecodeHex(t, "cc"), Size: 80_000, Ring: 5, Shards: 64}, // tie by size + } + // Pending on aa (worse), bb (best), cc (tie-best) + pending := [][]byte{mustDecodeHex(t, "aa"), mustDecodeHex(t, "bb"), mustDecodeHex(t, "cc")} + err := m.DecideJoins(100, shards, pending) + if err != nil { + t.Fatalf("DecideJoins error: %v", err) + } + rej := setOf(toHex(wm.rejected)) + cfm := setOf(toHex(wm.confirmed)) + if !(rej["aa"] && !rej["bb"] && !rej["cc"] && cfm["bb"] && cfm["cc"]) { + t.Fatalf("expected reject{aa} confirm{bb,cc}; got reject=%v confirm=%v", toHex(wm.rejected), toHex(wm.confirmed)) + } +} + +// Missing/invalid pending -> reject +func TestDecideJoins_PendingMissingOrInvalid_Reject(t *testing.T) { + wm := &mockWorkerManager{} + m := newTestManager(t, RewardGreedy, wm) + shards := []ShardDescriptor{ + {Filter: mustDecodeHex(t, "01"), Size: 100_000, Ring: 0, Shards: 1}, + } + pending := [][]byte{mustDecodeHex(t, "deadbeef"), nil, {}} + + err := m.DecideJoins(100, shards, pending) + if err != nil { + t.Fatalf("DecideJoins error: %v", err) + } + if len(wm.confirmed) != 0 || len(wm.rejected) != 1 || hex.EncodeToString(wm.rejected[0]) != "deadbeef" { + t.Fatalf("expected only deadbeef rejected; got reject=%v confirm=%v", toHex(wm.rejected), toHex(wm.confirmed)) + } +} + +func mustDecodeHex(t *testing.T, s string) []byte { + t.Helper() + b, err := hex.DecodeString(s) + if err != nil { + t.Fatalf("hex decode failed: %v", err) + } + return b +} + +func toHex(bs [][]byte) []string { + out := make([]string, 0, len(bs)) + for _, b := range bs { + out = append(out, hex.EncodeToString(b)) + } + return out +} + +func setOf(ss []string) map[string]bool { + m := make(map[string]bool, len(ss)) + for _, s := range ss { + m[s] = true + } + return m +} diff --git a/node/consensus/provers/prover_registry.go b/node/consensus/provers/prover_registry.go index 1fb8dde1..5e3904a2 100644 --- a/node/consensus/provers/prover_registry.go +++ b/node/consensus/provers/prover_registry.go @@ -3,6 +3,7 @@ package provers import ( "bytes" "encoding/binary" + "encoding/hex" "fmt" "sort" "sync" @@ -11,6 +12,7 @@ import ( "go.uber.org/zap" "golang.org/x/exp/slices" "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/global" + hgstate "source.quilibrium.com/quilibrium/monorepo/node/execution/state/hypergraph" "source.quilibrium.com/quilibrium/monorepo/types/consensus" "source.quilibrium.com/quilibrium/monorepo/types/execution/intrinsics" "source.quilibrium.com/quilibrium/monorepo/types/execution/state" @@ -100,7 +102,7 @@ func (r *ProverRegistry) ProcessStateTransition( r.currentFrame = frameNumber changes := state.Changeset() - r.logger.Debug("processing changeset", zap.Int("changeCount", len(changes))) + r.logger.Debug("processing changeset", zap.Int("change_count", len(changes))) // Process each change for _, change := range changes { @@ -149,13 +151,6 @@ func (r *ProverRegistry) GetProverInfo( ) if info, exists := r.proverCache[string(address)]; exists { - r.logger.Debug( - "prover info found", - zap.String("address", fmt.Sprintf("%x", address)), - zap.String("public_key", fmt.Sprintf("%x", info.PublicKey)), - zap.Uint8("status", uint8(info.Status)), - zap.Int("allocation_count", len(info.Allocations)), - ) return info, nil } @@ -269,11 +264,6 @@ func (r *ProverRegistry) GetActiveProvers( r.mu.RLock() defer r.mu.RUnlock() - r.logger.Debug( - "getting active provers", - zap.String("filter", fmt.Sprintf("%x", filter)), - ) - result, err := r.getProversByStatusInternal( filter, consensus.ProverStatusActive, @@ -283,7 +273,30 @@ func (r *ProverRegistry) GetActiveProvers( return nil, err } - r.logger.Debug("active provers retrieved", zap.Int("count", len(result))) + return result, nil +} + +// GetProvers implements ProverRegistry +func (r *ProverRegistry) GetProvers(filter []byte) ( + []*consensus.ProverInfo, + error, +) { + r.mu.RLock() + defer r.mu.RUnlock() + + r.logger.Debug( + "getting provers", + zap.String("filter", fmt.Sprintf("%x", filter)), + ) + + var result []*consensus.ProverInfo + result = append(result, r.filterCache[string(filter)]...) + + sort.Slice(result, func(i, j int) bool { + return bytes.Compare(result[i].Address, result[j].Address) == -1 + }) + + r.logger.Debug("provers retrieved", zap.Int("count", len(result))) return result, nil } @@ -402,7 +415,7 @@ func (r *ProverRegistry) getProversByStatusInternal( ) ([]*consensus.ProverInfo, error) { var result []*consensus.ProverInfo - for _, info := range r.proverCache { + for _, info := range r.filterCache[string(filter)] { for _, allocation := range info.Allocations { if allocation.Status == status && bytes.Equal( allocation.ConfirmationFilter, @@ -761,9 +774,20 @@ func (r *ProverRegistry) extractGlobalState() error { index := sort.Search(len(info), func(i int) bool { return bytes.Compare(info[i].Address, proverAddress) >= 0 }) - r.filterCache[string( + skipAdd := false + for _, i := range r.filterCache[string( allocation.ConfirmationFilter, - )] = slices.Insert(info, index, proverInfo) + )] { + if bytes.Equal(i.Address, proverAddress) { + skipAdd = true + break + } + } + if !skipAdd { + r.filterCache[string( + allocation.ConfirmationFilter, + )] = slices.Insert(info, index, proverInfo) + } } } } @@ -960,9 +984,20 @@ func (r *ProverRegistry) extractGlobalState() error { index := sort.Search(len(info), func(i int) bool { return bytes.Compare(info[i].Address, proverRef) >= 0 }) - r.filterCache[string( + skipAdd := false + for _, i := range r.filterCache[string( allocationInfo.ConfirmationFilter, - )] = slices.Insert(info, index, proverInfo) + )] { + if bytes.Equal(i.Address, proverRef) { + skipAdd = true + break + } + } + if !skipAdd { + r.filterCache[string( + allocationInfo.ConfirmationFilter, + )] = slices.Insert(info, index, proverInfo) + } } r.logger.Debug( @@ -986,9 +1021,6 @@ func (r *ProverRegistry) extractGlobalState() error { } } allocationsFound++ - default: - r.logger.Debug("unknown vertex type", zap.String("type", typeName)) - return errors.Wrap(errors.New("invalid type"), "extract global state") } } @@ -1076,20 +1108,38 @@ func (r *ProverRegistry) processProverChange( switch change.StateChange { case state.CreateStateChangeEvent, state.UpdateStateChangeEvent: + if !bytes.Equal(change.Discriminator, hgstate.VertexAddsDiscriminator) { + return nil + } + // A prover was created or updated if change.Value != nil && change.Value.DataValue() != nil { data := change.Value.DataValue() - // Check if this is a Prover or ProverAllocation - publicKey, err := r.rdfMultiprover.Get( + t, err := r.rdfMultiprover.GetType( global.GLOBAL_RDF_SCHEMA, - "prover:Prover", - "PublicKey", + intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], data, ) + if err != nil { + return nil + } + + // Check if this is a Prover or ProverAllocation + switch t { + case "prover:Prover": + r.logger.Debug("processing prover change") + publicKey, err := r.rdfMultiprover.Get( + global.GLOBAL_RDF_SCHEMA, + "prover:Prover", + "PublicKey", + data, + ) + if err != nil { + r.logger.Debug("no public key") + return nil + } - if err == nil && len(publicKey) > 0 { - // This is a Prover vertex statusBytes, err := r.rdfMultiprover.Get( global.GLOBAL_RDF_SCHEMA, "prover:Prover", @@ -1097,9 +1147,11 @@ func (r *ProverRegistry) processProverChange( data, ) if err != nil || len(statusBytes) == 0 { + r.logger.Debug("no status") return nil // Skip if no status } status := statusBytes[0] + r.logger.Debug("status of prover change", zap.Int("status", int(status))) // Map internal status to our ProverStatus enum var mappedStatus consensus.ProverStatus @@ -1185,33 +1237,16 @@ func (r *ProverRegistry) processProverChange( proverInfo.DelegateAddress = delegateAddress proverInfo.KickFrameNumber = kickFrameNumber } - - // If global prover is active, add to global trie - if mappedStatus == consensus.ProverStatusActive { - if err := r.addProverToTrie( - proverAddress, - publicKey, - nil, - frameNumber, - ); err != nil { - return errors.Wrap(err, "failed to add prover to global trie") - } - } else { - // Remove from global trie if not active - if err := r.removeProverFromTrie(proverAddress, nil); err != nil { - return errors.Wrap(err, "failed to remove prover from global trie") - } - } - } else { - // Try to read as ProverAllocation + case "allocation:ProverAllocation": + r.logger.Debug("processing prover allocation change") proverRef, err := r.rdfMultiprover.Get( global.GLOBAL_RDF_SCHEMA, "allocation:ProverAllocation", - "prover:Prover", + "Prover", data, ) if err != nil || len(proverRef) == 0 { - // Neither Prover nor ProverAllocation, skip + r.logger.Debug("no prover") return nil } @@ -1223,6 +1258,7 @@ func (r *ProverRegistry) processProverChange( data, ) if err != nil || len(statusBytes) == 0 { + r.logger.Debug("no status") return nil } status := statusBytes[0] @@ -1252,16 +1288,201 @@ func (r *ProverRegistry) processProverChange( zap.Uint8("status", uint8(mappedStatus)), ) - // Extract filters - confirmationFilter, _ := r.rdfMultiprover.Get( + // Extract data + confirmationFilter, err := r.rdfMultiprover.Get( global.GLOBAL_RDF_SCHEMA, "allocation:ProverAllocation", "ConfirmationFilter", data, ) + if err != nil { + return errors.Wrap(err, "process prover change") + } + + rejectionFilter, _ := r.rdfMultiprover.Get( + global.GLOBAL_RDF_SCHEMA, + "allocation:ProverAllocation", + "RejectionFilter", + data, + ) + + joinFrameNumberBytes, _ := r.rdfMultiprover.Get( + global.GLOBAL_RDF_SCHEMA, + "allocation:ProverAllocation", + "JoinFrameNumber", + data, + ) + + var joinFrameNumber uint64 + if len(joinFrameNumberBytes) != 0 { + joinFrameNumber = binary.BigEndian.Uint64(joinFrameNumberBytes) + } + + leaveFrameNumberBytes, _ := r.rdfMultiprover.Get( + global.GLOBAL_RDF_SCHEMA, + "allocation:ProverAllocation", + "LeaveFrameNumber", + data, + ) + + var leaveFrameNumber uint64 + if len(leaveFrameNumberBytes) != 0 { + leaveFrameNumber = binary.BigEndian.Uint64(leaveFrameNumberBytes) + } + + pauseFrameNumberBytes, _ := r.rdfMultiprover.Get( + global.GLOBAL_RDF_SCHEMA, + "allocation:ProverAllocation", + "PauseFrameNumber", + data, + ) + + var pauseFrameNumber uint64 + if len(pauseFrameNumberBytes) != 0 { + pauseFrameNumber = binary.BigEndian.Uint64(pauseFrameNumberBytes) + } + + resumeFrameNumberBytes, _ := r.rdfMultiprover.Get( + global.GLOBAL_RDF_SCHEMA, + "allocation:ProverAllocation", + "ResumeFrameNumber", + data, + ) + + var resumeFrameNumber uint64 + if len(resumeFrameNumberBytes) != 0 { + resumeFrameNumber = binary.BigEndian.Uint64(resumeFrameNumberBytes) + } + + kickFrameNumberBytes, _ := r.rdfMultiprover.Get( + global.GLOBAL_RDF_SCHEMA, + "allocation:ProverAllocation", + "KickFrameNumber", + data, + ) + + var kickFrameNumber uint64 + if len(kickFrameNumberBytes) != 0 { + kickFrameNumber = binary.BigEndian.Uint64(kickFrameNumberBytes) + } + + joinConfirmFrameNumberBytes, _ := r.rdfMultiprover.Get( + global.GLOBAL_RDF_SCHEMA, + "allocation:ProverAllocation", + "JoinConfirmFrameNumber", + data, + ) + + var joinConfirmFrameNumber uint64 + if len(joinConfirmFrameNumberBytes) != 0 { + joinConfirmFrameNumber = binary.BigEndian.Uint64( + joinConfirmFrameNumberBytes, + ) + } + + joinRejectFrameNumberBytes, _ := r.rdfMultiprover.Get( + global.GLOBAL_RDF_SCHEMA, + "allocation:ProverAllocation", + "JoinRejectFrameNumber", + data, + ) + + var joinRejectFrameNumber uint64 + if len(joinRejectFrameNumberBytes) != 0 { + joinRejectFrameNumber = binary.BigEndian.Uint64( + joinRejectFrameNumberBytes, + ) + } + + leaveConfirmFrameNumberBytes, _ := r.rdfMultiprover.Get( + global.GLOBAL_RDF_SCHEMA, + "allocation:ProverAllocation", + "LeaveConfirmFrameNumber", + data, + ) + + var leaveConfirmFrameNumber uint64 + if len(leaveConfirmFrameNumberBytes) != 0 { + leaveConfirmFrameNumber = binary.BigEndian.Uint64( + leaveConfirmFrameNumberBytes, + ) + } + + leaveRejectFrameNumberBytes, _ := r.rdfMultiprover.Get( + global.GLOBAL_RDF_SCHEMA, + "allocation:ProverAllocation", + "LeaveRejectFrameNumber", + data, + ) + + var leaveRejectFrameNumber uint64 + if len(leaveRejectFrameNumberBytes) != 0 { + leaveRejectFrameNumber = binary.BigEndian.Uint64( + leaveRejectFrameNumberBytes, + ) + } + + lastActiveFrameNumberBytes, _ := r.rdfMultiprover.Get( + global.GLOBAL_RDF_SCHEMA, + "allocation:ProverAllocation", + "LastActiveFrameNumber", + data, + ) + + var lastActiveFrameNumber uint64 + if len(lastActiveFrameNumberBytes) != 0 { + lastActiveFrameNumber = binary.BigEndian.Uint64( + lastActiveFrameNumberBytes, + ) + } // Find the prover this allocation belongs to if proverInfo, exists := r.proverCache[string(proverRef)]; exists { + found := false + for i, allocation := range proverInfo.Allocations { + if bytes.Equal(allocation.ConfirmationFilter, confirmationFilter) { + proverInfo.Allocations[i].Status = mappedStatus + proverInfo.Allocations[i].RejectionFilter = rejectionFilter + proverInfo.Allocations[i].JoinFrameNumber = joinFrameNumber + proverInfo.Allocations[i].LeaveFrameNumber = leaveFrameNumber + proverInfo.Allocations[i].PauseFrameNumber = pauseFrameNumber + proverInfo.Allocations[i].ResumeFrameNumber = resumeFrameNumber + proverInfo.Allocations[i].KickFrameNumber = kickFrameNumber + proverInfo.Allocations[i].JoinConfirmFrameNumber = + joinConfirmFrameNumber + proverInfo.Allocations[i].JoinRejectFrameNumber = + joinRejectFrameNumber + proverInfo.Allocations[i].LeaveConfirmFrameNumber = + leaveConfirmFrameNumber + proverInfo.Allocations[i].LeaveRejectFrameNumber = + leaveRejectFrameNumber + proverInfo.Allocations[i].LastActiveFrameNumber = + lastActiveFrameNumber + found = true + } + } + + if !found { + proverInfo.Allocations = append( + proverInfo.Allocations, + consensus.ProverAllocationInfo{ + Status: mappedStatus, + ConfirmationFilter: confirmationFilter, + RejectionFilter: rejectionFilter, + JoinFrameNumber: joinFrameNumber, + LeaveFrameNumber: leaveFrameNumber, + PauseFrameNumber: pauseFrameNumber, + ResumeFrameNumber: resumeFrameNumber, + KickFrameNumber: kickFrameNumber, + JoinConfirmFrameNumber: joinConfirmFrameNumber, + JoinRejectFrameNumber: joinRejectFrameNumber, + LeaveConfirmFrameNumber: leaveConfirmFrameNumber, + LeaveRejectFrameNumber: leaveRejectFrameNumber, + LastActiveFrameNumber: lastActiveFrameNumber, + }, + ) + } + // Update tries based on allocation status if mappedStatus == consensus.ProverStatusActive && len(confirmationFilter) > 0 { @@ -1271,9 +1492,10 @@ func (r *ProverRegistry) processProverChange( confirmationFilter, frameNumber, ); err != nil { - return errors.Wrap(err, "failed to add prover to filter trie") + return errors.Wrap(err, "process prover change") } - } else { + } else if mappedStatus == consensus.ProverStatusKicked || + mappedStatus == consensus.ProverStatusUnknown { // Remove from filter trie if not active if err := r.removeProverFromTrie( proverRef, @@ -1281,7 +1503,7 @@ func (r *ProverRegistry) processProverChange( ); err != nil { return errors.Wrap( err, - "failed to remove prover from filter trie", + "process prover change", ) } } @@ -1505,6 +1727,12 @@ func (r *ProverRegistry) GetAllActiveAppShardProvers() ( // Check if this prover has any active allocations (app shard provers) hasActiveAllocation := false for _, allocation := range proverInfo.Allocations { + r.logger.Debug( + "checking allocation status", + zap.String("address", hex.EncodeToString(proverInfo.Address)), + zap.String("filter", hex.EncodeToString(allocation.ConfirmationFilter)), + zap.Uint32("status", uint32(allocation.Status)), + ) if allocation.Status == consensus.ProverStatusActive && len(allocation.ConfirmationFilter) > 0 { hasActiveAllocation = true @@ -1514,6 +1742,10 @@ func (r *ProverRegistry) GetAllActiveAppShardProvers() ( // Only include provers with active allocations if hasActiveAllocation { + r.logger.Debug( + "copying prover info for status", + zap.String("address", hex.EncodeToString(proverInfo.Address)), + ) // Make a copy to avoid external modification proverCopy := &consensus.ProverInfo{ PublicKey: make([]byte, len(proverInfo.PublicKey)), @@ -1534,6 +1766,14 @@ func (r *ProverRegistry) GetAllActiveAppShardProvers() ( // Copy allocations for i, allocation := range proverInfo.Allocations { + r.logger.Debug( + "copying prover allocation for status", + zap.String("address", hex.EncodeToString(proverInfo.Address)), + zap.String( + "filter", + hex.EncodeToString(allocation.ConfirmationFilter), + ), + ) proverCopy.Allocations[i] = consensus.ProverAllocationInfo{ Status: allocation.Status, ConfirmationFilter: make( diff --git a/node/consensus/registration/cached_signer_registry.go b/node/consensus/registration/cached_signer_registry.go index 57c83380..c18333d9 100644 --- a/node/consensus/registration/cached_signer_registry.go +++ b/node/consensus/registration/cached_signer_registry.go @@ -198,8 +198,8 @@ func (c *CachedSignerRegistry) ValidateProvingKey( return nil } -// ValidateSignedKey validates a signed X448 key -func (c *CachedSignerRegistry) ValidateSignedKey( +// ValidateSignedX448Key validates a signed X448 key +func (c *CachedSignerRegistry) ValidateSignedX448Key( signedKey *protobufs.SignedX448Key, ) error { // First validate the structure @@ -219,6 +219,27 @@ func (c *CachedSignerRegistry) ValidateSignedKey( return nil } +// ValidateSignedDecaf448Key validates a signed Decaf448 key +func (c *CachedSignerRegistry) ValidateSignedDecaf448Key( + signedKey *protobufs.SignedDecaf448Key, +) error { + // First validate the structure + if err := signedKey.Validate(); err != nil { + return errors.Wrap(err, "validate signed key") + } + + // Then verify the signature using the appropriate verifier + if err := signedKey.Verify( + []byte("KEY_REGISTRY"), + c.blsConstructor, + c.bulletproofProver, + ); err != nil { + return errors.Wrap(err, "validate signed key") + } + + return nil +} + // PutIdentityKey stores an identity key func (c *CachedSignerRegistry) PutIdentityKey( txn store.Transaction, @@ -305,18 +326,47 @@ func (c *CachedSignerRegistry) PutCrossSignature( } // PutSignedKey stores a signed X448 key -func (c *CachedSignerRegistry) PutSignedKey( +func (c *CachedSignerRegistry) PutSignedX448Key( txn store.Transaction, address []byte, key *protobufs.SignedX448Key, ) error { // Validate the key - if err := c.ValidateSignedKey(key); err != nil { + if err := c.ValidateSignedX448Key(key); err != nil { return errors.Wrap(err, "put signed key") } // Store in the key store - if err := c.keyStore.PutSignedKey(txn, address, key); err != nil { + if err := c.keyStore.PutSignedX448Key(txn, address, key); err != nil { + return errors.Wrap(err, "put signed key") + } + + // Clear cache entries that might be affected + c.mu.Lock() + defer c.mu.Unlock() + + // Clear cache for parent key + addressBI, _ := poseidon.HashBytes(key.ParentKeyAddress) + var parentAddr [32]byte + addressBI.FillBytes(parentAddr[:]) + delete(c.cache, parentAddr) + + return nil +} + +// PutSignedDecaf448Key stores a signed Decaf448 key +func (c *CachedSignerRegistry) PutSignedDecaf448Key( + txn store.Transaction, + address []byte, + key *protobufs.SignedDecaf448Key, +) error { + // Validate the key + if err := c.ValidateSignedDecaf448Key(key); err != nil { + return errors.Wrap(err, "put signed key") + } + + // Store in the key store + if err := c.keyStore.PutSignedDecaf448Key(txn, address, key); err != nil { return errors.Wrap(err, "put signed key") } @@ -347,19 +397,34 @@ func (c *CachedSignerRegistry) GetProvingKey( return c.keyStore.GetProvingKey(address) } -// GetSignedKey retrieves a signed key by address -func (c *CachedSignerRegistry) GetSignedKey( +// GetSignedX448Key retrieves a signed key by address +func (c *CachedSignerRegistry) GetSignedX448Key( address []byte, ) (*protobufs.SignedX448Key, error) { - return c.keyStore.GetSignedKey(address) + return c.keyStore.GetSignedX448Key(address) } -// GetSignedKeysByParent retrieves all signed keys for a parent key -func (c *CachedSignerRegistry) GetSignedKeysByParent( +// GetSignedX448KeysByParent retrieves all signed keys for a parent key +func (c *CachedSignerRegistry) GetSignedX448KeysByParent( parentKeyAddress []byte, keyPurpose string, ) ([]*protobufs.SignedX448Key, error) { - return c.keyStore.GetSignedKeysByParent(parentKeyAddress, keyPurpose) + return c.keyStore.GetSignedX448KeysByParent(parentKeyAddress, keyPurpose) +} + +// GetSignedDecaf448Key retrieves a signed key by address +func (c *CachedSignerRegistry) GetSignedDecaf448Key( + address []byte, +) (*protobufs.SignedDecaf448Key, error) { + return c.keyStore.GetSignedDecaf448Key(address) +} + +// GetSignedDecaf448KeysByParent retrieves all signed keys for a parent key +func (c *CachedSignerRegistry) GetSignedDecaf448KeysByParent( + parentKeyAddress []byte, + keyPurpose string, +) ([]*protobufs.SignedDecaf448Key, error) { + return c.keyStore.GetSignedDecaf448KeysByParent(parentKeyAddress, keyPurpose) } // RangeProvingKeys returns an iterator over all proving keys @@ -378,12 +443,20 @@ func (c *CachedSignerRegistry) RangeIdentityKeys() ( return c.keyStore.RangeIdentityKeys() } -// RangeSignedKeys returns an iterator over signed keys -func (c *CachedSignerRegistry) RangeSignedKeys( +// RangeSignedX448Keys returns an iterator over signed keys +func (c *CachedSignerRegistry) RangeSignedX448Keys( parentKeyAddress []byte, keyPurpose string, ) (store.TypedIterator[*protobufs.SignedX448Key], error) { - return c.keyStore.RangeSignedKeys(parentKeyAddress, keyPurpose) + return c.keyStore.RangeSignedX448Keys(parentKeyAddress, keyPurpose) +} + +// RangeSignedDecaf448Keys returns an iterator over signed keys +func (c *CachedSignerRegistry) RangeSignedDecaf448Keys( + parentKeyAddress []byte, + keyPurpose string, +) (store.TypedIterator[*protobufs.SignedDecaf448Key], error) { + return c.keyStore.RangeSignedDecaf448Keys(parentKeyAddress, keyPurpose) } // GetAllSigners returns all cached signers diff --git a/node/consensus/registration/cached_signer_registry_integration_test.go b/node/consensus/registration/cached_signer_registry_integration_test.go index 19321dca..5ce8af92 100644 --- a/node/consensus/registration/cached_signer_registry_integration_test.go +++ b/node/consensus/registration/cached_signer_registry_integration_test.go @@ -158,7 +158,7 @@ func TestLoadExistingKeys(t *testing.T) { signedKeyAddressBI, _ := poseidon.HashBytes(signedKey.Key.KeyValue) signedKeyAddress := signedKeyAddressBI.FillBytes(make([]byte, 32)) - err = keyStore.PutSignedKey(txn, signedKeyAddress, signedKey) + err = keyStore.PutSignedX448Key(txn, signedKeyAddress, signedKey) require.NoError(t, err) } @@ -223,7 +223,7 @@ func TestFullWorkflow(t *testing.T) { signedKeyAddressBI, _ := poseidon.HashBytes(signedKey.Key.KeyValue) signedKeyAddress := signedKeyAddressBI.FillBytes(make([]byte, 32)) - err = keyStore.PutSignedKey(txn, signedKeyAddress, signedKey) + err = keyStore.PutSignedX448Key(txn, signedKeyAddress, signedKey) require.NoError(t, err) // Commit the transaction @@ -297,7 +297,7 @@ func TestValidationIntegration(t *testing.T) { randomAddress := generateTestAddress() signedKey.ParentKeyAddress = randomAddress - err = registry.ValidateSignedKey(signedKey) + err = registry.ValidateSignedX448Key(signedKey) require.Error(t, err) assert.Contains(t, err.Error(), "validate signed key") }) diff --git a/node/consensus/registration/cached_signer_registry_test.go b/node/consensus/registration/cached_signer_registry_test.go index c825afaf..77795648 100644 --- a/node/consensus/registration/cached_signer_registry_test.go +++ b/node/consensus/registration/cached_signer_registry_test.go @@ -325,12 +325,12 @@ func TestValidateSignedKey(t *testing.T) { addressBI, _ := poseidon.HashBytes(pubKey) signedKey.ParentKeyAddress = addressBI.FillBytes(make([]byte, 32)) - err := registry.ValidateSignedKey(signedKey) + err := registry.ValidateSignedX448Key(signedKey) require.NoError(t, err) }) t.Run("Nil signed key", func(t *testing.T) { - err := registry.ValidateSignedKey(nil) + err := registry.ValidateSignedX448Key(nil) require.Error(t, err) assert.Contains(t, err.Error(), "validate signed key") }) @@ -442,9 +442,9 @@ func TestPutSignedKey(t *testing.T) { signedKey.ParentKeyAddress = addressBI.FillBytes(make([]byte, 32)) // Mock the keyStore PutSignedKey - keyStore.On("PutSignedKey", mockTxn, address, signedKey).Return(nil) + keyStore.On("PutSignedX448Key", mockTxn, address, signedKey).Return(nil) - err = registry.PutSignedKey(mockTxn, address, signedKey) + err = registry.PutSignedX448Key(mockTxn, address, signedKey) require.NoError(t, err) keyStore.AssertExpectations(t) @@ -480,7 +480,7 @@ func TestGetKeyRegistry(t *testing.T) { KeysByPurpose: map[string]*protobufs.KeyCollection{ "inbox": { KeyPurpose: "inbox", - Keys: []*protobufs.SignedX448Key{ + X448Keys: []*protobufs.SignedX448Key{ createTestSignedX448Key(priv, "inbox"), }, }, diff --git a/node/consensus/time/app_time_reel.go b/node/consensus/time/app_time_reel.go index 961edcaf..8c101126 100644 --- a/node/consensus/time/app_time_reel.go +++ b/node/consensus/time/app_time_reel.go @@ -108,6 +108,9 @@ type AppTimeReel struct { ctx context.Context cancel context.CancelFunc wg sync.WaitGroup + + // Archive mode: whether to hold historic frame data + archiveMode bool } // NewAppTimeReel creates a new app time reel for a specific shard address @@ -116,6 +119,7 @@ func NewAppTimeReel( address []byte, proverRegistry consensus.ProverRegistry, clockStore store.ClockStore, + archiveMode bool, ) (*AppTimeReel, error) { cache, err := lru.New[string, *FrameNode](defaultAppCacheSize) if err != nil { @@ -148,9 +152,10 @@ func NewAppTimeReel( ) error { return nil }, - store: clockStore, - ctx: ctx, - cancel: cancel, + store: clockStore, + ctx: ctx, + cancel: cancel, + archiveMode: archiveMode, }, nil } @@ -309,11 +314,42 @@ func (a *AppTimeReel) Insert( return a.insertGenesisFrame(frame, frameID) } + // Non-archive: if we have no in-memory frames yet, accept the first as + // pseudo-root + if !a.archiveMode && a.root == nil && len(a.nodes) == 0 { + a.logger.Info("non-archive: accepting first frame as pseudo-root", + zap.String("address", fmt.Sprintf("%x", a.address)), + zap.Uint64("frame_number", frame.Header.FrameNumber)) + return a.insertGenesisFrame(frame, frameID) + } + // Try to find parent parentSelector := string(frame.Header.ParentSelector) parentNode := a.findNodeBySelector(frame.Header.ParentSelector) if parentNode == nil { + if !a.archiveMode && a.head != nil && + frame.Header.FrameNumber > a.head.Frame.Header.FrameNumber { + // ahead-of-head orphan: stage as pending and pre-insert as orphan node + a.addPendingFrame(frame, parentSelector) + + orphan := &FrameNode{ + Frame: frame, + Parent: nil, // reparent later when parent arrives + Children: make(map[string]*FrameNode), + Depth: 1, + } + + a.nodes[frameID] = orphan + a.framesByNumber[frame.Header.FrameNumber] = + append(a.framesByNumber[frame.Header.FrameNumber], orphan) + a.cache.Add(frameID, orphan) + + // Evaluate fork choice (may snap ahead if gap > 360) + a.evaluateForkChoice(orphan) + return nil + } + // Parent not found, add to pending frames a.addPendingFrame(frame, parentSelector) return nil @@ -452,8 +488,30 @@ func (a *AppTimeReel) processPendingFrames( for _, pending := range pendingList { frameID := a.ComputeFrameID(pending.Frame) - // Skip if already processed - if _, exists := a.nodes[frameID]; exists { + if existing, ok := a.nodes[frameID]; ok { + // Re-parent previously pre-inserted orphan + if existing.Parent == nil { + existing.Parent = parentNode + existing.Depth = parentNode.Depth + 1 + parentNode.Children[frameID] = existing + a.framesByNumber[pending.Frame.Header.FrameNumber] = + append( + a.framesByNumber[pending.Frame.Header.FrameNumber], + existing, + ) + a.cache.Add(frameID, existing) + + a.logger.Debug("reparented pending orphan frame", + zap.String("address", fmt.Sprintf("%x", a.address)), + zap.Uint64("frame_number", pending.Frame.Header.FrameNumber), + zap.String("id", frameID)) + + a.processPendingFrames(frameID, existing) + + a.evaluateForkChoice(existing) + } + + // Skip if already processed continue } @@ -498,9 +556,12 @@ func (a *AppTimeReel) findNodeBySelector(selector []byte) *FrameNode { // evaluateForkChoice evaluates fork choice and updates head if necessary func (a *AppTimeReel) evaluateForkChoice(newNode *FrameNode) { - if a.head == nil { + if a.head == nil || (!a.archiveMode && + newNode.Frame.Header.FrameNumber > a.head.Frame.Header.FrameNumber && + newNode.Frame.Header.FrameNumber-a.head.Frame.Header.FrameNumber > 360) { + oldHead := a.head a.head = newNode - a.sendHeadEvent(newNode, nil) + a.sendHeadEvent(newNode, oldHead) return } @@ -705,17 +766,45 @@ func (a *AppTimeReel) evaluateForkChoice(newNode *FrameNode) { } } -// findLeafNodes returns all leaf nodes (nodes with no children) -func (a *AppTimeReel) findLeafNodes() []*FrameNode { +// findLeafNodes returns all leaf nodes (nodes with no children) that are in the +// same connected component as the current head. This prevents spurious fork +// choice across disconnected forests (e.g., after a non-archive snap-ahead). +func (g *AppTimeReel) findLeafNodes() []*FrameNode { var leaves []*FrameNode - for _, node := range a.nodes { - if len(node.Children) == 0 { + if g.head == nil { + // Fallback: no head yet, return all leaves + for _, node := range g.nodes { + if len(node.Children) == 0 { + leaves = append(leaves, node) + } + } + + return leaves + } + + headRoot := g.findRoot(g.head) + for _, node := range g.nodes { + if len(node.Children) != 0 { + continue + } + + if g.findRoot(node) == headRoot { leaves = append(leaves, node) } } + return leaves } +// findRoot walks parents to identify the root of a node +func (a *AppTimeReel) findRoot(n *FrameNode) *FrameNode { + cur := n + for cur != nil && cur.Parent != nil { + cur = cur.Parent + } + return cur +} + // nodeToBranch converts a node and its lineage to a Branch for fork choice func (a *AppTimeReel) nodeToBranch(node *FrameNode) Branch { // Build lineage from this node backwards, but limit to 360 frames @@ -1313,8 +1402,8 @@ func (a *AppTimeReel) pruneOldFrames() { // pruneOldPendingFrames removes pending frames that are too old func (a *AppTimeReel) pruneOldPendingFrames() { - // Prune pending frames older than 5 minutes - const maxPendingAge = 5 * 60 * 1000 // 5 minutes in milliseconds + // Prune pending frames older than 1.5 hours + const maxPendingAge = 1 * 90 * 60 * 1000 // 1.5 hours in milliseconds currentTime := time.Now().UnixMilli() prunedCount := 0 @@ -1432,13 +1521,14 @@ func (a *AppTimeReel) bootstrapFromStore() error { latest, _, err := a.store.GetLatestShardClockFrame(a.address) if err != nil { if errors.Is(err, store.ErrNotFound) { - return nil // fresh DB + return nil } return errors.Wrap(err, "bootstrap from store") } latestNum := latest.Header.FrameNumber + var start uint64 - if latestNum+1 > maxTreeDepth { + if !a.archiveMode && latestNum+1 > maxTreeDepth { start = latestNum - (maxTreeDepth - 1) } else { start = 0 @@ -1478,18 +1568,22 @@ func (a *AppTimeReel) bootstrapFromStore() error { node.Parent = p node.Depth = p.Depth + 1 p.Children[frameID] = node + } else if !a.archiveMode && frame.Header.FrameNumber == start { + // treat it as pseudo-root + node.Depth = 0 + a.logger.Info("non-archive: treating first loaded frame as pseudo-root", + zap.String("address", fmt.Sprintf("%x", a.address)), + zap.Uint64("frame_number", frame.Header.FrameNumber)) } } - if a.root == nil { + if a.root == nil || (!a.archiveMode && frame.Header.FrameNumber == start) { a.root = node } a.nodes[frameID] = node - a.framesByNumber[frame.Header.FrameNumber] = append( - a.framesByNumber[frame.Header.FrameNumber], - node, - ) + a.framesByNumber[frame.Header.FrameNumber] = + append(a.framesByNumber[frame.Header.FrameNumber], node) a.cache.Add(frameID, node) prev = node @@ -1499,12 +1593,18 @@ func (a *AppTimeReel) bootstrapFromStore() error { a.updateTreeMetrics() if a.head != nil { - a.logger.Info( - "bootstrapped app reel from store", + a.logger.Info("bootstrapped app reel from store", zap.String("address", fmt.Sprintf("%x", a.address)), + zap.Uint64("loaded_from", start), zap.Uint64("loaded_to", a.head.Frame.Header.FrameNumber), zap.Int("loaded_count", len(a.nodes)), + zap.Bool("archive_mode", a.archiveMode), ) + if !a.archiveMode && a.root != nil { + a.logger.Info("non-archive: accepting last 360 frames as valid chain", + zap.Uint64("pseudo_root_frame", a.root.Frame.Header.FrameNumber), + zap.Uint64("head_frame", a.head.Frame.Header.FrameNumber)) + } } return nil } @@ -1549,15 +1649,14 @@ func (a *AppTimeReel) persistCanonicalFrames( if len(frames) == 0 { return nil } + txn, err := a.store.NewTransaction(false) if err != nil { return errors.Wrap(err, "persist canonical frames") } + for _, f := range frames { - if err := a.materializeFunc( - txn, - f, - ); err != nil { + if err := a.materializeFunc(txn, f); err != nil { _ = txn.Abort() return errors.Wrap(err, "persist canonical frames") } @@ -1574,8 +1673,24 @@ func (a *AppTimeReel) persistCanonicalFrames( return errors.Wrap(err, "persist canonical frames") } } + if err := txn.Commit(); err != nil { return errors.Wrap(err, "persist canonical frames") } + + // prune old frames in non-archive mode + if !a.archiveMode && a.head != nil && + a.head.Frame.Header.FrameNumber > maxTreeDepth { + oldestToKeep := a.head.Frame.Header.FrameNumber - maxTreeDepth + 1 + if err := a.store.DeleteShardClockFrameRange( + a.address, + 0, + oldestToKeep, + ); err != nil { + a.logger.Error("unable to delete shard frame range", + zap.String("address", fmt.Sprintf("%x", a.address)), + zap.Error(err)) + } + } return nil } diff --git a/node/consensus/time/app_time_reel_test.go b/node/consensus/time/app_time_reel_test.go index 3867ff1b..5812f005 100644 --- a/node/consensus/time/app_time_reel_test.go +++ b/node/consensus/time/app_time_reel_test.go @@ -48,7 +48,7 @@ func TestAppTimeReel_BasicOperations(t *testing.T) { logger, _ := zap.NewDevelopment() address := []byte("test_app_address") s := setupTestClockStore(t) - atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s) + atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s, true) require.NoError(t, err) err = atr.Start() @@ -132,7 +132,7 @@ func TestAppTimeReel_WrongAddress(t *testing.T) { logger, _ := zap.NewDevelopment() address := []byte("correct_address") s := setupTestClockStore(t) - atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s) + atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s, true) require.NoError(t, err) err = atr.Start() @@ -163,7 +163,7 @@ func TestAppTimeReel_Equivocation(t *testing.T) { logger, _ := zap.NewDevelopment() address := []byte("test_app_address") s := setupTestClockStore(t) - atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s) + atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s, true) require.NoError(t, err) err = atr.Start() @@ -265,7 +265,7 @@ func TestAppTimeReel_Fork(t *testing.T) { logger, _ := zap.NewDevelopment() address := []byte("test_app_address") s := setupTestClockStore(t) - atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s) + atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s, true) require.NoError(t, err) err = atr.Start() @@ -339,7 +339,7 @@ func TestAppTimeReel_ParentValidation(t *testing.T) { logger, _ := zap.NewDevelopment() address := []byte("test_app_address") s := setupTestClockStore(t) - atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s) + atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s, true) require.NoError(t, err) err = atr.Start() @@ -406,7 +406,7 @@ func TestAppTimeReel_ForkDetection(t *testing.T) { logger, _ := zap.NewDevelopment() address := []byte("test_app_address") s := setupTestClockStore(t) - atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s) + atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s, true) require.NoError(t, err) err = atr.Start() @@ -489,7 +489,7 @@ func TestAppTimeReel_ForkChoice_MoreSignatures(t *testing.T) { logger, _ := zap.NewDevelopment() address := []byte("test_app_address") s := setupTestClockStore(t) - atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s) + atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s, true) require.NoError(t, err) err = atr.Start() @@ -600,7 +600,7 @@ func TestAppTimeReel_ForkChoice_NoReplacement(t *testing.T) { logger, _ := zap.NewDevelopment() address := []byte("test_app_address") s := setupTestClockStore(t) - atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s) + atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s, true) require.NoError(t, err) err = atr.Start() @@ -711,7 +711,7 @@ func TestAppTimeReel_DeepForkChoice_ReverseInsertion(t *testing.T) { address := []byte("test_app_address") reg := createTestProverRegistry(false) s := setupTestClockStore(t) - atr, err := NewAppTimeReel(logger, address, reg, s) + atr, err := NewAppTimeReel(logger, address, reg, s, true) require.NoError(t, err) err = atr.Start() @@ -1044,7 +1044,7 @@ func TestAppTimeReel_MultipleProvers(t *testing.T) { logger, _ := zap.NewDevelopment() address := []byte("test_app_address") s := setupTestClockStore(t) - atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s) + atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s, true) require.NoError(t, err) err = atr.Start() @@ -1172,7 +1172,7 @@ func TestAppTimeReel_ComplexForkWithOutOfOrderInsertion(t *testing.T) { proverRegistry.On("GetOrderedProvers", mock.Anything, mock.Anything).Return(nil, errors.New("unknown parent selector")) s := setupTestClockStore(t) - atr, err := NewAppTimeReel(logger, address, proverRegistry, s) + atr, err := NewAppTimeReel(logger, address, proverRegistry, s, true) require.NoError(t, err) err = atr.Start() @@ -1389,7 +1389,7 @@ func TestAppTimeReel_TreePruning(t *testing.T) { logger, _ := zap.NewDevelopment() address := []byte("test_app_address") s := setupTestClockStore(t) - atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s) + atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s, true) require.NoError(t, err) err = atr.Start() @@ -1478,7 +1478,7 @@ func TestAppTimeReel_TreePruningWithForks(t *testing.T) { logger, _ := zap.NewDevelopment() address := []byte("test_app_address") s := setupTestClockStore(t) - atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s) + atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s, true) require.NoError(t, err) err = atr.Start() @@ -1598,7 +1598,7 @@ func TestAppTimeReel_ForkChoiceInsertionOrder(t *testing.T) { address := []byte("test_app_address") reg := createTestProverRegistry(false) s := setupTestClockStore(t) - atr, err := NewAppTimeReel(logger, address, reg, s) + atr, err := NewAppTimeReel(logger, address, reg, s, true) require.NoError(t, err) err = atr.Start() @@ -1814,7 +1814,7 @@ func TestAppTimeReel_ForkEventsWithReplay(t *testing.T) { logger, _ := zap.NewDevelopment() address := []byte("test_app_address") s := setupTestClockStore(t) - atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s) + atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s, true) require.NoError(t, err) err = atr.Start() @@ -1997,7 +1997,7 @@ func TestAppTimeReel_ComprehensiveEquivocation(t *testing.T) { logger, _ := zap.NewDevelopment() address := []byte("test_app_address") s := setupTestClockStore(t) - atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s) + atr, err := NewAppTimeReel(logger, address, createTestProverRegistry(true), s, true) require.NoError(t, err) err = atr.Start() @@ -2159,7 +2159,7 @@ func TestAppTimeReel_ProverRegistryForkChoice(t *testing.T) { proverRegistry.On("GetOrderedProvers", mock.Anything, mock.Anything).Return(nil, errors.New("unknown parent selector")) s := setupTestClockStore(t) - atr, err := NewAppTimeReel(logger, address, proverRegistry, s) + atr, err := NewAppTimeReel(logger, address, proverRegistry, s, true) require.NoError(t, err) err = atr.Start() @@ -2290,7 +2290,7 @@ func TestAppTimeReel_ProverRegistryWithOrderedProvers(t *testing.T) { proverRegistry.On("GetOrderedProvers", mock.Anything, mock.Anything).Return([][]byte{[]byte("default_prover")}, nil) s := setupTestClockStore(t) - atr, err := NewAppTimeReel(logger, address, proverRegistry, s) + atr, err := NewAppTimeReel(logger, address, proverRegistry, s, true) require.NoError(t, err) err = atr.Start() diff --git a/node/consensus/time/global_time_reel.go b/node/consensus/time/global_time_reel.go index e551a34b..d0cf073a 100644 --- a/node/consensus/time/global_time_reel.go +++ b/node/consensus/time/global_time_reel.go @@ -338,27 +338,35 @@ func (g *GlobalTimeReel) Insert( if parentNode == nil { if !g.archiveMode { - // In non-archive mode, check if we should accept this frame based on - // frame number proximity to our current head if g.head != nil { - // Check if frame is within reasonable range of our head - if frame.Header.FrameNumber > g.head.Frame.Header.FrameNumber && - frame.Header.FrameNumber <= g.head.Frame.Header.FrameNumber+10 { - // Frame is slightly ahead, add to pending + // Check if frame is ahead of our head + if frame.Header.FrameNumber > g.head.Frame.Header.FrameNumber { + // Frame is ahead, add to pending g.addPendingFrame(frame, parentSelector) - return nil - } else if frame.Header.FrameNumber < g.head.Frame.Header.FrameNumber && - g.head.Frame.Header.FrameNumber-frame.Header.FrameNumber > maxGlobalTreeDepth { - // Frame is too old, reject it - g.logger.Debug( - "rejecting old frame in non-archive mode", - zap.Uint64("frame_number", frame.Header.FrameNumber), - zap.Uint64("head_frame", g.head.Frame.Header.FrameNumber), + + // Insert frame into tree + newNode := &GlobalFrameNode{ + Frame: frame, + Parent: nil, + Children: make(map[string]*GlobalFrameNode), + Depth: 1, + } + + // Add to data structures + g.nodes[frameID] = newNode + g.framesByNumber[frame.Header.FrameNumber] = append( + g.framesByNumber[frame.Header.FrameNumber], + newNode, ) + g.cache.Add(frameID, newNode) + + // Evaluate fork choice if we have competing branches + g.evaluateForkChoice(newNode) return nil } } } + // Parent not found, add to pending frames g.addPendingFrame(frame, parentSelector) return nil @@ -408,7 +416,8 @@ func (g *GlobalTimeReel) Insert( return nil } -// insertGenesisFrame handles genesis frame insertion or pseudo-root in non-archive mode +// insertGenesisFrame handles genesis frame insertion or pseudo-root in +// non-archive mode func (g *GlobalTimeReel) insertGenesisFrame( frame *protobufs.GlobalFrame, frameID string, @@ -419,7 +428,8 @@ func (g *GlobalTimeReel) insertGenesisFrame( } if g.root != nil && !g.archiveMode { - // In non-archive mode, check if this frame should replace the current pseudo-root + // In non-archive mode, check if this frame should replace the current + // pseudo-root if frame.Header.FrameNumber >= g.root.Frame.Header.FrameNumber { // This frame is not older than current root, don't replace return errors.New("frame is not older than current root") @@ -517,8 +527,29 @@ func (g *GlobalTimeReel) processPendingFrames( for _, pending := range pendingList { frameID := g.ComputeFrameID(pending.Frame) - // Skip if already processed - if _, exists := g.nodes[frameID]; exists { + if existing, exists := g.nodes[frameID]; exists { + // Re-parent previously pre-inserted orphan + if existing.Parent == nil { + existing.Parent = parentNode + existing.Depth = parentNode.Depth + 1 + parentNode.Children[frameID] = existing + g.framesByNumber[pending.Frame.Header.FrameNumber] = append( + g.framesByNumber[pending.Frame.Header.FrameNumber], existing) + + g.cache.Add(frameID, existing) + + g.logger.Debug("reparented pending orphan frame", + zap.Uint64("frame_number", pending.Frame.Header.FrameNumber), + zap.String("id", frameID), + zap.String("parent_id", parentFrameID), + ) + + g.processPendingFrames(frameID, existing) + + g.evaluateForkChoice(existing) + } + + // Skip if already processed continue } @@ -564,9 +595,12 @@ func (g *GlobalTimeReel) findNodeBySelector(selector []byte) *GlobalFrameNode { // evaluateForkChoice evaluates fork choice and updates head if necessary func (g *GlobalTimeReel) evaluateForkChoice(newNode *GlobalFrameNode) { - if g.head == nil { + if g.head == nil || (!g.archiveMode && + newNode.Frame.Header.FrameNumber > g.head.Frame.Header.FrameNumber && + newNode.Frame.Header.FrameNumber-g.head.Frame.Header.FrameNumber > 360) { + oldHead := g.head g.head = newNode - g.sendHeadEvent(newNode, nil) + g.sendHeadEvent(newNode, oldHead) return } @@ -602,7 +636,8 @@ func (g *GlobalTimeReel) evaluateForkChoice(newNode *GlobalFrameNode) { } // If only one leaf at max depth, make it head - if len(competingLeaves) == 1 { + if len(competingLeaves) == 1 && + competingLeaves[0].Frame.Header.FrameNumber == g.head.Frame.Header.FrameNumber { chosenNode := competingLeaves[0] if chosenNode != g.head { oldHead := g.head @@ -777,17 +812,45 @@ func (g *GlobalTimeReel) evaluateForkChoice(newNode *GlobalFrameNode) { } } -// findLeafNodes returns all leaf nodes (nodes with no children) +// findLeafNodes returns all leaf nodes (nodes with no children) that are in the +// same connected component as the current head. This prevents spurious fork +// choice across disconnected forests (e.g., after a non-archive snap-ahead). func (g *GlobalTimeReel) findLeafNodes() []*GlobalFrameNode { var leaves []*GlobalFrameNode + if g.head == nil { + // Fallback: no head yet, return all leaves + for _, node := range g.nodes { + if len(node.Children) == 0 { + leaves = append(leaves, node) + } + } + + return leaves + } + + headRoot := g.findRoot(g.head) for _, node := range g.nodes { - if len(node.Children) == 0 { + if len(node.Children) != 0 { + continue + } + + if g.findRoot(node) == headRoot { leaves = append(leaves, node) } } + return leaves } +// findRoot walks parents to identify the root of a node +func (g *GlobalTimeReel) findRoot(n *GlobalFrameNode) *GlobalFrameNode { + cur := n + for cur != nil && cur.Parent != nil { + cur = cur.Parent + } + return cur +} + // nodeToBranch converts a node and its lineage to a Branch for fork choice func (g *GlobalTimeReel) nodeToBranch(node *GlobalFrameNode) Branch { // Build lineage from this node backwards, but limit to maxGlobalTreeDepth @@ -1274,9 +1337,9 @@ func (g *GlobalTimeReel) SetForkChoiceParams(params Params) { g.forkChoiceParams = params } -// pruneOldFrames removes frames older than maxGlobalTreeDepth from the in-memory -// cache to prevent unbounded memory growth. The store handles its own pruning -// based on archive mode. +// pruneOldFrames removes frames older than maxGlobalTreeDepth from the +// in-memory cache to prevent unbounded memory growth. The store handles its own +// pruning based on archive mode. func (g *GlobalTimeReel) pruneOldFrames() { if g.head == nil || g.head.Depth < maxGlobalTreeDepth { return // Not enough frames to prune @@ -1369,8 +1432,8 @@ func (g *GlobalTimeReel) pruneOldFrames() { // pruneOldPendingFrames removes pending frames that are too old func (g *GlobalTimeReel) pruneOldPendingFrames() { - // Prune pending frames older than 5 minutes - const maxPendingAge = 5 * 60 * 1000 // 5 minutes in milliseconds + // Prune pending frames older than 1.5 hours + const maxPendingAge = 1 * 90 * 60 * 1000 // 1.5 hours in milliseconds currentTime := time.Now().UnixMilli() prunedCount := 0 @@ -1598,7 +1661,8 @@ func (g *GlobalTimeReel) bootstrapFromStore() error { } // persistCanonicalFrames writes a contiguous set of canonical frames to the -// store in one txn. In non-archive mode, it also prunes old frames from the store. +// store in one txn. In non-archive mode, it also prunes old frames from the +// store. func (g *GlobalTimeReel) persistCanonicalFrames( frames []*protobufs.GlobalFrame, ) error { diff --git a/node/consensus/time/global_time_reel_test.go b/node/consensus/time/global_time_reel_test.go index 27df16aa..8b4402f1 100644 --- a/node/consensus/time/global_time_reel_test.go +++ b/node/consensus/time/global_time_reel_test.go @@ -1519,6 +1519,254 @@ func TestGlobalTimeReel_ComprehensiveEquivocation(t *testing.T) { } } +func TestGlobalTimeReel_NonArchive_BootstrapLoadsWindowOf360(t *testing.T) { + logger, _ := zap.NewDevelopment() + s := setupTestClockStore(t) + + // Persist 1000 -> 1500 (501 frames) so bootstrap has history to load. + buildAndPersistChain(t, s, 1000, 1500) + + // Start a new reel in non-archive mode; it should bootstrap only last 360. + tr, err := NewGlobalTimeReel(logger, createTestProverRegistry(true), s, 99, false) + require.NoError(t, err) + require.NoError(t, tr.Start()) + defer tr.Stop() + + head, err := tr.GetHead() + require.NoError(t, err) + assert.Equal(t, uint64(1500), head.Header.FrameNumber) + + info := tr.GetTreeInfo() + span := info["tree_span"].(uint64) + assert.LessOrEqual(t, span, uint64(maxGlobalTreeDepth), "tree span must be less than or equal to 360 in non-archive bootstrap") + + // Old in-memory nodes before the 360-window should not be retrievable via + // in-memory index. + _, err = tr.GetFramesByNumber(1000) + assert.Error(t, err, "old frames should not be in memory after non-archive bootstrap") +} + +func TestGlobalTimeReel_NonArchive_SnapForward_WhenGapExceeds360(t *testing.T) { + logger, _ := zap.NewDevelopment() + s := setupTestClockStore(t) + + // Persist a tiny tail 1000 -> 1020, so non-archive starts at 1020. + buildAndPersistChain(t, s, 1000, 1020) + + tr, err := NewGlobalTimeReel(logger, createTestProverRegistry(true), s, 99, false) + require.NoError(t, err) + require.NoError(t, tr.Start()) + defer tr.Stop() + + head, err := tr.GetHead() + require.NoError(t, err) + require.Equal(t, uint64(1020), head.Header.FrameNumber) + + // Insert a future frame whose height is > head + 360 (i.e. 1381). + // Parent is unknown: leave ParentSelector nil/garbage, non-archive path + // should snap to head. + future := &protobufs.GlobalFrame{ + Header: &protobufs.GlobalFrameHeader{ + FrameNumber: 1381, + Timestamp: time.Now().UnixMilli(), + Output: []byte("future_1381"), + ParentSelector: []byte("unknown_parent"), + }, + } + require.NoError(t, tr.Insert(context.Background(), future)) + + newHead, err := tr.GetHead() + require.NoError(t, err) + assert.Equal(t, uint64(1381), newHead.Header.FrameNumber, "gap over 360 should snap head to future frame") +} + +func TestGlobalTimeReel_NonArchive_PrunesStore_AsHeadAdvances(t *testing.T) { + logger, _ := zap.NewDevelopment() + s := setupTestClockStore(t) + + tr, err := NewGlobalTimeReel(logger, createTestProverRegistry(true), s, 99, false) + require.NoError(t, err) + require.NoError(t, tr.Start()) + defer tr.Stop() + + // Insert a contiguous chain via Insert so persistCanonicalFrames runs and + // prunes store. + var prev *protobufs.GlobalFrame + for n := uint64(1); n <= uint64(maxGlobalTreeDepth)+25; n++ { + f := createGlobalFrame(n, prev, []byte(fmt.Sprintf("out%d", n))) + require.NoError(t, tr.Insert(context.Background(), f)) + prev = f + } + + head, err := tr.GetHead() + require.NoError(t, err) + + // Oldest to keep in store should be (head - 360 + 1). + oldestToKeep := head.Header.FrameNumber - maxGlobalTreeDepth + 1 + + // Old frames should be gone from the store, head should remain. + _, err = s.GetGlobalClockFrame(1) + assert.Error(t, err, "very old frame should be pruned from store in non-archive mode") + + latest, err := s.GetLatestGlobalClockFrame() + require.NoError(t, err) + assert.Equal(t, head.Header.FrameNumber, latest.Header.FrameNumber) + + _, err = s.GetGlobalClockFrame(oldestToKeep) + assert.NoError(t, err, "boundary oldestToKeep should not be deleted") +} + +func TestGlobalTimeReel_NonArchive_PendingResolves_WhenParentArrives(t *testing.T) { + logger, _ := zap.NewDevelopment() + s := setupTestClockStore(t) + + tr, err := NewGlobalTimeReel(logger, createTestProverRegistry(true), s, 99, false) + require.NoError(t, err) + require.NoError(t, tr.Start()) + defer tr.Stop() + + ctx := context.Background() + + var prev *protobufs.GlobalFrame + for n := uint64(90); n <= 99; n++ { + f := createGlobalFrame(n, prev, []byte(fmt.Sprintf("base_%d", n))) + require.NoError(t, tr.Insert(ctx, f)) + prev = f + } + + // Insert the child frame (101) first, referencing the output of the parent + // (100), but 100 is not in the reel yet. Set child's ParentSelector to + // hash(out100). + out100 := []byte("base_100") + child101 := &protobufs.GlobalFrame{ + Header: &protobufs.GlobalFrameHeader{ + FrameNumber: 101, + Timestamp: time.Now().UnixMilli(), + Output: []byte("child_101"), + ParentSelector: computeGlobalPoseidonHash(out100), // points to future parent 100 + }, + } + require.NoError(t, tr.Insert(ctx, child101)) + + // Should appear in pending (under the selector for out100). + pending := tr.GetPendingFrames() + require.NotZero(t, len(pending), "child without known parent should be pending") + + // Now insert the missing parent 100 that links to 99 and has output out100. + parent100 := &protobufs.GlobalFrame{ + Header: &protobufs.GlobalFrameHeader{ + FrameNumber: 100, + Timestamp: time.Now().UnixMilli(), + Output: out100, + ParentSelector: computeGlobalPoseidonHash([]byte("base_99")), + }, + } + require.NoError(t, tr.Insert(ctx, parent100)) + + // Give a beat for pending processing. + time.Sleep(25 * time.Millisecond) + + // Pending for that selector should be cleared; head should advance to 101. + after := tr.GetPendingFrames() + for sel, list := range after { + assert.Failf(t, "unexpected pending remains", "selector=%x len=%d", sel, len(list)) + } + + head, err := tr.GetHead() + require.NoError(t, err) + assert.Equal(t, uint64(101), head.Header.FrameNumber) +} + +func TestGlobalTimeReel_NonArchive_SnapThenAppend_NoSpuriousForks(t *testing.T) { + logger, _ := zap.NewDevelopment() + s := setupTestClockStore(t) + + // Seed 0 -> 200 so the store has history + buildAndPersistChain(t, s, 0, 200) + + tr, err := NewGlobalTimeReel(logger, createTestProverRegistry(true), s, 99, false) + require.NoError(t, err) + require.NoError(t, tr.Start()) + defer tr.Stop() + + ctx := context.Background() + eventCh := tr.GetEventCh() + + // Drain any startup/new head events. +drain: + for { + select { + case <-eventCh: + case <-time.After(20 * time.Millisecond): + break drain + } + } + + // Confirm bootstrapped head is 200. + head, err := tr.GetHead() + require.NoError(t, err) + require.Equal(t, uint64(200), head.Header.FrameNumber) + + // Insert a far-ahead tip so that gap > 360 (induces snap ahead). + snapTip := &protobufs.GlobalFrame{ + Header: &protobufs.GlobalFrameHeader{ + FrameNumber: 561, + Timestamp: time.Now().UnixMilli(), + Output: []byte("snap_561"), + ParentSelector: []byte("unknown"), + }, + } + require.NoError(t, tr.Insert(ctx, snapTip)) + + // We should get a fork + select { + case ev := <-eventCh: + require.Equal(t, TimeReelEventForkDetected, ev.Type, "snap should be a fork event") + case <-time.After(200 * time.Millisecond): + t.Fatal("timeout waiting for fork event") + } + + // Now append a few sequential frames (562 -> 566) that chain to the snapped + // head. + var prev = snapTip + var forkEvents int + for n := uint64(562); n <= 566; n++ { + f := &protobufs.GlobalFrame{ + Header: &protobufs.GlobalFrameHeader{ + FrameNumber: n, + Timestamp: time.Now().UnixMilli(), + Output: []byte(fmt.Sprintf("snap_%d", n)), + ParentSelector: computeGlobalPoseidonHash(prev.Header.Output), + }, + } + require.NoError(t, tr.Insert(ctx, f)) + prev = f + + // Expect exactly one new-head event per append, and zero fork events. + select { + case ev := <-eventCh: + if ev.Type == TimeReelEventForkDetected { + forkEvents++ + } + require.Equal(t, TimeReelEventNewHead, ev.Type, "sequential append should be a head advance, not a fork") + case <-time.After(200 * time.Millisecond): + t.Fatalf("timeout waiting for head advance at %d", n) + } + } + + assert.Equal(t, 0, forkEvents, "no fork events should occur when linearly appending after snap") + + // Head should be at 566 + head, err = tr.GetHead() + require.NoError(t, err) + assert.Equal(t, uint64(566), head.Header.FrameNumber) + + // Tree should have exactly one branch in the head's component. + info := tr.GetTreeInfo() + branchCount := info["branch_count"].(int) + assert.Equal(t, 1, branchCount, "should present a single branch after snap + linear append") +} + func mustLatestGlobal(t *testing.T, s *store.PebbleClockStore) *protobufs.GlobalFrame { t.Helper() f, err := s.GetLatestGlobalClockFrame() @@ -1552,3 +1800,36 @@ func assertLatestNumOutput(t *testing.T, s *store.PebbleClockStore, n uint64, ou assert.Equal(t, n, f.Header.FrameNumber) assert.Equal(t, output, f.Header.Output) } + +func createGlobalFrame(num uint64, parent *protobufs.GlobalFrame, out []byte) *protobufs.GlobalFrame { + var sel []byte + if parent != nil { + sel = computeGlobalPoseidonHash(parent.Header.Output) + } + return &protobufs.GlobalFrame{ + Header: &protobufs.GlobalFrameHeader{ + FrameNumber: num, + Timestamp: time.Now().UnixMilli(), + Difficulty: 0, + Output: out, + ParentSelector: sel, + }, + } +} + +func buildAndPersistChain(t *testing.T, s *store.PebbleClockStore, start, end uint64) { + t.Helper() + logger, _ := zap.NewDevelopment() + // note: needs to be non-archive otherwise insert will only set as pending + reel, err := NewGlobalTimeReel(logger, createTestProverRegistry(true), s, 99, false) + require.NoError(t, err) + require.NoError(t, reel.Start()) + defer reel.Stop() + + var prev *protobufs.GlobalFrame + for n := start; n <= end; n++ { + f := createGlobalFrame(n, prev, []byte(fmt.Sprintf("out%d", n))) + require.NoError(t, reel.Insert(context.Background(), f)) + prev = f + } +} diff --git a/node/datarpc/data_worker_ipc_server.go b/node/datarpc/data_worker_ipc_server.go index 7367ae6b..60907842 100644 --- a/node/datarpc/data_worker_ipc_server.go +++ b/node/datarpc/data_worker_ipc_server.go @@ -24,6 +24,7 @@ import ( type DataWorkerIPCServer struct { protobufs.UnimplementedDataIPCServiceServer + listenAddrGRPC string config *config.Config logger *zap.Logger @@ -37,6 +38,7 @@ type DataWorkerIPCServer struct { appConsensusEngineFactory *app.AppConsensusEngineFactory appConsensusEngine *app.AppConsensusEngine server *grpc.Server + frameProver crypto.FrameProver quit chan struct{} } @@ -46,6 +48,7 @@ func NewDataWorkerIPCServer( signerRegistry consensus.SignerRegistry, proverRegistry consensus.ProverRegistry, peerInfoManager p2p.PeerInfoManager, + frameProver crypto.FrameProver, appConsensusEngineFactory *app.AppConsensusEngineFactory, logger *zap.Logger, coreId uint32, @@ -86,6 +89,7 @@ func NewDataWorkerIPCServer( appConsensusEngineFactory: appConsensusEngineFactory, signerRegistry: signerRegistry, proverRegistry: proverRegistry, + frameProver: frameProver, peerInfoManager: peerInfoManager, }, nil } @@ -139,6 +143,7 @@ func (r *DataWorkerIPCServer) RespawnServer(filter []byte) error { nil, map[string]channel.AllowedPeerPolicyType{ "quilibrium.node.application.pb.HypergraphComparisonService": channel.AnyProverPeer, + "quilibrium.node.node.pb.DataIPCService": channel.OnlySelfPeer, "quilibrium.node.global.pb.GlobalService": channel.OnlyGlobalProverPeer, "quilibrium.node.global.pb.AppShardService": channel.OnlyShardProverPeer, "quilibrium.node.global.pb.OnionService": channel.AnyPeer, @@ -183,6 +188,7 @@ func (r *DataWorkerIPCServer) RespawnServer(filter []byte) error { r.logger.Info( "data worker listening", zap.String("address", r.listenAddrGRPC), + zap.String("resolved", lis.Addr().String()), ) if len(filter) != 0 { globalTimeReel, err := r.appConsensusEngineFactory.CreateGlobalTimeReel() @@ -206,3 +212,21 @@ func (r *DataWorkerIPCServer) RespawnServer(filter []byte) error { return nil } + +// CreateJoinProof implements protobufs.DataIPCServiceServer. +func (r *DataWorkerIPCServer) CreateJoinProof( + ctx context.Context, + req *protobufs.CreateJoinProofRequest, +) (*protobufs.CreateJoinProofResponse, error) { + r.logger.Debug("received request to create join proof") + proof := r.frameProver.CalculateMultiProof( + [32]byte(req.Challenge), + req.Difficulty, + req.Ids, + req.ProverIndex, + ) + + return &protobufs.CreateJoinProofResponse{ + Response: proof[:], + }, nil +} diff --git a/node/execution/engines/compute_execution_engine.go b/node/execution/engines/compute_execution_engine.go index 79df70d1..cd402a8e 100644 --- a/node/execution/engines/compute_execution_engine.go +++ b/node/execution/engines/compute_execution_engine.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "math/big" "slices" + "strings" "sync" "github.com/pkg/errors" @@ -23,6 +24,8 @@ import ( "source.quilibrium.com/quilibrium/monorepo/types/keys" ) +var ErrUnsupportedMessageType = errors.New("unsupported message type") + type ComputeExecutionEngine struct { logger *zap.Logger hypergraph hypergraph.Hypergraph @@ -187,31 +190,9 @@ func (e *ComputeExecutionEngine) Prove( *protobufs.MessageRequest, error, ) { - addressStr := string(domain) - e.intrinsicsMutex.RLock() - intrinsic, exists := e.intrinsics[addressStr] - e.intrinsicsMutex.RUnlock() - if !exists { - // Try to load existing intrinsic - loaded, err := compute.LoadComputeIntrinsic( - domain, - e.hypergraph, - hgstate.NewHypergraphState(e.hypergraph), - e.inclusionProver, - e.bulletproofProver, - e.verEnc, - e.decafConstructor, - e.keyManager, - e.compiler, - ) - if err != nil { - return nil, errors.Wrap(err, "prove") - } - - e.intrinsicsMutex.Lock() - e.intrinsics[addressStr] = loaded - e.intrinsicsMutex.Unlock() - intrinsic = loaded + intrinsic, err := e.tryGetIntrinsic(domain) + if err != nil { + return nil, errors.Wrap(err, "prove") } if len(message) < 4 { @@ -219,7 +200,7 @@ func (e *ComputeExecutionEngine) Prove( } request := &protobufs.MessageRequest{} - err := request.FromCanonicalBytes(message) + err = request.FromCanonicalBytes(message) if err != nil { return nil, errors.Wrap(err, "prove") } @@ -294,6 +275,67 @@ func (e *ComputeExecutionEngine) Prove( return nil, errors.Wrap(errors.New("unsupported type"), "prove") } +func (e *ComputeExecutionEngine) Lock( + frameNumber uint64, + address []byte, + message []byte, +) ([][]byte, error) { + intrinsic, err := e.tryGetIntrinsic(address) + if err != nil { + // non-applicable + return nil, nil + } + + if len(message) > 4 && + binary.BigEndian.Uint32(message[:4]) == protobufs.MessageBundleType { + bundle := &protobufs.MessageBundle{} + err = bundle.FromCanonicalBytes(message) + if err != nil { + return nil, errors.Wrap(err, "lock") + } + + addresses := [][]byte{} + for _, r := range bundle.Requests { + req, err := r.ToCanonicalBytes() + if err != nil { + return nil, errors.Wrap(err, "lock") + } + + addrs, err := intrinsic.Lock(frameNumber, req[8:]) + if err != nil { + return nil, err + } + addresses = append(addresses, addrs...) + } + + return addresses, nil + } + + addresses, err := intrinsic.Lock(frameNumber, message) + return addresses, errors.Wrap(err, "lock") +} + +func (e *ComputeExecutionEngine) Unlock() error { + e.intrinsicsMutex.RLock() + errs := []string{} + for _, intrinsic := range e.intrinsics { + err := intrinsic.Unlock() + if err != nil { + errs = append(errs, err.Error()) + } + } + e.intrinsicsMutex.RUnlock() + + if len(errs) != 0 { + return errors.Wrap( + errors.Errorf("multiple errors: %s", strings.Join(errs, ", ")), + "unlock", + ) + } + + return nil +} + func (e *ComputeExecutionEngine) GetCost(message []byte) (*big.Int, error) { if len(message) < 4 { return nil, errors.Wrap(errors.New("invalid message"), "get cost") @@ -485,83 +527,38 @@ func (e *ComputeExecutionEngine) validateIndividualMessage( message *protobufs.MessageRequest, fromBundle bool, ) error { - isComputeOp := false - isUpdate := false - var err error - switch message.Request.(type) { - case *protobufs.MessageRequest_ComputeDeploy: - isComputeOp = true - isUpdate = true - case *protobufs.MessageRequest_ComputeUpdate: - isComputeOp = true - isUpdate = true - case *protobufs.MessageRequest_CodeDeploy: - isComputeOp = true - case *protobufs.MessageRequest_CodeExecute: - isComputeOp = true - case *protobufs.MessageRequest_CodeFinalize: - isComputeOp = true - } + payload, err := e.tryExtractMessageForIntrinsic(message) if err != nil { + if errors.Is(err, ErrUnsupportedMessageType) { + // Not a compute operation, this validation doesn't apply + return nil + } return errors.Wrap(err, "validate individual message") } - if !isComputeOp { - // Not a compute operation, this validation doesn't apply - return nil - } - // For compute deploy operations, just validate the structure - if isUpdate && fromBundle { + if (message.GetComputeDeploy() != nil || message.GetComputeUpdate() != nil) && + fromBundle { return errors.Wrap(message.Validate(), "validate individual message") } // For other operations, try to load the intrinsic and validate - addressStr := string(address) - e.intrinsicsMutex.RLock() - intrinsic, exists := e.intrinsics[addressStr] - e.intrinsicsMutex.RUnlock() - - if !exists { - // Try to load existing intrinsic - loaded, err := compute.LoadComputeIntrinsic( - address, - e.hypergraph, - hgstate.NewHypergraphState(e.hypergraph), - e.inclusionProver, - e.bulletproofProver, - e.verEnc, - e.decafConstructor, - e.keyManager, - e.compiler, - ) - if err != nil { - return errors.Wrap(err, "validate individual message") - } - - e.intrinsicsMutex.Lock() - e.intrinsics[addressStr] = loaded - e.intrinsicsMutex.Unlock() - intrinsic = loaded + intrinsic, err := e.tryGetIntrinsic(address) + if err != nil { + return errors.Wrap(err, "validate individual message") } - payload := []byte{} switch message.Request.(type) { case *protobufs.MessageRequest_ComputeDeploy: - err = errors.New("deployments must be bundled") + return errors.Wrap( + errors.New("deployments must be bundled"), + "validate individual message", + ) case *protobufs.MessageRequest_ComputeUpdate: - err = errors.New("updates must be bundled") - case *protobufs.MessageRequest_CodeDeploy: - payload, err = message.GetCodeDeploy().ToCanonicalBytes() - case *protobufs.MessageRequest_CodeExecute: - payload, err = message.GetCodeExecute().ToCanonicalBytes() - case *protobufs.MessageRequest_CodeFinalize: - payload, err = message.GetCodeFinalize().ToCanonicalBytes() - default: - err = errors.New("unsupported message type") - } - if err != nil { - return errors.Wrap(err, "validate individual message") + return errors.Wrap( + errors.New("updates must be bundled"), + "validate individual message", + ) } // Validate the operation @@ -861,22 +858,7 @@ func (e *ComputeExecutionEngine) processIndividualMessage( fromBundle bool, state state.State, ) (*execution.ProcessMessageResult, error) { - payload := []byte{} - var err error - switch message.Request.(type) { - case *protobufs.MessageRequest_ComputeDeploy: - payload, err = message.GetComputeDeploy().ToCanonicalBytes() - case *protobufs.MessageRequest_ComputeUpdate: - payload, err = message.GetComputeUpdate().ToCanonicalBytes() - case *protobufs.MessageRequest_CodeDeploy: - payload, err = message.GetCodeDeploy().ToCanonicalBytes() - case *protobufs.MessageRequest_CodeExecute: - payload, err = message.GetCodeExecute().ToCanonicalBytes() - case *protobufs.MessageRequest_CodeFinalize: - payload, err = message.GetCodeFinalize().ToCanonicalBytes() - default: - err = errors.New("unsupported message type") - } + payload, err := e.tryExtractMessageForIntrinsic(message) if err != nil { return nil, errors.Wrap(err, "process individual message") } @@ -912,32 +894,9 @@ func (e *ComputeExecutionEngine) processIndividualMessage( } // Otherwise, try to handle it as an operation on existing intrinsic - addressStr := string(address) - e.intrinsicsMutex.RLock() - intrinsic, exists := e.intrinsics[addressStr] - e.intrinsicsMutex.RUnlock() - - if !exists { - // Try to load existing intrinsic - loaded, err := compute.LoadComputeIntrinsic( - address, - e.hypergraph, - state, - e.inclusionProver, - e.bulletproofProver, - e.verEnc, - e.decafConstructor, - e.keyManager, - e.compiler, - ) - if err != nil { - return nil, errors.Wrap(err, "process individual message") - } - - e.intrinsicsMutex.Lock() - e.intrinsics[addressStr] = loaded - e.intrinsicsMutex.Unlock() - intrinsic = loaded + intrinsic, err := e.tryGetIntrinsic(address) + if err != nil { + return nil, errors.Wrap(err, "process individual message") } err = e.validateIndividualMessage(frameNumber, address, message, fromBundle) @@ -970,4 +929,60 @@ func (e *ComputeExecutionEngine) processIndividualMessage( }, nil } +func (e *ComputeExecutionEngine) tryGetIntrinsic( + address []byte, +) (intrinsics.Intrinsic, error) { + addressStr := string(address) + e.intrinsicsMutex.RLock() + intrinsic, exists := e.intrinsics[addressStr] + e.intrinsicsMutex.RUnlock() + + if !exists { + // Try to load existing intrinsic + loaded, err := compute.LoadComputeIntrinsic( + address, + e.hypergraph, + hgstate.NewHypergraphState(e.hypergraph), + e.inclusionProver, + e.bulletproofProver, + e.verEnc, + e.decafConstructor, + e.keyManager, + e.compiler, + ) + if err != nil { + return nil, errors.Wrap(err, "try get intrinsic") + } + + e.intrinsicsMutex.Lock() + e.intrinsics[addressStr] = loaded + e.intrinsicsMutex.Unlock() + intrinsic = loaded + } + + return intrinsic, nil +} + +func (e *ComputeExecutionEngine) tryExtractMessageForIntrinsic( + message *protobufs.MessageRequest, +) ([]byte, error) { + payload := []byte{} + var err error + switch message.Request.(type) { + case *protobufs.MessageRequest_ComputeDeploy: + payload, err = message.GetComputeDeploy().ToCanonicalBytes() + case *protobufs.MessageRequest_ComputeUpdate: + payload, err = message.GetComputeUpdate().ToCanonicalBytes() + case *protobufs.MessageRequest_CodeDeploy: + payload, err = message.GetCodeDeploy().ToCanonicalBytes() + case *protobufs.MessageRequest_CodeExecute: + payload, err = message.GetCodeExecute().ToCanonicalBytes() + case *protobufs.MessageRequest_CodeFinalize: + payload, err = message.GetCodeFinalize().ToCanonicalBytes() + default: + err = ErrUnsupportedMessageType + } + return payload, err +} + var _ execution.ShardExecutionEngine = (*ComputeExecutionEngine)(nil) diff --git a/node/execution/engines/compute_execution_engine_test.go b/node/execution/engines/compute_execution_engine_test.go index a3a58bd6..a232481c 100644 --- a/node/execution/engines/compute_execution_engine_test.go +++ b/node/execution/engines/compute_execution_engine_test.go @@ -16,13 +16,13 @@ import ( "time" "github.com/cloudflare/circl/sign/ed448" - "github.com/iden3/go-iden3-crypto/poseidon" "github.com/libp2p/go-libp2p/core/peer" "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.uber.org/zap" + "golang.org/x/crypto/sha3" "google.golang.org/grpc" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/wrapperspb" @@ -446,7 +446,7 @@ func createTestAppTimeReel( ) *consensustime.AppTimeReel { logger := zap.NewNop() proverRegistry := createTestProverRegistry() - appTimeReel, err := consensustime.NewAppTimeReel(logger, appAddress, proverRegistry, clockStore) + appTimeReel, err := consensustime.NewAppTimeReel(logger, appAddress, proverRegistry, clockStore, true) require.NoError(t, err) return appTimeReel } @@ -1071,10 +1071,10 @@ req:A a rdfs:Property; bundleBytes, err := bundle.ToCanonicalBytes() require.NoError(t, err) - deployHashBI, _ := poseidon.HashBytes(bundleBytes) + deployHash := sha3.Sum256(bundleBytes) msg := &protobufs.Message{ Address: compute.COMPUTE_INTRINSIC_DOMAIN[:], - Hash: deployHashBI.FillBytes(make([]byte, 32)), + Hash: deployHash[:], Payload: bundleBytes, } state := hgstate.NewHypergraphState(mockHG) @@ -1139,10 +1139,10 @@ req:A a rdfs:Property; bundleBytes, err = bundle.ToCanonicalBytes() require.NoError(t, err) - deployHashBI, _ = poseidon.HashBytes(bundleBytes) + deployHash := sha3.Sum256(bundleBytes) msg = &protobufs.Message{ Address: domain, - Hash: deployHashBI.FillBytes(make([]byte, 32)), + Hash: deployHash[:], Payload: bundleBytes, } result, err = engine.ProcessMessage(0, big.NewInt(0), msg.Address, msg.Payload, result.State) @@ -1273,12 +1273,12 @@ req:A a rdfs:Property; require.NoError(t, err) // Create message - hashBI, err := poseidon.HashBytes(ceBytes) + hash := sha3.Sum256(ceBytes) require.NoError(t, err) msg := &protobufs.Message{ Address: domain, - Hash: hashBI.FillBytes(make([]byte, 32)), + Hash: hash[:], Payload: ceBytes, } @@ -1337,12 +1337,12 @@ req:A a rdfs:Property; require.NoError(t, err) // Create message - hashBI, err := poseidon.HashBytes(cfBytes) + hash := sha3.Sum256(cfBytes) require.NoError(t, err) msg := &protobufs.Message{ Address: domain, - Hash: hashBI.FillBytes(make([]byte, 32)), + Hash: hash[:], Payload: cfBytes, } @@ -2366,12 +2366,12 @@ req:A a rdfs:Property; require.NoError(t, err) // Create message - hashBI, err := poseidon.HashBytes(bundleBytes) + hash := sha3.Sum256(bundleBytes) require.NoError(t, err) msg := &protobufs.Message{ Address: domain, - Hash: hashBI.FillBytes(make([]byte, 32)), + Hash: hash[:], Payload: bundleBytes, } @@ -4074,12 +4074,12 @@ req:A a rdfs:Property; require.NoError(t, err) // Create message - hashBI, err := poseidon.HashBytes(bundleBytes) + hash := sha3.Sum256(bundleBytes) require.NoError(t, err) msg := &protobufs.Message{ Address: domain, - Hash: hashBI.FillBytes(make([]byte, 32)), + Hash: hash[:], Payload: bundleBytes, } @@ -5332,12 +5332,12 @@ func createBundledMessage(t *testing.T, domain []byte, operations ...*protobufs. require.NoError(t, err) // Create the message - hashBI, err := poseidon.HashBytes(bundleBytes) + hash := sha3.Sum256(bundleBytes) require.NoError(t, err) return &protobufs.Message{ Address: domain, - Hash: hashBI.FillBytes(make([]byte, 32)), + Hash: hash[:], Payload: bundleBytes, } } diff --git a/node/execution/engines/factory.go b/node/execution/engines/factory.go index 5823fab9..8e8f82cf 100644 --- a/node/execution/engines/factory.go +++ b/node/execution/engines/factory.go @@ -61,6 +61,7 @@ func CreateExecutionEngine( verEnc crypto.VerifiableEncryptor, decafConstructor crypto.DecafConstructor, compiler compiler.CircuitCompiler, + frameProver crypto.FrameProver, mode ExecutionMode, ) (execution.ShardExecutionEngine, error) { switch engineType { @@ -76,6 +77,7 @@ func CreateExecutionEngine( bulletproofProver, verEnc, decafConstructor, + frameProver, ) case EngineTypeCompute: return NewComputeExecutionEngine( @@ -131,6 +133,7 @@ func CreateAllEngines( verEnc crypto.VerifiableEncryptor, decafConstructor crypto.DecafConstructor, compiler compiler.CircuitCompiler, + frameProver crypto.FrameProver, includeGlobal bool, ) ([]execution.ShardExecutionEngine, error) { engines := make([]execution.ShardExecutionEngine, 0, 4) @@ -153,6 +156,7 @@ func CreateAllEngines( verEnc, decafConstructor, compiler, + frameProver, mode, ) if err != nil { @@ -180,6 +184,7 @@ func CreateAllEngines( verEnc, decafConstructor, compiler, + frameProver, mode, ) if err != nil { diff --git a/node/execution/engines/factory_test.go b/node/execution/engines/factory_test.go index 03bf3d11..81419e7d 100644 --- a/node/execution/engines/factory_test.go +++ b/node/execution/engines/factory_test.go @@ -25,6 +25,7 @@ func TestCreateExecutionEngine(t *testing.T) { mockVerEnc := new(mocks.MockVerifiableEncryptor) mockDecaf := new(mocks.MockDecafConstructor) mockCompiler := new(mocks.MockCompiler) + mockFrameProver := new(mocks.MockFrameProver) tests := []struct { name string @@ -79,6 +80,7 @@ func TestCreateExecutionEngine(t *testing.T) { mockVerEnc, mockDecaf, mockCompiler, + mockFrameProver, engines.GlobalMode, ) @@ -109,6 +111,7 @@ func TestCreateAllEngines(t *testing.T) { mockVerEnc := new(mocks.MockVerifiableEncryptor) mockDecaf := new(mocks.MockDecafConstructor) mockCompiler := new(mocks.MockCompiler) + mockFrameProver := new(mocks.MockFrameProver) engines, err := engines.CreateAllEngines( logger, @@ -122,6 +125,7 @@ func TestCreateAllEngines(t *testing.T) { mockVerEnc, mockDecaf, mockCompiler, + mockFrameProver, true, // includeGlobal ) // CreateAllEngines doesn't return error, it just logs warnings diff --git a/node/execution/engines/global_execution_engine.go b/node/execution/engines/global_execution_engine.go index aa5499b2..82504793 100644 --- a/node/execution/engines/global_execution_engine.go +++ b/node/execution/engines/global_execution_engine.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "math/big" "slices" + "strings" "sync" "github.com/pkg/errors" @@ -35,6 +36,7 @@ type GlobalExecutionEngine struct { bulletproofProver crypto.BulletproofProver verEnc crypto.VerifiableEncryptor decafConstructor crypto.DecafConstructor + frameProver crypto.FrameProver // State intrinsics map[string]intrinsics.Intrinsic @@ -54,6 +56,7 @@ func NewGlobalExecutionEngine( bulletproofProver crypto.BulletproofProver, verEnc crypto.VerifiableEncryptor, decafConstructor crypto.DecafConstructor, + frameProver crypto.FrameProver, ) (*GlobalExecutionEngine, error) { return &GlobalExecutionEngine{ logger: logger, @@ -66,6 +69,7 @@ func NewGlobalExecutionEngine( bulletproofProver: bulletproofProver, verEnc: verEnc, decafConstructor: decafConstructor, + frameProver: frameProver, intrinsics: make(map[string]intrinsics.Intrinsic), }, nil } @@ -270,112 +274,13 @@ func (e *GlobalExecutionEngine) validateIndividualMessage( message *protobufs.MessageRequest, fromBundle bool, ) error { - isGlobalOp := false - var err error - switch r := message.Request.(type) { - case *protobufs.MessageRequest_Update: - isGlobalOp = true - case *protobufs.MessageRequest_Join: - for _, f := range r.Join.Filters { - if len(f) >= 32 { - l1 := up2p.GetBloomFilterIndices(f[:32], 256, 3) - path := []uint32{} - for _, p := range f[32:] { - path = append(path, uint32(p)) - } - shards, err := e.shardsStore.GetAppShards( - slices.Concat(l1, f[:32]), - path, - ) - if err != nil { - return errors.Wrap(err, "validate individual message") - } - if len(shards) != 1 || !slices.Equal(shards[0].Path, path) { - return errors.Wrap( - errors.New("invalid shard"), - "validate individual message", - ) - } - } - } - isGlobalOp = true - case *protobufs.MessageRequest_Leave: - isGlobalOp = true - case *protobufs.MessageRequest_Pause: - isGlobalOp = true - case *protobufs.MessageRequest_Resume: - isGlobalOp = true - case *protobufs.MessageRequest_Confirm: - isGlobalOp = true - case *protobufs.MessageRequest_Reject: - isGlobalOp = true - case *protobufs.MessageRequest_Kick: - isGlobalOp = true - } + // Try to get or load the global intrinsic + intrinsic, err := e.tryGetIntrinsic(address) if err != nil { return errors.Wrap(err, "validate individual message") } - if !isGlobalOp { - return errors.Wrap( - errors.New("invalid type"), - "validate individual message", - ) - } - - // Check if the message is for the global intrinsic - if !bytes.Equal(address, intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) { - return errors.Wrap( - errors.New("invalid address for global execution engine"), - "validate individual message", - ) - } - - // Try to get or load the global intrinsic - addressStr := string(address) - e.intrinsicsMutex.RLock() - intrinsic, exists := e.intrinsics[addressStr] - e.intrinsicsMutex.RUnlock() - - if !exists { - // Load the global intrinsic - loaded, err := global.LoadGlobalIntrinsic( - address, - e.hypergraph, - e.inclusionProver, - e.keyManager, - ) - if err != nil { - return errors.Wrap(err, "validate individual message") - } - - e.intrinsicsMutex.Lock() - e.intrinsics[addressStr] = loaded - e.intrinsicsMutex.Unlock() - intrinsic = loaded - } - - payload := []byte{} - switch message.Request.(type) { - case *protobufs.MessageRequest_Update: - payload, err = message.GetUpdate().ToCanonicalBytes() - case *protobufs.MessageRequest_Join: - payload, err = message.GetJoin().ToCanonicalBytes() - case *protobufs.MessageRequest_Leave: - payload, err = message.GetLeave().ToCanonicalBytes() - case *protobufs.MessageRequest_Pause: - payload, err = message.GetPause().ToCanonicalBytes() - case *protobufs.MessageRequest_Resume: - payload, err = message.GetResume().ToCanonicalBytes() - case *protobufs.MessageRequest_Confirm: - payload, err = message.GetConfirm().ToCanonicalBytes() - case *protobufs.MessageRequest_Reject: - payload, err = message.GetReject().ToCanonicalBytes() - case *protobufs.MessageRequest_Kick: - payload, err = message.GetKick().ToCanonicalBytes() - default: - err = errors.New("unsupported message type") - } + payload, err := e.tryExtractMessageForIntrinsic(message) if err != nil { return errors.Wrap(err, "validate individual message") } @@ -462,42 +367,6 @@ func (e *GlobalExecutionEngine) handleBundle( // Process each operation in the bundle sequentially for i, op := range bundle.Requests { - e.logger.Debug( - "processing bundled operation", - zap.Int("operation", i), - zap.String("address", hex.EncodeToString(address)), - ) - - isGlobalOp := false - switch op.Request.(type) { - case *protobufs.MessageRequest_Update: - isGlobalOp = true - case *protobufs.MessageRequest_Join: - isGlobalOp = true - case *protobufs.MessageRequest_Leave: - isGlobalOp = true - case *protobufs.MessageRequest_Pause: - isGlobalOp = true - case *protobufs.MessageRequest_Resume: - isGlobalOp = true - case *protobufs.MessageRequest_Confirm: - isGlobalOp = true - case *protobufs.MessageRequest_Reject: - isGlobalOp = true - case *protobufs.MessageRequest_Kick: - isGlobalOp = true - } - - if !isGlobalOp { - // Skip non-global operations (e.g., token payments, compute ops) - // They are retained in the bundle for reference but not processed here - e.logger.Debug( - "skipping non-global operation in bundle", - zap.Int("operation", i), - ) - continue - } - // Process this operation individually opResponses, err := e.processIndividualMessage( frameNumber, @@ -508,7 +377,13 @@ func (e *GlobalExecutionEngine) handleBundle( state, ) if err != nil { - return nil, errors.Wrap(err, "handle bundle") + // Skip non-global operations (e.g., token payments, compute ops) + // They are retained in the bundle for reference but not processed here + e.logger.Debug( + "skipping non-global operation in bundle", + zap.Int("operation", i), + ) + continue } // Collect responses @@ -535,62 +410,15 @@ func (e *GlobalExecutionEngine) processIndividualMessage( fromBundle bool, state state.State, ) (*execution.ProcessMessageResult, error) { - payload := []byte{} - var err error - switch message.Request.(type) { - case *protobufs.MessageRequest_Update: - payload, err = message.GetUpdate().ToCanonicalBytes() - case *protobufs.MessageRequest_Join: - payload, err = message.GetJoin().ToCanonicalBytes() - case *protobufs.MessageRequest_Leave: - payload, err = message.GetLeave().ToCanonicalBytes() - case *protobufs.MessageRequest_Pause: - payload, err = message.GetPause().ToCanonicalBytes() - case *protobufs.MessageRequest_Resume: - payload, err = message.GetResume().ToCanonicalBytes() - case *protobufs.MessageRequest_Confirm: - payload, err = message.GetConfirm().ToCanonicalBytes() - case *protobufs.MessageRequest_Reject: - payload, err = message.GetReject().ToCanonicalBytes() - case *protobufs.MessageRequest_Kick: - payload, err = message.GetKick().ToCanonicalBytes() - default: - err = errors.New("unsupported message type") - } + payload, err := e.tryExtractMessageForIntrinsic(message) if err != nil { return nil, errors.Wrap(err, "process individual message") } - // Check if the message is for the global intrinsic - if !bytes.Equal(address, intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) { - return nil, errors.Wrap( - errors.New("invalid address for global execution engine"), - "process individual message", - ) - } - // Try to get or load the global intrinsic - addressStr := string(address) - e.intrinsicsMutex.RLock() - intrinsic, exists := e.intrinsics[addressStr] - e.intrinsicsMutex.RUnlock() - - if !exists { - // Load the global intrinsic - loaded, err := global.LoadGlobalIntrinsic( - address, - e.hypergraph, - e.inclusionProver, - e.keyManager, - ) - if err != nil { - return nil, errors.Wrap(err, "process individual message") - } - - e.intrinsicsMutex.Lock() - e.intrinsics[addressStr] = loaded - e.intrinsicsMutex.Unlock() - intrinsic = loaded + intrinsic, err := e.tryGetIntrinsic(address) + if err != nil { + return nil, errors.Wrap(err, "process individual message") } err = e.validateIndividualMessage(frameNumber, address, message, fromBundle) @@ -636,4 +464,155 @@ func (e *GlobalExecutionEngine) Prove( return nil, errors.New("unimplemented") } +func (e *GlobalExecutionEngine) Lock( + frameNumber uint64, + address []byte, + message []byte, +) ([][]byte, error) { + intrinsic, err := e.tryGetIntrinsic(address) + if err != nil { + // non-applicable + return nil, nil + } + + if len(message) > 4 && + binary.BigEndian.Uint32(message[:4]) == protobufs.MessageBundleType { + bundle := &protobufs.MessageBundle{} + err = bundle.FromCanonicalBytes(message) + if err != nil { + return nil, errors.Wrap(err, "lock") + } + + addresses := [][]byte{} + for _, r := range bundle.Requests { + req, err := r.ToCanonicalBytes() + if err != nil { + return nil, errors.Wrap(err, "lock") + } + + addrs, err := intrinsic.Lock(frameNumber, req[8:]) + if err != nil { + return nil, err + } + addresses = append(addresses, addrs...) + } + + return addresses, nil + } + + return intrinsic.Lock(frameNumber, message) +} + +func (e *GlobalExecutionEngine) Unlock() error { + e.intrinsicsMutex.RLock() + errs := []string{} + for _, intrinsic := range e.intrinsics { + err := intrinsic.Unlock() + if err != nil { + errs = append(errs, err.Error()) + } + } + e.intrinsicsMutex.RUnlock() + + if len(errs) != 0 { + return errors.Wrap( + errors.Errorf("multiple errors: %s", strings.Join(errs, ", ")), + "unlock", + ) + } + + return nil +} + +func (e *GlobalExecutionEngine) tryGetIntrinsic(address []byte) ( + intrinsics.Intrinsic, + error, +) { + // Check if the message is for the global intrinsic + if !bytes.Equal(address, intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) { + return nil, errors.Wrap( + errors.New("invalid address for global execution engine"), + "try get intrinsic", + ) + } + + addressStr := string(address) + e.intrinsicsMutex.RLock() + intrinsic, exists := e.intrinsics[addressStr] + e.intrinsicsMutex.RUnlock() + + if !exists { + // Load the global intrinsic + loaded, err := global.LoadGlobalIntrinsic( + address, + e.hypergraph, + e.inclusionProver, + e.keyManager, + e.frameProver, + e.clockStore, + ) + if err != nil { + return nil, errors.Wrap(err, "try get intrinsic") + } + + e.intrinsicsMutex.Lock() + e.intrinsics[addressStr] = loaded + e.intrinsicsMutex.Unlock() + intrinsic = loaded + } + + return intrinsic, nil +} + +func (e *GlobalExecutionEngine) tryExtractMessageForIntrinsic( + message *protobufs.MessageRequest, +) ([]byte, error) { + payload := []byte{} + var err error + switch r := message.Request.(type) { + case *protobufs.MessageRequest_Update: + payload, err = r.Update.ToCanonicalBytes() + case *protobufs.MessageRequest_Join: + for _, f := range r.Join.Filters { + if len(f) >= 32 { + l1 := up2p.GetBloomFilterIndices(f[:32], 256, 3) + path := []uint32{} + for _, p := range f[32:] { + path = append(path, uint32(p)) + } + shards, err := e.shardsStore.GetAppShards( + slices.Concat(l1, f[:32]), + path, + ) + if err != nil { + return nil, errors.Wrap(err, "try extract message for intrinsic") + } + if len(shards) != 1 || !slices.Equal(shards[0].Path, path) { + return nil, errors.Wrap( + errors.New("invalid shard"), + "try extract message for intrinsic", + ) + } + } + } + payload, err = r.Join.ToCanonicalBytes() + case *protobufs.MessageRequest_Leave: + payload, err = r.Leave.ToCanonicalBytes() + case *protobufs.MessageRequest_Pause: + payload, err = r.Pause.ToCanonicalBytes() + case *protobufs.MessageRequest_Resume: + payload, err = r.Resume.ToCanonicalBytes() + case *protobufs.MessageRequest_Confirm: + payload, err = r.Confirm.ToCanonicalBytes() + case *protobufs.MessageRequest_Reject: + payload, err = r.Reject.ToCanonicalBytes() + case *protobufs.MessageRequest_Kick: + payload, err = r.Kick.ToCanonicalBytes() + default: + err = errors.New("unsupported message type") + } + + return payload, errors.Wrap(err, "try extract message for intrinsic") +} + var _ execution.ShardExecutionEngine = (*GlobalExecutionEngine)(nil) diff --git a/node/execution/engines/global_execution_engine_test.go b/node/execution/engines/global_execution_engine_test.go index d7fae7c3..763c1b4b 100644 --- a/node/execution/engines/global_execution_engine_test.go +++ b/node/execution/engines/global_execution_engine_test.go @@ -35,6 +35,7 @@ func TestGlobalExecutionEngine_Start(t *testing.T) { mockBulletproofProver := new(mocks.MockBulletproofProver) mockVerEnc := new(mocks.MockVerifiableEncryptor) mockDecaf := new(mocks.MockDecafConstructor) + mockFrameProver := new(mocks.MockFrameProver) engine, err := engines.NewGlobalExecutionEngine( logger, @@ -47,6 +48,7 @@ func TestGlobalExecutionEngine_Start(t *testing.T) { mockBulletproofProver, mockVerEnc, mockDecaf, + mockFrameProver, ) require.NoError(t, err) @@ -108,7 +110,7 @@ func TestGlobalExecutionEngine_ProcessMessage(t *testing.T) { }, address: []byte("invalid_address"), wantErr: true, - errContains: "invalid address for global execution engine", + errContains: "invalid shard", }, } @@ -124,6 +126,7 @@ func TestGlobalExecutionEngine_ProcessMessage(t *testing.T) { mockBulletproofProver := new(mocks.MockBulletproofProver) mockVerEnc := new(mocks.MockVerifiableEncryptor) mockDecaf := new(mocks.MockDecafConstructor) + mockFrameProver := new(mocks.MockFrameProver) tt.setupMocks(mockHG, mockInclusionProver, mockKeyManager) @@ -138,6 +141,7 @@ func TestGlobalExecutionEngine_ProcessMessage(t *testing.T) { mockBulletproofProver, mockVerEnc, mockDecaf, + mockFrameProver, ) require.NoError(t, err) @@ -208,6 +212,7 @@ func TestGlobalExecutionEngine_AllOperationTypes(t *testing.T) { mockBulletproofProver := new(mocks.MockBulletproofProver) mockVerEnc := new(mocks.MockVerifiableEncryptor) mockDecaf := new(mocks.MockDecafConstructor) + mockFrameProver := new(mocks.MockFrameProver) // Set up mocks for loading global intrinsic mockInclusionProver.On("VerifyInclusion", mock.Anything, mock.Anything, mock.Anything).Return(true, nil).Maybe() @@ -363,6 +368,7 @@ func TestGlobalExecutionEngine_AllOperationTypes(t *testing.T) { mockBulletproofProver, mockVerEnc, mockDecaf, + mockFrameProver, ) require.NoError(t, err) diff --git a/node/execution/engines/hypergraph_execution_engine.go b/node/execution/engines/hypergraph_execution_engine.go index 23c6a1a2..f1e0ea29 100644 --- a/node/execution/engines/hypergraph_execution_engine.go +++ b/node/execution/engines/hypergraph_execution_engine.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "math/big" "slices" + "strings" "sync" "github.com/pkg/errors" @@ -396,29 +397,9 @@ func (e *HypergraphExecutionEngine) validateIndividualMessage( } // For other operations, try to load the intrinsic and validate - addressStr := string(address) - e.intrinsicsMutex.RLock() - intrinsic, exists := e.intrinsics[addressStr] - e.intrinsicsMutex.RUnlock() - - if !exists { - // Try to load existing intrinsic - loaded, err := hypergraphintrinsic.LoadHypergraphIntrinsic( - address, - e.hypergraph, - e.inclusionProver, - e.keyManager, - nil, // Signer can and should be nil for verifier path - e.verEnc, - ) - if err != nil { - return errors.Wrap(err, "validate individual message") - } - - e.intrinsicsMutex.Lock() - e.intrinsics[addressStr] = loaded - e.intrinsicsMutex.Unlock() - intrinsic = loaded + intrinsic, err := e.tryGetIntrinsic(address) + if err != nil { + return errors.Wrap(err, "validate individual message") } payload := []byte{} @@ -486,6 +467,66 @@ func (e *HypergraphExecutionEngine) ProcessMessage( ) } +func (e *HypergraphExecutionEngine) Lock( + frameNumber uint64, + address []byte, + message []byte, +) ([][]byte, error) { + intrinsic, err := e.tryGetIntrinsic(address) + if err != nil { + // non-applicable + return nil, nil + } + + if len(message) > 4 && + binary.BigEndian.Uint32(message[:4]) == protobufs.MessageBundleType { + bundle := &protobufs.MessageBundle{} + err = bundle.FromCanonicalBytes(message) + if err != nil { + return nil, errors.Wrap(err, "lock") + } + + addresses := [][]byte{} + for _, r := range bundle.Requests { + req, err := r.ToCanonicalBytes() + if err != nil { + return nil, errors.Wrap(err, "lock") + } + + addrs, err := intrinsic.Lock(frameNumber, req[8:]) + if err != nil { + return nil, err + } + addresses = append(addresses, addrs...) + } + + return addresses, nil + } + + return intrinsic.Lock(frameNumber, message) +} + +func (e *HypergraphExecutionEngine) Unlock() error { + e.intrinsicsMutex.RLock() + errs := []string{} + for _, intrinsic := range e.intrinsics { + err := intrinsic.Unlock() + if err != nil { + errs = append(errs, err.Error()) + } + } + e.intrinsicsMutex.RUnlock() + + if len(errs) != 0 { + return errors.Wrap( + errors.Errorf("multiple errors: %s", strings.Join(errs, ", ")), + "unlock", + ) + } + + return nil +} + func (e *HypergraphExecutionEngine) handleBundle( frameNumber uint64, feeMultiplier *big.Int, @@ -644,29 +685,9 @@ func (e *HypergraphExecutionEngine) processIndividualMessage( } // Otherwise, try to handle it as an operation on existing intrinsic - addressStr := string(address) - e.intrinsicsMutex.RLock() - intrinsic, exists := e.intrinsics[addressStr] - e.intrinsicsMutex.RUnlock() - - if !exists { - // Try to load existing intrinsic - loaded, err := hypergraphintrinsic.LoadHypergraphIntrinsic( - address, - e.hypergraph, - e.inclusionProver, - e.keyManager, - nil, // Signer can and should be nil for verifier path - e.verEnc, - ) - if err != nil { - return nil, errors.Wrap(err, "process individual message") - } - - e.intrinsicsMutex.Lock() - e.intrinsics[addressStr] = loaded - e.intrinsicsMutex.Unlock() - intrinsic = loaded + intrinsic, err := e.tryGetIntrinsic(address) + if err != nil { + return nil, errors.Wrap(err, "process individual message") } err = e.validateIndividualMessage(frameNumber, address, message, fromBundle) @@ -816,4 +837,35 @@ func (e *HypergraphExecutionEngine) handleDeploy( }, nil } +func (e *HypergraphExecutionEngine) tryGetIntrinsic( + address []byte, +) (intrinsics.Intrinsic, error) { + addressStr := string(address) + e.intrinsicsMutex.RLock() + intrinsic, exists := e.intrinsics[addressStr] + e.intrinsicsMutex.RUnlock() + + if !exists { + // Try to load existing intrinsic + loaded, err := hypergraphintrinsic.LoadHypergraphIntrinsic( + address, + e.hypergraph, + e.inclusionProver, + e.keyManager, + nil, // Signer can and should be nil for verifier path + e.verEnc, + ) + if err != nil { + return nil, errors.Wrap(err, "try get intrinsic") + } + + e.intrinsicsMutex.Lock() + e.intrinsics[addressStr] = loaded + e.intrinsicsMutex.Unlock() + intrinsic = loaded + } + + return intrinsic, nil +} + var _ execution.ShardExecutionEngine = (*HypergraphExecutionEngine)(nil) diff --git a/node/execution/engines/hypergraph_execution_engine_test.go b/node/execution/engines/hypergraph_execution_engine_test.go index a364accc..55731338 100644 --- a/node/execution/engines/hypergraph_execution_engine_test.go +++ b/node/execution/engines/hypergraph_execution_engine_test.go @@ -5,12 +5,12 @@ import ( "math/big" "testing" - "github.com/iden3/go-iden3-crypto/poseidon" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.uber.org/zap" + "golang.org/x/crypto/sha3" hgcrdt "source.quilibrium.com/quilibrium/monorepo/hypergraph" "source.quilibrium.com/quilibrium/monorepo/node/execution/engines" "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/hypergraph" @@ -293,9 +293,8 @@ func TestHypergraphExecutionEngine_BundledMessages(t *testing.T) { } // Set hash - hashBI, err := poseidon.HashBytes(bundleMsg.Payload) - require.NoError(t, err) - bundleMsg.Hash = hashBI.FillBytes(make([]byte, 32)) + hash := sha3.Sum256(bundleMsg.Payload) + bundleMsg.Hash = hash[:] // Process bundle state := hgstate.NewHypergraphState(mockHG) diff --git a/node/execution/engines/token_execution_engine.go b/node/execution/engines/token_execution_engine.go index 9317f191..6e6201d6 100644 --- a/node/execution/engines/token_execution_engine.go +++ b/node/execution/engines/token_execution_engine.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "math/big" "slices" + "strings" "sync" "github.com/pkg/errors" @@ -22,7 +23,8 @@ import ( "source.quilibrium.com/quilibrium/monorepo/types/store" ) -// ExecutionMode defines whether the engine is running in global or application mode +// ExecutionMode defines whether the engine is running in global or application +// mode type ExecutionMode int const ( @@ -435,29 +437,9 @@ func (e *TokenExecutionEngine) validateIndividualMessage( } // For other operations, try to load the intrinsic and validate - addressStr := string(address) - e.intrinsicsMutex.RLock() - intrinsic, exists := e.intrinsics[addressStr] - e.intrinsicsMutex.RUnlock() - - if !exists { // Try to load existing intrinsic - loaded, err := token.LoadTokenIntrinsic( - address, - e.hypergraph, - e.verEnc, - e.decafConstructor, - e.bulletproofProver, - e.inclusionProver, - e.keyManager, - ) - if err != nil { - return errors.Wrap(err, "validate individual message") - } - - e.intrinsicsMutex.Lock() - e.intrinsics[addressStr] = loaded - e.intrinsicsMutex.Unlock() - intrinsic = loaded + intrinsic, err := e.tryGetIntrinsic(address) + if err != nil { + return errors.Wrap(err, "validate individual message") } payload := []byte{} @@ -545,6 +527,66 @@ func (e *TokenExecutionEngine) ProcessMessage( return result, nil } +func (e *TokenExecutionEngine) Lock( + frameNumber uint64, + address []byte, + message []byte, +) ([][]byte, error) { + intrinsic, err := e.tryGetIntrinsic(address) + if err != nil { + // non-applicable + return nil, nil + } + + if len(message) > 4 && + binary.BigEndian.Uint32(message[:4]) == protobufs.MessageBundleType { + bundle := &protobufs.MessageBundle{} + err = bundle.FromCanonicalBytes(message) + if err != nil { + return nil, errors.Wrap(err, "lock") + } + + addresses := [][]byte{} + for _, r := range bundle.Requests { + req, err := r.ToCanonicalBytes() + if err != nil { + return nil, errors.Wrap(err, "lock") + } + + addrs, err := intrinsic.Lock(frameNumber, req[8:]) + if err != nil { + return nil, err + } + addresses = append(addresses, addrs...) + } + + return addresses, nil + } + + return intrinsic.Lock(frameNumber, message) +} + +func (e *TokenExecutionEngine) Unlock() error { + e.intrinsicsMutex.RLock() + errs := []string{} + for _, intrinsic := range e.intrinsics { + err := intrinsic.Unlock() + if err != nil { + errs = append(errs, err.Error()) + } + } + e.intrinsicsMutex.RUnlock() + + if len(errs) != 0 { + return errors.Wrap( + errors.Errorf("multiple errors: %s", strings.Join(errs, ", ")), + "unlock", + ) + } + + return nil +} + func (e *TokenExecutionEngine) handleBundle( frameNumber uint64, feeMultiplier *big.Int, @@ -704,30 +746,9 @@ func (e *TokenExecutionEngine) processIndividualMessage( } // Otherwise, try to handle it as an operation on existing intrinsic - addressStr := string(domain) - e.intrinsicsMutex.RLock() - intrinsic, exists := e.intrinsics[addressStr] - e.intrinsicsMutex.RUnlock() - - if !exists { - // Try to load existing intrinsic - loaded, err := token.LoadTokenIntrinsic( - domain, - e.hypergraph, - e.verEnc, - e.decafConstructor, - e.bulletproofProver, - e.inclusionProver, - e.keyManager, - ) - if err != nil { - return nil, errors.Wrap(err, "process individual message") - } - - e.intrinsicsMutex.Lock() - e.intrinsics[addressStr] = loaded - e.intrinsicsMutex.Unlock() - intrinsic = loaded + intrinsic, err := e.tryGetIntrinsic(domain) + if err != nil { + return nil, errors.Wrap(err, "process individual message") } err = e.validateIndividualMessage(frameNumber, domain, message, fromBundle) @@ -889,4 +910,35 @@ func (e *TokenExecutionEngine) handleDeploy( }, nil } +func (e *TokenExecutionEngine) tryGetIntrinsic( + address []byte, +) (intrinsics.Intrinsic, error) { + addressStr := string(address) + e.intrinsicsMutex.RLock() + intrinsic, exists := e.intrinsics[addressStr] + e.intrinsicsMutex.RUnlock() + + if !exists { // Try to load existing intrinsic + loaded, err := token.LoadTokenIntrinsic( + address, + e.hypergraph, + e.verEnc, + e.decafConstructor, + e.bulletproofProver, + e.inclusionProver, + e.keyManager, + ) + if err != nil { + return nil, errors.Wrap(err, "try get intrinsic") + } + + e.intrinsicsMutex.Lock() + e.intrinsics[addressStr] = loaded + e.intrinsicsMutex.Unlock() + intrinsic = loaded + } + + return intrinsic, nil +} + var _ execution.ShardExecutionEngine = (*TokenExecutionEngine)(nil) diff --git a/node/execution/engines/token_execution_engine_test.go b/node/execution/engines/token_execution_engine_test.go index 6ddf8434..a01b4e6e 100644 --- a/node/execution/engines/token_execution_engine_test.go +++ b/node/execution/engines/token_execution_engine_test.go @@ -7,12 +7,12 @@ import ( "slices" "testing" - "github.com/iden3/go-iden3-crypto/poseidon" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.uber.org/zap" + "golang.org/x/crypto/sha3" "source.quilibrium.com/quilibrium/monorepo/node/execution/engines" "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token" hgstate "source.quilibrium.com/quilibrium/monorepo/node/execution/state/hypergraph" @@ -248,9 +248,8 @@ func TestTokenExecutionEngine_BundledMessages(t *testing.T) { } // Set hash - hashBI, err := poseidon.HashBytes(bundleMsg.Payload) - require.NoError(t, err) - bundleMsg.Hash = hashBI.FillBytes(make([]byte, 32)) + hash := sha3.Sum256(bundleMsg.Payload) + bundleMsg.Hash = hash[:] // Process bundle state := hgstate.NewHypergraphState(mockHG) diff --git a/node/execution/intrinsics/compute/compute_intrinsic.go b/node/execution/intrinsics/compute/compute_intrinsic.go index e649f90d..0da1afa4 100644 --- a/node/execution/intrinsics/compute/compute_intrinsic.go +++ b/node/execution/intrinsics/compute/compute_intrinsic.go @@ -1082,117 +1082,135 @@ func (c *ComputeIntrinsic) InvokeStep( } // Lock implements intrinsics.Intrinsic. -func (c *ComputeIntrinsic) Lock( - writeAddresses [][]byte, - readAddresses [][]byte, -) error { - c.lockedReadsMx.Lock() - c.lockedWritesMx.Lock() - defer c.lockedReadsMx.Unlock() - defer c.lockedWritesMx.Unlock() +func (a *ComputeIntrinsic) Lock( + frameNumber uint64, + input []byte, +) ([][]byte, error) { + a.lockedReadsMx.Lock() + a.lockedWritesMx.Lock() + defer a.lockedReadsMx.Unlock() + defer a.lockedWritesMx.Unlock() + + if a.lockedReads == nil { + a.lockedReads = make(map[string]int) + } - if c.lockedReads == nil { - c.lockedReads = make(map[string]int) + if a.lockedWrites == nil { + a.lockedWrites = make(map[string]struct{}) } - if c.lockedWrites == nil { - c.lockedWrites = make(map[string]struct{}) + // Check type prefix to determine request type + if len(input) < 4 { + observability.LockErrors.WithLabelValues( + "compute", + "invalid_input", + ).Inc() + return nil, errors.Wrap(errors.New("input too short"), "lock") } - for _, address := range writeAddresses { - if _, ok := c.lockedWrites[string(address)]; ok { - return errors.Wrap( + // Read the type prefix + typePrefix := binary.BigEndian.Uint32(input[:4]) + + var reads, writes [][]byte + var err error + + // Handle each type based on type prefix + switch typePrefix { + case protobufs.CodeDeploymentType: + reads, writes, err = a.tryLockCodeDeployment(frameNumber, input) + if err != nil { + return nil, err + } + + observability.LockTotal.WithLabelValues( + "compute", + "code_deployment", + ).Inc() + + case protobufs.CodeExecuteType: + reads, writes, err = a.tryLockCodeExecute(frameNumber, input) + if err != nil { + return nil, err + } + + observability.LockTotal.WithLabelValues("compute", "code_execute").Inc() + + case protobufs.CodeFinalizeType: + reads, writes, err = a.tryLockCodeFinalize(frameNumber, input) + if err != nil { + return nil, err + } + + observability.LockTotal.WithLabelValues( + "compute", + "code_finalize", + ).Inc() + + default: + observability.LockErrors.WithLabelValues( + "compute", + "unknown_type", + ).Inc() + return nil, errors.Wrap( + errors.New("unknown compute request type"), + "lock", + ) + } + + for _, address := range writes { + if _, ok := a.lockedWrites[string(address)]; ok { + return nil, errors.Wrap( fmt.Errorf("address %x is already locked for writing", address), "lock", ) } - if _, ok := c.lockedReads[string(address)]; ok { - return errors.Wrap( + if _, ok := a.lockedReads[string(address)]; ok { + return nil, errors.Wrap( fmt.Errorf("address %x is already locked for reading", address), "lock", ) } } - for _, address := range readAddresses { - if _, ok := c.lockedWrites[string(address)]; ok { - return errors.Wrap( + for _, address := range reads { + if _, ok := a.lockedWrites[string(address)]; ok { + return nil, errors.Wrap( fmt.Errorf("address %x is already locked for writing", address), "lock", ) } } - for _, address := range writeAddresses { - c.lockedWrites[string(address)] = struct{}{} - c.lockedReads[string(address)] = c.lockedReads[string(address)] + 1 - } - - for _, address := range readAddresses { - c.lockedReads[string(address)] = c.lockedReads[string(address)] + 1 - } - - return nil -} - -// Unlock implements intrinsics.Intrinsic. -func (c *ComputeIntrinsic) Unlock( - writeAddresses [][]byte, - readAddresses [][]byte, -) error { - c.lockedReadsMx.Lock() - c.lockedWritesMx.Lock() - defer c.lockedReadsMx.Unlock() - defer c.lockedWritesMx.Unlock() + set := map[string]struct{}{} - if c.lockedReads == nil { - c.lockedReads = make(map[string]int) + for _, address := range writes { + a.lockedWrites[string(address)] = struct{}{} + a.lockedReads[string(address)] = a.lockedReads[string(address)] + 1 + set[string(address)] = struct{}{} } - if c.lockedWrites == nil { - c.lockedWrites = make(map[string]struct{}) + for _, address := range reads { + a.lockedReads[string(address)] = a.lockedReads[string(address)] + 1 + set[string(address)] = struct{}{} } - alteredWriteLocks := make(map[string]struct{}) - for k, v := range c.lockedWrites { - alteredWriteLocks[k] = v + result := [][]byte{} + for a := range set { + result = append(result, []byte(a)) } - for _, address := range writeAddresses { - delete(alteredWriteLocks, string(address)) - } - - for _, address := range readAddresses { - if _, ok := alteredWriteLocks[string(address)]; ok { - return errors.Wrap( - fmt.Errorf("address %x is still locked for writing", address), - "unlock", - ) - } - } + return result, nil +} - for _, address := range writeAddresses { - delete(c.lockedWrites, string(address)) - i, ok := c.lockedReads[string(address)] - if ok { - if i <= 1 { - delete(c.lockedReads, string(address)) - } else { - c.lockedReads[string(address)] = i - 1 - } - } - } +// Unlock implements intrinsics.Intrinsic. +func (a *ComputeIntrinsic) Unlock() error { + a.lockedReadsMx.Lock() + a.lockedWritesMx.Lock() + defer a.lockedReadsMx.Unlock() + defer a.lockedWritesMx.Unlock() - for _, address := range readAddresses { - i, ok := c.lockedReads[string(address)] - if ok { - if i <= 1 { - delete(c.lockedReads, string(address)) - } else { - c.lockedReads[string(address)] = i - 1 - } - } - } + a.lockedReads = make(map[string]int) + a.lockedWrites = make(map[string]struct{}) return nil } @@ -1332,4 +1350,137 @@ type ComputeUpdate struct { OwnerSignature *protobufs.BLS48581AggregateSignature } +func (c *ComputeIntrinsic) tryLockCodeDeployment( + frameNumber uint64, + input []byte, +) ( + [][]byte, + [][]byte, + error, +) { + codeDeployment := &CodeDeployment{} + if err := codeDeployment.FromBytes(input, c.compiler); err != nil { + observability.LockErrors.WithLabelValues( + "compute", + "code_deployment", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + reads, err := codeDeployment.GetReadAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "compute", + "code_deployment", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + writes, err := codeDeployment.GetWriteAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "compute", + "code_deployment", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + return reads, writes, nil +} + +func (c *ComputeIntrinsic) tryLockCodeExecute( + frameNumber uint64, + input []byte, +) ( + [][]byte, + [][]byte, + error, +) { + codeExecute := &CodeExecute{} + if err := codeExecute.FromBytes( + input, + c.hypergraph, + c.bulletproofProver, + c.inclusionProver, + c.verEnc, + c.decafConstructor, + c.keyManager, + c.rdfMultiprover, + ); err != nil { + observability.LockErrors.WithLabelValues( + "compute", + "code_execute", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + reads, err := codeExecute.GetReadAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "compute", + "code_execute", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + writes, err := codeExecute.GetWriteAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "compute", + "code_execute", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + return reads, writes, nil +} + +func (c *ComputeIntrinsic) tryLockCodeFinalize( + frameNumber uint64, + input []byte, +) ( + [][]byte, + [][]byte, + error, +) { + codeFinalize := &CodeFinalize{} + if err := codeFinalize.FromBytes( + input, + c.domain, + c.hypergraph, + c.bulletproofProver, + c.inclusionProver, + c.verEnc, + c.keyManager, + c.config, + nil, + ); err != nil { + observability.LockErrors.WithLabelValues( + "compute", + "code_finalize", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + reads, err := codeFinalize.GetReadAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "compute", + "code_finalize", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + writes, err := codeFinalize.GetWriteAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "compute", + "code_finalize", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + return reads, writes, nil +} + var _ intrinsics.Intrinsic = (*ComputeIntrinsic)(nil) diff --git a/node/execution/intrinsics/compute/compute_intrinsic_code_deployment.go b/node/execution/intrinsics/compute/compute_intrinsic_code_deployment.go index 9c42d380..7c3f98dd 100644 --- a/node/execution/intrinsics/compute/compute_intrinsic_code_deployment.go +++ b/node/execution/intrinsics/compute/compute_intrinsic_code_deployment.go @@ -85,6 +85,37 @@ func (c *CodeDeployment) Prove(frameNumber uint64) (err error) { return nil } +func (c *CodeDeployment) GetReadAddresses( + frameNumber uint64, +) ([][]byte, error) { + return nil, nil +} + +func (c *CodeDeployment) GetWriteAddresses( + frameNumber uint64, +) ([][]byte, error) { + // Get the domain from the hypergraph + domain := c.Domain + + // Generate a unique address for this code file + codeAddressBI, err := poseidon.HashBytes( + slices.Concat( + domain[:], + c.Circuit, + ), + ) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + codeAddress := codeAddressBI.FillBytes(make([]byte, 32)) + codeFullAddress := [64]byte{} + copy(codeFullAddress[:32], c.Domain[:]) + copy(codeFullAddress[32:], codeAddress) + + return [][]byte{codeFullAddress[:]}, nil +} + // Verify implements intrinsics.IntrinsicOperation func (c *CodeDeployment) Verify(frameNumber uint64) (bool, error) { buf := bytes.NewReader(c.Circuit) diff --git a/node/execution/intrinsics/compute/compute_intrinsic_code_execute.go b/node/execution/intrinsics/compute/compute_intrinsic_code_execute.go index 2cd025bb..acc9079d 100644 --- a/node/execution/intrinsics/compute/compute_intrinsic_code_execute.go +++ b/node/execution/intrinsics/compute/compute_intrinsic_code_execute.go @@ -5,6 +5,7 @@ import ( "encoding/binary" "fmt" "math/big" + "slices" "github.com/pkg/errors" hg "source.quilibrium.com/quilibrium/monorepo/node/execution/state/hypergraph" @@ -330,6 +331,21 @@ func (c *CodeExecute) Prove(frameNumber uint64) error { return nil } +func (c *CodeExecute) GetReadAddresses( + frameNumber uint64, +) ([][]byte, error) { + return nil, nil +} + +func (c *CodeExecute) GetWriteAddresses( + frameNumber uint64, +) ([][]byte, error) { + return [][]byte{slices.Concat( + c.Domain[:], + c.Rendezvous[:], + )}, nil +} + // Verify implements intrinsics.IntrinsicOperation. func (c *CodeExecute) Verify(frameNumber uint64) (bool, error) { if !bytes.Equal(c.ProofOfPayment[0], make([]byte, 56)) { diff --git a/node/execution/intrinsics/compute/compute_intrinsic_code_finalize.go b/node/execution/intrinsics/compute/compute_intrinsic_code_finalize.go index 32d9be0d..102e160f 100644 --- a/node/execution/intrinsics/compute/compute_intrinsic_code_finalize.go +++ b/node/execution/intrinsics/compute/compute_intrinsic_code_finalize.go @@ -302,6 +302,47 @@ func (c *CodeFinalize) Prove(frameNumber uint64) error { return errors.Wrap(err, "prove") } +func (c *CodeFinalize) GetReadAddresses( + frameNumber uint64, +) ([][]byte, error) { + return nil, nil +} + +func (c *CodeFinalize) GetWriteAddresses( + frameNumber uint64, +) ([][]byte, error) { + // Generate results address + resultsBI, err := poseidon.HashBytes(slices.Concat( + c.Rendezvous[:], + []byte("RESULTS_CODE_FINALIZE"), + )) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + resultsAddress := resultsBI.FillBytes(make([]byte, 32)) + + // Generate state changes address similar to results address + changesBI, err := poseidon.HashBytes(slices.Concat( + c.Rendezvous[:], + []byte("STATE_CHANGES_CODE_FINALIZE"), + )) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + changesAddress := changesBI.FillBytes(make([]byte, 32)) + + return [][]byte{ + slices.Concat( + c.domain[:], + resultsAddress, + ), + slices.Concat( + c.domain[:], + changesAddress, + ), + }, nil +} + // Verify implements intrinsics.IntrinsicOperation. func (c *CodeFinalize) Verify(frameNumber uint64) (bool, error) { // Verify all results are present diff --git a/node/execution/intrinsics/compute/compute_intrinsic_rbls48581_ferret_integration_test.go b/node/execution/intrinsics/compute/compute_intrinsic_rbls48581_ferret_integration_test.go index 646c49bd..0e9ba5bb 100644 --- a/node/execution/intrinsics/compute/compute_intrinsic_rbls48581_ferret_integration_test.go +++ b/node/execution/intrinsics/compute/compute_intrinsic_rbls48581_ferret_integration_test.go @@ -392,45 +392,6 @@ func main(a, b int) int { assert.Contains(t, err.Error(), "unknown operation type: 99") }) - // Test Lock/Unlock mechanism - t.Run("LockUnlock", func(t *testing.T) { - // Test addresses - writeAddr1 := []byte("write_address_1") - writeAddr2 := []byte("write_address_2") - readAddr1 := []byte("read_address_1") - readAddr2 := []byte("read_address_2") - - // Lock addresses - err := computeIntrinsic.Lock([][]byte{writeAddr1}, [][]byte{readAddr1}) - require.NoError(t, err) - - // Try to lock same write address again - should fail - err = computeIntrinsic.Lock([][]byte{writeAddr1}, [][]byte{}) - assert.Error(t, err) - assert.Contains(t, err.Error(), "already locked for writing") - - // Try to lock for reading an address that's locked for writing - should fail - err = computeIntrinsic.Lock([][]byte{}, [][]byte{writeAddr1}) - assert.Error(t, err) - assert.Contains(t, err.Error(), "already locked for writing") - - // Lock additional addresses - err = computeIntrinsic.Lock([][]byte{writeAddr2}, [][]byte{readAddr2}) - require.NoError(t, err) - - // Unlock first set - err = computeIntrinsic.Unlock([][]byte{writeAddr1}, [][]byte{readAddr1}) - require.NoError(t, err) - - // Now we should be able to lock writeAddr1 again - err = computeIntrinsic.Lock([][]byte{writeAddr1}, [][]byte{}) - require.NoError(t, err) - - // Unlock all - err = computeIntrinsic.Unlock([][]byte{writeAddr1, writeAddr2}, [][]byte{readAddr2}) - require.NoError(t, err) - }) - // Test LoadComputeIntrinsic t.Run("LoadComputeIntrinsic", func(t *testing.T) { var state state.State = hgstate.NewHypergraphState(hg) diff --git a/node/execution/intrinsics/global/global_conversions.go b/node/execution/intrinsics/global/global_conversions.go index 6fdf6ea2..c19a4133 100644 --- a/node/execution/intrinsics/global/global_conversions.go +++ b/node/execution/intrinsics/global/global_conversions.go @@ -7,6 +7,7 @@ import ( "source.quilibrium.com/quilibrium/monorepo/types/hypergraph" "source.quilibrium.com/quilibrium/monorepo/types/keys" "source.quilibrium.com/quilibrium/monorepo/types/schema" + "source.quilibrium.com/quilibrium/monorepo/types/store" "source.quilibrium.com/quilibrium/monorepo/types/tries" ) @@ -147,6 +148,8 @@ func ProverJoinFromProtobuf( signer crypto.Signer, inclusionProver crypto.InclusionProver, keyManager keys.KeyManager, + frameProver crypto.FrameProver, + frameStore store.ClockStore, ) (*ProverJoin, error) { if pb == nil { return nil, nil @@ -178,10 +181,13 @@ func ProverJoinFromProtobuf( FrameNumber: pb.FrameNumber, PublicKeySignatureBLS48581: *pubKeySig, MergeTargets: mergeTargets, - // Private fields will be set by caller - hypergraph: hg, - keyManager: keyManager, - rdfMultiprover: nil, // Will be set by caller + DelegateAddress: pb.DelegateAddress, + Proof: pb.Proof, + hypergraph: hg, + keyManager: keyManager, + rdfMultiprover: nil, // Will be set by caller + frameProver: frameProver, + frameStore: frameStore, }, nil } @@ -201,6 +207,8 @@ func (p *ProverJoin) ToProtobuf() *protobufs.ProverJoin { Filters: p.Filters, FrameNumber: p.FrameNumber, PublicKeySignatureBls48581: p.PublicKeySignatureBLS48581.ToProtobuf(), + Proof: p.Proof, + DelegateAddress: p.DelegateAddress, MergeTargets: mergeTargets, } } @@ -582,6 +590,8 @@ func GlobalRequestFromProtobuf( signer crypto.Signer, inclusionProver crypto.InclusionProver, keyManager keys.KeyManager, + frameProver crypto.FrameProver, + frameStore store.ClockStore, ) (interface{}, error) { if pb == nil { return nil, nil @@ -596,6 +606,8 @@ func GlobalRequestFromProtobuf( signer, inclusionProver, keyManager, + frameProver, + frameStore, ) case *protobufs.MessageRequest_Leave: diff --git a/node/execution/intrinsics/global/global_intrinsic.go b/node/execution/intrinsics/global/global_intrinsic.go index 6295b326..794bd801 100644 --- a/node/execution/intrinsics/global/global_intrinsic.go +++ b/node/execution/intrinsics/global/global_intrinsic.go @@ -17,6 +17,7 @@ import ( "source.quilibrium.com/quilibrium/monorepo/types/hypergraph" "source.quilibrium.com/quilibrium/monorepo/types/keys" "source.quilibrium.com/quilibrium/monorepo/types/schema" + "source.quilibrium.com/quilibrium/monorepo/types/store" ) type GlobalIntrinsic struct { @@ -29,6 +30,8 @@ type GlobalIntrinsic struct { rdfMultiprover *schema.RDFMultiprover hypergraph hypergraph.Hypergraph keyManager keys.KeyManager + frameProver crypto.FrameProver + frameStore store.ClockStore } var GLOBAL_RDF_SCHEMA = `BASE @@ -217,7 +220,7 @@ func (a *GlobalIntrinsic) Validate( // Check type prefix to determine request type if len(input) < 4 { - observability.InvokeStepErrors.WithLabelValues( + observability.ValidateErrors.WithLabelValues( "global", "invalid_input", ).Inc() @@ -247,6 +250,8 @@ func (a *GlobalIntrinsic) Validate( nil, nil, a.keyManager, + a.frameProver, + a.frameStore, ) if err != nil { observability.ValidateErrors.WithLabelValues( @@ -675,6 +680,8 @@ func (a *GlobalIntrinsic) InvokeStep( nil, nil, a.keyManager, + a.frameProver, + a.frameStore, ) if err != nil { observability.InvokeStepErrors.WithLabelValues( @@ -1185,9 +1192,9 @@ func (a *GlobalIntrinsic) InvokeStep( // Lock implements intrinsics.Intrinsic. func (a *GlobalIntrinsic) Lock( - writeAddresses [][]byte, - readAddresses [][]byte, -) error { + frameNumber uint64, + input []byte, +) ([][]byte, error) { a.lockedReadsMx.Lock() a.lockedWritesMx.Lock() defer a.lockedReadsMx.Unlock() @@ -1201,102 +1208,555 @@ func (a *GlobalIntrinsic) Lock( a.lockedWrites = make(map[string]struct{}) } - for _, address := range writeAddresses { + // Check type prefix to determine request type + if len(input) < 4 { + observability.LockErrors.WithLabelValues( + "global", + "invalid_input", + ).Inc() + return nil, errors.Wrap(errors.New("input too short"), "lock") + } + + // Read the type prefix + typePrefix := binary.BigEndian.Uint32(input[:4]) + + var reads, writes [][]byte + var err error + + // Handle each type based on type prefix + switch typePrefix { + case protobufs.ProverJoinType: + reads, writes, err = a.tryLockJoin(frameNumber, input) + if err != nil { + return nil, err + } + + observability.LockTotal.WithLabelValues("global", "prover_join").Inc() + + case protobufs.ProverLeaveType: + reads, writes, err = a.tryLockLeave(frameNumber, input) + if err != nil { + return nil, err + } + + observability.LockTotal.WithLabelValues( + "global", + "prover_leave", + ).Inc() + + case protobufs.ProverPauseType: + reads, writes, err = a.tryLockPause(frameNumber, input) + if err != nil { + return nil, err + } + + observability.LockTotal.WithLabelValues( + "global", + "prover_pause", + ).Inc() + + case protobufs.ProverResumeType: + reads, writes, err = a.tryLockResume(frameNumber, input) + if err != nil { + return nil, err + } + + observability.LockTotal.WithLabelValues( + "global", + "prover_resume", + ).Inc() + + case protobufs.ProverConfirmType: + reads, writes, err = a.tryLockConfirm(frameNumber, input) + if err != nil { + return nil, err + } + + observability.LockTotal.WithLabelValues( + "global", + "prover_confirm", + ).Inc() + + case protobufs.ProverRejectType: + reads, writes, err = a.tryLockReject(frameNumber, input) + if err != nil { + return nil, err + } + + observability.LockTotal.WithLabelValues( + "global", + "prover_reject", + ).Inc() + + case protobufs.ProverKickType: + reads, writes, err = a.tryLockKick(frameNumber, input) + if err != nil { + return nil, err + } + + observability.LockTotal.WithLabelValues("global", "prover_kick").Inc() + + default: + observability.LockErrors.WithLabelValues( + "global", + "unknown_type", + ).Inc() + return nil, errors.Wrap( + errors.New("unknown global request type"), + "lock", + ) + } + + for _, address := range writes { if _, ok := a.lockedWrites[string(address)]; ok { - return errors.Wrap( + return nil, errors.Wrap( fmt.Errorf("address %x is already locked for writing", address), "lock", ) } if _, ok := a.lockedReads[string(address)]; ok { - return errors.Wrap( + return nil, errors.Wrap( fmt.Errorf("address %x is already locked for reading", address), "lock", ) } } - for _, address := range readAddresses { + for _, address := range reads { if _, ok := a.lockedWrites[string(address)]; ok { - return errors.Wrap( + return nil, errors.Wrap( fmt.Errorf("address %x is already locked for writing", address), "lock", ) } } - for _, address := range writeAddresses { + set := map[string]struct{}{} + + for _, address := range writes { a.lockedWrites[string(address)] = struct{}{} a.lockedReads[string(address)] = a.lockedReads[string(address)] + 1 + set[string(address)] = struct{}{} } - for _, address := range readAddresses { + for _, address := range reads { a.lockedReads[string(address)] = a.lockedReads[string(address)] + 1 + set[string(address)] = struct{}{} } - return nil + result := [][]byte{} + for a := range set { + result = append(result, []byte(a)) + } + + return result, nil } // Unlock implements intrinsics.Intrinsic. -func (a *GlobalIntrinsic) Unlock( - writeAddresses [][]byte, - readAddresses [][]byte, -) error { +func (a *GlobalIntrinsic) Unlock() error { a.lockedReadsMx.Lock() a.lockedWritesMx.Lock() defer a.lockedReadsMx.Unlock() defer a.lockedWritesMx.Unlock() - if a.lockedReads == nil { - a.lockedReads = make(map[string]int) + a.lockedReads = make(map[string]int) + a.lockedWrites = make(map[string]struct{}) + + return nil +} + +func (a *GlobalIntrinsic) tryLockJoin(frameNumber uint64, input []byte) ( + [][]byte, + [][]byte, + error, +) { + // Parse ProverJoin directly from input + pbJoin := &protobufs.ProverJoin{} + if err := pbJoin.FromCanonicalBytes(input); err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_join", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - if a.lockedWrites == nil { - a.lockedWrites = make(map[string]struct{}) + // Convert from protobuf to intrinsics type + op, err := ProverJoinFromProtobuf( + pbJoin, + a.hypergraph, + nil, + nil, + a.keyManager, + a.frameProver, + a.frameStore, + ) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_join", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - alteredWriteLocks := make(map[string]struct{}) - for k, v := range a.lockedWrites { - alteredWriteLocks[k] = v + // Set runtime dependencies + op.rdfMultiprover = a.rdfMultiprover + op.hypergraph = a.hypergraph + op.keyManager = a.keyManager + + reads, err := op.GetReadAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_join", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - for _, address := range writeAddresses { - delete(alteredWriteLocks, string(address)) + writes, err := op.GetWriteAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_join", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - for _, address := range readAddresses { - if _, ok := alteredWriteLocks[string(address)]; ok { - return errors.Wrap( - fmt.Errorf("address %x is still locked for writing", address), - "unlock", - ) - } + return reads, writes, nil +} + +func (a *GlobalIntrinsic) tryLockLeave(frameNumber uint64, input []byte) ( + [][]byte, + [][]byte, + error, +) { + // Parse ProverLeave directly from input + pbLeave := &protobufs.ProverLeave{} + if err := pbLeave.FromCanonicalBytes(input); err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_leave", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - for _, address := range writeAddresses { - delete(a.lockedWrites, string(address)) - i, ok := a.lockedReads[string(address)] - if ok { - if i <= 1 { - delete(a.lockedReads, string(address)) - } else { - a.lockedReads[string(address)] = i - 1 - } - } + // Convert from protobuf to intrinsics type + op, err := ProverLeaveFromProtobuf( + pbLeave, + a.hypergraph, + nil, + nil, + a.keyManager, + ) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_leave", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - for _, address := range readAddresses { - i, ok := a.lockedReads[string(address)] - if ok { - if i <= 1 { - delete(a.lockedReads, string(address)) - } else { - a.lockedReads[string(address)] = i - 1 - } - } + // Set runtime dependencies + op.rdfMultiprover = a.rdfMultiprover + op.hypergraph = a.hypergraph + op.keyManager = a.keyManager + + reads, err := op.GetReadAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_leave", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - return nil + writes, err := op.GetWriteAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_leave", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + return reads, writes, nil +} + +func (a *GlobalIntrinsic) tryLockPause(frameNumber uint64, input []byte) ( + [][]byte, + [][]byte, + error, +) { + // Parse ProverPause directly from input + pbPause := &protobufs.ProverPause{} + if err := pbPause.FromCanonicalBytes(input); err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_pause", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + // Convert from protobuf to intrinsics type + op, err := ProverPauseFromProtobuf( + pbPause, + a.hypergraph, + nil, + nil, + a.keyManager, + ) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_pause", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + // Set runtime dependencies + op.rdfMultiprover = a.rdfMultiprover + op.hypergraph = a.hypergraph + op.keyManager = a.keyManager + + reads, err := op.GetReadAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_pause", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + writes, err := op.GetWriteAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_pause", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + return reads, writes, nil +} + +func (a *GlobalIntrinsic) tryLockResume(frameNumber uint64, input []byte) ( + [][]byte, + [][]byte, + error, +) { + // Parse ProverResume directly from input + pbResume := &protobufs.ProverResume{} + if err := pbResume.FromCanonicalBytes(input); err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_resume", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + // Convert from protobuf to intrinsics type + op, err := ProverResumeFromProtobuf( + pbResume, + a.hypergraph, + nil, + nil, + a.keyManager, + ) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_resume", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + // Set runtime dependencies + op.rdfMultiprover = a.rdfMultiprover + op.hypergraph = a.hypergraph + op.keyManager = a.keyManager + + reads, err := op.GetReadAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_resume", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + writes, err := op.GetWriteAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_resume", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + return reads, writes, nil +} + +func (a *GlobalIntrinsic) tryLockConfirm(frameNumber uint64, input []byte) ( + [][]byte, + [][]byte, + error, +) { + // Parse ProverConfirm directly from input + pbConfirm := &protobufs.ProverConfirm{} + if err := pbConfirm.FromCanonicalBytes(input); err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_confirm", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + // Convert from protobuf to intrinsics type + op, err := ProverConfirmFromProtobuf( + pbConfirm, + a.hypergraph, + nil, + nil, + a.keyManager, + ) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_confirm", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + // Set runtime dependencies + op.rdfMultiprover = a.rdfMultiprover + op.hypergraph = a.hypergraph + op.keyManager = a.keyManager + + reads, err := op.GetReadAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_confirm", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + writes, err := op.GetWriteAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_confirm", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + return reads, writes, nil +} + +func (a *GlobalIntrinsic) tryLockReject(frameNumber uint64, input []byte) ( + [][]byte, + [][]byte, + error, +) { + // Parse ProverReject directly from input + pbReject := &protobufs.ProverReject{} + if err := pbReject.FromCanonicalBytes(input); err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_reject", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + // Convert from protobuf to intrinsics type + op, err := ProverRejectFromProtobuf( + pbReject, + a.hypergraph, + nil, + nil, + a.keyManager, + ) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_reject", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + // Set runtime dependencies + op.rdfMultiprover = a.rdfMultiprover + op.hypergraph = a.hypergraph + op.keyManager = a.keyManager + + reads, err := op.GetReadAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_reject", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + writes, err := op.GetWriteAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_reject", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + return reads, writes, nil +} + +func (a *GlobalIntrinsic) tryLockKick(frameNumber uint64, input []byte) ( + [][]byte, + [][]byte, + error, +) { + // Parse ProverKick directly from input + pbKick := &protobufs.ProverKick{} + if err := pbKick.FromCanonicalBytes(input); err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_kick", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + // Convert from protobuf to intrinsics type + op, err := ProverKickFromProtobuf(pbKick, a.hypergraph, nil, a.keyManager) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_kick", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + // Set runtime dependencies + op.rdfMultiprover = a.rdfMultiprover + op.hypergraph = a.hypergraph + + reads, err := op.GetReadAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_kick", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + writes, err := op.GetWriteAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "global", + "prover_kick", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + return reads, writes, nil } // LoadGlobalIntrinsic loads the global intrinsic from the global intrinsic @@ -1307,6 +1767,8 @@ func LoadGlobalIntrinsic( hypergraph hypergraph.Hypergraph, inclusionProver crypto.InclusionProver, keyManager keys.KeyManager, + frameProver crypto.FrameProver, + frameStore store.ClockStore, ) (*GlobalIntrinsic, error) { // Verify the address is the global intrinsic address if !bytes.Equal(address, intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) { @@ -1329,6 +1791,8 @@ func LoadGlobalIntrinsic( rdfMultiprover: rdfMultiprover, hypergraph: hypergraph, keyManager: keyManager, + frameProver: frameProver, + frameStore: frameStore, }, nil } diff --git a/node/execution/intrinsics/global/global_intrinsic_rbls48581_integration_test.go b/node/execution/intrinsics/global/global_intrinsic_rbls48581_integration_test.go index 7d41154e..3d617836 100644 --- a/node/execution/intrinsics/global/global_intrinsic_rbls48581_integration_test.go +++ b/node/execution/intrinsics/global/global_intrinsic_rbls48581_integration_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" + "golang.org/x/crypto/sha3" "source.quilibrium.com/quilibrium/monorepo/bls48581" "source.quilibrium.com/quilibrium/monorepo/bulletproofs" "source.quilibrium.com/quilibrium/monorepo/config" @@ -21,11 +22,13 @@ import ( "source.quilibrium.com/quilibrium/monorepo/node/keys" "source.quilibrium.com/quilibrium/monorepo/node/store" "source.quilibrium.com/quilibrium/monorepo/node/tests" + "source.quilibrium.com/quilibrium/monorepo/protobufs" "source.quilibrium.com/quilibrium/monorepo/types/crypto" "source.quilibrium.com/quilibrium/monorepo/types/execution/intrinsics" "source.quilibrium.com/quilibrium/monorepo/types/hypergraph" "source.quilibrium.com/quilibrium/monorepo/types/schema" qcrypto "source.quilibrium.com/quilibrium/monorepo/types/tries" + "source.quilibrium.com/quilibrium/monorepo/vdf" "source.quilibrium.com/quilibrium/monorepo/verenc" ) @@ -112,15 +115,24 @@ func TestGlobalProverOperations_Integration(t *testing.T) { // Test data filter := []byte("integration-test-filter000000000000000") filter2 := []byte("integration-test-filter000000000000002") - frameNumber := uint64(123456789) - + frameNumber := uint64(100) + pebbleDB := store.NewPebbleDB(zap.L(), &config.DBConfig{InMemoryDONOTUSE: true, Path: ".test/global"}, 0) + frameStore := store.NewPebbleClockStore(pebbleDB, zap.L()) + txn, err := frameStore.NewTransaction(false) + require.NoError(t, err) + frameStore.PutGlobalClockFrame(&protobufs.GlobalFrame{Header: &protobufs.GlobalFrameHeader{FrameNumber: 100, Output: make([]byte, 516), Difficulty: 50000}}, txn) + txn.Commit() // Test ProverJoin with signatures t.Run("ProverJoin", func(t *testing.T) { // Create a fresh hypergraph for ProverJoin (no pre-existing prover) hg, _, rm := createHypergraph(t) - proverJoin, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, keyManager, hg, rm) + proverJoin, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, keyManager, hg, rm, vdf.NewWesolowskiFrameProver(zap.L()), frameStore) require.NoError(t, err) + challenge := sha3.Sum256(make([]byte, 516)) + addr, _ := poseidon.HashBytes(signer.Public().([]byte)) + out := vdf.NewWesolowskiFrameProver(zap.L()).CalculateMultiProof(challenge, 50000, [][]byte{slices.Concat(addr.FillBytes(make([]byte, 32)), filter, binary.BigEndian.AppendUint32(nil, 0))}, 0) + proverJoin.Proof = out[:] // Generate the signatures with keys err = proverJoin.Prove(frameNumber) @@ -137,8 +149,19 @@ func TestGlobalProverOperations_Integration(t *testing.T) { // Create a fresh hypergraph for ProverJoin (no pre-existing prover) hg, _, rm := createHypergraph(t) - proverJoin, err := global.NewProverJoin([][]byte{filter, filter2}, frameNumber, nil, nil, keyManager, hg, rm) + proverJoin, err := global.NewProverJoin([][]byte{filter, filter2}, frameNumber, nil, nil, keyManager, hg, rm, vdf.NewWesolowskiFrameProver(zap.L()), frameStore) require.NoError(t, err) + challenge := sha3.Sum256(make([]byte, 516)) + addr, _ := poseidon.HashBytes(signer.Public().([]byte)) + out1 := vdf.NewWesolowskiFrameProver(zap.L()).CalculateMultiProof(challenge, 50000, [][]byte{ + slices.Concat(addr.FillBytes(make([]byte, 32)), filter, binary.BigEndian.AppendUint32(nil, 0)), + slices.Concat(addr.FillBytes(make([]byte, 32)), filter2, binary.BigEndian.AppendUint32(nil, 1)), + }, 0) + out2 := vdf.NewWesolowskiFrameProver(zap.L()).CalculateMultiProof(challenge, 50000, [][]byte{ + slices.Concat(addr.FillBytes(make([]byte, 32)), filter, binary.BigEndian.AppendUint32(nil, 0)), + slices.Concat(addr.FillBytes(make([]byte, 32)), filter2, binary.BigEndian.AppendUint32(nil, 1)), + }, 1) + proverJoin.Proof = slices.Concat(out1[:], out2[:]) // Generate the signatures with keys err = proverJoin.Prove(frameNumber) @@ -439,14 +462,14 @@ func TestGlobalProverOperations_Integration(t *testing.T) { require.NotNil(t, differentPubKey) // Attempt to verify a signature created with the original key using the different key - proverJoin, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, keyManager, hg, rm) + proverJoin, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, keyManager, hg, rm, vdf.NewWesolowskiFrameProver(zap.L()), frameStore) require.NoError(t, err) err = proverJoin.Prove(frameNumber) require.NoError(t, err) // Replace the key manager with the different one // This simulates an attempt to verify with a different key - proverJoin2, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, differentKeyManager, hg, rm) + proverJoin2, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, differentKeyManager, hg, rm, vdf.NewWesolowskiFrameProver(zap.L()), frameStore) require.NoError(t, err) proverJoin2.PublicKeySignatureBLS48581 = proverJoin.PublicKeySignatureBLS48581 proverJoin2.PublicKeySignatureBLS48581.PublicKey = []byte("foobar") diff --git a/node/execution/intrinsics/global/global_intrinsic_state_machine_integration_test.go b/node/execution/intrinsics/global/global_intrinsic_state_machine_integration_test.go index 8d217e7f..6d1ac552 100644 --- a/node/execution/intrinsics/global/global_intrinsic_state_machine_integration_test.go +++ b/node/execution/intrinsics/global/global_intrinsic_state_machine_integration_test.go @@ -25,6 +25,7 @@ import ( tkeys "source.quilibrium.com/quilibrium/monorepo/types/keys" "source.quilibrium.com/quilibrium/monorepo/types/schema" "source.quilibrium.com/quilibrium/monorepo/types/tries" + "source.quilibrium.com/quilibrium/monorepo/vdf" "source.quilibrium.com/quilibrium/monorepo/verenc" ) @@ -111,13 +112,15 @@ func TestProverJoinConfirmFlow(t *testing.T) { keyManager, hg, state, rdfMultiprover := setupTestEnvironment(t) address := getProverAddress(t, keyManager) filter := []byte("test-filter") + pebbleDB := store.NewPebbleDB(zap.L(), &config.DBConfig{InMemoryDONOTUSE: true, Path: ".test/global"}, 0) + frameStore := store.NewPebbleClockStore(pebbleDB, zap.L()) // Test 1: Join at frame 252840 t.Run("Join and confirm after 360 frames", func(t *testing.T) { joinFrame := uint64(252840) // Create and prove join - proverJoin, err := global.NewProverJoin([][]byte{filter}, joinFrame, nil, nil, keyManager, hg, rdfMultiprover) + proverJoin, err := global.NewProverJoin([][]byte{filter}, joinFrame, nil, nil, keyManager, hg, rdfMultiprover, vdf.NewWesolowskiFrameProver(zap.L()), frameStore) require.NoError(t, err) err = proverJoin.Prove(joinFrame) require.NoError(t, err) @@ -164,12 +167,14 @@ func TestProverJoinRejectFlow(t *testing.T) { keyManager, hg, state, rdfMultiprover := setupTestEnvironment(t) address := getProverAddress(t, keyManager) filter := []byte("test-filter") + pebbleDB := store.NewPebbleDB(zap.L(), &config.DBConfig{InMemoryDONOTUSE: true, Path: ".test/global"}, 0) + frameStore := store.NewPebbleClockStore(pebbleDB, zap.L()) t.Run("Join and reject immediately", func(t *testing.T) { joinFrame := uint64(252840) // Create and prove join - proverJoin, err := global.NewProverJoin([][]byte{filter}, joinFrame, nil, nil, keyManager, hg, rdfMultiprover) + proverJoin, err := global.NewProverJoin([][]byte{filter}, joinFrame, nil, nil, keyManager, hg, rdfMultiprover, vdf.NewWesolowskiFrameProver(zap.L()), frameStore) require.NoError(t, err) err = proverJoin.Prove(joinFrame) require.NoError(t, err) @@ -204,10 +209,12 @@ func TestProverPauseResumeFlow(t *testing.T) { keyManager, hg, state, rdfMultiprover := setupTestEnvironment(t) address := getProverAddress(t, keyManager) filter := []byte("test-filter") + pebbleDB := store.NewPebbleDB(zap.L(), &config.DBConfig{InMemoryDONOTUSE: true, Path: ".test/global"}, 0) + frameStore := store.NewPebbleClockStore(pebbleDB, zap.L()) // First join and confirm to get to active state joinFrame := uint64(252840) - proverJoin, err := global.NewProverJoin([][]byte{filter}, joinFrame, nil, nil, keyManager, hg, rdfMultiprover) + proverJoin, err := global.NewProverJoin([][]byte{filter}, joinFrame, nil, nil, keyManager, hg, rdfMultiprover, vdf.NewWesolowskiFrameProver(zap.L()), frameStore) require.NoError(t, err) err = proverJoin.Prove(joinFrame) require.NoError(t, err) @@ -264,10 +271,12 @@ func TestProverLeaveFlow(t *testing.T) { keyManager, hg, state, rdfMultiprover := setupTestEnvironment(t) address := getProverAddress(t, keyManager) filter := []byte("test-filter") + pebbleDB := store.NewPebbleDB(zap.L(), &config.DBConfig{InMemoryDONOTUSE: true, Path: ".test/global"}, 0) + frameStore := store.NewPebbleClockStore(pebbleDB, zap.L()) // First join and confirm to get to active state joinFrame := uint64(252840) - proverJoin, err := global.NewProverJoin([][]byte{filter}, joinFrame, nil, nil, keyManager, hg, rdfMultiprover) + proverJoin, err := global.NewProverJoin([][]byte{filter}, joinFrame, nil, nil, keyManager, hg, rdfMultiprover, vdf.NewWesolowskiFrameProver(zap.L()), frameStore) require.NoError(t, err) err = proverJoin.Prove(joinFrame) require.NoError(t, err) @@ -335,10 +344,12 @@ func TestProverLeaveRejectFlow(t *testing.T) { keyManager, hg, state, rdfMultiprover := setupTestEnvironment(t) address := getProverAddress(t, keyManager) filter := []byte("test-filter") + pebbleDB := store.NewPebbleDB(zap.L(), &config.DBConfig{InMemoryDONOTUSE: true, Path: ".test/global"}, 0) + frameStore := store.NewPebbleClockStore(pebbleDB, zap.L()) // First join and confirm to get to active state joinFrame := uint64(252840) - proverJoin, err := global.NewProverJoin([][]byte{filter}, joinFrame, nil, nil, keyManager, hg, rdfMultiprover) + proverJoin, err := global.NewProverJoin([][]byte{filter}, joinFrame, nil, nil, keyManager, hg, rdfMultiprover, vdf.NewWesolowskiFrameProver(zap.L()), frameStore) require.NoError(t, err) err = proverJoin.Prove(joinFrame) require.NoError(t, err) @@ -387,12 +398,14 @@ func TestProverLeaveRejectFlow(t *testing.T) { func TestProverTimingEdgeCases(t *testing.T) { keyManager, hg, state, rdfMultiprover := setupTestEnvironment(t) filter := []byte("test-filter") + pebbleDB := store.NewPebbleDB(zap.L(), &config.DBConfig{InMemoryDONOTUSE: true, Path: ".test/global"}, 0) + frameStore := store.NewPebbleClockStore(pebbleDB, zap.L()) t.Run("Join before 252840 with special confirmation rules", func(t *testing.T) { joinFrame := uint64(252000) // Create and prove join - proverJoin, err := global.NewProverJoin([][]byte{filter}, joinFrame, nil, nil, keyManager, hg, rdfMultiprover) + proverJoin, err := global.NewProverJoin([][]byte{filter}, joinFrame, nil, nil, keyManager, hg, rdfMultiprover, vdf.NewWesolowskiFrameProver(zap.L()), frameStore) require.NoError(t, err) err = proverJoin.Prove(joinFrame) require.NoError(t, err) @@ -427,7 +440,7 @@ func TestProverTimingEdgeCases(t *testing.T) { t.Run("Pause timeout causes implicit leave", func(t *testing.T) { // First get to active state joinFrame := uint64(252840) - proverJoin, err := global.NewProverJoin([][]byte{filter}, joinFrame, nil, nil, keyManager, hg, rdfMultiprover) + proverJoin, err := global.NewProverJoin([][]byte{filter}, joinFrame, nil, nil, keyManager, hg, rdfMultiprover, vdf.NewWesolowskiFrameProver(zap.L()), frameStore) require.NoError(t, err) err = proverJoin.Prove(joinFrame) require.NoError(t, err) @@ -466,10 +479,12 @@ func TestProverTimingEdgeCases(t *testing.T) { func TestProverInvalidStateTransitions(t *testing.T) { keyManager, hg, state, rdfMultiprover := setupTestEnvironment(t) filter := []byte("test-filter") + pebbleDB := store.NewPebbleDB(zap.L(), &config.DBConfig{InMemoryDONOTUSE: true, Path: ".test/global"}, 0) + frameStore := store.NewPebbleClockStore(pebbleDB, zap.L()) // Join first joinFrame := uint64(252840) - proverJoin, err := global.NewProverJoin([][]byte{filter}, joinFrame, nil, nil, keyManager, hg, rdfMultiprover) + proverJoin, err := global.NewProverJoin([][]byte{filter}, joinFrame, nil, nil, keyManager, hg, rdfMultiprover, vdf.NewWesolowskiFrameProver(zap.L()), frameStore) require.NoError(t, err) err = proverJoin.Prove(joinFrame) require.NoError(t, err) diff --git a/node/execution/intrinsics/global/global_prover_confirm.go b/node/execution/intrinsics/global/global_prover_confirm.go index 5b7fb262..7288d9bd 100644 --- a/node/execution/intrinsics/global/global_prover_confirm.go +++ b/node/execution/intrinsics/global/global_prover_confirm.go @@ -321,6 +321,61 @@ func (p *ProverConfirm) Prove(frameNumber uint64) error { return nil } +func (p *ProverConfirm) GetReadAddresses(frameNumber uint64) ([][]byte, error) { + return nil, nil +} + +func (p *ProverConfirm) GetWriteAddresses(frameNumber uint64) ([][]byte, error) { + proverAddress := p.PublicKeySignatureBLS48581.Address + proverFullAddress := [64]byte{} + copy(proverFullAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) + copy(proverFullAddress[32:], proverAddress) + + // Get the existing prover vertex + proverTree, err := p.hypergraph.GetVertexData(proverFullAddress) + if err != nil || proverTree == nil { + return nil, errors.Wrap( + errors.New("prover not found"), + "get write addresses", + ) + } + + // Get prover public key for allocation lookup + publicKey, err := p.rdfMultiprover.Get( + GLOBAL_RDF_SCHEMA, + "prover:Prover", + "PublicKey", + proverTree, + ) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + // Calculate allocation address: + allocationAddressBI, err := poseidon.HashBytes( + slices.Concat([]byte("PROVER_ALLOCATION"), publicKey, p.Filter), + ) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + allocationAddress := allocationAddressBI.FillBytes(make([]byte, 32)) + allocationFullAddress := [64]byte{} + copy(allocationFullAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) + copy(allocationFullAddress[32:], allocationAddress) + + addresses := map[string]struct{}{} + addresses[string(proverFullAddress[:])] = struct{}{} + addresses[string(allocationFullAddress[:])] = struct{}{} + + result := [][]byte{} + for key := range addresses { + result = append(result, []byte(key)) + } + + return result, nil +} + // Verify implements intrinsics.IntrinsicOperation. func (p *ProverConfirm) Verify(frameNumber uint64) (bool, error) { // Create confirm message contents @@ -430,7 +485,7 @@ func (p *ProverConfirm) Verify(frameNumber uint64) (bool, error) { joinFrame := binary.BigEndian.Uint64(joinFrameBytes) // Check timing constraints - if joinFrame < 252840 { + if joinFrame < 252840 && joinFrame >= 244100 { if frameNumber < 252840 { // If joined before frame 252840, cannot confirm until frame 252840 return false, errors.Wrap( @@ -448,8 +503,10 @@ func (p *ProverConfirm) Verify(frameNumber uint64) (bool, error) { } // For joins before 252840, once we reach frame 252840, they can confirm - // immediately, for joins after 252840, normal 360 frame wait applies - if joinFrame >= 252480 { + // immediately, for joins after 252840, normal 360 frame wait applies. + // If the join frame precedes the genesis frame (e.g. not mainnet), we + // ignore the topic altogether + if joinFrame >= 252480 || joinFrame <= 244100 { framesSinceJoin := frameNumber - joinFrame if framesSinceJoin < 360 { return false, errors.Wrap( diff --git a/node/execution/intrinsics/global/global_prover_join.go b/node/execution/intrinsics/global/global_prover_join.go index 75636da5..b4b0c510 100644 --- a/node/execution/intrinsics/global/global_prover_join.go +++ b/node/execution/intrinsics/global/global_prover_join.go @@ -2,6 +2,7 @@ package global import ( "encoding/binary" + "fmt" "math/big" "slices" @@ -9,6 +10,7 @@ import ( pcrypto "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/peer" "github.com/pkg/errors" + "golang.org/x/crypto/sha3" hgcrdt "source.quilibrium.com/quilibrium/monorepo/hypergraph" "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/global/compat" "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token" @@ -19,6 +21,7 @@ import ( "source.quilibrium.com/quilibrium/monorepo/types/hypergraph" "source.quilibrium.com/quilibrium/monorepo/types/keys" "source.quilibrium.com/quilibrium/monorepo/types/schema" + "source.quilibrium.com/quilibrium/monorepo/types/store" "source.quilibrium.com/quilibrium/monorepo/types/tries" qcrypto "source.quilibrium.com/quilibrium/monorepo/types/tries" ) @@ -67,11 +70,15 @@ type ProverJoin struct { // The optional delegated address for rewards to accrue, when omitted, uses // the prover address DelegateAddress []byte + // The proof element assuring availability and commitment of the workers + Proof []byte // Private fields keyManager keys.KeyManager hypergraph hypergraph.Hypergraph rdfMultiprover *schema.RDFMultiprover + frameProver crypto.FrameProver + frameStore store.ClockStore } func NewProverJoin( @@ -82,6 +89,8 @@ func NewProverJoin( keyManager keys.KeyManager, hypergraph hypergraph.Hypergraph, rdfMultiprover *schema.RDFMultiprover, + frameProver crypto.FrameProver, + frameStore store.ClockStore, ) (*ProverJoin, error) { return &ProverJoin{ Filters: filters, @@ -91,6 +100,8 @@ func NewProverJoin( keyManager: keyManager, hypergraph: hypergraph, rdfMultiprover: rdfMultiprover, + frameProver: frameProver, + frameStore: frameStore, }, nil } @@ -255,9 +266,16 @@ func (p *ProverJoin) Materialize( delegateAddress = p.DelegateAddress } + derivedRewardAddress, err := poseidon.HashBytes( + slices.Concat(token.QUIL_TOKEN_ADDRESS[:], proverAddress), + ) + if err != nil { + return nil, errors.Wrap(err, "materialize") + } + err = p.rdfMultiprover.Set( GLOBAL_RDF_SCHEMA, - token.QUIL_TOKEN_ADDRESS, + intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], "reward:ProverReward", "DelegateAddress", delegateAddress, @@ -271,7 +289,7 @@ func (p *ProverJoin) Materialize( zeroBalance := make([]byte, 32) err = p.rdfMultiprover.Set( GLOBAL_RDF_SCHEMA, - token.QUIL_TOKEN_ADDRESS, + intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], "reward:ProverReward", "Balance", zeroBalance, @@ -283,16 +301,16 @@ func (p *ProverJoin) Materialize( // Create reward vertex in QUIL token address rewardVertex := hg.NewVertexAddMaterializedState( - [32]byte(token.QUIL_TOKEN_ADDRESS), - [32]byte(proverAddress), + [32]byte(intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]), + [32]byte(derivedRewardAddress.FillBytes(make([]byte, 32))), frameNumber, nil, rewardTree, ) err = hg.Set( - token.QUIL_TOKEN_ADDRESS, - proverAddress, + intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], + derivedRewardAddress.FillBytes(make([]byte, 32)), hgstate.VertexAddsDiscriminator, frameNumber, rewardVertex, @@ -347,7 +365,7 @@ func (p *ProverJoin) Materialize( intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], "allocation:ProverAllocation", "Prover", - slices.Concat(intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], proverAddress), + proverAddress, allocationTree, ) if err != nil { @@ -430,6 +448,39 @@ func (p *ProverJoin) Materialize( hyperedge.AddExtrinsic(allocationVertex.GetVertex()) } + for _, mt := range p.MergeTargets { + spentMergeBI, err := poseidon.HashBytes(slices.Concat( + []byte("PROVER_JOIN_MERGE"), + mt.PublicKey, + )) + if err != nil { + return nil, errors.Wrap(err, "materialize") + } + + // confirm this has not already been used + spentAddress := [64]byte{} + copy(spentAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) + copy(spentAddress[32:], spentMergeBI.FillBytes(make([]byte, 32))) + spentMergeVertex := hg.NewVertexAddMaterializedState( + intrinsics.GLOBAL_INTRINSIC_ADDRESS, + [32]byte(spentMergeBI.FillBytes(make([]byte, 32))), + frameNumber, + nil, + &tries.VectorCommitmentTree{}, + ) + + err = hg.Set( + intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], + spentMergeBI.FillBytes(make([]byte, 32)), + hgstate.VertexAddsDiscriminator, + frameNumber, + spentMergeVertex, + ) + if err != nil { + return nil, errors.Wrap(err, "materialize") + } + } + var priorHyperedge *tries.VectorCommitmentTree previousHyperedge, err := hg.Get( intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], @@ -539,8 +590,86 @@ func (p *ProverJoin) Prove(frameNumber uint64) error { return nil } +func (p *ProverJoin) GetReadAddresses(frameNumber uint64) ([][]byte, error) { + return nil, nil +} + +func (p *ProverJoin) GetWriteAddresses(frameNumber uint64) ([][]byte, error) { + publicKey := p.PublicKeySignatureBLS48581.PublicKey + proverAddressBI, err := poseidon.HashBytes(publicKey) + if err != nil || proverAddressBI == nil { + return nil, errors.Wrap( + errors.New("invalid address"), + "get write addresses", + ) + } + proverAddress := proverAddressBI.FillBytes(make([]byte, 32)) + + proverFullAddress := [64]byte{} + copy(proverFullAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) + copy(proverFullAddress[32:], proverAddress) + + addresses := map[string]struct{}{} + addresses[string(proverFullAddress[:])] = struct{}{} + + derivedRewardAddress, err := poseidon.HashBytes( + slices.Concat(token.QUIL_TOKEN_ADDRESS[:], proverAddress), + ) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + addresses[string(slices.Concat( + intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], + derivedRewardAddress.FillBytes(make([]byte, 32)), + ))] = struct{}{} + + for _, filter := range p.Filters { + allocationAddressBI, err := poseidon.HashBytes( + slices.Concat([]byte("PROVER_ALLOCATION"), publicKey, filter), + ) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + allocationAddress := allocationAddressBI.FillBytes(make([]byte, 32)) + + addresses[string(slices.Concat( + intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], + allocationAddress, + ))] = struct{}{} + } + + for _, mt := range p.MergeTargets { + spentMergeBI, err := poseidon.HashBytes(slices.Concat( + []byte("PROVER_JOIN_MERGE"), + mt.PublicKey, + )) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + addresses[string(slices.Concat( + intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], + spentMergeBI.FillBytes(make([]byte, 32)), + ))] = struct{}{} + } + + result := [][]byte{} + for key := range addresses { + result = append(result, []byte(key)) + } + + return result, nil +} + // Verify implements intrinsics.IntrinsicOperation. -func (p *ProverJoin) Verify(frameNumber uint64) (bool, error) { +func (p *ProverJoin) Verify(frameNumber uint64) (valid bool, err error) { + defer func() { + if r := recover(); r != nil { + valid = false + err = fmt.Errorf("panic from: %v", r) + } + }() // First check if prover can join (not in tree or in left state) addressBI, err := poseidon.HashBytes(p.PublicKeySignatureBLS48581.PublicKey) if err != nil { @@ -554,6 +683,82 @@ func (p *ProverJoin) Verify(frameNumber uint64) (bool, error) { } } + if len(p.Proof)%516 != 0 || len(p.Proof)/516 != len(p.Filters) { + return false, errors.Wrap(errors.New("proof size mismatch"), "verify") + } + + // Disallow too old of a request + if p.FrameNumber+10 < frameNumber { + return false, errors.Wrap(errors.New("outdated request"), "verify") + } + + frame, err := p.frameStore.GetGlobalClockFrame(p.FrameNumber) + if err != nil { + return false, errors.Wrap(errors.Wrap( + err, + fmt.Sprintf("frame number: %d", p.FrameNumber), + ), "verify") + } + + // Prepare challenge for verification + challenge := sha3.Sum256(frame.Header.Output) + ids := [][]byte{} + for idx, filter := range p.Filters { + ids = append(ids, slices.Concat( + address, + filter, + binary.BigEndian.AppendUint32(nil, uint32(idx)), + )) + } + + solutions := [][516]byte{} + for i := range p.Filters { + solutions = append(solutions, [516]byte(p.Proof[i*516:(i+1)*516])) + } + valid, err = p.frameProver.VerifyMultiProof( + challenge, + frame.Header.Difficulty, + ids, + solutions, + ) + if err != nil || !valid { + return false, errors.Wrap(errors.New("invalid multi proof"), "verify") + } + + for _, mt := range p.MergeTargets { + valid, err := p.keyManager.ValidateSignature( + mt.KeyType, + mt.PublicKey, + p.PublicKeySignatureBLS48581.PublicKey, + mt.Signature, + []byte("PROVER_JOIN_MERGE"), + ) + if err != nil || !valid { + return false, errors.Wrap(err, "verify") + } + + spentMergeBI, err := poseidon.HashBytes(slices.Concat( + []byte("PROVER_JOIN_MERGE"), + mt.PublicKey, + )) + if err != nil { + return false, errors.Wrap(err, "verify") + } + + // confirm this has not already been used + spentAddress := [64]byte{} + copy(spentAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) + copy(spentAddress[32:], spentMergeBI.FillBytes(make([]byte, 32))) + + v, err := p.hypergraph.GetVertex(spentAddress) + if err == nil && v != nil { + return false, errors.Wrap( + errors.New("merge target already used"), + "verify", + ) + } + } + // Create composite address: GLOBAL_INTRINSIC_ADDRESS + prover address fullAddress := [64]byte{} copy(fullAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) @@ -609,12 +814,12 @@ func (p *ProverJoin) Verify(frameNumber uint64) (bool, error) { popDomain := []byte("BLS48_POP_SK") // Verify the signature - valid, err := p.keyManager.ValidateSignature( + valid, err = p.keyManager.ValidateSignature( crypto.KeyTypeBLS48581G1, p.PublicKeySignatureBLS48581.PublicKey, joinMessage, p.PublicKeySignatureBLS48581.Signature, - joinDomain.Bytes(), + joinDomain.FillBytes(make([]byte, 32)), ) if err != nil || !valid { return false, errors.Wrap(errors.New("invalid signature"), "verify") diff --git a/node/execution/intrinsics/global/global_prover_join_test.go b/node/execution/intrinsics/global/global_prover_join_test.go index 8202789a..0570080a 100644 --- a/node/execution/intrinsics/global/global_prover_join_test.go +++ b/node/execution/intrinsics/global/global_prover_join_test.go @@ -21,6 +21,7 @@ import ( "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/global" "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/global/compat" hgstate "source.quilibrium.com/quilibrium/monorepo/node/execution/state/hypergraph" + "source.quilibrium.com/quilibrium/monorepo/protobufs" "source.quilibrium.com/quilibrium/monorepo/types/crypto" "source.quilibrium.com/quilibrium/monorepo/types/execution/intrinsics" thypergraph "source.quilibrium.com/quilibrium/monorepo/types/hypergraph" @@ -34,6 +35,14 @@ func TestProverJoin_Verify(t *testing.T) { mockKeyManager := new(mocks.MockKeyManager) mockHypergraph := new(mocks.MockHypergraph) mockInclusionProver := new(mocks.MockInclusionProver) + mockFrameProver := new(mocks.MockFrameProver) + mockFrameStore := new(mocks.MockClockStore) + mockFrameStore.On("GetGlobalClockFrame", mock.Anything).Return(&protobufs.GlobalFrame{ + Header: &protobufs.GlobalFrameHeader{ + FrameNumber: 12345, + Output: make([]byte, 516), + }, + }, nil) // Test data filter := []byte("testfiltertestfiltertestfilterte") @@ -45,8 +54,9 @@ func TestProverJoin_Verify(t *testing.T) { // Create the prover join operation rdfMultiprover := createMockRDFMultiprover() - proverJoin, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover) + proverJoin, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover, mockFrameProver, mockFrameStore) require.NoError(t, err) + proverJoin.Proof = make([]byte, 516) // Set up the signature data manually proverJoin.PublicKeySignatureBLS48581 = global.BLS48581SignatureWithProofOfPossession{ @@ -73,6 +83,7 @@ func TestProverJoin_Verify(t *testing.T) { copy(fullAddress[32:], address) mockHypergraph.On("GetVertexData", fullAddress).Return(nil, assert.AnError) mockHypergraph.On("GetProver").Return(mockInclusionProver) + mockFrameProver.On("VerifyMultiProof", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(true, nil) // Configure mock key manager mockKeyManager.On("ValidateSignature", @@ -110,13 +121,14 @@ func TestProverJoin_Verify(t *testing.T) { []byte("signature"), joinDomain.Bytes(), ).Return(false, nil) - proverJoin, err = global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover) + proverJoin, err = global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover, mockFrameProver, mockFrameStore) require.NoError(t, err) proverJoin.PublicKeySignatureBLS48581 = global.BLS48581SignatureWithProofOfPossession{ Signature: []byte("signature"), PublicKey: pubKey, PopSignature: []byte("pop_signature"), } + proverJoin.Proof = make([]byte, 516) valid, err = proverJoin.Verify(frameNumber) require.Error(t, err) assert.False(t, valid) @@ -146,13 +158,14 @@ func TestProverJoin_Verify(t *testing.T) { []byte("BLS48_POP_SK"), ).Return(true, nil) - proverJoin, err = global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover) + proverJoin, err = global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover, mockFrameProver, mockFrameStore) require.NoError(t, err) proverJoin.PublicKeySignatureBLS48581 = global.BLS48581SignatureWithProofOfPossession{ Signature: []byte("signature"), PublicKey: pubKey, PopSignature: []byte("pop_signature"), } + proverJoin.Proof = make([]byte, 516) valid, err = proverJoin.Verify(frameNumber) require.Error(t, err) assert.Contains(t, err.Error(), "prover already exists in non-left state") @@ -183,8 +196,9 @@ func TestProverJoin_Verify(t *testing.T) { []byte("BLS48_POP_SK"), ).Return(true, nil) - proverJoin, err = global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover) + proverJoin, err = global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover, mockFrameProver, mockFrameStore) require.NoError(t, err) + proverJoin.Proof = make([]byte, 516) proverJoin.PublicKeySignatureBLS48581 = global.BLS48581SignatureWithProofOfPossession{ Signature: []byte("signature"), PublicKey: pubKey, @@ -202,6 +216,8 @@ func TestProverJoin_Materialize(t *testing.T) { mockHypergraph := new(mocks.MockHypergraph) hypergraphState := hgstate.NewHypergraphState(mockHypergraph) mockInclusionProver := new(mocks.MockInclusionProver) + mockFrameProver := new(mocks.MockFrameProver) + mockFrameStore := new(mocks.MockClockStore) // Test data filter := []byte("testfiltertestfiltertestfilterte") @@ -258,7 +274,7 @@ func TestProverJoin_Materialize(t *testing.T) { // Create the prover join operation rdfMultiprover := createMockRDFMultiprover() - proverJoin, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover) + proverJoin, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover, mockFrameProver, mockFrameStore) require.NoError(t, err) // Set up the signature data @@ -281,6 +297,8 @@ func TestProverJoin_Materialize(t *testing.T) { mockHypergraph := new(mocks.MockHypergraph) hypergraphState := hgstate.NewHypergraphState(mockHypergraph) mockInclusionProver := new(mocks.MockInclusionProver) + mockFrameProver := new(mocks.MockFrameProver) + mockFrameStore := new(mocks.MockClockStore) // Test data filter := []byte("testfiltertestfiltertestfilterte") @@ -354,7 +372,7 @@ func TestProverJoin_Materialize(t *testing.T) { // Create the prover join operation rdfMultiprover := createMockRDFMultiprover() - proverJoin, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover) + proverJoin, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover, mockFrameProver, mockFrameStore) require.NoError(t, err) // Set up the signature data @@ -377,6 +395,8 @@ func TestProverJoin_Materialize(t *testing.T) { mockHypergraph := new(mocks.MockHypergraph) hypergraphState := hgstate.NewHypergraphState(mockHypergraph) mockInclusionProver := new(mocks.MockInclusionProver) + mockFrameProver := new(mocks.MockFrameProver) + mockFrameStore := new(mocks.MockClockStore) // Test data filter := []byte("testfiltertestfiltertestfilterte") @@ -412,7 +432,7 @@ func TestProverJoin_Materialize(t *testing.T) { // Create the prover join operation rdfMultiprover := createMockRDFMultiprover() - proverJoin, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover) + proverJoin, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover, mockFrameProver, mockFrameStore) require.NoError(t, err) // Set up the signature data @@ -435,6 +455,8 @@ func TestProverJoin_Materialize(t *testing.T) { mockKeyManager := new(mocks.MockKeyManager) mockHypergraph := new(mocks.MockHypergraph) hypergraphState := hgstate.NewHypergraphState(mockHypergraph) + mockFrameProver := new(mocks.MockFrameProver) + mockFrameStore := new(mocks.MockClockStore) // Test data filter := []byte("testfiltertestfiltertestfilterte") @@ -442,7 +464,7 @@ func TestProverJoin_Materialize(t *testing.T) { // Create the prover join operation rdfMultiprover := createMockRDFMultiprover() - proverJoin, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover) + proverJoin, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover, mockFrameProver, mockFrameStore) require.NoError(t, err) // Set up the signature data with nil public key (will cause poseidon hash error) @@ -465,6 +487,8 @@ func TestProverJoin_Materialize(t *testing.T) { mockHypergraph := new(mocks.MockHypergraph) hypergraphState := hgstate.NewHypergraphState(mockHypergraph) mockInclusionProver := new(mocks.MockInclusionProver) + mockFrameProver := new(mocks.MockFrameProver) + mockFrameStore := new(mocks.MockClockStore) // Test data filter := []byte("testfiltertestfiltertestfilterte") @@ -560,7 +584,7 @@ func TestProverJoin_Materialize(t *testing.T) { // Create the prover join operation rdfMultiprover := createMockRDFMultiprover() - proverJoin, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover) + proverJoin, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover, mockFrameProver, mockFrameStore) require.NoError(t, err) // Set up the signature data @@ -594,6 +618,7 @@ func TestProverJoin_GetCost(t *testing.T) { // Setup mockKeyManager := new(mocks.MockKeyManager) mockHypergraph := new(mocks.MockHypergraph) + mockFrameStore := new(mocks.MockClockStore) // Test data filter := []byte("testfiltertestfiltertestfilterte") @@ -605,7 +630,7 @@ func TestProverJoin_GetCost(t *testing.T) { // Create the prover join operation rdfMultiprover := createMockRDFMultiprover() - proverJoin, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover) + proverJoin, err := global.NewProverJoin([][]byte{filter}, frameNumber, nil, nil, mockKeyManager, mockHypergraph, rdfMultiprover, &mocks.MockFrameProver{}, mockFrameStore) require.NoError(t, err) // Set up the signature data manually diff --git a/node/execution/intrinsics/global/global_prover_kick.go b/node/execution/intrinsics/global/global_prover_kick.go index 79043bb8..95544fe4 100644 --- a/node/execution/intrinsics/global/global_prover_kick.go +++ b/node/execution/intrinsics/global/global_prover_kick.go @@ -339,6 +339,49 @@ func (p *ProverKick) Prove(frameNumber uint64) error { return nil } +func (p *ProverKick) GetReadAddresses(frameNumber uint64) ([][]byte, error) { + return nil, nil +} + +func (p *ProverKick) GetWriteAddresses(frameNumber uint64) ([][]byte, error) { + // Compute the kicked prover's address from their public key + kickedAddressBI, err := poseidon.HashBytes(p.KickedProverPublicKey) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + kickedAddress := kickedAddressBI.FillBytes(make([]byte, 32)) + + fullAddress := [64]byte{} + copy(fullAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) + copy(fullAddress[32:], kickedAddress) + hyperedgeAddress := [64]byte{} + copy(hyperedgeAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) + copy(hyperedgeAddress[32:], kickedAddress) + + hyperedge, err := p.hypergraph.GetHyperedge(hyperedgeAddress) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + addresses := map[string]struct{}{} + addresses[string(fullAddress[:])] = struct{}{} + addresses[string(hyperedgeAddress[:])] = struct{}{} + + vertices := tries.GetAllPreloadedLeaves(hyperedge.GetExtrinsicTree().Root) + if err == nil && len(vertices) > 0 { + for _, vertex := range vertices { + addresses[string(vertex.Key)] = struct{}{} + } + } + + result := [][]byte{} + for key := range addresses { + result = append(result, []byte(key)) + } + + return result, nil +} + // Verify implements intrinsics.IntrinsicOperation. func (p *ProverKick) Verify(frameNumber uint64) (bool, error) { // First verify the conflicting frames prove equivocation diff --git a/node/execution/intrinsics/global/global_prover_leave.go b/node/execution/intrinsics/global/global_prover_leave.go index 684eb511..d347e812 100644 --- a/node/execution/intrinsics/global/global_prover_leave.go +++ b/node/execution/intrinsics/global/global_prover_leave.go @@ -274,6 +274,64 @@ func (p *ProverLeave) Prove(frameNumber uint64) error { return nil } +func (p *ProverLeave) GetReadAddresses(frameNumber uint64) ([][]byte, error) { + return nil, nil +} + +func (p *ProverLeave) GetWriteAddresses(frameNumber uint64) ([][]byte, error) { + proverAddress := p.PublicKeySignatureBLS48581.Address + proverFullAddress := [64]byte{} + copy(proverFullAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) + copy(proverFullAddress[32:], proverAddress) + + addresses := map[string]struct{}{} + addresses[string(proverFullAddress[:])] = struct{}{} + + // Get the existing prover vertex + proverTree, err := p.hypergraph.GetVertexData(proverFullAddress) + if err != nil || proverTree == nil { + return nil, errors.Wrap( + errors.New("prover not found"), + "get write addresses", + ) + } + + // Get prover public key for allocation lookups + publicKey, err := p.rdfMultiprover.Get( + GLOBAL_RDF_SCHEMA, + "prover:Prover", + "PublicKey", + proverTree, + ) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + // Update allocations for each filter + for _, filter := range p.Filters { + // Calculate allocation address: + allocationAddressBI, err := poseidon.HashBytes( + slices.Concat([]byte("PROVER_ALLOCATION"), publicKey, filter), + ) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + allocationAddress := allocationAddressBI.FillBytes(make([]byte, 32)) + allocationFullAddress := [64]byte{} + copy(allocationFullAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) + copy(allocationFullAddress[32:], allocationAddress) + + addresses[string(allocationFullAddress[:])] = struct{}{} + } + + result := [][]byte{} + for key := range addresses { + result = append(result, []byte(key)) + } + + return result, nil +} + // Verify implements intrinsics.IntrinsicOperation. func (p *ProverLeave) Verify(frameNumber uint64) (bool, error) { // Create leave message contents diff --git a/node/execution/intrinsics/global/global_prover_pause.go b/node/execution/intrinsics/global/global_prover_pause.go index c65a7049..ae0ac3e3 100644 --- a/node/execution/intrinsics/global/global_prover_pause.go +++ b/node/execution/intrinsics/global/global_prover_pause.go @@ -265,6 +265,61 @@ func (p *ProverPause) Prove(frameNumber uint64) error { return nil } +func (p *ProverPause) GetReadAddresses(frameNumber uint64) ([][]byte, error) { + return nil, nil +} + +func (p *ProverPause) GetWriteAddresses(frameNumber uint64) ([][]byte, error) { + proverAddress := p.PublicKeySignatureBLS48581.Address + proverFullAddress := [64]byte{} + copy(proverFullAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) + copy(proverFullAddress[32:], proverAddress) + + // Get the existing prover vertex + proverTree, err := p.hypergraph.GetVertexData(proverFullAddress) + if err != nil || proverTree == nil { + return nil, errors.Wrap( + errors.New("prover not found"), + "get write addresses", + ) + } + + // Get prover public key for allocation lookup + publicKey, err := p.rdfMultiprover.Get( + GLOBAL_RDF_SCHEMA, + "prover:Prover", + "PublicKey", + proverTree, + ) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + // Calculate allocation address: + allocationAddressBI, err := poseidon.HashBytes( + slices.Concat([]byte("PROVER_ALLOCATION"), publicKey, p.Filter), + ) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + allocationAddress := allocationAddressBI.FillBytes(make([]byte, 32)) + allocationFullAddress := [64]byte{} + copy(allocationFullAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) + copy(allocationFullAddress[32:], allocationAddress) + + addresses := map[string]struct{}{} + addresses[string(proverFullAddress[:])] = struct{}{} + addresses[string(allocationFullAddress[:])] = struct{}{} + + result := [][]byte{} + for key := range addresses { + result = append(result, []byte(key)) + } + + return result, nil +} + // Verify implements intrinsics.IntrinsicOperation. func (p *ProverPause) Verify(frameNumber uint64) (bool, error) { // Create pause message contents diff --git a/node/execution/intrinsics/global/global_prover_reject.go b/node/execution/intrinsics/global/global_prover_reject.go index d34abed6..e9f5e21f 100644 --- a/node/execution/intrinsics/global/global_prover_reject.go +++ b/node/execution/intrinsics/global/global_prover_reject.go @@ -312,6 +312,61 @@ func (p *ProverReject) Prove(frameNumber uint64) error { return nil } +func (p *ProverReject) GetReadAddresses(frameNumber uint64) ([][]byte, error) { + return nil, nil +} + +func (p *ProverReject) GetWriteAddresses(frameNumber uint64) ([][]byte, error) { + proverAddress := p.PublicKeySignatureBLS48581.Address + proverFullAddress := [64]byte{} + copy(proverFullAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) + copy(proverFullAddress[32:], proverAddress) + + // Get the existing prover vertex + proverTree, err := p.hypergraph.GetVertexData(proverFullAddress) + if err != nil || proverTree == nil { + return nil, errors.Wrap( + errors.New("prover not found"), + "get write addresses", + ) + } + + // Get prover public key for allocation lookup + publicKey, err := p.rdfMultiprover.Get( + GLOBAL_RDF_SCHEMA, + "prover:Prover", + "PublicKey", + proverTree, + ) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + // Calculate allocation address: + allocationAddressBI, err := poseidon.HashBytes( + slices.Concat([]byte("PROVER_ALLOCATION"), publicKey, p.Filter), + ) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + allocationAddress := allocationAddressBI.FillBytes(make([]byte, 32)) + allocationFullAddress := [64]byte{} + copy(allocationFullAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) + copy(allocationFullAddress[32:], allocationAddress) + + addresses := map[string]struct{}{} + addresses[string(proverFullAddress[:])] = struct{}{} + addresses[string(allocationFullAddress[:])] = struct{}{} + + result := [][]byte{} + for key := range addresses { + result = append(result, []byte(key)) + } + + return result, nil +} + // Verify implements intrinsics.IntrinsicOperation. func (p *ProverReject) Verify(frameNumber uint64) (bool, error) { // Create reject message contents diff --git a/node/execution/intrinsics/global/global_prover_resume.go b/node/execution/intrinsics/global/global_prover_resume.go index f43426f9..56a710ad 100644 --- a/node/execution/intrinsics/global/global_prover_resume.go +++ b/node/execution/intrinsics/global/global_prover_resume.go @@ -264,6 +264,61 @@ func (p *ProverResume) Prove(frameNumber uint64) error { return nil } +func (p *ProverResume) GetReadAddresses(frameNumber uint64) ([][]byte, error) { + return nil, nil +} + +func (p *ProverResume) GetWriteAddresses(frameNumber uint64) ([][]byte, error) { + proverAddress := p.PublicKeySignatureBLS48581.Address + proverFullAddress := [64]byte{} + copy(proverFullAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) + copy(proverFullAddress[32:], proverAddress) + + // Get the existing prover vertex + proverTree, err := p.hypergraph.GetVertexData(proverFullAddress) + if err != nil || proverTree == nil { + return nil, errors.Wrap( + errors.New("prover not found"), + "get write addresses", + ) + } + + // Get prover public key for allocation lookup + publicKey, err := p.rdfMultiprover.Get( + GLOBAL_RDF_SCHEMA, + "prover:Prover", + "PublicKey", + proverTree, + ) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + // Calculate allocation address: + allocationAddressBI, err := poseidon.HashBytes( + slices.Concat([]byte("PROVER_ALLOCATION"), publicKey, p.Filter), + ) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + allocationAddress := allocationAddressBI.FillBytes(make([]byte, 32)) + allocationFullAddress := [64]byte{} + copy(allocationFullAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) + copy(allocationFullAddress[32:], allocationAddress) + + addresses := map[string]struct{}{} + addresses[string(proverFullAddress[:])] = struct{}{} + addresses[string(allocationFullAddress[:])] = struct{}{} + + result := [][]byte{} + for key := range addresses { + result = append(result, []byte(key)) + } + + return result, nil +} + // Verify implements intrinsics.IntrinsicOperation. func (p *ProverResume) Verify(frameNumber uint64) (bool, error) { // Create resume message contents diff --git a/node/execution/intrinsics/global/global_prover_update.go b/node/execution/intrinsics/global/global_prover_update.go index 2ab218db..88f5a0c1 100644 --- a/node/execution/intrinsics/global/global_prover_update.go +++ b/node/execution/intrinsics/global/global_prover_update.go @@ -88,6 +88,14 @@ func (p *ProverUpdate) Materialize( ) } + rewardAddress, err := poseidon.HashBytes(slices.Concat( + token.QUIL_TOKEN_ADDRESS[:], + proverAddress, + )) + if err != nil { + return nil, errors.Wrap(err, "materialize") + } + // Ensure the prover exists (under GLOBAL_INTRINSIC_ADDRESS + proverAddress) proverFullAddr := [64]byte{} copy(proverFullAddr[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) @@ -132,12 +140,11 @@ func (p *ProverUpdate) Materialize( ) } - // Now update only the reward entry under the QUIL token namespace: - // key = (token.QUIL_TOKEN_ADDRESS , proverAddress) in VertexAddsDiscriminator + // Now update only the reward entry in VertexAddsDiscriminator // We will preserve the existing Balance and only set DelegateAddress. rewardPriorVertex, err := hg.Get( - token.QUIL_TOKEN_ADDRESS, - proverAddress, + intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], + rewardAddress.FillBytes(make([]byte, 32)), hgstate.VertexAddsDiscriminator, ) if err != nil { @@ -162,7 +169,7 @@ func (p *ProverUpdate) Materialize( // Set new DelegateAddress if err := p.rdfMultiprover.Set( GLOBAL_RDF_SCHEMA, - token.QUIL_TOKEN_ADDRESS, + intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], "reward:ProverReward", "DelegateAddress", p.DelegateAddress, @@ -172,8 +179,8 @@ func (p *ProverUpdate) Materialize( } unmodifiedPrior, err := hg.Get( - token.QUIL_TOKEN_ADDRESS, - proverAddress, + intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], + rewardAddress.FillBytes(make([]byte, 32)), hgstate.VertexAddsDiscriminator, ) var unmodifiedTree *tries.VectorCommitmentTree @@ -190,16 +197,16 @@ func (p *ProverUpdate) Materialize( // Build the updated reward vertex rewardVertex := hg.NewVertexAddMaterializedState( - [32]byte(token.QUIL_TOKEN_ADDRESS), - [32]byte(slices.Clone(proverAddress)), + [32]byte(intrinsics.GLOBAL_INTRINSIC_ADDRESS), + [32]byte(slices.Clone(rewardAddress.FillBytes(make([]byte, 32)))), frameNumber, unmodifiedTree, rewardPriorTree, ) if err := hg.Set( - token.QUIL_TOKEN_ADDRESS, - proverAddress, + intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], + rewardAddress.FillBytes(make([]byte, 32)), hgstate.VertexAddsDiscriminator, frameNumber, rewardVertex, @@ -260,6 +267,41 @@ func (p *ProverUpdate) Prove(frameNumber uint64) error { return nil } +func (p *ProverUpdate) GetReadAddresses(frameNumber uint64) ([][]byte, error) { + return nil, nil +} + +func (p *ProverUpdate) GetWriteAddresses(frameNumber uint64) ([][]byte, error) { + proverAddress := p.PublicKeySignatureBLS48581.Address + proverFullAddress := [64]byte{} + copy(proverFullAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) + copy(proverFullAddress[32:], proverAddress) + + rewardAddressBI, err := poseidon.HashBytes(slices.Concat( + token.QUIL_TOKEN_ADDRESS[:], + proverAddress, + )) + if err != nil { + return nil, errors.Wrap(err, "get write address") + } + + rewardAddress := rewardAddressBI.FillBytes(make([]byte, 32)) + rewardFullAddress := [64]byte{} + copy(rewardFullAddress[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) + copy(rewardFullAddress[32:], rewardAddress) + + addresses := map[string]struct{}{} + addresses[string(proverFullAddress[:])] = struct{}{} + addresses[string(rewardFullAddress[:])] = struct{}{} + + result := [][]byte{} + for key := range addresses { + result = append(result, []byte(key)) + } + + return result, nil +} + // Verify implements intrinsics.IntrinsicOperation. func (p *ProverUpdate) Verify(frameNumber uint64) (bool, error) { if p.hypergraph == nil { diff --git a/node/execution/intrinsics/global/global_prover_update_test.go b/node/execution/intrinsics/global/global_prover_update_test.go index 98f04817..06ee974b 100644 --- a/node/execution/intrinsics/global/global_prover_update_test.go +++ b/node/execution/intrinsics/global/global_prover_update_test.go @@ -241,23 +241,24 @@ func TestProverUpdate_Materialize_PreservesBalance(t *testing.T) { nonZero := make([]byte, 32) binary.BigEndian.PutUint64(nonZero[24:], 12345) require.NoError(t, rdf.Set( - global.GLOBAL_RDF_SCHEMA, token.QUIL_TOKEN_ADDRESS, + global.GLOBAL_RDF_SCHEMA, intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], "reward:ProverReward", "Balance", nonZero, rewardPrior, )) fullProver := [64]byte{} fullReward := [64]byte{} + rewardAddr, err := poseidon.HashBytes(slices.Concat(token.QUIL_TOKEN_ADDRESS[:], addr)) copy(fullProver[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) - copy(fullReward[:32], token.QUIL_TOKEN_ADDRESS) + copy(fullReward[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) copy(fullProver[32:], addr) - copy(fullReward[32:], addr) + copy(fullReward[32:], rewardAddr.FillBytes(make([]byte, 32))) mockHG.On("GetVertex", fullProver).Return(nil, nil) mockHG.On("GetVertexData", fullProver).Return(proverTree, nil) mockHG.On("GetVertex", fullReward).Return(nil, nil) mockHG.On("GetVertexData", fullReward).Return(rewardPrior, nil) // Hypergraph lookups - mockHG.On("Get", token.QUIL_TOKEN_ADDRESS, addr, hgstate.VertexAddsDiscriminator).Return(rewardPrior, nil) + mockHG.On("Get", intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], rewardAddr.FillBytes(make([]byte, 32)), hgstate.VertexAddsDiscriminator).Return(rewardPrior, nil) mockHG.On("Get", intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], addr, hgstate.HyperedgeAddsDiscriminator).Return(nil, assert.AnError) delegate := make([]byte, 32) @@ -271,8 +272,8 @@ func TestProverUpdate_Materialize_PreservesBalance(t *testing.T) { On("SetVertexData", mock.Anything, mock.MatchedBy(func(id [64]byte) bool { - return bytes.Equal(id[:32], token.QUIL_TOKEN_ADDRESS) && - bytes.Equal(id[32:], addr) + return bytes.Equal(id[:32], intrinsics.GLOBAL_INTRINSIC_ADDRESS[:]) && + bytes.Equal(id[32:], rewardAddr.FillBytes(make([]byte, 32))) }), mock.MatchedBy(func(tree *qcrypto.VectorCommitmentTree) bool { d, err := rdf.Get(global.GLOBAL_RDF_SCHEMA, "reward:ProverReward", "DelegateAddress", tree) diff --git a/node/execution/intrinsics/global/global_serialization.go b/node/execution/intrinsics/global/global_serialization.go index 4c7ec34d..6b7af602 100644 --- a/node/execution/intrinsics/global/global_serialization.go +++ b/node/execution/intrinsics/global/global_serialization.go @@ -6,6 +6,7 @@ import ( "source.quilibrium.com/quilibrium/monorepo/types/crypto" "source.quilibrium.com/quilibrium/monorepo/types/hypergraph" "source.quilibrium.com/quilibrium/monorepo/types/keys" + "source.quilibrium.com/quilibrium/monorepo/types/store" ) // ToBytes serializes a BLS48581SignatureWithProofOfPossession to bytes using @@ -102,7 +103,7 @@ func (p *ProverJoin) FromBytes(data []byte) error { // Note: Runtime dependencies are not available here // They need to be injected separately after deserialization - converted, err := ProverJoinFromProtobuf(pb, nil, nil, nil, nil) + converted, err := ProverJoinFromProtobuf(pb, nil, nil, nil, nil, nil, nil) if err != nil { return errors.Wrap(err, "from bytes") } @@ -369,13 +370,23 @@ func GlobalRequestFromBytes( signer crypto.Signer, inclusionProver crypto.InclusionProver, keyManager keys.KeyManager, + frameProver crypto.FrameProver, + frameStore store.ClockStore, ) (interface{}, error) { pb := &protobufs.MessageRequest{} if err := pb.FromCanonicalBytes(data); err != nil { return nil, errors.Wrap(err, "global request from bytes") } - return GlobalRequestFromProtobuf(pb, hg, signer, inclusionProver, keyManager) + return GlobalRequestFromProtobuf( + pb, + hg, + signer, + inclusionProver, + keyManager, + frameProver, + frameStore, + ) } // ToBytes serializes a ProverUpdate to bytes using protobuf diff --git a/node/execution/intrinsics/hypergraph/hypergraph_hyperedge_add.go b/node/execution/intrinsics/hypergraph/hypergraph_hyperedge_add.go index 419970e1..637ff5c9 100644 --- a/node/execution/intrinsics/hypergraph/hypergraph_hyperedge_add.go +++ b/node/execution/intrinsics/hypergraph/hypergraph_hyperedge_add.go @@ -125,6 +125,25 @@ func (h *HyperedgeAdd) Prove(frameNumber uint64) error { return nil } +func (h *HyperedgeAdd) GetReadAddresses( + frameNumber uint64, +) ([][]byte, error) { + return nil, nil +} + +func (h *HyperedgeAdd) GetWriteAddresses( + frameNumber uint64, +) ([][]byte, error) { + hyperedgeID := h.Value.GetID() + + return [][]byte{ + slices.Concat( + h.Domain[:], + hyperedgeID[32:], + ), + }, nil +} + // Verify implements intrinsics.IntrinsicOperation. func (h *HyperedgeAdd) Verify(frameNumber uint64) (bool, error) { if h.Value == nil { diff --git a/node/execution/intrinsics/hypergraph/hypergraph_hyperedge_remove.go b/node/execution/intrinsics/hypergraph/hypergraph_hyperedge_remove.go index 37ca2e14..53dac138 100644 --- a/node/execution/intrinsics/hypergraph/hypergraph_hyperedge_remove.go +++ b/node/execution/intrinsics/hypergraph/hypergraph_hyperedge_remove.go @@ -92,6 +92,25 @@ func (h *HyperedgeRemove) Prove(frameNumber uint64) error { return nil } +func (h *HyperedgeRemove) GetReadAddresses( + frameNumber uint64, +) ([][]byte, error) { + return nil, nil +} + +func (h *HyperedgeRemove) GetWriteAddresses( + frameNumber uint64, +) ([][]byte, error) { + hyperedgeID := h.Value.GetID() + + return [][]byte{ + slices.Concat( + h.Domain[:], + hyperedgeID[32:], + ), + }, nil +} + // Verify implements intrinsics.IntrinsicOperation. func (h *HyperedgeRemove) Verify(frameNumber uint64) (bool, error) { // Verify that the hyperedge is valid diff --git a/node/execution/intrinsics/hypergraph/hypergraph_intrinsic.go b/node/execution/intrinsics/hypergraph/hypergraph_intrinsic.go index 6e9d2018..493a171e 100644 --- a/node/execution/intrinsics/hypergraph/hypergraph_intrinsic.go +++ b/node/execution/intrinsics/hypergraph/hypergraph_intrinsic.go @@ -1108,9 +1108,9 @@ func (h *HypergraphIntrinsic) InvokeStep( // Lock implements intrinsics.Intrinsic. func (h *HypergraphIntrinsic) Lock( - writeAddresses [][]byte, - readAddresses [][]byte, -) error { + frameNumber uint64, + input []byte, +) ([][]byte, error) { h.lockedReadsMx.Lock() h.lockedWritesMx.Lock() defer h.lockedReadsMx.Unlock() @@ -1124,102 +1124,314 @@ func (h *HypergraphIntrinsic) Lock( h.lockedWrites = make(map[string]struct{}) } - for _, address := range writeAddresses { + // Check type prefix to determine request type + if len(input) < 4 { + observability.LockErrors.WithLabelValues( + "hypergraph", + "invalid_input", + ).Inc() + return nil, errors.Wrap(errors.New("input too short"), "lock") + } + + // Read the type prefix + typePrefix := binary.BigEndian.Uint32(input[:4]) + + var reads, writes [][]byte + var err error + + // Handle each type based on type prefix + switch typePrefix { + case protobufs.VertexAddType: + reads, writes, err = h.tryLockVertexAdd(frameNumber, input) + if err != nil { + return nil, err + } + + observability.LockTotal.WithLabelValues("hypergraph", "vertex_add").Inc() + + case protobufs.VertexRemoveType: + reads, writes, err = h.tryLockVertexRemove(frameNumber, input) + if err != nil { + return nil, err + } + + observability.LockTotal.WithLabelValues( + "hypergraph", + "vertex_remove", + ).Inc() + + case protobufs.HyperedgeAddType: + reads, writes, err = h.tryLockHyperedgeAdd(frameNumber, input) + if err != nil { + return nil, err + } + + observability.LockTotal.WithLabelValues( + "hypergraph", + "hyperedge_add", + ).Inc() + + case protobufs.HyperedgeRemoveType: + reads, writes, err = h.tryLockHyperedgeRemove(frameNumber, input) + if err != nil { + return nil, err + } + + observability.LockTotal.WithLabelValues( + "hypergraph", + "hyperedge_remove", + ).Inc() + + default: + observability.LockErrors.WithLabelValues( + "hypergraph", + "unknown_type", + ).Inc() + return nil, errors.Wrap( + errors.New("unknown compute request type"), + "lock", + ) + } + + for _, address := range writes { if _, ok := h.lockedWrites[string(address)]; ok { - return errors.Wrap( + return nil, errors.Wrap( fmt.Errorf("address %x is already locked for writing", address), "lock", ) } if _, ok := h.lockedReads[string(address)]; ok { - return errors.Wrap( + return nil, errors.Wrap( fmt.Errorf("address %x is already locked for reading", address), "lock", ) } } - for _, address := range readAddresses { + for _, address := range reads { if _, ok := h.lockedWrites[string(address)]; ok { - return errors.Wrap( + return nil, errors.Wrap( fmt.Errorf("address %x is already locked for writing", address), "lock", ) } } - for _, address := range writeAddresses { + set := map[string]struct{}{} + + for _, address := range writes { h.lockedWrites[string(address)] = struct{}{} h.lockedReads[string(address)] = h.lockedReads[string(address)] + 1 + set[string(address)] = struct{}{} } - for _, address := range readAddresses { + for _, address := range reads { h.lockedReads[string(address)] = h.lockedReads[string(address)] + 1 + set[string(address)] = struct{}{} } - return nil + result := [][]byte{} + for a := range set { + result = append(result, []byte(a)) + } + + return result, nil } // Unlock implements intrinsics.Intrinsic. -func (h *HypergraphIntrinsic) Unlock( - writeAddresses [][]byte, - readAddresses [][]byte, -) error { +func (h *HypergraphIntrinsic) Unlock() error { h.lockedReadsMx.Lock() h.lockedWritesMx.Lock() defer h.lockedReadsMx.Unlock() defer h.lockedWritesMx.Unlock() - if h.lockedReads == nil { - h.lockedReads = make(map[string]int) + h.lockedReads = make(map[string]int) + h.lockedWrites = make(map[string]struct{}) + + return nil +} + +func (h *HypergraphIntrinsic) tryLockVertexAdd( + frameNumber uint64, + input []byte, +) ( + [][]byte, + [][]byte, + error, +) { + pbVertexAdd := &protobufs.VertexAdd{} + if err := pbVertexAdd.FromCanonicalBytes(input); err != nil { + observability.LockErrors.WithLabelValues( + "hypergraph", + "vertex_add", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + vertexAdd, err := VertexAddFromProtobuf( + pbVertexAdd, + h.inclusionProver, + h.keyManager, + h.signer, + h.verenc, + h.config, + ) + if err != nil { + observability.LockErrors.WithLabelValues( + "hypergraph", + "vertex_add", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - if h.lockedWrites == nil { - h.lockedWrites = make(map[string]struct{}) + reads, err := vertexAdd.GetReadAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "hypergraph", + "vertex_add", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - alteredWriteLocks := make(map[string]struct{}) - for k, v := range h.lockedWrites { - alteredWriteLocks[k] = v + writes, err := vertexAdd.GetWriteAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "hypergraph", + "vertex_add", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - for _, address := range writeAddresses { - delete(alteredWriteLocks, string(address)) + return reads, writes, nil +} + +func (h *HypergraphIntrinsic) tryLockVertexRemove( + frameNumber uint64, + input []byte, +) ( + [][]byte, + [][]byte, + error, +) { + vertexRemove := &VertexRemove{} + if err := vertexRemove.FromBytes( + input, + h.config, + h.keyManager, + h.signer, + ); err != nil { + observability.LockErrors.WithLabelValues( + "hypergraph", + "vertex_remove", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - for _, address := range readAddresses { - if _, ok := alteredWriteLocks[string(address)]; ok { - return errors.Wrap( - fmt.Errorf("address %x is still locked for writing", address), - "unlock", - ) - } + reads, err := vertexRemove.GetReadAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "hypergraph", + "vertex_remove", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - for _, address := range writeAddresses { - delete(h.lockedWrites, string(address)) - i, ok := h.lockedReads[string(address)] - if ok { - if i <= 1 { - delete(h.lockedReads, string(address)) - } else { - h.lockedReads[string(address)] = i - 1 - } - } + writes, err := vertexRemove.GetWriteAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "hypergraph", + "vertex_remove", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - for _, address := range readAddresses { - i, ok := h.lockedReads[string(address)] - if ok { - if i <= 1 { - delete(h.lockedReads, string(address)) - } else { - h.lockedReads[string(address)] = i - 1 - } - } + return reads, writes, nil +} + +func (h *HypergraphIntrinsic) tryLockHyperedgeAdd( + frameNumber uint64, + input []byte, +) ( + [][]byte, + [][]byte, + error, +) { + hyperedgeAdd := &HyperedgeAdd{} + if err := hyperedgeAdd.FromBytes( + input, + h.config, + h.inclusionProver, + h.keyManager, + h.signer, + ); err != nil { + observability.LockErrors.WithLabelValues( + "hypergraph", + "hyperedge_add", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - return nil + reads, err := hyperedgeAdd.GetReadAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "hypergraph", + "hyperedge_add", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + writes, err := hyperedgeAdd.GetWriteAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "hypergraph", + "hyperedge_add", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + return reads, writes, nil +} + +func (h *HypergraphIntrinsic) tryLockHyperedgeRemove( + frameNumber uint64, + input []byte, +) ( + [][]byte, + [][]byte, + error, +) { + hyperedgeRemove := &HyperedgeRemove{} + if err := hyperedgeRemove.FromBytes( + input, + h.config, + h.keyManager, + h.signer, + ); err != nil { + observability.LockErrors.WithLabelValues( + "hypergraph", + "hyperedge_remove", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + reads, err := hyperedgeRemove.GetReadAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "hypergraph", + "hyperedge_remove", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + writes, err := hyperedgeRemove.GetWriteAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "hypergraph", + "hyperedge_remove", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + return reads, writes, nil } var _ intrinsics.Intrinsic = (*HypergraphIntrinsic)(nil) diff --git a/node/execution/intrinsics/hypergraph/hypergraph_intrinsic_test.go b/node/execution/intrinsics/hypergraph/hypergraph_intrinsic_test.go index 81732175..34650051 100644 --- a/node/execution/intrinsics/hypergraph/hypergraph_intrinsic_test.go +++ b/node/execution/intrinsics/hypergraph/hypergraph_intrinsic_test.go @@ -119,134 +119,3 @@ func TestLoadHypergraphIntrinsic(t *testing.T) { mockHypergraph.AssertCalled(t, "GetVertex", vertexId) mockHypergraph.AssertCalled(t, "GetVertexData", vertexId) } - -func TestLock(t *testing.T) { - _, mockHypergraph := setupMockHypergraph(t) - - // Create a valid configuration - config := &hypergraph.HypergraphIntrinsicConfiguration{ - ReadPublicKey: make([]byte, 57), - WritePublicKey: make([]byte, 57), - } - - // Create a new intrinsic - intrinsic := hypergraph.NewHypergraphIntrinsic(config, mockHypergraph, nil, &mocks.MockKeyManager{}, nil, nil) - - t.Run("Lock successful", func(t *testing.T) { - writeAddresses := [][]byte{[]byte("write1"), []byte("write2")} - readAddresses := [][]byte{[]byte("read1"), []byte("read2")} - - // Lock the addresses - err := intrinsic.Lock(writeAddresses, readAddresses) - assert.NoError(t, err) - - // Try to lock the same write address (should fail) - err = intrinsic.Lock([][]byte{[]byte("write1")}, [][]byte{}) - assert.Error(t, err) - - // Try to lock the same read address for writing (should fail) - err = intrinsic.Lock([][]byte{[]byte("read1")}, [][]byte{}) - assert.Error(t, err) - - // Lock a new write address (should succeed) - err = intrinsic.Lock([][]byte{[]byte("write3")}, [][]byte{}) - assert.NoError(t, err) - - // Lock a new read address (should succeed) - err = intrinsic.Lock([][]byte{}, [][]byte{[]byte("read3")}) - assert.NoError(t, err) - }) - - t.Run("Lock same address multiple times for reading", func(t *testing.T) { - // Create a new intrinsic for clean state - intrinsic := hypergraph.NewHypergraphIntrinsic(config, mockHypergraph, nil, &mocks.MockKeyManager{}, nil, nil) - - // Lock an address for reading - err := intrinsic.Lock([][]byte{}, [][]byte{[]byte("shared")}) - assert.NoError(t, err) - - // Lock the same address for reading again (should succeed) - err = intrinsic.Lock([][]byte{}, [][]byte{[]byte("shared")}) - assert.NoError(t, err) - - // Try to lock for writing (should fail) - err = intrinsic.Lock([][]byte{[]byte("shared")}, [][]byte{}) - assert.Error(t, err) - }) -} - -func TestUnlock(t *testing.T) { - _, mockHypergraph := setupMockHypergraph(t) - - // Create a valid configuration - config := &hypergraph.HypergraphIntrinsicConfiguration{ - ReadPublicKey: make([]byte, 57), - WritePublicKey: make([]byte, 57), - } - - // Create a new intrinsic - intrinsic := hypergraph.NewHypergraphIntrinsic(config, mockHypergraph, nil, &mocks.MockKeyManager{}, nil, nil) - - t.Run("Unlock after lock", func(t *testing.T) { - writeAddresses := [][]byte{{0x01, 0x02}, {0x01, 0x03}} - readAddresses := [][]byte{{0x02, 0x02}, {0x02, 0x03}} - - // Lock the addresses - err := intrinsic.Lock(writeAddresses, readAddresses) - assert.NoError(t, err) - - // Unlock the addresses - err = intrinsic.Unlock(writeAddresses, readAddresses) - assert.NoError(t, err) - - // Lock them again (should succeed since they were unlocked) - err = intrinsic.Lock(writeAddresses, readAddresses) - assert.NoError(t, err) - }) - - t.Run("Unlock with referenced read lock", func(t *testing.T) { - // Create a new intrinsic for clean state - intrinsic := hypergraph.NewHypergraphIntrinsic(config, mockHypergraph, nil, &mocks.MockKeyManager{}, nil, nil) - - // Lock an address for reading twice - readAddress := []byte("shared") - err := intrinsic.Lock([][]byte{}, [][]byte{readAddress}) - assert.NoError(t, err) - err = intrinsic.Lock([][]byte{}, [][]byte{readAddress}) - assert.NoError(t, err) - - // Unlock once (should still be locked) - err = intrinsic.Unlock([][]byte{}, [][]byte{readAddress}) - assert.NoError(t, err) - - // Try to lock for writing (should still fail as read lock is still there) - err = intrinsic.Lock([][]byte{readAddress}, [][]byte{}) - assert.Error(t, err) - - // Unlock again (should completely unlock) - err = intrinsic.Unlock([][]byte{}, [][]byte{readAddress}) - assert.NoError(t, err) - - // Now should be able to lock for writing - err = intrinsic.Lock([][]byte{readAddress}, [][]byte{}) - assert.NoError(t, err) - }) - - t.Run("Cannot unlock read address with write lock", func(t *testing.T) { - // Create a new intrinsic for clean state - intrinsic := hypergraph.NewHypergraphIntrinsic(config, mockHypergraph, nil, &mocks.MockKeyManager{}, nil, nil) - - // Lock an address for writing - writeAddress := []byte("locked") - err := intrinsic.Lock([][]byte{writeAddress}, [][]byte{}) - assert.NoError(t, err) - - // Try to unlock as read (should fail) - err = intrinsic.Unlock([][]byte{}, [][]byte{writeAddress}) - assert.Error(t, err) - - // Unlock as write (should succeed) - err = intrinsic.Unlock([][]byte{writeAddress}, [][]byte{}) - assert.NoError(t, err) - }) -} diff --git a/node/execution/intrinsics/hypergraph/hypergraph_vertex_add.go b/node/execution/intrinsics/hypergraph/hypergraph_vertex_add.go index 712c6e50..436efdc4 100644 --- a/node/execution/intrinsics/hypergraph/hypergraph_vertex_add.go +++ b/node/execution/intrinsics/hypergraph/hypergraph_vertex_add.go @@ -158,6 +158,23 @@ func (h *VertexAdd) Prove(frameNumber uint64) error { return nil } +func (h *VertexAdd) GetReadAddresses( + frameNumber uint64, +) ([][]byte, error) { + return nil, nil +} + +func (h *VertexAdd) GetWriteAddresses( + frameNumber uint64, +) ([][]byte, error) { + return [][]byte{ + slices.Concat( + h.Domain[:], + h.DataAddress[:], + ), + }, nil +} + // Verify implements intrinsics.IntrinsicOperation. func (h *VertexAdd) Verify(frameNumber uint64) (bool, error) { // Check if data is valid and can be committed diff --git a/node/execution/intrinsics/hypergraph/hypergraph_vertex_remove.go b/node/execution/intrinsics/hypergraph/hypergraph_vertex_remove.go index 3d85033d..9a2a9590 100644 --- a/node/execution/intrinsics/hypergraph/hypergraph_vertex_remove.go +++ b/node/execution/intrinsics/hypergraph/hypergraph_vertex_remove.go @@ -78,6 +78,23 @@ func (h *VertexRemove) Prove(frameNumber uint64) error { return nil } +func (h *VertexRemove) GetReadAddresses( + frameNumber uint64, +) ([][]byte, error) { + return nil, nil +} + +func (h *VertexRemove) GetWriteAddresses( + frameNumber uint64, +) ([][]byte, error) { + return [][]byte{ + slices.Concat( + h.Domain[:], + h.DataAddress[:], + ), + }, nil +} + // Verify implements intrinsics.IntrinsicOperation. func (h *VertexRemove) Verify(frameNumber uint64) (bool, error) { message := make([]byte, 0, 64) diff --git a/node/execution/intrinsics/metrics.go b/node/execution/intrinsics/metrics.go index 81eec84c..3bf31976 100644 --- a/node/execution/intrinsics/metrics.go +++ b/node/execution/intrinsics/metrics.go @@ -65,6 +65,69 @@ var ( []string{"intrinsic_type", "operation"}, ) + // Lock operation metrics + LockDuration = promauto.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "lock_duration_seconds", + Help: "Time taken to lock an intrinsic step", + Buckets: prometheus.DefBuckets, + }, + []string{"intrinsic_type"}, // intrinsic type only for overall timing + ) + + LockTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "lock_total", + Help: "Total number of successful lock operations", + }, + []string{"intrinsic_type", "operation"}, + ) + + LockErrors = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "lock_errors_total", + Help: "Total number of failed lock operations", + }, + []string{"intrinsic_type", "operation"}, + ) + + UnlockDuration = promauto.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "unlock_duration_seconds", + Help: "Time taken to unlock an intrinsic step", + Buckets: prometheus.DefBuckets, + }, + []string{"intrinsic_type"}, // intrinsic type only for overall timing + ) + + UnlockTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "unlock_total", + Help: "Total number of successful unlock operations", + }, + []string{"intrinsic_type", "operation"}, + ) + + UnlockErrors = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: subsystem, + Name: "unlock_errors_total", + Help: "Total number of failed unlock operations", + }, + []string{"intrinsic_type", "operation"}, + ) + // InvokeStep operation metrics InvokeStepDuration = promauto.NewHistogramVec( prometheus.HistogramOpts{ diff --git a/node/execution/intrinsics/token/token_intrinsic.go b/node/execution/intrinsics/token/token_intrinsic.go index 16045c29..8ce4f461 100644 --- a/node/execution/intrinsics/token/token_intrinsic.go +++ b/node/execution/intrinsics/token/token_intrinsic.go @@ -751,9 +751,9 @@ func (t *TokenIntrinsic) InvokeStep( // Lock implements intrinsics.Intrinsic. func (t *TokenIntrinsic) Lock( - writeAddresses [][]byte, - readAddresses [][]byte, -) error { + frameNumber uint64, + input []byte, +) ([][]byte, error) { t.lockedReadsMx.Lock() t.lockedWritesMx.Lock() defer t.lockedReadsMx.Unlock() @@ -767,102 +767,267 @@ func (t *TokenIntrinsic) Lock( t.lockedWrites = make(map[string]struct{}) } - for _, address := range writeAddresses { + // Check type prefix to determine request type + if len(input) < 4 { + observability.LockErrors.WithLabelValues( + "token", + "invalid_input", + ).Inc() + return nil, errors.Wrap(errors.New("input too short"), "lock") + } + + // Read the type prefix + typePrefix := binary.BigEndian.Uint32(input[:4]) + + var reads, writes [][]byte + var err error + + // Handle each type based on type prefix + switch typePrefix { + case protobufs.TransactionType: + reads, writes, err = t.tryLockTransaction(frameNumber, input) + if err != nil { + return nil, err + } + + observability.LockTotal.WithLabelValues("token", "transaction").Inc() + + case protobufs.PendingTransactionType: + reads, writes, err = t.tryLockPendingTransaction(frameNumber, input) + if err != nil { + return nil, err + } + + observability.LockTotal.WithLabelValues( + "token", + "pending_transaction", + ).Inc() + + case protobufs.MintTransactionType: + reads, writes, err = t.tryLockMintTransaction(frameNumber, input) + if err != nil { + return nil, err + } + + observability.LockTotal.WithLabelValues( + "token", + "mint_transaction", + ).Inc() + + default: + observability.LockErrors.WithLabelValues( + "token", + "unknown_type", + ).Inc() + return nil, errors.Wrap( + errors.New("unknown compute request type"), + "lock", + ) + } + + for _, address := range writes { if _, ok := t.lockedWrites[string(address)]; ok { - return errors.Wrap( + return nil, errors.Wrap( fmt.Errorf("address %x is already locked for writing", address), "lock", ) } if _, ok := t.lockedReads[string(address)]; ok { - return errors.Wrap( + return nil, errors.Wrap( fmt.Errorf("address %x is already locked for reading", address), "lock", ) } } - for _, address := range readAddresses { + for _, address := range reads { if _, ok := t.lockedWrites[string(address)]; ok { - return errors.Wrap( + return nil, errors.Wrap( fmt.Errorf("address %x is already locked for writing", address), "lock", ) } } - for _, address := range writeAddresses { + set := map[string]struct{}{} + + for _, address := range writes { t.lockedWrites[string(address)] = struct{}{} t.lockedReads[string(address)] = t.lockedReads[string(address)] + 1 + set[string(address)] = struct{}{} } - for _, address := range readAddresses { + for _, address := range reads { t.lockedReads[string(address)] = t.lockedReads[string(address)] + 1 + set[string(address)] = struct{}{} } - return nil + result := [][]byte{} + for a := range set { + result = append(result, []byte(a)) + } + + return result, nil } // Unlock implements intrinsics.Intrinsic. -func (t *TokenIntrinsic) Unlock( - writeAddresses [][]byte, - readAddresses [][]byte, -) error { +func (t *TokenIntrinsic) Unlock() error { t.lockedReadsMx.Lock() t.lockedWritesMx.Lock() defer t.lockedReadsMx.Unlock() defer t.lockedWritesMx.Unlock() - if t.lockedReads == nil { - t.lockedReads = make(map[string]int) + t.lockedReads = make(map[string]int) + t.lockedWrites = make(map[string]struct{}) + + return nil +} + +func (t *TokenIntrinsic) tryLockTransaction( + frameNumber uint64, + input []byte, +) ( + [][]byte, + [][]byte, + error, +) { + tx := &Transaction{} + if err := tx.FromBytes( + input, + t.config, + t.hypergraph, + t.bulletproofProver, + t.inclusionProver, + t.verEnc, + t.decafConstructor, + keys.ToKeyRing(t.keyManager, true), + "", + t.rdfMultiprover, + ); err != nil { + observability.LockErrors.WithLabelValues( + "token", + "transaction", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - if t.lockedWrites == nil { - t.lockedWrites = make(map[string]struct{}) + reads, err := tx.GetReadAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "token", + "transaction", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - alteredWriteLocks := make(map[string]struct{}) - for k, v := range t.lockedWrites { - alteredWriteLocks[k] = v + writes, err := tx.GetWriteAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "token", + "transaction", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - for _, address := range writeAddresses { - delete(alteredWriteLocks, string(address)) + return reads, writes, nil +} + +func (t *TokenIntrinsic) tryLockPendingTransaction( + frameNumber uint64, + input []byte, +) ( + [][]byte, + [][]byte, + error, +) { + pendingTx := &PendingTransaction{} + if err := pendingTx.FromBytes( + input, + t.config, + t.hypergraph, + t.bulletproofProver, + t.inclusionProver, + t.verEnc, + t.decafConstructor, + keys.ToKeyRing(t.keyManager, true), + "", + t.rdfMultiprover, + ); err != nil { + observability.LockErrors.WithLabelValues( + "token", + "pending_transaction", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - for _, address := range readAddresses { - if _, ok := alteredWriteLocks[string(address)]; ok { - return errors.Wrap( - fmt.Errorf("address %x is still locked for writing", address), - "unlock", - ) - } + reads, err := pendingTx.GetReadAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "token", + "pending_transaction", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - for _, address := range writeAddresses { - delete(t.lockedWrites, string(address)) - i, ok := t.lockedReads[string(address)] - if ok { - if i <= 1 { - delete(t.lockedReads, string(address)) - } else { - t.lockedReads[string(address)] = i - 1 - } - } + writes, err := pendingTx.GetWriteAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "token", + "pending_transaction", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - for _, address := range readAddresses { - i, ok := t.lockedReads[string(address)] - if ok { - if i <= 1 { - delete(t.lockedReads, string(address)) - } else { - t.lockedReads[string(address)] = i - 1 - } - } + return reads, writes, nil +} + +func (t *TokenIntrinsic) tryLockMintTransaction( + frameNumber uint64, + input []byte, +) ( + [][]byte, + [][]byte, + error, +) { + mintTx := &MintTransaction{} + if err := mintTx.FromBytes( + input, + t.config, + t.hypergraph, + t.bulletproofProver, + t.inclusionProver, + t.verEnc, + t.decafConstructor, + keys.ToKeyRing(t.keyManager, true), + "", + t.rdfMultiprover, + ); err != nil { + observability.LockErrors.WithLabelValues( + "token", + "mint_transaction", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") } - return nil + reads, err := mintTx.GetReadAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "token", + "mint_transaction", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + writes, err := mintTx.GetWriteAddresses(frameNumber) + if err != nil { + observability.LockErrors.WithLabelValues( + "token", + "mint_transaction", + ).Inc() + return nil, nil, errors.Wrap(err, "lock") + } + + return reads, writes, nil } func (t *TokenIntrinsic) GetRDFSchemaDocument() string { diff --git a/node/execution/intrinsics/token/token_intrinsic_mint_transaction.go b/node/execution/intrinsics/token/token_intrinsic_mint_transaction.go index b1aa7102..1dda458f 100644 --- a/node/execution/intrinsics/token/token_intrinsic_mint_transaction.go +++ b/node/execution/intrinsics/token/token_intrinsic_mint_transaction.go @@ -768,7 +768,7 @@ func (i *MintTransactionInput) proveWithProofOfMeaningfulWork( // signature is the delegated prover key. pubKey := prover.Public().([]byte) var address []byte - if len(i.contextData) == 32 { + if len(i.contextData) != 32 { addressBI, err := poseidon.HashBytes(pubKey) if err != nil { return nil, errors.Wrap( @@ -777,9 +777,27 @@ func (i *MintTransactionInput) proveWithProofOfMeaningfulWork( ) } address = addressBI.FillBytes(make([]byte, 32)) + } else { + address = i.contextData } proverRootDomain := [32]byte(tx.Domain) + rewardAddress := address + if bytes.Equal(tx.Domain[:], QUIL_TOKEN_ADDRESS) { + // Special case: PoMW mints under QUIL use global records for proofs + proverRootDomain = intrinsics.GLOBAL_INTRINSIC_ADDRESS + derivedRewardAddress, err := poseidon.HashBytes( + slices.Concat(QUIL_TOKEN_ADDRESS[:], address), + ) + if err != nil { + return nil, errors.Wrap( + err, + "prove with mint with proof of meaningful work", + ) + } + + rewardAddress = derivedRewardAddress.FillBytes(make([]byte, 32)) + } proof, err := tx.hypergraph.CreateTraversalProof( proverRootDomain, @@ -787,7 +805,7 @@ func (i *MintTransactionInput) proveWithProofOfMeaningfulWork( hypergraph.AddsPhaseType, [][]byte{slices.Concat( proverRootDomain[:], - address, + rewardAddress, )}, ) if err != nil { @@ -816,7 +834,7 @@ func (i *MintTransactionInput) proveWithProofOfMeaningfulWork( proverData, err := tx.hypergraph.GetVertexData([64]byte(slices.Concat( proverRootDomain[:], - address, + rewardAddress, ))) if err != nil { return nil, errors.Wrap( @@ -1701,7 +1719,31 @@ func (i *MintTransactionInput) verifyWithProofOfMeaningfulWork( return errors.Wrap(err, "verify with mint with proof of meaningful work") } + delegatedAddressBI, err := poseidon.HashBytes(i.Proofs[1][32 : 585+32]) + if err != nil { + return errors.Wrap( + err, + "verify with mint with proof of meaningful work", + ) + } + proverRootDomain := [32]byte(tx.Domain) + if bytes.Equal(tx.Domain[:], QUIL_TOKEN_ADDRESS) { + // Special case: PoMW mints under QUIL use global records for proofs + proverRootDomain = intrinsics.GLOBAL_INTRINSIC_ADDRESS + delegatedAddressBI, err = poseidon.HashBytes( + slices.Concat( + QUIL_TOKEN_ADDRESS[:], + delegatedAddressBI.FillBytes(make([]byte, 32)), + ), + ) + if err != nil { + return errors.Wrap( + err, + "verify with mint with proof of meaningful work", + ) + } + } // Verify the membership proof of the prover: if valid, err := tx.hypergraph.VerifyTraversalProof( @@ -1718,19 +1760,12 @@ func (i *MintTransactionInput) verifyWithProofOfMeaningfulWork( pubkey := i.Proofs[1][32 : 585+32] signature := i.Proofs[1][585+32:] - delegatedAddressBI, err := poseidon.HashBytes(i.Proofs[1][32 : 585+32]) - if err != nil { - return errors.Wrap( - err, - "verify with mint with proof of meaningful work", - ) - } // Verify the state proof of the address: if valid, err := i.verifyProof( tx.hypergraph, [][]byte{ - delegatedAddressBI.FillBytes(make([]byte, 32)), + i.Proofs[1][:32], i.Value.FillBytes(make([]byte, 32)), }, i.Proofs[2], @@ -1749,7 +1784,7 @@ func (i *MintTransactionInput) verifyWithProofOfMeaningfulWork( h.Write([]byte{0}) h.Write(slices.Concat( proverRootDomain[:], - i.Proofs[1][:32], + delegatedAddressBI.FillBytes(make([]byte, 32)), )) h.Write(traversalProof.SubProofs[0].Ys[len(traversalProof.SubProofs[0].Ys)-1]) @@ -2078,8 +2113,17 @@ func (tx *MintTransaction) GetCost() (*big.Int, error) { return size, nil } +func (tx *MintTransaction) GetReadAddresses( + frameNumber uint64, +) ([][]byte, error) { + return nil, nil +} + // GetWriteAddresses implements intrinsics.IntrinsicOperation. -func (tx *MintTransaction) GetWriteAddresses() [][]byte { +func (tx *MintTransaction) GetWriteAddresses(frameNumber uint64) ( + [][]byte, + error, +) { addresses := [][]byte{} // Each output creates a new coin, which is written to an address based on @@ -2107,26 +2151,28 @@ func (tx *MintTransaction) GetWriteAddresses() [][]byte { for i := range tx.Inputs { proverRootDomain := [32]byte(tx.Domain) - - proverAddress := slices.Concat( - proverRootDomain[:], - tx.Inputs[i].Proofs[1][:32], - ) - // Check if not already in addresses - found := false - for _, addr := range addresses { - if bytes.Equal(addr, proverAddress) { - found = true - break + rewardAddress := []byte{} + if bytes.Equal(tx.Domain[:], QUIL_TOKEN_ADDRESS) { + // Special case: PoMW mints under QUIL use global records for proofs + proverRootDomain = intrinsics.GLOBAL_INTRINSIC_ADDRESS + rewardAddressBI, err := poseidon.HashBytes(slices.Concat( + QUIL_TOKEN_ADDRESS[:], + tx.Inputs[i].Proofs[1][:32], + )) + if err != nil { + return nil, errors.Wrap(err, "materialize") } + rewardAddress = rewardAddressBI.FillBytes(make([]byte, 32)) } - if !found { - addresses = append(addresses, proverAddress) - } + + addresses = append(addresses, slices.Concat( + proverRootDomain[:], + rewardAddress, + )) } } - return addresses + return addresses, nil } // Materialize implements intrinsics.IntrinsicOperation. @@ -2146,11 +2192,24 @@ func (tx *MintTransaction) Materialize( for i := 0; i < len(tx.Inputs); i++ { proverRootDomain := [32]byte(tx.Domain) + rewardAddress := tx.Inputs[i].Proofs[1][:32] + if bytes.Equal(tx.Domain[:], QUIL_TOKEN_ADDRESS) { + // Special case: PoMW mints under QUIL use global records for proofs + proverRootDomain = intrinsics.GLOBAL_INTRINSIC_ADDRESS + rewardAddressBI, err := poseidon.HashBytes(slices.Concat( + QUIL_TOKEN_ADDRESS[:], + tx.Inputs[i].Proofs[1][:32], + )) + if err != nil { + return nil, errors.Wrap(err, "materialize") + } + rewardAddress = rewardAddressBI.FillBytes(make([]byte, 32)) + } // Get current prover state vertex, err := state.Get( proverRootDomain[:], - tx.Inputs[i].Proofs[1][:32], + rewardAddress, hgstate.VertexAddsDiscriminator, ) if err != nil { @@ -2182,15 +2241,16 @@ func (tx *MintTransaction) Materialize( totalMinted.Add(totalMinted, input.Value) } - // Subtract from prover balance - newBalance := new(big.Int).Sub(currentBalance, totalMinted) - if newBalance.Sign() < 0 { + if currentBalance.Cmp(totalMinted) < 0 { return nil, errors.Wrap( errors.New("insufficient prover balance"), "materialize", ) } + // Subtract from prover balance + newBalance := new(big.Int).Sub(currentBalance, totalMinted) + // Set new balance at index 1 newBalanceBytes := newBalance.FillBytes(make([]byte, 32)) if err := proverTree.Insert( @@ -2205,7 +2265,7 @@ func (tx *MintTransaction) Materialize( // Create materialized state for prover update proverUpdate := hypergraphState.NewVertexAddMaterializedState( proverRootDomain, - [32]byte(tx.Inputs[i].Proofs[1][:32]), + [32]byte(rewardAddress), frameNumber, nil, proverTree, @@ -2214,7 +2274,7 @@ func (tx *MintTransaction) Materialize( // Set the state err = hypergraphState.Set( proverRootDomain[:], - tx.Inputs[i].Proofs[1][:32], + rewardAddress, hgstate.VertexAddsDiscriminator, frameNumber, proverUpdate, diff --git a/node/execution/intrinsics/token/token_intrinsic_pending_transaction.go b/node/execution/intrinsics/token/token_intrinsic_pending_transaction.go index 01361008..46f4a9a9 100644 --- a/node/execution/intrinsics/token/token_intrinsic_pending_transaction.go +++ b/node/execution/intrinsics/token/token_intrinsic_pending_transaction.go @@ -1504,6 +1504,30 @@ func (tx *PendingTransaction) Prove(frameNumber uint64) error { return nil } +func (tx *PendingTransaction) GetReadAddresses( + frameNumber uint64, +) ([][]byte, error) { + return nil, nil +} + +func (tx *PendingTransaction) GetWriteAddresses( + frameNumber uint64, +) ([][]byte, error) { + addresses := [][]byte{} + + // Build the trees if not already built + if err := tx.buildPendingTransactionTrees(); err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + // Add pending transactions using cached trees + for i := range tx.cachedTrees { + addresses = append(addresses, tx.cachedAddresses[i]) + } + + return addresses, nil +} + func (tx *PendingTransaction) GetChallenge() ([]byte, error) { transcript := []byte{} transcript = append(transcript, tx.Domain[:]...) diff --git a/node/execution/intrinsics/token/token_intrinsic_rbls48581_bulletproofs_integration_test.go b/node/execution/intrinsics/token/token_intrinsic_rbls48581_bulletproofs_integration_test.go index 6d04ab02..0adfa7e5 100644 --- a/node/execution/intrinsics/token/token_intrinsic_rbls48581_bulletproofs_integration_test.go +++ b/node/execution/intrinsics/token/token_intrinsic_rbls48581_bulletproofs_integration_test.go @@ -29,6 +29,7 @@ import ( "source.quilibrium.com/quilibrium/monorepo/node/store" "source.quilibrium.com/quilibrium/monorepo/node/tests" "source.quilibrium.com/quilibrium/monorepo/types/crypto" + "source.quilibrium.com/quilibrium/monorepo/types/execution/intrinsics" "source.quilibrium.com/quilibrium/monorepo/types/execution/state" thypergraph "source.quilibrium.com/quilibrium/monorepo/types/hypergraph" "source.quilibrium.com/quilibrium/monorepo/types/schema" @@ -230,6 +231,7 @@ func TestValidMintWithProofOfMeaningfulWorkTransaction(t *testing.T) { assert.NoError(t, err) proveraddr, err := poseidon.HashBytes(prover.Public().([]byte)) + rewardaddr, err := poseidon.HashBytes(slices.Concat(token.QUIL_TOKEN_ADDRESS[:], proveraddr.FillBytes(make([]byte, 32)))) txn, _ := hg.NewTransaction(false) rand1 := make([]byte, 32) rand2 := make([]byte, 32) @@ -240,10 +242,10 @@ func TestValidMintWithProofOfMeaningfulWorkTransaction(t *testing.T) { tree := &qcrypto.VectorCommitmentTree{} tree.Insert([]byte{0}, proveraddr.FillBytes(make([]byte, 32)), nil, big.NewInt(0)) tree.Insert([]byte{1 << 2}, big.NewInt(10000).FillBytes(make([]byte, 32)), nil, big.NewInt(0)) - vert := hypergraph.NewVertex([32]byte(token.QUIL_TOKEN_ADDRESS), [32]byte(proveraddr.FillBytes(make([]byte, 32))), tree.Commit(ip, false), big.NewInt(74)) + vert := hypergraph.NewVertex([32]byte(intrinsics.GLOBAL_INTRINSIC_ADDRESS), [32]byte(rewardaddr.FillBytes(make([]byte, 32))), tree.Commit(ip, false), big.NewInt(74)) err = hg.AddVertex(txn, vert) assert.NoError(t, err) - err = hg.SetVertexData(txn, [64]byte(slices.Concat(token.QUIL_TOKEN_ADDRESS[:], proveraddr.FillBytes(make([]byte, 32)))), tree) + err = hg.SetVertexData(txn, [64]byte(slices.Concat(intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], rewardaddr.FillBytes(make([]byte, 32)))), tree) assert.NoError(t, err) hg.AddVertex(txn, hypergraph.NewVertex([32]byte(token.QUIL_TOKEN_ADDRESS), [32]byte(rand1), nil, big.NewInt(74))) err = txn.Commit() @@ -2420,6 +2422,9 @@ func TestFullTokenFlow_MintPendingTransaction(t *testing.T) { proveraddr, err := poseidon.HashBytes(prover.Public().([]byte)) assert.NoError(t, err) + rewardAddress, err := poseidon.HashBytes(slices.Concat(token.QUIL_TOKEN_ADDRESS[:], proveraddr.FillBytes(make([]byte, 32)))) + assert.NoError(t, err) + proverTree := &qcrypto.VectorCommitmentTree{} proverTree.Insert([]byte{0}, proveraddr.FillBytes(make([]byte, 32)), nil, big.NewInt(0)) proverTree.Insert([]byte{1 << 2}, big.NewInt(10000).FillBytes(make([]byte, 32)), nil, big.NewInt(0)) @@ -2427,8 +2432,8 @@ func TestFullTokenFlow_MintPendingTransaction(t *testing.T) { // Set up prover with 10000 balance txn, _ := hg.NewTransaction(false) vert := hypergraph.NewVertex( - [32]byte(token.QUIL_TOKEN_ADDRESS), - [32]byte(proveraddr.FillBytes(make([]byte, 32))), + [32]byte(intrinsics.GLOBAL_INTRINSIC_ADDRESS), + [32]byte(rewardAddress.FillBytes(make([]byte, 32))), proverTree.Commit(ip, false), big.NewInt(74), ) @@ -2656,7 +2661,7 @@ func TestFullTokenFlow_MintPendingTransaction(t *testing.T) { assert.Nil(t, acceptSpendVertex) // Should not be spent // Verify prover balance is reduced by 10000 - globalVertex, err := hg.GetVertexData([64]byte(append(token.QUIL_TOKEN_ADDRESS[:], proveraddr.FillBytes(make([]byte, 32))...))) + globalVertex, err := hg.GetVertexData([64]byte(append(intrinsics.GLOBAL_INTRINSIC_ADDRESS[:], rewardAddress.FillBytes(make([]byte, 32))...))) assert.NoError(t, err) assert.NotNil(t, globalVertex) amtBytes, err := globalVertex.Get([]byte{1 << 2}) diff --git a/node/execution/intrinsics/token/token_intrinsic_transaction.go b/node/execution/intrinsics/token/token_intrinsic_transaction.go index 36264fac..32b10a58 100644 --- a/node/execution/intrinsics/token/token_intrinsic_transaction.go +++ b/node/execution/intrinsics/token/token_intrinsic_transaction.go @@ -1271,6 +1271,171 @@ func (tx *Transaction) Prove(frameNumber uint64) error { return nil } +func (tx *Transaction) GetReadAddresses( + frameNumber uint64, +) ([][]byte, error) { + return nil, nil +} + +func (tx *Transaction) GetWriteAddresses( + frameNumber uint64, +) ([][]byte, error) { + // Create the coin type hash + coinTypeBI, err := poseidon.HashBytes( + slices.Concat(tx.Domain[:], []byte("coin:Coin")), + ) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + coinTypeBytes := coinTypeBI.FillBytes(make([]byte, 32)) + + addresses := [][]byte{} + + // For each output, create a coin + for _, output := range tx.Outputs { + // Create coin tree + coinTree := &qcrypto.VectorCommitmentTree{} + + // Index 0: FrameNumber + if err := coinTree.Insert( + []byte{0}, + output.FrameNumber, + nil, + big.NewInt(8), + ); err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + // Index 1: Commitment + if err := coinTree.Insert( + []byte{1 << 2}, + output.Commitment, + nil, + big.NewInt(56), + ); err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + // Index 2: OneTimeKey + if err := coinTree.Insert( + []byte{2 << 2}, + output.RecipientOutput.OneTimeKey, + nil, + big.NewInt(56), + ); err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + // Index 3: VerificationKey + if err := coinTree.Insert( + []byte{3 << 2}, + output.RecipientOutput.VerificationKey, + nil, + big.NewInt(56), + ); err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + // Index 4: CoinBalance (encrypted) + if err := coinTree.Insert( + []byte{4 << 2}, + output.RecipientOutput.CoinBalance, + nil, + big.NewInt(56), + ); err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + // Index 5: Mask (encrypted) + if err := coinTree.Insert( + []byte{5 << 2}, + output.RecipientOutput.Mask, + nil, + big.NewInt(56), + ); err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + // Index 6 & 7: Additional references (for non-divisible tokens) + if len(output.RecipientOutput.AdditionalReference) == 64 && + len(output.RecipientOutput.AdditionalReferenceKey) == 56 { + if err := coinTree.Insert( + []byte{6 << 2}, + output.RecipientOutput.AdditionalReference, + nil, + big.NewInt(56), + ); err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + if err := coinTree.Insert( + []byte{7 << 2}, + output.RecipientOutput.AdditionalReferenceKey, + nil, + big.NewInt(56), + ); err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + } + + // Type marker at max index + if err := coinTree.Insert( + bytes.Repeat([]byte{0xff}, 32), + coinTypeBytes, + nil, + big.NewInt(32), + ); err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + // Compute address and add to state + commit := coinTree.Commit(tx.inclusionProver, false) + outAddrBI, err := poseidon.HashBytes(commit) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + coinAddress := outAddrBI.FillBytes(make([]byte, 32)) + + addresses = append(addresses, slices.Concat( + tx.Domain[:], + coinAddress, + )) + } + + // Mark inputs as spent + for _, input := range tx.Inputs { + if len(input.Signature) == 336 { + // Standard format + verificationKey := input.Signature[56*4 : 56*5] + spendCheckBI, err := poseidon.HashBytes(verificationKey) + if err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + // Create spent marker + spentTree := &qcrypto.VectorCommitmentTree{} + if err := spentTree.Insert( + []byte{0}, + []byte{0x01}, + nil, + big.NewInt(0), + ); err != nil { + return nil, errors.Wrap(err, "get write addresses") + } + + spentAddress := spendCheckBI.FillBytes(make([]byte, 32)) + + addresses = append(addresses, slices.Concat( + tx.Domain[:], + spentAddress, + )) + } + } + + return addresses, nil +} + func (tx *Transaction) GetChallenge() ([]byte, error) { transcript := []byte{} transcript = append(transcript, tx.Domain[:]...) diff --git a/node/execution/intrinsics/token/token_update_integration_test.go b/node/execution/intrinsics/token/token_update_integration_test.go index 31cdb6ea..0570c143 100644 --- a/node/execution/intrinsics/token/token_update_integration_test.go +++ b/node/execution/intrinsics/token/token_update_integration_test.go @@ -1,3 +1,6 @@ +//go:build integrationtest +// +build integrationtest + package token_test import ( diff --git a/node/execution/manager/execution_manager.go b/node/execution/manager/execution_manager.go index e729f9f2..7312a893 100644 --- a/node/execution/manager/execution_manager.go +++ b/node/execution/manager/execution_manager.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "math/big" "slices" + "strings" "sync" "time" @@ -44,6 +45,7 @@ type ExecutionEngineManager struct { verEnc crypto.VerifiableEncryptor decafConstructor crypto.DecafConstructor compiler compiler.CircuitCompiler + frameProver crypto.FrameProver includeGlobal bool quit chan struct{} wg sync.WaitGroup @@ -62,6 +64,7 @@ func NewExecutionEngineManager( verEnc crypto.VerifiableEncryptor, decafConstructor crypto.DecafConstructor, compiler compiler.CircuitCompiler, + frameProver crypto.FrameProver, includeGlobal bool, ) (*ExecutionEngineManager, error) { return &ExecutionEngineManager{ @@ -79,6 +82,7 @@ func NewExecutionEngineManager( verEnc: verEnc, decafConstructor: decafConstructor, compiler: compiler, + frameProver: frameProver, includeGlobal: includeGlobal, quit: make(chan struct{}), }, nil @@ -101,6 +105,7 @@ func (m *ExecutionEngineManager) InitializeEngines() error { m.verEnc, m.decafConstructor, m.compiler, + m.frameProver, m.includeGlobal, ) if err != nil { @@ -617,6 +622,45 @@ func (m *ExecutionEngineManager) ProcessMessage( ) } +// ValidateMessage validates a message without materializing state changes +func (m *ExecutionEngineManager) Lock( + frameNumber uint64, + address []byte, + message []byte, +) error { + m.enginesMu.RLock() + defer m.enginesMu.RUnlock() + + engine := m.selectEngine(address) + if engine == nil { + return errors.Errorf("no execution engine found for address: %x", address) + } + + return engine.Lock(frameNumber, address, message) +} + +func (m *ExecutionEngineManager) Unlock() error { + m.enginesMu.RLock() + defer m.enginesMu.RUnlock() + + errs := []string{} + for _, engine := range m.engines { + err := engine.Unlock() + if err != nil { + errs = append(errs, err.Error()) + } + } + + if len(errs) != 0 { + return errors.Wrap( + errors.Errorf("multiple errors: %s", strings.Join(errs, ", ")), + "unlock", + ) + } + + return nil +} + // ValidateMessage validates a message without materializing state changes func (m *ExecutionEngineManager) ValidateMessage( frameNumber uint64, diff --git a/node/go.mod b/node/go.mod index c416a3ff..fe44253b 100644 --- a/node/go.mod +++ b/node/go.mod @@ -49,6 +49,7 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 github.com/libp2p/go-libp2p v0.41.1 github.com/libp2p/go-libp2p-kad-dht v0.23.0 + github.com/marcopolo/simnet v0.0.1 github.com/shopspring/decimal v1.4.0 google.golang.org/protobuf v1.36.6 gopkg.in/yaml.v2 v2.4.0 @@ -62,9 +63,9 @@ require ( source.quilibrium.com/quilibrium/monorepo/hypergraph v0.0.0-00010101000000-000000000000 source.quilibrium.com/quilibrium/monorepo/nekryptology v0.0.0-00010101000000-000000000000 source.quilibrium.com/quilibrium/monorepo/protobufs v0.0.0-00010101000000-000000000000 + source.quilibrium.com/quilibrium/monorepo/rpm v0.0.0-00010101000000-000000000000 source.quilibrium.com/quilibrium/monorepo/types v0.0.0-00010101000000-000000000000 source.quilibrium.com/quilibrium/monorepo/utils v0.0.0-00010101000000-000000000000 - source.quilibrium.com/quilibrium/monorepo/rpm v0.0.0-00010101000000-000000000000 source.quilibrium.com/quilibrium/monorepo/vdf v0.0.0-00010101000000-000000000000 source.quilibrium.com/quilibrium/monorepo/verenc v0.0.0-00010101000000-000000000000 ) @@ -101,7 +102,6 @@ require ( github.com/pion/webrtc/v4 v4.1.2 // indirect github.com/rychipman/easylex v0.0.0-20160129204217-49ee7767142f // indirect github.com/stretchr/objx v0.5.2 // indirect - github.com/txaty/go-merkletree v0.2.2 // indirect github.com/wlynxg/anet v0.0.5 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/otel v1.34.0 // indirect @@ -125,7 +125,7 @@ require ( github.com/getsentry/sentry-go v0.27.0 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/gorilla/websocket v1.5.3 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/multiformats/go-multiaddr v0.16.1 diff --git a/node/go.sum b/node/go.sum index 1b433938..65dce228 100644 --- a/node/go.sum +++ b/node/go.sum @@ -13,8 +13,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 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/agiledragon/gomonkey/v2 v2.11.0 h1:5oxSgA+tC1xuGsrIorR+sYiziYltmJyEZ9qA25b6l5U= -github.com/agiledragon/gomonkey/v2 v2.11.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= 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.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= @@ -463,8 +461,6 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/txaty/go-merkletree v0.2.2 h1:K5bHDFK+Q3KK+gEJeyTOECKuIwl/LVo4CI+cm0/p34g= -github.com/txaty/go-merkletree v0.2.2/go.mod h1:w5HPEu7ubNw5LzS+91m+1/GtuZcWHKiPU3vEGi+ThJM= 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= diff --git a/node/main.go b/node/main.go index c9c753a8..a492f434 100644 --- a/node/main.go +++ b/node/main.go @@ -455,10 +455,10 @@ func main() { zap.Int64("data_worker_reserved_memory", dataWorkerReservedMemory), ) logger.Warn("you are at risk of running out of memory during runtime") - case availableOverhead < 8*1024*1024*1024: + case availableOverhead < 2*1024*1024*1024: logger.Warn( "the memory available to the node, unallocated to "+ - "the data workers, is less than 8gb", + "the data workers, is less than 2gb", zap.Int64("available_overhead", availableOverhead), ) logger.Warn("you are at risk of running out of memory during runtime") @@ -486,7 +486,7 @@ func main() { // Start the master node quitCh := make(chan struct{}) go func() { - if err := masterNode.Start(); err != nil { + if err := masterNode.Start(quitCh); err != nil { logger.Error("master node start error", zap.Error(err)) close(quitCh) } diff --git a/node/p2p/blossomsub.go b/node/p2p/blossomsub.go index 327b9b2d..4ab113e7 100644 --- a/node/p2p/blossomsub.go +++ b/node/p2p/blossomsub.go @@ -64,11 +64,12 @@ type appScore struct { } type BlossomSub struct { - ps *blossomsub.PubSub - ctx context.Context - logger *zap.Logger - peerID peer.ID - bitmaskMap map[string]*blossomsub.Bitmask + ps *blossomsub.PubSub + ctx context.Context + logger *zap.Logger + peerID peer.ID + derivedPeerID peer.ID + bitmaskMap map[string]*blossomsub.Bitmask // Track which bit slices belong to which original bitmasks, used to reference // count bitmasks for closed subscriptions subscriptionTracker map[string][][]byte @@ -109,6 +110,252 @@ func getPeerID(p2pConfig *config.P2PConfig) peer.ID { return id } +// NewBlossomSubWithHost creates a new blossomsub instance with a pre-defined +// host. This method is intended for integration tests that need something +// more realistic for pubsub purposes, with a supplied simulator (see +// node/tests/simnet.go for utility methods to construct a flaky host) +func NewBlossomSubWithHost( + p2pConfig *config.P2PConfig, + engineConfig *config.EngineConfig, + logger *zap.Logger, + coreId uint, + isBootstrapPeer bool, + host host.Host, + privKey crypto.PrivKey, + bootstrapHosts []host.Host, +) *BlossomSub { + ctx := context.Background() + if coreId == 0 { + logger = logger.With(zap.String("process", "master")) + } else { + logger = logger.With(zap.String( + "process", + fmt.Sprintf("worker %d", coreId), + )) + } + + bs := &BlossomSub{ + ctx: ctx, + logger: logger, + bitmaskMap: make(map[string]*blossomsub.Bitmask), + subscriptionTracker: make(map[string][][]byte), + signKey: privKey, + peerScore: make(map[string]*appScore), + p2pConfig: *p2pConfig, + } + + idService := internal.IDServiceFromHost(host) + + logger.Info("established peer id", zap.String("peer_id", host.ID().String())) + + reachabilitySub, err := host.EventBus().Subscribe( + &event.EvtLocalReachabilityChanged{}, + eventbus.Name("blossomsub"), + ) + if err != nil { + logger.Panic("error subscribing to reachability events", zap.Error(err)) + } + go func() { + defer reachabilitySub.Close() + instance := "node" + if coreId != 0 { + instance = "worker" + } + logger := logger.Named("reachability") + for { + select { + case <-ctx.Done(): + return + case evt, ok := <-reachabilitySub.Out(): + if !ok { + return + } + state := evt.(event.EvtLocalReachabilityChanged).Reachability + bs.reachability.Store(&state) + switch state { + case network.ReachabilityPublic: + logger.Info( + instance+" is externally reachable", + zap.Uint("core_id", coreId), + ) + case network.ReachabilityPrivate: + logger.Error( + instance+" is not externally reachable", + zap.Uint("core_id", coreId), + ) + case network.ReachabilityUnknown: + logger.Info( + instance+" reachability is unknown", + zap.Uint("core_id", coreId), + ) + default: + logger.Debug("unknown reachability state", zap.Any("state", state)) + } + } + } + }() + + bootstrappers := []peer.AddrInfo{} + for _, bh := range bootstrapHosts { + // manually construct the p2p string, kind of kludgy, but this is intended + // for use with tests + ai, err := peer.AddrInfoFromString( + bh.Addrs()[0].String() + "/p2p/" + bh.ID().String(), + ) + if err != nil { + panic(fmt.Sprintf("error for addr %v, %+v:", bh.Addrs()[0], err)) + } + bootstrappers = append(bootstrappers, *ai) + } + kademliaDHT := initDHT( + ctx, + logger, + host, + isBootstrapPeer, + bootstrappers, + p2pConfig.Network, + ) + host = routedhost.Wrap(host, kademliaDHT) + + routingDiscovery := routing.NewRoutingDiscovery(kademliaDHT) + util.Advertise(ctx, routingDiscovery, getNetworkNamespace(p2pConfig.Network)) + + minBootstrapPeers := min(len(bootstrappers), p2pConfig.MinBootstrapPeers) + bootstrap := internal.NewPeerConnector( + ctx, + zap.NewNop(), + host, + idService, + minBootstrapPeers, + p2pConfig.BootstrapParallelism, + internal.NewStaticPeerSource(bootstrappers, true), + ) + if err := bootstrap.Connect(ctx); err != nil { + logger.Panic("error connecting to bootstrap peers", zap.Error(err)) + } + bs.bootstrap = bootstrap + + discovery := internal.NewPeerConnector( + ctx, + zap.NewNop(), + host, + idService, + p2pConfig.D, + p2pConfig.DiscoveryParallelism, + internal.NewRoutingDiscoveryPeerSource( + routingDiscovery, + getNetworkNamespace(p2pConfig.Network), + p2pConfig.DiscoveryPeerLookupLimit, + ), + ) + if err := discovery.Connect(ctx); err != nil { + logger.Panic("error connecting to discovery peers", zap.Error(err)) + } + discovery = internal.NewChainedPeerConnector(ctx, bootstrap, discovery) + bs.discovery = discovery + + internal.MonitorPeers( + ctx, + logger.Named("peer-monitor"), + host, + p2pConfig.PingTimeout, + p2pConfig.PingPeriod, + p2pConfig.PingAttempts, + ) + + var tracer *blossomsub.JSONTracer + if p2pConfig.TraceLogStdout { + tracer, err = blossomsub.NewStdoutJSONTracer() + if err != nil { + panic(errors.Wrap(err, "error building stdout tracer")) + } + } else if p2pConfig.TraceLogFile != "" { + tracer, err = blossomsub.NewJSONTracer(p2pConfig.TraceLogFile) + if err != nil { + logger.Panic("error building file tracer", zap.Error(err)) + } + } + + blossomOpts := []blossomsub.Option{ + blossomsub.WithStrictSignatureVerification(true), + blossomsub.WithValidateQueueSize(blossomsub.DefaultValidateQueueSize), + blossomsub.WithValidateWorkers(1), + blossomsub.WithPeerOutboundQueueSize( + blossomsub.DefaultPeerOutboundQueueSize, + ), + } + + if tracer != nil { + blossomOpts = append(blossomOpts, blossomsub.WithEventTracer(tracer)) + } + blossomOpts = append(blossomOpts, blossomsub.WithPeerScore( + &blossomsub.PeerScoreParams{ + SkipAtomicValidation: false, + BitmaskScoreCap: 0, + IPColocationFactorWeight: 0, + IPColocationFactorThreshold: 6, + BehaviourPenaltyWeight: -10, + BehaviourPenaltyThreshold: 100, + BehaviourPenaltyDecay: .5, + DecayInterval: DecayInterval, + DecayToZero: .1, + RetainScore: 60 * time.Minute, + AppSpecificScore: func(p peer.ID) float64 { + return float64(bs.GetPeerScore([]byte(p))) + }, + AppSpecificWeight: 10.0, + }, + &blossomsub.PeerScoreThresholds{ + SkipAtomicValidation: false, + GossipThreshold: -2000, + PublishThreshold: -5000, + GraylistThreshold: -10000, + AcceptPXThreshold: 1, + OpportunisticGraftThreshold: 2, + }, + )) + blossomOpts = append(blossomOpts, observability.WithPrometheusRawTracer()) + if p2pConfig.Network == 0 { + logger.Info("enabling blacklist for bootstrappers for blossomsub") + blossomOpts = append(blossomOpts, blossomsub.WithPeerFilter( + internal.NewStaticPeerFilter( + []peer.ID{}, + internal.PeerAddrInfosToPeerIDSlice(bootstrappers), + true, + ), + )) + } + blossomOpts = append(blossomOpts, blossomsub.WithDiscovery( + internal.NewPeerConnectorDiscovery(discovery), + )) + blossomOpts = append(blossomOpts, blossomsub.WithMessageIdFn( + func(pmsg *pb.Message) []byte { + id := sha256.Sum256(pmsg.Data) + return id[:] + }), + ) + + params := toBlossomSubParams(p2pConfig) + rt := blossomsub.NewBlossomSubRouter(host, params, bs.p2pConfig.Network) + blossomOpts = append(blossomOpts, rt.WithDefaultTagTracer()) + pubsub, err := blossomsub.NewBlossomSubWithRouter(ctx, host, rt, blossomOpts...) + if err != nil { + logger.Panic("error creating pubsub", zap.Error(err)) + } + + peerID := host.ID() + bs.dht = kademliaDHT + bs.ps = pubsub + bs.peerID = peerID + bs.h = host + bs.signKey = privKey + bs.derivedPeerID = peerID + + go bs.background(ctx) + + return bs +} + func NewBlossomSub( p2pConfig *config.P2PConfig, engineConfig *config.EngineConfig, @@ -166,30 +413,33 @@ func NewBlossomSub( } isBootstrapPeer := false - peerId := getPeerID(p2pConfig) - if p2pConfig.Network == 0 { - for _, peerAddr := range config.BootstrapPeers { - peerinfo, err := peer.AddrInfoFromString(peerAddr) - if err != nil { - logger.Panic("error getting peer info", zap.Error(err)) - } + if coreId == 0 { + peerId := getPeerID(p2pConfig) - if bytes.Equal([]byte(peerinfo.ID), []byte(peerId)) { - isBootstrapPeer = true - break - } - } - } else { - for _, peerAddr := range p2pConfig.BootstrapPeers { - peerinfo, err := peer.AddrInfoFromString(peerAddr) - if err != nil { - logger.Panic("error getting peer info", zap.Error(err)) + if p2pConfig.Network == 0 { + for _, peerAddr := range config.BootstrapPeers { + peerinfo, err := peer.AddrInfoFromString(peerAddr) + if err != nil { + logger.Panic("error getting peer info", zap.Error(err)) + } + + if bytes.Equal([]byte(peerinfo.ID), []byte(peerId)) { + isBootstrapPeer = true + break + } } + } else { + for _, peerAddr := range p2pConfig.BootstrapPeers { + peerinfo, err := peer.AddrInfoFromString(peerAddr) + if err != nil { + logger.Panic("error getting peer info", zap.Error(err)) + } - if bytes.Equal([]byte(peerinfo.ID), []byte(peerId)) { - isBootstrapPeer = true - break + if bytes.Equal([]byte(peerinfo.ID), []byte(peerId)) { + isBootstrapPeer = true + break + } } } } @@ -212,6 +462,7 @@ func NewBlossomSub( } var privKey crypto.PrivKey + var derivedPeerId peer.ID if p2pConfig.PeerPrivKey != "" { peerPrivKey, err := hex.DecodeString(p2pConfig.PeerPrivKey) if err != nil { @@ -223,7 +474,21 @@ func NewBlossomSub( logger.Panic("error unmarshaling peerkey", zap.Error(err)) } - opts = append(opts, libp2p.Identity(privKey)) + derivedPeerId, err = peer.IDFromPrivateKey(privKey) + if err != nil { + logger.Panic("error deriving peer id", zap.Error(err)) + } + + if coreId == 0 { + opts = append(opts, libp2p.Identity(privKey)) + } else { + workerKey, _, err := crypto.GenerateEd448Key(rand.Reader) + if err != nil { + logger.Panic("error generating worker peerkey", zap.Error(err)) + } + + opts = append(opts, libp2p.Identity(workerKey)) + } } allowedPeers := []peer.AddrInfo{} @@ -246,6 +511,26 @@ func NewBlossomSub( } allowedPeers = append(allowedPeers, directPeers...) + opts = append( + opts, + libp2p.SwarmOpts( + swarm.WithUDPBlackHoleSuccessCounter( + &swarm.BlackHoleSuccessCounter{ + N: 8000, + MinSuccesses: 1, + Name: "permissive-udp", + }, + ), + swarm.WithIPv6BlackHoleSuccessCounter( + &swarm.BlackHoleSuccessCounter{ + N: 8000, + MinSuccesses: 1, + Name: "permissive-ip6", + }, + ), + ), + ) + if p2pConfig.LowWatermarkConnections != -1 && p2pConfig.HighWatermarkConnections != -1 { cm, err := connmgr.NewConnManager( @@ -264,10 +549,6 @@ func NewBlossomSub( logger.Panic("error creating resource manager", zap.Error(err)) } - opts = append( - opts, - libp2p.SwarmOpts(swarm.WithReadOnlyBlackHoleDetector()), - ) opts = append(opts, libp2p.ConnectionManager(cm)) opts = append(opts, libp2p.ResourceManager(rm)) } @@ -280,6 +561,7 @@ func NewBlossomSub( signKey: privKey, peerScore: make(map[string]*appScore), p2pConfig: *p2pConfig, + derivedPeerID: derivedPeerId, } h, err := libp2p.New(opts...) @@ -459,6 +741,7 @@ func NewBlossomSub( ) blossomOpts = append(blossomOpts, observability.WithPrometheusRawTracer()) if p2pConfig.Network == 0 { + logger.Info("enabling blacklist for bootstrappers for blossomsub") blossomOpts = append(blossomOpts, blossomsub.WithPeerFilter( internal.NewStaticPeerFilter( []peer.ID{}, @@ -621,7 +904,12 @@ func (b *BlossomSub) refreshScores() { } func (b *BlossomSub) PublishToBitmask(bitmask []byte, data []byte) error { - err := b.ps.Publish(b.ctx, bitmask, data) + err := b.ps.Publish( + b.ctx, + bitmask, + data, + blossomsub.WithSecretKeyAndPeerId(b.signKey, b.derivedPeerID), + ) if err != nil && errors.Is(err, blossomsub.ErrBitmaskClosed) && b.p2pConfig.Network == 99 { // Ignore bitmask closed errors for devnet @@ -666,6 +954,10 @@ func (b *BlossomSub) Subscribe( b.subscriptionTracker[string(bitmask)] = bitSlices b.subscriptionMutex.Unlock() + // If the bitmask count is greater than three, this is a broad subscribe + // and the caller is expected to handle disambiguation of addresses + exact := len(bm) <= 3 + subs := []*blossomsub.Subscription{} for _, bit := range bm { sub, err := bit.Subscribe( @@ -679,10 +971,12 @@ func (b *BlossomSub) Subscribe( b.subscriptionMutex.Unlock() return errors.Wrap(err, "subscribe") } + b.subscriptionMutex.Lock() _, ok := b.bitmaskMap[string(bit.Bitmask())] if !ok { b.bitmaskMap[string(bit.Bitmask())] = bit } + b.subscriptionMutex.Unlock() subs = append(subs, sub) } @@ -698,17 +992,23 @@ func (b *BlossomSub) Subscribe( go func() { for { - b.subscribeHandler(sub, copiedBitmask, handler) + b.subscribeHandler(sub, copiedBitmask, exact, handler) } }() } + b.logger.Info( + "successfully subscribed to bitmask", + zap.String("bitmask", hex.EncodeToString(bitmask)), + ) + return nil } func (b *BlossomSub) subscribeHandler( sub *blossomsub.Subscription, copiedBitmask []byte, + exact bool, handler func(message *pb.Message) error, ) { defer func() { @@ -727,7 +1027,7 @@ func (b *BlossomSub) subscribeHandler( zap.Error(err), ) } - if bytes.Equal(m.Bitmask, copiedBitmask) { + if bytes.Equal(m.Bitmask, copiedBitmask) || !exact { if err = handler(m.Message); err != nil { b.logger.Debug("message handler returned error", zap.Error(err)) } @@ -830,7 +1130,7 @@ func (b *BlossomSub) UnregisterValidator(bitmask []byte) error { } func (b *BlossomSub) GetPeerID() []byte { - return []byte(b.peerID) + return []byte(b.derivedPeerID) } func (b *BlossomSub) GetRandomPeer(bitmask []byte) ([]byte, error) { @@ -1044,8 +1344,11 @@ func (b *BlossomSub) GetOwnMultiaddrs() []ma.Multiaddr { return b.filterAndPrioritizeAddrs(allAddrs) } -// filterAndPrioritizeAddrs filters and prioritizes addresses for external visibility -func (b *BlossomSub) filterAndPrioritizeAddrs(addrs []ma.Multiaddr) []ma.Multiaddr { +// filterAndPrioritizeAddrs filters and prioritizes addresses for external +// visibility +func (b *BlossomSub) filterAndPrioritizeAddrs( + addrs []ma.Multiaddr, +) []ma.Multiaddr { var public, private, relay []ma.Multiaddr for _, addr := range addrs { @@ -1122,7 +1425,8 @@ func (b *BlossomSub) isPublicAddr(addr ma.Multiaddr) bool { return !ip.IsPrivate() && !ip.IsLoopback() && !ip.IsUnspecified() } -// isPrivateButRoutable checks if this is a private but potentially routable address +// isPrivateButRoutable checks if this is a private but potentially routable +// address func (b *BlossomSub) isPrivateButRoutable(addr ma.Multiaddr) bool { ipComponent, err := addr.ValueForProtocol(ma.P_IP4) if err != nil { @@ -1199,23 +1503,27 @@ func (b *BlossomSub) GetDirectChannel( return nil, errors.Wrap(err, "get direct channel") } + var lastError error for _, addr := range pi.Addrs { - mga, err := mn.ToNetAddr(addr) - if err != nil { - return nil, errors.Wrap(err, "get direct channel") + var mga net.Addr + mga, lastError = mn.ToNetAddr(addr) + if lastError != nil { + continue } - cc, err := grpc.NewClient( + + var cc *grpc.ClientConn + cc, lastError = grpc.NewClient( mga.String(), grpc.WithTransportCredentials(creds), ) - if err != nil { - return nil, errors.Wrap(err, "dial direct channel") + if lastError != nil { + continue } return cc, nil } - return nil, nil + return nil, errors.Wrap(lastError, "get direct channel") } func (b *BlossomSub) GetPublicKey() []byte { diff --git a/node/p2p/internal/peer_connector.go b/node/p2p/internal/peer_connector.go index 5980f9a3..46e0921f 100644 --- a/node/p2p/internal/peer_connector.go +++ b/node/p2p/internal/peer_connector.go @@ -20,6 +20,8 @@ type PeerConnector interface { Connect(context.Context) error } +// TODO(2.1.1+): metrics only, no debug logging unless configurable logging, too +// noisy type peerConnector struct { ctx context.Context logger *zap.Logger @@ -29,10 +31,18 @@ type peerConnector struct { minPeers int parallelism int source PeerSource + warned bool } // Connect implements PeerConnector. func (pc *peerConnector) Connect(ctx context.Context) error { + if pc.minPeers == 0 && !pc.warned { + pc.warned = true + pc.logger.Warn( + "skipped due to minpeer = 0, make sure this was intentional", + ) + return nil + } done := make(chan struct{}) select { case <-ctx.Done(): @@ -70,7 +80,6 @@ func (pc *peerConnector) connectToPeer( if p.ID == pc.host.ID() || pc.host.Network().Connectedness(p.ID) == network.Connected || pc.host.Network().Connectedness(p.ID) == network.Limited { - logger.Debug("peer already connected") atomic.AddUint32(duplicate, 1) return } @@ -79,7 +88,6 @@ func (pc *peerConnector) connectToPeer( conn, err := pc.host.Network().DialPeer(ctx, p.ID) if err != nil { - logger.Debug("error while connecting to dht peer", zap.Error(err)) atomic.AddUint32(failure, 1) return } @@ -88,11 +96,9 @@ func (pc *peerConnector) connectToPeer( case <-ctx.Done(): return case <-time.After(identify.DefaultTimeout / 2): - logger.Debug("identifying peer timed out") atomic.AddUint32(failure, 1) _ = conn.Close() case <-pc.idService.IdentifyWait(conn): - logger.Debug("connected to peer") atomic.AddUint32(success, 1) } } @@ -107,10 +113,8 @@ func (pc *peerConnector) connectToPeers( defer wg.Wait() for p := range ch { logger := pc.logger.With(zap.String("peer_id", p.ID.String())) - logger.Debug("received peer") if atomic.LoadUint32(success) >= uint32(pc.minPeers) { - logger.Debug("reached max findings") return } @@ -136,16 +140,7 @@ func (pc *peerConnector) connectToPeers( func (pc *peerConnector) connect() { logger := pc.logger - logger.Debug("initiating peer connections") var success, failure, duplicate uint32 - defer func() { - logger.Debug( - "completed peer connections", - zap.Uint32("success", success), - zap.Uint32("failure", failure), - zap.Uint32("duplicate", duplicate), - ) - }() ctx, cancel := context.WithCancel(pc.ctx) defer cancel() diff --git a/node/p2p/internal/peer_monitor.go b/node/p2p/internal/peer_monitor.go index 4afad4fd..e774e303 100644 --- a/node/p2p/internal/peer_monitor.go +++ b/node/p2p/internal/peer_monitor.go @@ -18,7 +18,11 @@ type peerMonitor struct { attempts int } -func (pm *peerMonitor) pingOnce(ctx context.Context, logger *zap.Logger, peer peer.ID) bool { +func (pm *peerMonitor) pingOnce( + ctx context.Context, + logger *zap.Logger, + peer peer.ID, +) bool { pingCtx, cancel := context.WithTimeout(ctx, pm.timeout) defer cancel() select { @@ -36,7 +40,12 @@ func (pm *peerMonitor) pingOnce(ctx context.Context, logger *zap.Logger, peer pe return true } -func (pm *peerMonitor) ping(ctx context.Context, logger *zap.Logger, wg *sync.WaitGroup, peer peer.ID) { +func (pm *peerMonitor) ping( + ctx context.Context, + logger *zap.Logger, + wg *sync.WaitGroup, + peer peer.ID, +) { defer wg.Done() for i := 0; i < pm.attempts; i++ { pm.pingOnce(ctx, logger, peer) @@ -63,11 +72,15 @@ func (pm *peerMonitor) run(ctx context.Context, logger *zap.Logger) { } } -// MonitorPeers periodically looks up the peers connected to the host and pings them -// repeatedly to ensure they are still reachable. If the peer is not reachable after -// the attempts, the connections to the peer are closed. +// MonitorPeers periodically looks up the peers connected to the host and pings +// them repeatedly to ensure they are still reachable. If the peer is not +// reachable after the attempts, the connections to the peer are closed. func MonitorPeers( - ctx context.Context, logger *zap.Logger, h host.Host, timeout, period time.Duration, attempts int, + ctx context.Context, + logger *zap.Logger, + h host.Host, + timeout, period time.Duration, + attempts int, ) { ps := ping.NewPingService(h) pm := &peerMonitor{ diff --git a/node/p2p/internal/peer_source.go b/node/p2p/internal/peer_source.go index 1c32e93b..fd330174 100644 --- a/node/p2p/internal/peer_source.go +++ b/node/p2p/internal/peer_source.go @@ -20,7 +20,10 @@ type staticPeerSource struct { } // Peers implements PeerSource. -func (s *staticPeerSource) Peers(context.Context) (<-chan peer.AddrInfo, error) { +func (s *staticPeerSource) Peers(context.Context) ( + <-chan peer.AddrInfo, + error, +) { peers := s.peers if s.permute { peers = Permuted(s.peers) @@ -45,12 +48,19 @@ type routingDiscoveryPeerSource struct { } // Peers implements PeerSource. -func (d *routingDiscoveryPeerSource) Peers(ctx context.Context) (<-chan peer.AddrInfo, error) { +func (d *routingDiscoveryPeerSource) Peers(ctx context.Context) ( + <-chan peer.AddrInfo, + error, +) { return d.discovery.FindPeers(ctx, d.namespace, discovery.Limit(d.limit)) } // NewRoutingDiscoveryPeerSource creates a new discovery peer source. -func NewRoutingDiscoveryPeerSource(discovery *routing.RoutingDiscovery, namespace string, limit int) PeerSource { +func NewRoutingDiscoveryPeerSource( + discovery *routing.RoutingDiscovery, + namespace string, + limit int, +) PeerSource { return &routingDiscoveryPeerSource{ discovery: discovery, namespace: namespace, diff --git a/node/p2p/onion/onion_integration_test.go b/node/p2p/onion/onion_integration_test.go index c401dfc3..ea1835b3 100644 --- a/node/p2p/onion/onion_integration_test.go +++ b/node/p2p/onion/onion_integration_test.go @@ -94,6 +94,41 @@ type memKeyStore struct { signed map[string][]*protobufs.SignedX448Key // parentAddr(string) -> keys } +// DeleteSignedDecaf448Key implements store.KeyStore. +func (m *memKeyStore) DeleteSignedDecaf448Key(txn store.Transaction, address []byte) error { + panic("unimplemented") +} + +// DeleteSignedX448Key implements store.KeyStore. +func (m *memKeyStore) DeleteSignedX448Key(txn store.Transaction, address []byte) error { + panic("unimplemented") +} + +// GetSignedDecaf448Key implements store.KeyStore. +func (m *memKeyStore) GetSignedDecaf448Key(address []byte) (*protobufs.SignedDecaf448Key, error) { + panic("unimplemented") +} + +// GetSignedDecaf448KeysByParent implements store.KeyStore. +func (m *memKeyStore) GetSignedDecaf448KeysByParent(parentKeyAddress []byte, keyPurpose string) ([]*protobufs.SignedDecaf448Key, error) { + panic("unimplemented") +} + +// GetSignedX448Key implements store.KeyStore. +func (m *memKeyStore) GetSignedX448Key(address []byte) (*protobufs.SignedX448Key, error) { + panic("unimplemented") +} + +// PutSignedDecaf448Key implements store.KeyStore. +func (m *memKeyStore) PutSignedDecaf448Key(txn store.Transaction, address []byte, key *protobufs.SignedDecaf448Key) error { + panic("unimplemented") +} + +// RangeSignedDecaf448Keys implements store.KeyStore. +func (m *memKeyStore) RangeSignedDecaf448Keys(parentKeyAddress []byte, keyPurpose string) (store.TypedIterator[*protobufs.SignedDecaf448Key], error) { + panic("unimplemented") +} + // DeleteSignedKey implements store.KeyStore. func (m *memKeyStore) DeleteSignedKey(txn store.Transaction, address []byte) error { panic("unimplemented") @@ -123,7 +158,7 @@ func newMemKeyStore() *memKeyStore { return &memKeyStore{signed: make(map[string][]*protobufs.SignedX448Key)} } -func (m *memKeyStore) GetSignedKeysByParent(parentKeyAddress []byte, keyPurpose string) ([]*protobufs.SignedX448Key, error) { +func (m *memKeyStore) GetSignedX448KeysByParent(parentKeyAddress []byte, keyPurpose string) ([]*protobufs.SignedX448Key, error) { return m.signed[string(parentKeyAddress)], nil } @@ -134,7 +169,7 @@ func (m *memKeyStore) RangeProvingKeys() (store.TypedIterator[*protobufs.BLS4858 func (m *memKeyStore) RangeIdentityKeys() (store.TypedIterator[*protobufs.Ed448PublicKey], error) { return nil, nil } -func (m *memKeyStore) RangeSignedKeys([]byte, string) (store.TypedIterator[*protobufs.SignedX448Key], error) { +func (m *memKeyStore) RangeSignedX448Keys([]byte, string) (store.TypedIterator[*protobufs.SignedX448Key], error) { return nil, nil } func (m *memKeyStore) GetIdentityKey([]byte) (*protobufs.Ed448PublicKey, error) { return nil, nil } @@ -154,10 +189,10 @@ func (m *memKeyStore) PutProvingKey(store.Transaction, []byte, *protobufs.BLS485 func (m *memKeyStore) PutCrossSignature(store.Transaction, []byte, []byte, []byte, []byte) error { return nil } -func (m *memKeyStore) PutSignedKey(store.Transaction, []byte, *protobufs.SignedX448Key) error { +func (m *memKeyStore) PutSignedX448Key(store.Transaction, []byte, *protobufs.SignedX448Key) error { return nil } -func (m *memKeyStore) GetSignedKeysByParentAndPurpose([]byte, string) ([]*protobufs.SignedX448Key, error) { +func (m *memKeyStore) GetSignedX448KeysByParentAndPurpose([]byte, string) ([]*protobufs.SignedX448Key, error) { return nil, nil } func (m *memKeyStore) Begin() (store.Transaction, error) { return nil, nil } diff --git a/node/p2p/onion/router.go b/node/p2p/onion/router.go index 34a63c34..11bf7048 100644 --- a/node/p2p/onion/router.go +++ b/node/p2p/onion/router.go @@ -945,7 +945,7 @@ func hasCapability(pm *p2p.PeerInfo, x uint32) bool { func (r *OnionRouter) resolveOnionKey( peerIdentityAddr []byte, ) ([]byte, error) { - keys, err := r.signers.GetSignedKeysByParent(peerIdentityAddr, r.keyUsage) + keys, err := r.signers.GetSignedX448KeysByParent(peerIdentityAddr, r.keyUsage) if err != nil { return nil, err } diff --git a/node/p2p/peer_authenticator.go b/node/p2p/peer_authenticator.go index 9fd38113..acbd9b1b 100644 --- a/node/p2p/peer_authenticator.go +++ b/node/p2p/peer_authenticator.go @@ -155,12 +155,14 @@ func (p *PeerAuthenticator) CreateServerTLSCredentials() ( verifiedChains [][]*x509.Certificate, ) error { if len(rawCerts) == 0 { + p.logger.Debug("no peer certificate provided") return errors.New("no peer certificate provided") } // Parse the peer certificate peerCert, err := x509.ParseCertificate(rawCerts[0]) if err != nil { + p.logger.Debug("could not parse peer certificate") return errors.Wrap(err, "failed to parse peer certificate") } @@ -168,15 +170,18 @@ func (p *PeerAuthenticator) CreateServerTLSCredentials() ( // from the same Ed448 seed by checking if the xsign matches peerEd25519PubKey, ok := peerCert.PublicKey.(ed25519.PublicKey) if !ok { + p.logger.Debug("peer certificate has invalid key type") return errors.New("peer certificate does not use Ed25519 key") } if len(peerCert.DNSNames) != 1 { + p.logger.Debug("dns mismatch") return errors.New("peer certificate dns mismatch") } xsign, err := hex.DecodeString(peerCert.DNSNames[0]) if err != nil { + p.logger.Debug("failed ot parse xsign") return errors.Wrap(err, "failed to parse xsign") } @@ -187,19 +192,24 @@ func (p *PeerAuthenticator) CreateServerTLSCredentials() ( "", ) if !valid { + p.logger.Debug("peer certificate invalid xsign") return errors.New("peer certificate invalid xsign") } pubkey, err := crypto.UnmarshalEd448PublicKey(xsign[:57]) if err != nil { + p.logger.Debug("could not obtain ed448 pubkey") return err } _, err = ppeer.IDFromPublicKey(pubkey) if err != nil { + p.logger.Debug("could not derive peer id") return err } + p.logger.Debug("certificate check succeeded") + return nil }, InsecureSkipVerify: true, // We handle verification in VerifyPeerCertificate diff --git a/node/store/constants.go b/node/store/constants.go index bdec3705..577223b7 100644 --- a/node/store/constants.go +++ b/node/store/constants.go @@ -87,20 +87,24 @@ const ( // Key store indexes: const ( - KEY_DATA = 0x00 - KEY_BUNDLE_INDEX_EARLIEST = 0x10 - KEY_BUNDLE_INDEX_LATEST = 0x20 - KEY_IDENTITY = 0x30 - KEY_PROVING = 0x31 - KEY_CROSS_SIGNATURE = 0x40 - KEY_SIGNED_KEY_BY_ID = 0x50 - KEY_SIGNED_KEY_BY_PARENT = 0x51 - KEY_SIGNED_KEY_BY_PURPOSE = 0x52 - KEY_SIGNED_KEY_BY_EXPIRY = 0x53 - KEY_DEVICE_PRE_KEY_BY_ID = 0x60 - KEY_DEVICE_PRE_KEY_BY_DEVICE = 0x61 - KEY_DEVICE_PRE_KEY_AVAILABLE = 0x62 - KEY_DEVICE_PRE_KEY_ONE_TIME = 0x63 + KEY_DATA = 0x00 + KEY_BUNDLE_INDEX_EARLIEST = 0x10 + KEY_BUNDLE_INDEX_LATEST = 0x20 + KEY_IDENTITY = 0x30 + KEY_PROVING = 0x31 + KEY_CROSS_SIGNATURE = 0x40 + KEY_X448_SIGNED_KEY_BY_ID = 0x50 + KEY_X448_SIGNED_KEY_BY_PARENT = 0x51 + KEY_X448_SIGNED_KEY_BY_PURPOSE = 0x52 + KEY_X448_SIGNED_KEY_BY_EXPIRY = 0x53 + KEY_DECAF448_SIGNED_KEY_BY_ID = 0x54 + KEY_DECAF448_SIGNED_KEY_BY_PARENT = 0x55 + KEY_DECAF448_SIGNED_KEY_BY_PURPOSE = 0x56 + KEY_DECAF448_SIGNED_KEY_BY_EXPIRY = 0x57 + KEY_DEVICE_PRE_KEY_BY_ID = 0x60 + KEY_DEVICE_PRE_KEY_BY_DEVICE = 0x61 + KEY_DEVICE_PRE_KEY_AVAILABLE = 0x62 + KEY_DEVICE_PRE_KEY_ONE_TIME = 0x63 ) // Shard store indexes: diff --git a/node/store/key.go b/node/store/key.go index bfab460f..66190ebd 100644 --- a/node/store/key.go +++ b/node/store/key.go @@ -27,14 +27,20 @@ type PebbleProvingKeyIterator struct { i store.Iterator } -type PebbleSignedKeyIterator struct { +type PebbleSignedX448KeyIterator struct { + i store.Iterator + db *PebbleKeyStore +} + +type PebbleSignedDecaf448KeyIterator struct { i store.Iterator db *PebbleKeyStore } var _ store.TypedIterator[*protobufs.Ed448PublicKey] = (*PebbleIdentityKeyIterator)(nil) var _ store.TypedIterator[*protobufs.BLS48581SignatureWithProofOfPossession] = (*PebbleProvingKeyIterator)(nil) -var _ store.TypedIterator[*protobufs.SignedX448Key] = (*PebbleSignedKeyIterator)(nil) +var _ store.TypedIterator[*protobufs.SignedX448Key] = (*PebbleSignedX448KeyIterator)(nil) +var _ store.TypedIterator[*protobufs.SignedDecaf448Key] = (*PebbleSignedDecaf448KeyIterator)(nil) var _ store.KeyStore = (*PebbleKeyStore)(nil) // Identity key iterator methods @@ -126,19 +132,19 @@ func (p *PebbleProvingKeyIterator) Close() error { } // Signed key iterator methods -func (p *PebbleSignedKeyIterator) First() bool { +func (p *PebbleSignedX448KeyIterator) First() bool { return p.i.First() } -func (p *PebbleSignedKeyIterator) Next() bool { +func (p *PebbleSignedX448KeyIterator) Next() bool { return p.i.Next() } -func (p *PebbleSignedKeyIterator) Valid() bool { +func (p *PebbleSignedX448KeyIterator) Valid() bool { return p.i.Valid() } -func (p *PebbleSignedKeyIterator) Value() ( +func (p *PebbleSignedX448KeyIterator) Value() ( *protobufs.SignedX448Key, error, ) { @@ -148,7 +154,7 @@ func (p *PebbleSignedKeyIterator) Value() ( key := p.i.Key()[len(p.i.Key())-32:] - signedKey, err := p.db.GetSignedKey(key) + signedKey, err := p.db.GetSignedX448Key(key) if err != nil { return nil, errors.Wrap( errors.Wrap(err, store.ErrInvalidData.Error()), @@ -159,14 +165,58 @@ func (p *PebbleSignedKeyIterator) Value() ( return signedKey, nil } -func (p *PebbleSignedKeyIterator) TruncatedValue() ( +func (p *PebbleSignedX448KeyIterator) TruncatedValue() ( *protobufs.SignedX448Key, error, ) { return p.Value() } -func (p *PebbleSignedKeyIterator) Close() error { +func (p *PebbleSignedX448KeyIterator) Close() error { + return errors.Wrap(p.i.Close(), "closing iterator") +} + +func (p *PebbleSignedDecaf448KeyIterator) First() bool { + return p.i.First() +} + +func (p *PebbleSignedDecaf448KeyIterator) Next() bool { + return p.i.Next() +} + +func (p *PebbleSignedDecaf448KeyIterator) Valid() bool { + return p.i.Valid() +} + +func (p *PebbleSignedDecaf448KeyIterator) Value() ( + *protobufs.SignedDecaf448Key, + error, +) { + if !p.i.Valid() { + return nil, store.ErrNotFound + } + + key := p.i.Key()[len(p.i.Key())-32:] + + signedKey, err := p.db.GetSignedDecaf448Key(key) + if err != nil { + return nil, errors.Wrap( + errors.Wrap(err, store.ErrInvalidData.Error()), + "get signed key iterator value", + ) + } + + return signedKey, nil +} + +func (p *PebbleSignedDecaf448KeyIterator) TruncatedValue() ( + *protobufs.SignedDecaf448Key, + error, +) { + return p.Value() +} + +func (p *PebbleSignedDecaf448KeyIterator) Close() error { return errors.Wrap(p.i.Close(), "closing iterator") } @@ -197,13 +247,13 @@ func crossSignatureKey( return key } -func signedKeyKey(address []byte) []byte { - key := []byte{KEY_BUNDLE, KEY_SIGNED_KEY_BY_ID} +func signedX448KeyKey(address []byte) []byte { + key := []byte{KEY_BUNDLE, KEY_X448_SIGNED_KEY_BY_ID} key = append(key, address...) return key } -func signedKeyByParentKey( +func signedX448KeyByParentKey( parentKeyAddress []byte, keyPurpose string, keyAddress []byte, @@ -211,25 +261,63 @@ func signedKeyByParentKey( purpose := make([]byte, 8) copy(purpose[:len(keyPurpose)], []byte(keyPurpose)) - key := []byte{KEY_BUNDLE, KEY_SIGNED_KEY_BY_PARENT} + key := []byte{KEY_BUNDLE, KEY_X448_SIGNED_KEY_BY_PARENT} key = append(key, parentKeyAddress...) key = append(key, purpose...) key = append(key, keyAddress...) return key } -func signedKeyByPurposeKey(keyPurpose string, keyAddress []byte) []byte { +func signedX448KeyByPurposeKey(keyPurpose string, keyAddress []byte) []byte { purpose := make([]byte, 8) copy(purpose[:len(keyPurpose)], []byte(keyPurpose)) - key := []byte{KEY_BUNDLE, KEY_SIGNED_KEY_BY_PURPOSE} + key := []byte{KEY_BUNDLE, KEY_X448_SIGNED_KEY_BY_PURPOSE} key = append(key, purpose...) key = append(key, keyAddress...) return key } -func signedKeyExpiryKey(expiresAt uint64, keyAddress []byte) []byte { - key := []byte{KEY_BUNDLE, KEY_SIGNED_KEY_BY_EXPIRY} +func signedX448KeyExpiryKey(expiresAt uint64, keyAddress []byte) []byte { + key := []byte{KEY_BUNDLE, KEY_X448_SIGNED_KEY_BY_EXPIRY} + key = binary.BigEndian.AppendUint64(key, expiresAt) + key = append(key, keyAddress...) + return key +} + +func signedDecaf448KeyKey(address []byte) []byte { + key := []byte{KEY_BUNDLE, KEY_DECAF448_SIGNED_KEY_BY_ID} + key = append(key, address...) + return key +} + +func signedDecaf448KeyByParentKey( + parentKeyAddress []byte, + keyPurpose string, + keyAddress []byte, +) []byte { + purpose := make([]byte, 8) + copy(purpose[:len(keyPurpose)], []byte(keyPurpose)) + + key := []byte{KEY_BUNDLE, KEY_DECAF448_SIGNED_KEY_BY_PARENT} + key = append(key, parentKeyAddress...) + key = append(key, purpose...) + key = append(key, keyAddress...) + return key +} + +func signedDecaf448KeyByPurposeKey(keyPurpose string, keyAddress []byte) []byte { + purpose := make([]byte, 8) + copy(purpose[:len(keyPurpose)], []byte(keyPurpose)) + + key := []byte{KEY_BUNDLE, KEY_DECAF448_SIGNED_KEY_BY_PURPOSE} + key = append(key, purpose...) + key = append(key, keyAddress...) + return key +} + +func signedDecaf448KeyExpiryKey(expiresAt uint64, keyAddress []byte) []byte { + key := []byte{KEY_BUNDLE, KEY_DECAF448_SIGNED_KEY_BY_EXPIRY} key = binary.BigEndian.AppendUint64(key, expiresAt) key = append(key, keyAddress...) return key @@ -421,75 +509,141 @@ func (p *PebbleKeyStore) RangeIdentityKeys() ( return &PebbleIdentityKeyIterator{i: iter}, nil } -// PutSignedKey stores a signed X448 key -func (p *PebbleKeyStore) PutSignedKey( +// PutSignedX448Key stores a signed X448 key +func (p *PebbleKeyStore) PutSignedX448Key( txn store.Transaction, address []byte, key *protobufs.SignedX448Key, ) error { data, err := proto.Marshal(key) if err != nil { - return errors.Wrap(err, "put signed key") + return errors.Wrap(err, "put signed x448 key") + } + + // Store by address + if err := txn.Set(signedX448KeyKey(address), data); err != nil { + return errors.Wrap(err, "put signed x448 key") + } + + // Store by parent key index + if err := txn.Set( + signedX448KeyByParentKey(key.ParentKeyAddress, key.KeyPurpose, address), + []byte{0x01}, // Just a marker + ); err != nil { + return errors.Wrap(err, "put signed x448 key") + } + + // Store by purpose index + if err := txn.Set( + signedX448KeyByPurposeKey(key.KeyPurpose, address), + []byte{0x01}, // Just a marker + ); err != nil { + return errors.Wrap(err, "put signed x448 key") + } + + // Store by expiry if set + if key.ExpiresAt > 0 { + if err := txn.Set( + signedX448KeyExpiryKey(key.ExpiresAt, address), + []byte{0x01}, // Just a marker + ); err != nil { + return errors.Wrap(err, "put signed x448 key") + } + } + + return nil +} + +// PutSignedDecaf448Key stores a signed Decaf448 key +func (p *PebbleKeyStore) PutSignedDecaf448Key( + txn store.Transaction, + address []byte, + key *protobufs.SignedDecaf448Key, +) error { + data, err := proto.Marshal(key) + if err != nil { + return errors.Wrap(err, "put signed decaf448 key") } // Store by address - if err := txn.Set(signedKeyKey(address), data); err != nil { - return errors.Wrap(err, "put signed key") + if err := txn.Set(signedDecaf448KeyKey(address), data); err != nil { + return errors.Wrap(err, "put signed decaf448 key") } // Store by parent key index if err := txn.Set( - signedKeyByParentKey(key.ParentKeyAddress, key.KeyPurpose, address), + signedDecaf448KeyByParentKey(key.ParentKeyAddress, key.KeyPurpose, address), []byte{0x01}, // Just a marker ); err != nil { - return errors.Wrap(err, "put signed key") + return errors.Wrap(err, "put signed decaf448 key") } // Store by purpose index if err := txn.Set( - signedKeyByPurposeKey(key.KeyPurpose, address), + signedDecaf448KeyByPurposeKey(key.KeyPurpose, address), []byte{0x01}, // Just a marker ); err != nil { - return errors.Wrap(err, "put signed key") + return errors.Wrap(err, "put signed decaf448 key") } // Store by expiry if set if key.ExpiresAt > 0 { if err := txn.Set( - signedKeyExpiryKey(key.ExpiresAt, address), + signedDecaf448KeyExpiryKey(key.ExpiresAt, address), []byte{0x01}, // Just a marker ); err != nil { - return errors.Wrap(err, "put signed key") + return errors.Wrap(err, "put signed decaf448 key") } } return nil } -// GetSignedKey retrieves a signed key by address -func (p *PebbleKeyStore) GetSignedKey( +// GetSignedX448Key retrieves a signed key by address +func (p *PebbleKeyStore) GetSignedX448Key( address []byte, ) (*protobufs.SignedX448Key, error) { - value, closer, err := p.db.Get(signedKeyKey(address)) + value, closer, err := p.db.Get(signedX448KeyKey(address)) if err != nil { if errors.Is(err, pebble.ErrNotFound) { return nil, store.ErrNotFound } - return nil, errors.Wrap(err, "get signed key") + return nil, errors.Wrap(err, "get signed x448 key") } defer closer.Close() key := &protobufs.SignedX448Key{} if err := proto.Unmarshal(value, key); err != nil { - return nil, errors.Wrap(err, "get signed key") + return nil, errors.Wrap(err, "get signed x448 key") + } + + return key, nil +} + +// GetSignedDecaf448Key retrieves a signed key by address +func (p *PebbleKeyStore) GetSignedDecaf448Key( + address []byte, +) (*protobufs.SignedDecaf448Key, error) { + value, closer, err := p.db.Get(signedDecaf448KeyKey(address)) + if err != nil { + if errors.Is(err, pebble.ErrNotFound) { + return nil, store.ErrNotFound + } + return nil, errors.Wrap(err, "get signed decaf448 key") + } + defer closer.Close() + + key := &protobufs.SignedDecaf448Key{} + if err := proto.Unmarshal(value, key); err != nil { + return nil, errors.Wrap(err, "get signed decaf448 key") } return key, nil } -// GetSignedKeysByParent retrieves all signed keys for a parent key, optionally -// filtered by purpose -func (p *PebbleKeyStore) GetSignedKeysByParent( +// GetSignedX448KeysByParent retrieves all signed keys for a parent key, +// optionally filtered by purpose +func (p *PebbleKeyStore) GetSignedX448KeysByParent( parentKeyAddress []byte, keyPurpose string, ) ([]*protobufs.SignedX448Key, error) { @@ -499,11 +653,11 @@ func (p *PebbleKeyStore) GetSignedKeysByParent( purpose := make([]byte, 8) copy(purpose[:len(keyPurpose)], []byte(keyPurpose)) - prefix = []byte{KEY_BUNDLE, KEY_SIGNED_KEY_BY_PARENT} + prefix = []byte{KEY_BUNDLE, KEY_X448_SIGNED_KEY_BY_PARENT} prefix = append(prefix, parentKeyAddress...) prefix = append(prefix, purpose...) } else { - prefix = []byte{KEY_BUNDLE, KEY_SIGNED_KEY_BY_PARENT} + prefix = []byte{KEY_BUNDLE, KEY_X448_SIGNED_KEY_BY_PARENT} prefix = append(prefix, parentKeyAddress...) } @@ -512,7 +666,7 @@ func (p *PebbleKeyStore) GetSignedKeysByParent( iter, err := p.db.NewIter(prefix, endPrefixBI.Bytes()) if err != nil { - return nil, errors.Wrap(err, "get signed keys by parent") + return nil, errors.Wrap(err, "get signed x448 keys by parent") } defer iter.Close() @@ -521,7 +675,7 @@ func (p *PebbleKeyStore) GetSignedKeysByParent( keyAddress := iter.Key()[len(iter.Key())-32:] // Get the actual key data - keyData, closer, err := p.db.Get(signedKeyKey(keyAddress)) + keyData, closer, err := p.db.Get(signedX448KeyKey(keyAddress)) if err != nil { continue } @@ -539,48 +693,148 @@ func (p *PebbleKeyStore) GetSignedKeysByParent( return keys, nil } -// DeleteSignedKey removes a signed key -func (p *PebbleKeyStore) DeleteSignedKey( +// GetSignedDecaf448KeysByParent retrieves all signed keys for a parent key, +// optionally filtered by purpose +func (p *PebbleKeyStore) GetSignedDecaf448KeysByParent( + parentKeyAddress []byte, + keyPurpose string, +) ([]*protobufs.SignedDecaf448Key, error) { + var prefix []byte + if keyPurpose != "" { + // Create prefix without keyId to get all keys of this purpose + purpose := make([]byte, 8) + copy(purpose[:len(keyPurpose)], []byte(keyPurpose)) + + prefix = []byte{KEY_BUNDLE, KEY_DECAF448_SIGNED_KEY_BY_PARENT} + prefix = append(prefix, parentKeyAddress...) + prefix = append(prefix, purpose...) + } else { + prefix = []byte{KEY_BUNDLE, KEY_DECAF448_SIGNED_KEY_BY_PARENT} + prefix = append(prefix, parentKeyAddress...) + } + + endPrefixBI := new(big.Int).SetBytes(prefix) + endPrefixBI.Add(endPrefixBI, big.NewInt(1)) + + iter, err := p.db.NewIter(prefix, endPrefixBI.Bytes()) + if err != nil { + return nil, errors.Wrap(err, "get signed decaf448 keys by parent") + } + defer iter.Close() + + var keys []*protobufs.SignedDecaf448Key + for iter.First(); iter.Valid(); iter.Next() { + keyAddress := iter.Key()[len(iter.Key())-32:] + + // Get the actual key data + keyData, closer, err := p.db.Get(signedDecaf448KeyKey(keyAddress)) + if err != nil { + continue + } + + key := &protobufs.SignedDecaf448Key{} + if err := proto.Unmarshal(keyData, key); err != nil { + closer.Close() + continue + } + closer.Close() + + keys = append(keys, key) + } + + return keys, nil +} + +// DeleteSignedX448Key removes a signed key +func (p *PebbleKeyStore) DeleteSignedX448Key( txn store.Transaction, address []byte, ) error { // First get the key to extract metadata for index deletion - value, closer, err := p.db.Get(signedKeyKey(address)) + value, closer, err := p.db.Get(signedX448KeyKey(address)) if err != nil { if errors.Is(err, pebble.ErrNotFound) { return store.ErrNotFound } - return errors.Wrap(err, "delete signed key") + return errors.Wrap(err, "delete signed x448 key") } defer closer.Close() key := &protobufs.SignedX448Key{} if err := proto.Unmarshal(value, key); err != nil { - return errors.Wrap(err, "delete signed key") + return errors.Wrap(err, "delete signed x448 key") } // Delete all indexes - if err := txn.Delete(signedKeyKey(address)); err != nil { - return errors.Wrap(err, "delete signed key") + if err := txn.Delete(signedX448KeyKey(address)); err != nil { + return errors.Wrap(err, "delete signed x448 key") } if err := txn.Delete( - signedKeyByParentKey(key.ParentKeyAddress, key.KeyPurpose, address), + signedX448KeyByParentKey(key.ParentKeyAddress, key.KeyPurpose, address), ); err != nil { - return errors.Wrap(err, "delete signed key") + return errors.Wrap(err, "delete signed x448 key") } if err := txn.Delete( - signedKeyByPurposeKey(key.KeyPurpose, address), + signedX448KeyByPurposeKey(key.KeyPurpose, address), ); err != nil { - return errors.Wrap(err, "delete signed key") + return errors.Wrap(err, "delete signed x448 key") } if key.ExpiresAt > 0 { if err := txn.Delete( - signedKeyExpiryKey(key.ExpiresAt, address), + signedX448KeyExpiryKey(key.ExpiresAt, address), ); err != nil { - return errors.Wrap(err, "delete signed key") + return errors.Wrap(err, "delete signed x448 key") + } + } + + return nil +} + +// DeleteSignedDecaf448Key removes a signed key +func (p *PebbleKeyStore) DeleteSignedDecaf448Key( + txn store.Transaction, + address []byte, +) error { + // First get the key to extract metadata for index deletion + value, closer, err := p.db.Get(signedDecaf448KeyKey(address)) + if err != nil { + if errors.Is(err, pebble.ErrNotFound) { + return store.ErrNotFound + } + return errors.Wrap(err, "delete signed decaf448 key") + } + defer closer.Close() + + key := &protobufs.SignedDecaf448Key{} + if err := proto.Unmarshal(value, key); err != nil { + return errors.Wrap(err, "delete signed decaf448 key") + } + + // Delete all indexes + if err := txn.Delete(signedDecaf448KeyKey(address)); err != nil { + return errors.Wrap(err, "delete signed decaf448 key") + } + + if err := txn.Delete( + signedDecaf448KeyByParentKey(key.ParentKeyAddress, key.KeyPurpose, address), + ); err != nil { + return errors.Wrap(err, "delete signed decaf448 key") + } + + if err := txn.Delete( + signedDecaf448KeyByPurposeKey(key.KeyPurpose, address), + ); err != nil { + return errors.Wrap(err, "delete signed decaf448 key") + } + + if key.ExpiresAt > 0 { + if err := txn.Delete( + signedDecaf448KeyExpiryKey(key.ExpiresAt, address), + ); err != nil { + return errors.Wrap(err, "delete signed decaf448 key") } } @@ -592,8 +846,8 @@ func (p *PebbleKeyStore) ReapExpiredKeys() error { currentTime := uint64(time.Now().Unix()) // Iterate through all keys with expiry - prefix := []byte{KEY_BUNDLE, KEY_SIGNED_KEY_BY_EXPIRY} - endPrefix := []byte{KEY_BUNDLE, KEY_SIGNED_KEY_BY_EXPIRY + 1} + prefix := []byte{KEY_BUNDLE, KEY_X448_SIGNED_KEY_BY_EXPIRY} + endPrefix := []byte{KEY_BUNDLE, KEY_X448_SIGNED_KEY_BY_EXPIRY + 1} iter, err := p.db.NewIter(prefix, endPrefix) if err != nil { return errors.Wrap(err, "reap expired keys") @@ -624,7 +878,41 @@ func (p *PebbleKeyStore) ReapExpiredKeys() error { keyAddress := indexKey[len(prefix)+8:] // Delete the key - if err := p.DeleteSignedKey(txn, keyAddress); err != nil { + if err := p.DeleteSignedX448Key(txn, keyAddress); err != nil { + p.logger.Warn("failed to delete expired key", zap.Error(err)) + continue + } + + deletedCount++ + } + + // Iterate through all decaf keys with expiry + decafPrefix := []byte{KEY_BUNDLE, KEY_DECAF448_SIGNED_KEY_BY_EXPIRY} + decafEndPrefix := []byte{KEY_BUNDLE, KEY_DECAF448_SIGNED_KEY_BY_EXPIRY + 1} + decafIter, err := p.db.NewIter(decafPrefix, decafEndPrefix) + if err != nil { + return errors.Wrap(err, "reap expired keys") + } + defer decafIter.Close() + for decafIter.First(); decafIter.Valid(); decafIter.Next() { + indexKey := decafIter.Key() + + // Extract expiry time + if len(indexKey) < len(prefix)+8 { + continue + } + expiryTime := binary.BigEndian.Uint64(indexKey[len(prefix) : len(prefix)+8]) + + // If not expired, we can stop (keys are sorted by expiry) + if expiryTime > currentTime { + break + } + + // Extract key address + keyAddress := indexKey[len(prefix)+8:] + + // Delete the key + if err := p.DeleteSignedDecaf448Key(txn, keyAddress); err != nil { p.logger.Warn("failed to delete expired key", zap.Error(err)) continue } @@ -689,18 +977,63 @@ func (p *PebbleKeyStore) GetKeyRegistry( } // Get all signed keys by parent (identity key) - allKeys, err := p.GetSignedKeysByParent(identityKeyAddress, "") + allKeys, err := p.GetSignedX448KeysByParent(identityKeyAddress, "") if err == nil { // Group by purpose for _, key := range allKeys { if _, exists := registry.KeysByPurpose[key.KeyPurpose]; !exists { registry.KeysByPurpose[key.KeyPurpose] = &protobufs.KeyCollection{ - KeyPurpose: key.KeyPurpose, - Keys: []*protobufs.SignedX448Key{}, + KeyPurpose: key.KeyPurpose, + X448Keys: []*protobufs.SignedX448Key{}, + Decaf448Keys: []*protobufs.SignedDecaf448Key{}, + } + } + registry.KeysByPurpose[key.KeyPurpose].X448Keys = append( + registry.KeysByPurpose[key.KeyPurpose].X448Keys, key, + ) + if registry.LastUpdated < key.CreatedAt { + registry.LastUpdated = key.CreatedAt + } + } + } + + // If we have a prover key, also get keys signed by it + if registry.ProverKey != nil && len(crossSigData) > 0 { + proverKeyAddress := crossSigData[:32] + proverKeys, err := p.GetSignedX448KeysByParent(proverKeyAddress, "") + if err == nil { + for _, key := range proverKeys { + if _, exists := registry.KeysByPurpose[key.KeyPurpose]; !exists { + registry.KeysByPurpose[key.KeyPurpose] = &protobufs.KeyCollection{ + KeyPurpose: key.KeyPurpose, + X448Keys: []*protobufs.SignedX448Key{}, + Decaf448Keys: []*protobufs.SignedDecaf448Key{}, + } + } + registry.KeysByPurpose[key.KeyPurpose].X448Keys = append( + registry.KeysByPurpose[key.KeyPurpose].X448Keys, key, + ) + if registry.LastUpdated < key.CreatedAt { + registry.LastUpdated = key.CreatedAt + } + } + } + } + + // Get all signed keys by parent (identity key) + allDecafKeys, err := p.GetSignedDecaf448KeysByParent(identityKeyAddress, "") + if err == nil { + // Group by purpose + for _, key := range allDecafKeys { + if _, exists := registry.KeysByPurpose[key.KeyPurpose]; !exists { + registry.KeysByPurpose[key.KeyPurpose] = &protobufs.KeyCollection{ + KeyPurpose: key.KeyPurpose, + X448Keys: []*protobufs.SignedX448Key{}, + Decaf448Keys: []*protobufs.SignedDecaf448Key{}, } } - registry.KeysByPurpose[key.KeyPurpose].Keys = append( - registry.KeysByPurpose[key.KeyPurpose].Keys, key, + registry.KeysByPurpose[key.KeyPurpose].Decaf448Keys = append( + registry.KeysByPurpose[key.KeyPurpose].Decaf448Keys, key, ) if registry.LastUpdated < key.CreatedAt { registry.LastUpdated = key.CreatedAt @@ -711,17 +1044,18 @@ func (p *PebbleKeyStore) GetKeyRegistry( // If we have a prover key, also get keys signed by it if registry.ProverKey != nil && len(crossSigData) > 0 { proverKeyAddress := crossSigData[:32] - proverKeys, err := p.GetSignedKeysByParent(proverKeyAddress, "") + proverKeys, err := p.GetSignedDecaf448KeysByParent(proverKeyAddress, "") if err == nil { for _, key := range proverKeys { if _, exists := registry.KeysByPurpose[key.KeyPurpose]; !exists { registry.KeysByPurpose[key.KeyPurpose] = &protobufs.KeyCollection{ - KeyPurpose: key.KeyPurpose, - Keys: []*protobufs.SignedX448Key{}, + KeyPurpose: key.KeyPurpose, + X448Keys: []*protobufs.SignedX448Key{}, + Decaf448Keys: []*protobufs.SignedDecaf448Key{}, } } - registry.KeysByPurpose[key.KeyPurpose].Keys = append( - registry.KeysByPurpose[key.KeyPurpose].Keys, key, + registry.KeysByPurpose[key.KeyPurpose].Decaf448Keys = append( + registry.KeysByPurpose[key.KeyPurpose].Decaf448Keys, key, ) if registry.LastUpdated < key.CreatedAt { registry.LastUpdated = key.CreatedAt @@ -780,18 +1114,19 @@ func (p *PebbleKeyStore) GetKeyRegistryByProver( } // Get all signed keys by parent (prover key) - allKeys, err := p.GetSignedKeysByParent(proverKeyAddress, "") + allKeys, err := p.GetSignedX448KeysByParent(proverKeyAddress, "") if err == nil { // Group by purpose for _, key := range allKeys { if _, exists := registry.KeysByPurpose[key.KeyPurpose]; !exists { registry.KeysByPurpose[key.KeyPurpose] = &protobufs.KeyCollection{ - KeyPurpose: key.KeyPurpose, - Keys: []*protobufs.SignedX448Key{}, + KeyPurpose: key.KeyPurpose, + X448Keys: []*protobufs.SignedX448Key{}, + Decaf448Keys: []*protobufs.SignedDecaf448Key{}, } } - registry.KeysByPurpose[key.KeyPurpose].Keys = append( - registry.KeysByPurpose[key.KeyPurpose].Keys, key, + registry.KeysByPurpose[key.KeyPurpose].X448Keys = append( + registry.KeysByPurpose[key.KeyPurpose].X448Keys, key, ) if registry.LastUpdated < key.CreatedAt { registry.LastUpdated = key.CreatedAt @@ -802,17 +1137,62 @@ func (p *PebbleKeyStore) GetKeyRegistryByProver( // If we have a prover key, also get keys signed by it if registry.ProverKey != nil && len(crossSigData) > 0 { proverKeyAddress := crossSigData[:32] - proverKeys, err := p.GetSignedKeysByParent(proverKeyAddress, "") + proverKeys, err := p.GetSignedX448KeysByParent(proverKeyAddress, "") if err == nil { for _, key := range proverKeys { if _, exists := registry.KeysByPurpose[key.KeyPurpose]; !exists { registry.KeysByPurpose[key.KeyPurpose] = &protobufs.KeyCollection{ - KeyPurpose: key.KeyPurpose, - Keys: []*protobufs.SignedX448Key{}, + KeyPurpose: key.KeyPurpose, + X448Keys: []*protobufs.SignedX448Key{}, + Decaf448Keys: []*protobufs.SignedDecaf448Key{}, } } - registry.KeysByPurpose[key.KeyPurpose].Keys = append( - registry.KeysByPurpose[key.KeyPurpose].Keys, key, + registry.KeysByPurpose[key.KeyPurpose].X448Keys = append( + registry.KeysByPurpose[key.KeyPurpose].X448Keys, key, + ) + if registry.LastUpdated < key.CreatedAt { + registry.LastUpdated = key.CreatedAt + } + } + } + } + + // Get all signed keys by parent (prover key) + allDecafKeys, err := p.GetSignedDecaf448KeysByParent(proverKeyAddress, "") + if err == nil { + // Group by purpose + for _, key := range allDecafKeys { + if _, exists := registry.KeysByPurpose[key.KeyPurpose]; !exists { + registry.KeysByPurpose[key.KeyPurpose] = &protobufs.KeyCollection{ + KeyPurpose: key.KeyPurpose, + X448Keys: []*protobufs.SignedX448Key{}, + Decaf448Keys: []*protobufs.SignedDecaf448Key{}, + } + } + registry.KeysByPurpose[key.KeyPurpose].Decaf448Keys = append( + registry.KeysByPurpose[key.KeyPurpose].Decaf448Keys, key, + ) + if registry.LastUpdated < key.CreatedAt { + registry.LastUpdated = key.CreatedAt + } + } + } + + // If we have a prover key, also get keys signed by it + if registry.ProverKey != nil && len(crossSigData) > 0 { + proverKeyAddress := crossSigData[:32] + proverKeys, err := p.GetSignedDecaf448KeysByParent(proverKeyAddress, "") + if err == nil { + for _, key := range proverKeys { + if _, exists := registry.KeysByPurpose[key.KeyPurpose]; !exists { + registry.KeysByPurpose[key.KeyPurpose] = &protobufs.KeyCollection{ + KeyPurpose: key.KeyPurpose, + X448Keys: []*protobufs.SignedX448Key{}, + Decaf448Keys: []*protobufs.SignedDecaf448Key{}, + } + } + registry.KeysByPurpose[key.KeyPurpose].Decaf448Keys = append( + registry.KeysByPurpose[key.KeyPurpose].Decaf448Keys, key, ) if registry.LastUpdated < key.CreatedAt { registry.LastUpdated = key.CreatedAt @@ -824,8 +1204,8 @@ func (p *PebbleKeyStore) GetKeyRegistryByProver( return registry, nil } -// RangeSignedKeys returns an iterator over signed keys, optionally filtered -func (p *PebbleKeyStore) RangeSignedKeys( +// RangeSignedX448Keys returns an iterator over signed keys, optionally filtered +func (p *PebbleKeyStore) RangeSignedX448Keys( parentKeyAddress []byte, keyPurpose string, ) (store.TypedIterator[*protobufs.SignedX448Key], error) { @@ -833,23 +1213,76 @@ func (p *PebbleKeyStore) RangeSignedKeys( if parentKeyAddress != nil && keyPurpose != "" { // Range for specific parent and purpose - startKey = signedKeyByParentKey(parentKeyAddress, keyPurpose, []byte{0x00}) - endKey = signedKeyByParentKey(parentKeyAddress, keyPurpose, []byte{0xff}) + startKey = signedX448KeyByParentKey( + parentKeyAddress, + keyPurpose, + []byte{0x00}, + ) + endKey = signedX448KeyByParentKey( + parentKeyAddress, + keyPurpose, + []byte{0xff}, + ) + } else if parentKeyAddress != nil { + // Range for specific parent, all purposes + startKey = []byte{KEY_BUNDLE, KEY_X448_SIGNED_KEY_BY_PARENT} + startKey = append(startKey, parentKeyAddress...) + endKey = []byte{KEY_BUNDLE, KEY_X448_SIGNED_KEY_BY_PARENT} + endKey = append(endKey, parentKeyAddress...) + endKey = append(endKey, 0xff) + } else if keyPurpose != "" { + // Range for specific purpose, all parents + startKey = signedX448KeyByPurposeKey(keyPurpose, []byte{0x00}) + endKey = signedX448KeyByPurposeKey(keyPurpose, []byte{0xff}) + } else { + // Range all signed keys + startKey = []byte{KEY_BUNDLE, KEY_X448_SIGNED_KEY_BY_ID} + endKey = []byte{KEY_BUNDLE, KEY_X448_SIGNED_KEY_BY_ID + 1} + } + + iter, err := p.db.NewIter(startKey, endKey) + if err != nil { + return nil, errors.Wrap(err, "range signed keys") + } + + return &PebbleSignedX448KeyIterator{i: iter, db: p}, nil +} + +// RangeSignedDecaf448Keys returns an iterator over signed keys, optionally +// filtered +func (p *PebbleKeyStore) RangeSignedDecaf448Keys( + parentKeyAddress []byte, + keyPurpose string, +) (store.TypedIterator[*protobufs.SignedDecaf448Key], error) { + var startKey, endKey []byte + + if parentKeyAddress != nil && keyPurpose != "" { + // Range for specific parent and purpose + startKey = signedDecaf448KeyByParentKey( + parentKeyAddress, + keyPurpose, + []byte{0x00}, + ) + endKey = signedDecaf448KeyByParentKey( + parentKeyAddress, + keyPurpose, + []byte{0xff}, + ) } else if parentKeyAddress != nil { // Range for specific parent, all purposes - startKey = []byte{KEY_BUNDLE, KEY_SIGNED_KEY_BY_PARENT} + startKey = []byte{KEY_BUNDLE, KEY_DECAF448_SIGNED_KEY_BY_PARENT} startKey = append(startKey, parentKeyAddress...) - endKey = []byte{KEY_BUNDLE, KEY_SIGNED_KEY_BY_PARENT} + endKey = []byte{KEY_BUNDLE, KEY_DECAF448_SIGNED_KEY_BY_PARENT} endKey = append(endKey, parentKeyAddress...) endKey = append(endKey, 0xff) } else if keyPurpose != "" { // Range for specific purpose, all parents - startKey = signedKeyByPurposeKey(keyPurpose, []byte{0x00}) - endKey = signedKeyByPurposeKey(keyPurpose, []byte{0xff}) + startKey = signedDecaf448KeyByPurposeKey(keyPurpose, []byte{0x00}) + endKey = signedDecaf448KeyByPurposeKey(keyPurpose, []byte{0xff}) } else { // Range all signed keys - startKey = []byte{KEY_BUNDLE, KEY_SIGNED_KEY_BY_ID} - endKey = []byte{KEY_BUNDLE, KEY_SIGNED_KEY_BY_ID + 1} + startKey = []byte{KEY_BUNDLE, KEY_DECAF448_SIGNED_KEY_BY_ID} + endKey = []byte{KEY_BUNDLE, KEY_DECAF448_SIGNED_KEY_BY_ID + 1} } iter, err := p.db.NewIter(startKey, endKey) @@ -857,5 +1290,5 @@ func (p *PebbleKeyStore) RangeSignedKeys( return nil, errors.Wrap(err, "range signed keys") } - return &PebbleSignedKeyIterator{i: iter, db: p}, nil + return &PebbleSignedDecaf448KeyIterator{i: iter, db: p}, nil } diff --git a/node/store/key_test.go b/node/store/key_test.go index 23c22fb0..9a48f594 100644 --- a/node/store/key_test.go +++ b/node/store/key_test.go @@ -167,37 +167,37 @@ func TestPebbleKeyStore_SignedKeys(t *testing.T) { txn, err := store.NewTransaction() require.NoError(t, err) - err = store.PutSignedKey(txn, keyAddress, signedKey) + err = store.PutSignedX448Key(txn, keyAddress, signedKey) require.NoError(t, err) err = txn.Commit() require.NoError(t, err) // Test getting signed key - retrievedKey, err := store.GetSignedKey(keyAddress) + retrievedKey, err := store.GetSignedX448Key(keyAddress) require.NoError(t, err) assert.True(t, bytes.Equal(signedKey.Key.KeyValue, retrievedKey.Key.KeyValue)) assert.True(t, bytes.Equal(signedKey.ParentKeyAddress, retrievedKey.ParentKeyAddress)) assert.Equal(t, signedKey.KeyPurpose, retrievedKey.KeyPurpose) // Test getting by parent - keys, err := store.GetSignedKeysByParent(parentKeyAddress, "") + keys, err := store.GetSignedX448KeysByParent(parentKeyAddress, "") require.NoError(t, err) assert.Len(t, keys, 1) assert.True(t, bytes.Equal(signedKey.Key.KeyValue, keys[0].Key.KeyValue)) // Test getting by parent and purpose - keys, err = store.GetSignedKeysByParent(parentKeyAddress, "inbox") + keys, err = store.GetSignedX448KeysByParent(parentKeyAddress, "inbox") require.NoError(t, err) assert.Len(t, keys, 1) // Test getting by parent and wrong purpose - keys, err = store.GetSignedKeysByParent(parentKeyAddress, "device") + keys, err = store.GetSignedX448KeysByParent(parentKeyAddress, "device") require.NoError(t, err) assert.Len(t, keys, 0) // Test non-existent key - _, err = store.GetSignedKey(generateRandomBytes(t, 32)) + _, err = store.GetSignedX448Key(generateRandomBytes(t, 32)) assert.ErrorIs(t, err, tstore.ErrNotFound) } @@ -219,7 +219,7 @@ func TestPebbleKeyStore_SignedKeysMultiplePurposes(t *testing.T) { keyAddresses[i] = keyAddress signedKey := createTestSignedX448Key(t, parentKeyAddress, purpose) - err = store.PutSignedKey(txn, keyAddress, signedKey) + err = store.PutSignedX448Key(txn, keyAddress, signedKey) require.NoError(t, err) } @@ -227,20 +227,20 @@ func TestPebbleKeyStore_SignedKeysMultiplePurposes(t *testing.T) { require.NoError(t, err) // Test getting all keys by parent - keys, err := store.GetSignedKeysByParent(parentKeyAddress, "") + keys, err := store.GetSignedX448KeysByParent(parentKeyAddress, "") require.NoError(t, err) assert.Len(t, keys, len(purposes)) // Test getting keys by specific purpose for _, purpose := range purposes { - keys, err = store.GetSignedKeysByParent(parentKeyAddress, purpose) + keys, err = store.GetSignedX448KeysByParent(parentKeyAddress, purpose) require.NoError(t, err) assert.Len(t, keys, 1) assert.Equal(t, purpose, keys[0].KeyPurpose) } } -func TestPebbleKeyStore_DeleteSignedKey(t *testing.T) { +func TestPebbleKeyStore_DeleteSignedX448Key(t *testing.T) { store := setupTestKeyStore(t) defer store.db.Close() @@ -252,32 +252,32 @@ func TestPebbleKeyStore_DeleteSignedKey(t *testing.T) { txn, err := store.NewTransaction() require.NoError(t, err) - err = store.PutSignedKey(txn, keyAddress, signedKey) + err = store.PutSignedX448Key(txn, keyAddress, signedKey) require.NoError(t, err) err = txn.Commit() require.NoError(t, err) // Verify it exists - _, err = store.GetSignedKey(keyAddress) + _, err = store.GetSignedX448Key(keyAddress) require.NoError(t, err) // Delete the key txn, err = store.NewTransaction() require.NoError(t, err) - err = store.DeleteSignedKey(txn, keyAddress) + err = store.DeleteSignedX448Key(txn, keyAddress) require.NoError(t, err) err = txn.Commit() require.NoError(t, err) // Verify it's deleted - _, err = store.GetSignedKey(keyAddress) + _, err = store.GetSignedX448Key(keyAddress) assert.ErrorIs(t, err, tstore.ErrNotFound) // Verify it's removed from parent index - keys, err := store.GetSignedKeysByParent(parentKeyAddress, "") + keys, err := store.GetSignedX448KeysByParent(parentKeyAddress, "") require.NoError(t, err) assert.Len(t, keys, 0) } @@ -308,13 +308,13 @@ func TestPebbleKeyStore_ExpiredKeys(t *testing.T) { txn, err := store.NewTransaction() require.NoError(t, err) - err = store.PutSignedKey(txn, expiredKeyAddress, expiredKey) + err = store.PutSignedX448Key(txn, expiredKeyAddress, expiredKey) require.NoError(t, err) - err = store.PutSignedKey(txn, validKeyAddress, validKey) + err = store.PutSignedX448Key(txn, validKeyAddress, validKey) require.NoError(t, err) - err = store.PutSignedKey(txn, permanentKeyAddress, permanentKey) + err = store.PutSignedX448Key(txn, permanentKeyAddress, permanentKey) require.NoError(t, err) err = txn.Commit() @@ -325,14 +325,14 @@ func TestPebbleKeyStore_ExpiredKeys(t *testing.T) { require.NoError(t, err) // Verify expired key is deleted - _, err = store.GetSignedKey(expiredKeyAddress) + _, err = store.GetSignedX448Key(expiredKeyAddress) assert.ErrorIs(t, err, tstore.ErrNotFound) // Verify valid keys remain - _, err = store.GetSignedKey(validKeyAddress) + _, err = store.GetSignedX448Key(validKeyAddress) require.NoError(t, err) - _, err = store.GetSignedKey(permanentKeyAddress) + _, err = store.GetSignedX448Key(permanentKeyAddress) require.NoError(t, err) } @@ -376,13 +376,13 @@ func TestPebbleKeyStore_GetKeyRegistry(t *testing.T) { err = store.PutCrossSignature(txn, identityKeyAddress, provingKeyAddress, identitySig, provingSig) require.NoError(t, err) - err = store.PutSignedKey(txn, inboxKeyAddress, inboxKey) + err = store.PutSignedX448Key(txn, inboxKeyAddress, inboxKey) require.NoError(t, err) - err = store.PutSignedKey(txn, deviceKeyAddress, deviceKey) + err = store.PutSignedX448Key(txn, deviceKeyAddress, deviceKey) require.NoError(t, err) - err = store.PutSignedKey(txn, preKeyAddress, preKey) + err = store.PutSignedX448Key(txn, preKeyAddress, preKey) require.NoError(t, err) err = txn.Commit() @@ -412,15 +412,15 @@ func TestPebbleKeyStore_GetKeyRegistry(t *testing.T) { assert.Len(t, registry.KeysByPurpose, 3) // inbox, device, pre assert.NotNil(t, registry.KeysByPurpose["inbox"]) - assert.Len(t, registry.KeysByPurpose["inbox"].Keys, 1) + assert.Len(t, registry.KeysByPurpose["inbox"].X448Keys, 1) assert.Equal(t, "inbox", registry.KeysByPurpose["inbox"].KeyPurpose) assert.NotNil(t, registry.KeysByPurpose["device"]) - assert.Len(t, registry.KeysByPurpose["device"].Keys, 1) + assert.Len(t, registry.KeysByPurpose["device"].X448Keys, 1) assert.Equal(t, "device", registry.KeysByPurpose["device"].KeyPurpose) assert.NotNil(t, registry.KeysByPurpose["pre"]) - assert.Len(t, registry.KeysByPurpose["pre"].Keys, 1) + assert.Len(t, registry.KeysByPurpose["pre"].X448Keys, 1) assert.Equal(t, "pre", registry.KeysByPurpose["pre"].KeyPurpose) // Test GetKeyRegistryByProver @@ -542,7 +542,7 @@ func TestPebbleKeyStore_Iterators(t *testing.T) { key := createTestSignedX448Key(t, parentKeyAddress, "test") signedKeys[string(address)] = key - err = store.PutSignedKey(txn, address, key) + err = store.PutSignedX448Key(txn, address, key) require.NoError(t, err) } @@ -550,7 +550,7 @@ func TestPebbleKeyStore_Iterators(t *testing.T) { require.NoError(t, err) // Test RangeSignedKeys - iter3, err := store.RangeSignedKeys(parentKeyAddress, "test") + iter3, err := store.RangeSignedX448Keys(parentKeyAddress, "test") require.NoError(t, err) defer iter3.Close() diff --git a/node/tests/simnet.go b/node/tests/simnet.go new file mode 100644 index 00000000..5bfa4ae0 --- /dev/null +++ b/node/tests/simnet.go @@ -0,0 +1,85 @@ +package tests + +import ( + "context" + "testing" + "time" + + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/p2p/net/swarm" + simlibp2p "github.com/libp2p/go-libp2p/x/simlibp2p" + "github.com/marcopolo/simnet" + "github.com/stretchr/testify/require" +) + +func GenerateSimnetHosts(t *testing.T, count int, opts []libp2p.Option) ( + *simnet.Simnet, + *simlibp2p.SimpleLibp2pNetworkMeta, + func(), +) { + latency := 400 * time.Millisecond + linkSettings := simnet.NodeBiDiLinkSettings{ + Downlink: simnet.LinkSettings{ + BitsPerSecond: 20 * simlibp2p.OneMbps, + Latency: latency / 2, + }, // Divide by two since this is latency for each direction + Uplink: simnet.LinkSettings{ + BitsPerSecond: 1 * simlibp2p.OneMbps, + Latency: latency / 2, + }, + } + set := []simlibp2p.NodeLinkSettingsAndIndex{} + for i := 0; i < count; i++ { + set = append(set, simlibp2p.NodeLinkSettingsAndIndex{ + LinkSettings: linkSettings, + Idx: i, + }) + } + network, meta, err := simlibp2p.SimpleLibp2pNetwork( + set, + simlibp2p.NetworkSettings{ + OptsForHostIdx: func(idx int) []libp2p.Option { + return []libp2p.Option{ + libp2p.SwarmOpts( + swarm.WithUDPBlackHoleSuccessCounter( + &swarm.BlackHoleSuccessCounter{ + N: 8000, + MinSuccesses: 1, + Name: "permissive-udp", + }, + ), + swarm.WithIPv6BlackHoleSuccessCounter( + &swarm.BlackHoleSuccessCounter{ + N: 8000, + MinSuccesses: 1, + Name: "permissive-ip6", + }, + ), + ), + } + }, + }, + ) + require.NoError(t, err) + network.Start() + return network, meta, func() { + network.Close() + + for _, node := range meta.Nodes { + node.Close() + } + } +} + +func ConnectSimnetHosts(t *testing.T, a, b host.Host) { + err := a.Connect( + context.Background(), + peer.AddrInfo{ + ID: b.ID(), + Addrs: b.Addrs(), + }, + ) + require.NoError(t, err) +} diff --git a/node/worker/manager.go b/node/worker/manager.go index 9c2055bd..b6151585 100644 --- a/node/worker/manager.go +++ b/node/worker/manager.go @@ -2,17 +2,27 @@ package worker import ( "context" + "encoding/hex" "fmt" "os" "os/exec" + "strings" "sync" "time" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/multiformats/go-multiaddr" + mn "github.com/multiformats/go-multiaddr/net" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "go.uber.org/zap" + "google.golang.org/grpc" "source.quilibrium.com/quilibrium/monorepo/config" + "source.quilibrium.com/quilibrium/monorepo/node/p2p" "source.quilibrium.com/quilibrium/monorepo/node/store" + "source.quilibrium.com/quilibrium/monorepo/protobufs" + "source.quilibrium.com/quilibrium/monorepo/types/channel" typesStore "source.quilibrium.com/quilibrium/monorepo/types/store" typesWorker "source.quilibrium.com/quilibrium/monorepo/types/worker" ) @@ -25,11 +35,22 @@ type WorkerManager struct { mu sync.RWMutex started bool config *config.Config - proposeFunc func(coreId uint, filter []byte) error + proposeFunc func( + coreIds []uint, + filters [][]byte, + serviceClients map[uint]*grpc.ClientConn, + ) error + decideFunc func( + reject [][]byte, + confirm [][]byte, + ) error // When automatic, hold reference to the workers dataWorkers []*exec.Cmd + // IPC service clients + serviceClients map[uint]*grpc.ClientConn + // In-memory cache for quick lookups workersByFilter map[string]uint // filter hash -> worker id filtersByWorker map[uint][]byte // worker id -> filter @@ -42,7 +63,15 @@ func NewWorkerManager( store typesStore.WorkerStore, logger *zap.Logger, config *config.Config, - proposeFunc func(coreId uint, filter []byte) error, + proposeFunc func( + coreIds []uint, + filters [][]byte, + serviceClients map[uint]*grpc.ClientConn, + ) error, + decideFunc func( + reject [][]byte, + confirm [][]byte, + ) error, ) typesWorker.WorkerManager { return &WorkerManager{ store: store, @@ -50,8 +79,10 @@ func NewWorkerManager( workersByFilter: make(map[string]uint), filtersByWorker: make(map[uint][]byte), allocatedWorkers: make(map[uint]bool), + serviceClients: make(map[uint]*grpc.ClientConn), config: config, proposeFunc: proposeFunc, + decideFunc: decideFunc, } } @@ -67,15 +98,16 @@ func (w *WorkerManager) Start(ctx context.Context) error { w.ctx, w.cancel = context.WithCancel(ctx) + w.started = true + + go w.spawnDataWorkers() + // Load existing workers from the store if err := w.loadWorkersFromStore(); err != nil { w.logger.Error("failed to load workers from store", zap.Error(err)) return errors.Wrap(err, "start") } - go w.spawnDataWorkers() - - w.started = true w.logger.Info("worker manager started successfully") return nil } @@ -121,6 +153,10 @@ func (w *WorkerManager) RegisterWorker(info *typesStore.WorkerInfo) error { w.mu.Lock() defer w.mu.Unlock() + return w.registerWorker(info) +} + +func (w *WorkerManager) registerWorker(info *typesStore.WorkerInfo) error { if !w.started { workerOperationsTotal.WithLabelValues("register", "error").Inc() return errors.New("worker manager not started") @@ -133,13 +169,6 @@ func (w *WorkerManager) RegisterWorker(info *typesStore.WorkerInfo) error { zap.Bool("automatic", info.Automatic), ) - // Check if worker already exists - existingWorker, err := w.store.GetWorker(info.CoreId) - if err == nil && existingWorker != nil { - workerOperationsTotal.WithLabelValues("register", "error").Inc() - return errors.New("worker already registered") - } - // Save to store txn, err := w.store.NewTransaction(false) if err != nil { @@ -174,6 +203,7 @@ func (w *WorkerManager) RegisterWorker(info *typesStore.WorkerInfo) error { "worker registered successfully", zap.Uint("core_id", info.CoreId), ) + return nil } @@ -253,6 +283,22 @@ func (w *WorkerManager) AllocateWorker(coreId uint, filter []byte) error { filterKey := string(worker.Filter) w.workersByFilter[filterKey] = coreId } + + // Refresh worker + svc, err := w.getIPCOfWorker(coreId) + if err != nil { + w.logger.Error("could not get ipc of worker", zap.Error(err)) + return errors.Wrap(err, "allocate worker") + } + + _, err = svc.Respawn(w.ctx, &protobufs.RespawnRequest{ + Filter: worker.Filter, + }) + if err != nil { + w.logger.Error("could not respawn worker", zap.Error(err)) + return errors.Wrap(err, "allocate worker") + } + w.filtersByWorker[coreId] = worker.Filter w.allocatedWorkers[coreId] = true @@ -323,6 +369,21 @@ func (w *WorkerManager) DeallocateWorker(coreId uint) error { return errors.Wrap(err, "deallocate worker") } + // Refresh worker + svc, err := w.getIPCOfWorker(coreId) + if err != nil { + w.logger.Error("could not get ipc of worker", zap.Error(err)) + return errors.Wrap(err, "allocate worker") + } + + _, err = svc.Respawn(w.ctx, &protobufs.RespawnRequest{ + Filter: []byte{}, + }) + if err != nil { + w.logger.Error("could not respawn worker", zap.Error(err)) + return errors.Wrap(err, "allocate worker") + } + // Mark as deallocated in cache delete(w.allocatedWorkers, coreId) @@ -418,10 +479,29 @@ func (w *WorkerManager) RangeWorkers() ([]*typesStore.WorkerInfo, error) { return w.store.RangeWorkers() } -// ProposeAllocation invokes a proposal function set by the parent of the +// ProposeAllocations invokes a proposal function set by the parent of the // manager. -func (w *WorkerManager) ProposeAllocation(coreId uint, filter []byte) error { - return w.proposeFunc(coreId, filter) +func (w *WorkerManager) ProposeAllocations( + coreIds []uint, + filters [][]byte, +) error { + for _, coreId := range coreIds { + _, err := w.getIPCOfWorker(coreId) + if err != nil { + w.logger.Error("could not get ipc of worker", zap.Error(err)) + return errors.Wrap(err, "allocate worker") + } + } + return w.proposeFunc(coreIds, filters, w.serviceClients) +} + +// DecideAllocations invokes a deciding function set by the parent of the +// manager. +func (w *WorkerManager) DecideAllocations( + reject [][]byte, + confirm [][]byte, +) error { + return w.decideFunc(reject, confirm) } // loadWorkersFromStore loads all workers from persistent storage into memory @@ -431,6 +511,16 @@ func (w *WorkerManager) loadWorkersFromStore() error { return errors.Wrap(err, "load workers from store") } + if len(workers) != w.config.Engine.DataWorkerCount { + for i := range w.config.Engine.DataWorkerCount { + _, err := w.getIPCOfWorker(uint(i + 1)) + if err != nil { + w.logger.Error("could not obtain IPC for worker", zap.Error(err)) + continue + } + } + } + var totalStorage uint64 var allocatedCount int for _, worker := range workers { @@ -445,6 +535,19 @@ func (w *WorkerManager) loadWorkersFromStore() error { allocatedCount++ } totalStorage += uint64(worker.TotalStorage) + svc, err := w.getIPCOfWorker(worker.CoreId) + if err != nil { + w.logger.Error("could not obtain IPC for worker", zap.Error(err)) + continue + } + + _, err = svc.Respawn(w.ctx, &protobufs.RespawnRequest{ + Filter: worker.Filter, + }) + if err != nil { + w.logger.Error("could not respawn worker", zap.Error(err)) + continue + } } // Update metrics @@ -456,8 +559,133 @@ func (w *WorkerManager) loadWorkersFromStore() error { return nil } -func (w *WorkerManager) spawnDataWorkers() { +func (w *WorkerManager) getMultiaddrOfWorker(coreId uint) ( + multiaddr.Multiaddr, + error, +) { + rpcMultiaddr := fmt.Sprintf( + w.config.Engine.DataWorkerBaseListenMultiaddr, + int(w.config.Engine.DataWorkerBaseStreamPort)+int(coreId-1), + ) + if len(w.config.Engine.DataWorkerStreamMultiaddrs) != 0 { + rpcMultiaddr = w.config.Engine.DataWorkerStreamMultiaddrs[coreId-1] + } + + rpcMultiaddr = strings.Replace(rpcMultiaddr, "/0.0.0.0/", "/127.0.0.1/", 1) + rpcMultiaddr = strings.Replace(rpcMultiaddr, "/0:0:0:0:0:0:0:0/", "/::1/", 1) + rpcMultiaddr = strings.Replace(rpcMultiaddr, "/::/", "/::1/", 1) + + ma, err := multiaddr.StringCast(rpcMultiaddr) + return ma, errors.Wrap(err, "get multiaddr of worker") +} + +func (w *WorkerManager) getP2PMultiaddrOfWorker(coreId uint) ( + multiaddr.Multiaddr, + error, +) { + p2pMultiaddr := fmt.Sprintf( + w.config.Engine.DataWorkerBaseListenMultiaddr, + int(w.config.Engine.DataWorkerBaseP2PPort)+int(coreId-1), + ) + + if len(w.config.Engine.DataWorkerP2PMultiaddrs) != 0 { + p2pMultiaddr = w.config.Engine.DataWorkerP2PMultiaddrs[coreId-1] + } + + ma, err := multiaddr.StringCast(p2pMultiaddr) + return ma, errors.Wrap(err, "get p2p multiaddr of worker") +} + +func (w *WorkerManager) getIPCOfWorker(coreId uint) ( + protobufs.DataIPCServiceClient, + error, +) { + client, ok := w.serviceClients[coreId] + if !ok { + w.logger.Info("reconnecting to worker", zap.Uint("core_id", coreId)) + addr, err := w.getMultiaddrOfWorker(coreId) + if err != nil { + return nil, errors.Wrap(err, "get ipc of worker") + } + + mga, err := mn.ToNetAddr(addr) + if err != nil { + return nil, errors.Wrap(err, "get ipc of worker") + } + + peerPrivKey, err := hex.DecodeString(w.config.P2P.PeerPrivKey) + if err != nil { + w.logger.Error("error unmarshaling peerkey", zap.Error(err)) + return nil, errors.Wrap(err, "get ipc of worker") + } + + if _, ok := w.filtersByWorker[coreId]; !ok { + p2pAddr, err := w.getP2PMultiaddrOfWorker(coreId) + if err != nil { + return nil, errors.Wrap(err, "get ipc of worker") + } + err = w.registerWorker(&typesStore.WorkerInfo{ + CoreId: coreId, + ListenMultiaddr: p2pAddr.String(), + StreamListenMultiaddr: addr.String(), + Filter: nil, + TotalStorage: 0, + Automatic: len(w.config.Engine.DataWorkerP2PMultiaddrs) == 0, + Allocated: false, + }) + if err != nil { + return nil, errors.Wrap(err, "get ipc of worker") + } + } + + privKey, err := crypto.UnmarshalEd448PrivateKey(peerPrivKey) + if err != nil { + w.logger.Error("error unmarshaling peerkey", zap.Error(err)) + return nil, errors.Wrap(err, "get ipc of worker") + } + + pub := privKey.GetPublic() + id, err := peer.IDFromPublicKey(pub) + if err != nil { + w.logger.Error("error unmarshaling peerkey", zap.Error(err)) + return nil, errors.Wrap(err, "get ipc of worker") + } + + creds, err := p2p.NewPeerAuthenticator( + w.logger, + w.config.P2P, + nil, + nil, + nil, + nil, + [][]byte{[]byte(id)}, + map[string]channel.AllowedPeerPolicyType{ + "quilibrium.node.node.pb.DataIPCService": channel.OnlySelfPeer, + }, + map[string]channel.AllowedPeerPolicyType{}, + ).CreateClientTLSCredentials([]byte(id)) + if err != nil { + return nil, errors.Wrap(err, "get ipc of worker") + } + + client, err = grpc.NewClient( + mga.String(), + grpc.WithTransportCredentials(creds), + ) + if err != nil { + + return nil, errors.Wrap(err, "get ipc of worker") + } + + w.serviceClients[coreId] = client + } + + return protobufs.NewDataIPCServiceClient(client), nil +} + +func (w *WorkerManager) spawnDataWorkers() { + if len(w.config.Engine.DataWorkerP2PMultiaddrs) != 0 { w.logger.Warn( "data workers configured by multiaddr, be sure these are running...", ) @@ -478,7 +706,7 @@ func (w *WorkerManager) spawnDataWorkers() { for i := 1; i <= w.config.Engine.DataWorkerCount; i++ { i := i go func() { - for { + for w.started { args := []string{ fmt.Sprintf("--core=%d", i), fmt.Sprintf("--parent-process=%d", os.Getpid()), diff --git a/node/worker/manager_test.go b/node/worker/manager_test.go index f4d98568..09d83942 100644 --- a/node/worker/manager_test.go +++ b/node/worker/manager_test.go @@ -2,15 +2,25 @@ package worker import ( "context" + "crypto/rand" + "encoding/hex" "errors" "io" "testing" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/multiformats/go-multiaddr" + mn "github.com/multiformats/go-multiaddr/net" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" + "google.golang.org/grpc" "source.quilibrium.com/quilibrium/monorepo/config" + qgrpc "source.quilibrium.com/quilibrium/monorepo/node/internal/grpc" + "source.quilibrium.com/quilibrium/monorepo/node/p2p" "source.quilibrium.com/quilibrium/monorepo/node/store" + "source.quilibrium.com/quilibrium/monorepo/protobufs" + "source.quilibrium.com/quilibrium/monorepo/types/channel" typesStore "source.quilibrium.com/quilibrium/monorepo/types/store" ) @@ -139,7 +149,7 @@ func (t *mockTransaction) Abort() error { func TestWorkerManager_StartStop(t *testing.T) { logger, _ := zap.NewDevelopment() store := newMockWorkerStore() - manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreId uint, filter []byte) error { return nil }) + manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreIds []uint, filters [][]byte, serviceClients map[uint]*grpc.ClientConn) error { return nil }, func(reject [][]byte, confirm [][]byte) error { return nil }) // Test starting the manager ctx := context.Background() @@ -164,7 +174,7 @@ func TestWorkerManager_StartStop(t *testing.T) { func TestWorkerManager_RegisterWorker(t *testing.T) { logger, _ := zap.NewDevelopment() store := newMockWorkerStore() - manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreId uint, filter []byte) error { return nil }) + manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreIds []uint, filters [][]byte, serviceClients map[uint]*grpc.ClientConn) error { return nil }, func(reject [][]byte, confirm [][]byte) error { return nil }) // Start the manager ctx := context.Background() @@ -191,17 +201,12 @@ func TestWorkerManager_RegisterWorker(t *testing.T) { assert.Equal(t, workerInfo.CoreId, storedWorker.CoreId) assert.Equal(t, workerInfo.ListenMultiaddr, storedWorker.ListenMultiaddr) assert.Equal(t, workerInfo.Filter, storedWorker.Filter) - - // Test registering the same worker again should fail - err = manager.RegisterWorker(workerInfo) - assert.Error(t, err) - assert.Contains(t, err.Error(), "already registered") } func TestWorkerManager_RegisterWorkerNotStarted(t *testing.T) { logger, _ := zap.NewDevelopment() store := newMockWorkerStore() - manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreId uint, filter []byte) error { return nil }) + manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreIds []uint, filters [][]byte, serviceClients map[uint]*grpc.ClientConn) error { return nil }, func(reject [][]byte, confirm [][]byte) error { return nil }) // Try to register without starting workerInfo := &typesStore.WorkerInfo{ @@ -221,11 +226,72 @@ func TestWorkerManager_RegisterWorkerNotStarted(t *testing.T) { func TestWorkerManager_AllocateDeallocateWorker(t *testing.T) { logger, _ := zap.NewDevelopment() store := newMockWorkerStore() - manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreId uint, filter []byte) error { return nil }) + engcfg := (config.EngineConfig{}).WithDefaults() + engcfg.DataWorkerCount = 2 + engcfg.DataWorkerP2PMultiaddrs = []string{"/ip4/0.0.0.0/tcp/8000", "/ip4/0.0.0.0/tcp/8000"} + engcfg.DataWorkerStreamMultiaddrs = []string{"/ip4/0.0.0.0/tcp/60002", "/ip4/0.0.0.0/tcp/60002"} + p2pcfg := (config.P2PConfig{}).WithDefaults() + priv, _, err := crypto.GenerateEd448Key(rand.Reader) + require.NoError(t, err) + k, _ := priv.Raw() + p2pcfg.PeerPrivKey = hex.EncodeToString(k) + manager := NewWorkerManager(store, logger, &config.Config{Engine: &engcfg, P2P: &p2pcfg}, func(coreIds []uint, filters [][]byte, serviceClients map[uint]*grpc.ClientConn) error { return nil }, func(reject [][]byte, confirm [][]byte) error { return nil }) + auth := p2p.NewPeerAuthenticator( + zap.L(), + &p2pcfg, + nil, + nil, + nil, + nil, + nil, + map[string]channel.AllowedPeerPolicyType{ + "quilibrium.node.application.pb.HypergraphComparisonService": channel.AnyProverPeer, + "quilibrium.node.node.pb.DataIPCService": channel.OnlySelfPeer, + "quilibrium.node.global.pb.GlobalService": channel.OnlyGlobalProverPeer, + "quilibrium.node.global.pb.AppShardService": channel.OnlyShardProverPeer, + "quilibrium.node.global.pb.OnionService": channel.AnyPeer, + "quilibrium.node.global.pb.KeyRegistryService": channel.OnlySelfPeer, + }, + map[string]channel.AllowedPeerPolicyType{ + "/quilibrium.node.application.pb.HypergraphComparisonService/HyperStream": channel.OnlyShardProverPeer, + "/quilibrium.node.global.pb.MixnetService/GetTag": channel.AnyPeer, + "/quilibrium.node.global.pb.MixnetService/PutTag": channel.AnyPeer, + "/quilibrium.node.global.pb.MixnetService/PutMessage": channel.AnyPeer, + "/quilibrium.node.global.pb.MixnetService/RoundStream": channel.OnlyGlobalProverPeer, + "/quilibrium.node.global.pb.DispatchService/PutInboxMessage": channel.OnlySelfPeer, + "/quilibrium.node.global.pb.DispatchService/GetInboxMessages": channel.OnlySelfPeer, + "/quilibrium.node.global.pb.DispatchService/PutHub": channel.OnlySelfPeer, + "/quilibrium.node.global.pb.DispatchService/GetHub": channel.OnlySelfPeer, + "/quilibrium.node.global.pb.DispatchService/Sync": channel.AnyProverPeer, + "/quilibrium.node.ferretproxy.pb.FerretProxy/AliceProxy": channel.OnlySelfPeer, + "/quilibrium.node.ferretproxy.pb.FerretProxy/BobProxy": channel.AnyPeer, + }, + ) + + tlsCreds, err := auth.CreateServerTLSCredentials() + require.NoError(t, err) + server := qgrpc.NewServer( + grpc.Creds(tlsCreds), + grpc.MaxRecvMsgSize(10*1024*1024), + grpc.MaxSendMsgSize(10*1024*1024), + ) + + mg, err := multiaddr.NewMultiaddr("/ip4/0.0.0.0/tcp/60002") + require.NoError(t, err) + + lis, err := mn.Listen(mg) + require.NoError(t, err) + go func() { + protobufs.RegisterDataIPCServiceServer(server, &mockIPC{}) + if err := server.Serve(mn.NetListener(lis)); err != nil { + zap.L().Info("terminating server", zap.Error(err)) + } + }() + defer server.Stop() // Start the manager ctx := context.Background() - err := manager.Start(ctx) + err = manager.Start(ctx) require.NoError(t, err) defer manager.Stop() @@ -275,7 +341,7 @@ func TestWorkerManager_AllocateDeallocateWorker(t *testing.T) { func TestWorkerManager_AllocateNonExistentWorker(t *testing.T) { logger, _ := zap.NewDevelopment() store := newMockWorkerStore() - manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreId uint, filter []byte) error { return nil }) + manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreIds []uint, filters [][]byte, serviceClients map[uint]*grpc.ClientConn) error { return nil }, func(reject [][]byte, confirm [][]byte) error { return nil }) // Start the manager ctx := context.Background() @@ -292,7 +358,7 @@ func TestWorkerManager_AllocateNonExistentWorker(t *testing.T) { func TestWorkerManager_GetWorkerIdByFilter(t *testing.T) { logger, _ := zap.NewDevelopment() store := newMockWorkerStore() - manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreId uint, filter []byte) error { return nil }) + manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreIds []uint, filters [][]byte, serviceClients map[uint]*grpc.ClientConn) error { return nil }, func(reject [][]byte, confirm [][]byte) error { return nil }) // Start the manager ctx := context.Background() @@ -328,7 +394,7 @@ func TestWorkerManager_GetWorkerIdByFilter(t *testing.T) { func TestWorkerManager_GetFilterByWorkerId(t *testing.T) { logger, _ := zap.NewDevelopment() store := newMockWorkerStore() - manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreId uint, filter []byte) error { return nil }) + manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreIds []uint, filters [][]byte, serviceClients map[uint]*grpc.ClientConn) error { return nil }, func(reject [][]byte, confirm [][]byte) error { return nil }) // Start the manager ctx := context.Background() @@ -389,7 +455,7 @@ func TestWorkerManager_LoadWorkersOnStart(t *testing.T) { store.workersByFilter[string(worker2.Filter)] = worker2 // Create manager and start it - manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreId uint, filter []byte) error { return nil }) + manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreIds []uint, filters [][]byte, serviceClients map[uint]*grpc.ClientConn) error { return nil }, func(reject [][]byte, confirm [][]byte) error { return nil }) ctx := context.Background() err := manager.Start(ctx) require.NoError(t, err) @@ -416,7 +482,7 @@ func TestWorkerManager_LoadWorkersOnStart(t *testing.T) { func TestWorkerManager_ConcurrentOperations(t *testing.T) { logger, _ := zap.NewDevelopment() store := newMockWorkerStore() - manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreId uint, filter []byte) error { return nil }) + manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreIds []uint, filters [][]byte, serviceClients map[uint]*grpc.ClientConn) error { return nil }, func(reject [][]byte, confirm [][]byte) error { return nil }) // Start the manager ctx := context.Background() @@ -457,11 +523,72 @@ func TestWorkerManager_ConcurrentOperations(t *testing.T) { func TestWorkerManager_EmptyFilter(t *testing.T) { logger, _ := zap.NewDevelopment() store := newMockWorkerStore() - manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreId uint, filter []byte) error { return nil }) + engcfg := (config.EngineConfig{}).WithDefaults() + engcfg.DataWorkerCount = 1 + engcfg.DataWorkerP2PMultiaddrs = []string{"/ip4/0.0.0.0/tcp/8000"} + engcfg.DataWorkerStreamMultiaddrs = []string{"/ip4/0.0.0.0/tcp/60000"} + p2pcfg := (config.P2PConfig{}).WithDefaults() + priv, _, err := crypto.GenerateEd448Key(rand.Reader) + require.NoError(t, err) + k, _ := priv.Raw() + p2pcfg.PeerPrivKey = hex.EncodeToString(k) + manager := NewWorkerManager(store, logger, &config.Config{Engine: &engcfg, P2P: &p2pcfg}, func(coreIds []uint, filters [][]byte, serviceClients map[uint]*grpc.ClientConn) error { return nil }, func(reject [][]byte, confirm [][]byte) error { return nil }) + auth := p2p.NewPeerAuthenticator( + zap.L(), + &p2pcfg, + nil, + nil, + nil, + nil, + nil, + map[string]channel.AllowedPeerPolicyType{ + "quilibrium.node.application.pb.HypergraphComparisonService": channel.AnyProverPeer, + "quilibrium.node.node.pb.DataIPCService": channel.OnlySelfPeer, + "quilibrium.node.global.pb.GlobalService": channel.OnlyGlobalProverPeer, + "quilibrium.node.global.pb.AppShardService": channel.OnlyShardProverPeer, + "quilibrium.node.global.pb.OnionService": channel.AnyPeer, + "quilibrium.node.global.pb.KeyRegistryService": channel.OnlySelfPeer, + }, + map[string]channel.AllowedPeerPolicyType{ + "/quilibrium.node.application.pb.HypergraphComparisonService/HyperStream": channel.OnlyShardProverPeer, + "/quilibrium.node.global.pb.MixnetService/GetTag": channel.AnyPeer, + "/quilibrium.node.global.pb.MixnetService/PutTag": channel.AnyPeer, + "/quilibrium.node.global.pb.MixnetService/PutMessage": channel.AnyPeer, + "/quilibrium.node.global.pb.MixnetService/RoundStream": channel.OnlyGlobalProverPeer, + "/quilibrium.node.global.pb.DispatchService/PutInboxMessage": channel.OnlySelfPeer, + "/quilibrium.node.global.pb.DispatchService/GetInboxMessages": channel.OnlySelfPeer, + "/quilibrium.node.global.pb.DispatchService/PutHub": channel.OnlySelfPeer, + "/quilibrium.node.global.pb.DispatchService/GetHub": channel.OnlySelfPeer, + "/quilibrium.node.global.pb.DispatchService/Sync": channel.AnyProverPeer, + "/quilibrium.node.ferretproxy.pb.FerretProxy/AliceProxy": channel.OnlySelfPeer, + "/quilibrium.node.ferretproxy.pb.FerretProxy/BobProxy": channel.AnyPeer, + }, + ) + + tlsCreds, err := auth.CreateServerTLSCredentials() + require.NoError(t, err) + server := qgrpc.NewServer( + grpc.Creds(tlsCreds), + grpc.MaxRecvMsgSize(10*1024*1024), + grpc.MaxSendMsgSize(10*1024*1024), + ) + + mg, err := multiaddr.NewMultiaddr("/ip4/0.0.0.0/tcp/60000") + require.NoError(t, err) + + lis, err := mn.Listen(mg) + require.NoError(t, err) + go func() { + protobufs.RegisterDataIPCServiceServer(server, &mockIPC{}) + if err := server.Serve(mn.NetListener(lis)); err != nil { + zap.L().Info("terminating server", zap.Error(err)) + } + }() + defer server.Stop() // Start the manager ctx := context.Background() - err := manager.Start(ctx) + err = manager.Start(ctx) require.NoError(t, err) defer manager.Stop() @@ -522,11 +649,72 @@ func TestWorkerManager_EmptyFilter(t *testing.T) { func TestWorkerManager_FilterUpdate(t *testing.T) { logger, _ := zap.NewDevelopment() store := newMockWorkerStore() - manager := NewWorkerManager(store, logger, &config.Config{Engine: &config.EngineConfig{}}, func(coreId uint, filter []byte) error { return nil }) + engcfg := (config.EngineConfig{}).WithDefaults() + engcfg.DataWorkerCount = 2 + engcfg.DataWorkerP2PMultiaddrs = []string{"/ip4/0.0.0.0/tcp/8000", "/ip4/0.0.0.0/tcp/8000"} + engcfg.DataWorkerStreamMultiaddrs = []string{"/ip4/0.0.0.0/tcp/60001", "/ip4/0.0.0.0/tcp/60001"} + p2pcfg := (config.P2PConfig{}).WithDefaults() + priv, _, err := crypto.GenerateEd448Key(rand.Reader) + require.NoError(t, err) + k, _ := priv.Raw() + p2pcfg.PeerPrivKey = hex.EncodeToString(k) + manager := NewWorkerManager(store, logger, &config.Config{Engine: &engcfg, P2P: &p2pcfg}, func(coreIds []uint, filters [][]byte, serviceClients map[uint]*grpc.ClientConn) error { return nil }, func(reject [][]byte, confirm [][]byte) error { return nil }) + auth := p2p.NewPeerAuthenticator( + zap.L(), + &p2pcfg, + nil, + nil, + nil, + nil, + nil, + map[string]channel.AllowedPeerPolicyType{ + "quilibrium.node.application.pb.HypergraphComparisonService": channel.AnyProverPeer, + "quilibrium.node.node.pb.DataIPCService": channel.OnlySelfPeer, + "quilibrium.node.global.pb.GlobalService": channel.OnlyGlobalProverPeer, + "quilibrium.node.global.pb.AppShardService": channel.OnlyShardProverPeer, + "quilibrium.node.global.pb.OnionService": channel.AnyPeer, + "quilibrium.node.global.pb.KeyRegistryService": channel.OnlySelfPeer, + }, + map[string]channel.AllowedPeerPolicyType{ + "/quilibrium.node.application.pb.HypergraphComparisonService/HyperStream": channel.OnlyShardProverPeer, + "/quilibrium.node.global.pb.MixnetService/GetTag": channel.AnyPeer, + "/quilibrium.node.global.pb.MixnetService/PutTag": channel.AnyPeer, + "/quilibrium.node.global.pb.MixnetService/PutMessage": channel.AnyPeer, + "/quilibrium.node.global.pb.MixnetService/RoundStream": channel.OnlyGlobalProverPeer, + "/quilibrium.node.global.pb.DispatchService/PutInboxMessage": channel.OnlySelfPeer, + "/quilibrium.node.global.pb.DispatchService/GetInboxMessages": channel.OnlySelfPeer, + "/quilibrium.node.global.pb.DispatchService/PutHub": channel.OnlySelfPeer, + "/quilibrium.node.global.pb.DispatchService/GetHub": channel.OnlySelfPeer, + "/quilibrium.node.global.pb.DispatchService/Sync": channel.AnyProverPeer, + "/quilibrium.node.ferretproxy.pb.FerretProxy/AliceProxy": channel.OnlySelfPeer, + "/quilibrium.node.ferretproxy.pb.FerretProxy/BobProxy": channel.AnyPeer, + }, + ) + + tlsCreds, err := auth.CreateServerTLSCredentials() + require.NoError(t, err) + server := qgrpc.NewServer( + grpc.Creds(tlsCreds), + grpc.MaxRecvMsgSize(10*1024*1024), + grpc.MaxSendMsgSize(10*1024*1024), + ) + + mg, err := multiaddr.NewMultiaddr("/ip4/0.0.0.0/tcp/60001") + require.NoError(t, err) + + lis, err := mn.Listen(mg) + require.NoError(t, err) + go func() { + protobufs.RegisterDataIPCServiceServer(server, &mockIPC{}) + if err := server.Serve(mn.NetListener(lis)); err != nil { + zap.L().Info("terminating server", zap.Error(err)) + } + }() + defer server.Stop() // Start the manager ctx := context.Background() - err := manager.Start(ctx) + err = manager.Start(ctx) require.NoError(t, err) defer manager.Stop() @@ -581,3 +769,12 @@ func TestWorkerManager_FilterUpdate(t *testing.T) { require.NoError(t, err) assert.Equal(t, newFilter, filter) } + +type mockIPC struct { + protobufs.DataIPCServiceServer +} + +// Respawn implements protobufs.DataIPCServiceServer. +func (m *mockIPC) Respawn(context.Context, *protobufs.RespawnRequest) (*protobufs.RespawnResponse, error) { + return &protobufs.RespawnResponse{}, nil +} diff --git a/protobufs/canonical_types.go b/protobufs/canonical_types.go index 552c5df9..9c238e80 100644 --- a/protobufs/canonical_types.go +++ b/protobufs/canonical_types.go @@ -27,6 +27,7 @@ const ( SignedDevicePreKeyType uint32 = 0x0121 KeyCollectionType uint32 = 0x0122 KeyRegistryType uint32 = 0x0123 + SignedDecaf448KeyType uint32 = 0x0124 // Channel types (0x0200 - 0x02FF) P2PChannelEnvelopeType uint32 = 0x0200 diff --git a/protobufs/global.go b/protobufs/global.go index 5267067c..0b87a461 100644 --- a/protobufs/global.go +++ b/protobufs/global.go @@ -3,6 +3,7 @@ package protobufs import ( "bytes" "encoding/binary" + "slices" "time" "github.com/multiformats/go-multiaddr" @@ -318,6 +319,18 @@ func (p *ProverJoin) ToCanonicalBytes() ([]byte, error) { } } + // Write proof + if err := binary.Write( + buf, + binary.BigEndian, + uint32(len(p.Proof)), + ); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + if _, err := buf.Write(p.Proof); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + return buf.Bytes(), nil } @@ -411,6 +424,16 @@ func (p *ProverJoin) FromCanonicalBytes(data []byte) error { } } + // Read proof + var proofLen uint32 + if err := binary.Read(buf, binary.BigEndian, &proofLen); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + p.Proof = make([]byte, proofLen) + if _, err := buf.Read(p.Proof); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + return nil } @@ -2067,6 +2090,18 @@ func (f *FrameVote) ToCanonicalBytes() ([]byte, error) { return nil, errors.Wrap(err, "to canonical bytes") } + // Write filter + if err := binary.Write( + buf, + binary.BigEndian, + uint32(len(f.Filter)), + ); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + if _, err := buf.Write(f.Filter); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + // Write frame_number if err := binary.Write(buf, binary.BigEndian, f.FrameNumber); err != nil { return nil, errors.Wrap(err, "to canonical bytes") @@ -2093,6 +2128,10 @@ func (f *FrameVote) ToCanonicalBytes() ([]byte, error) { return nil, errors.Wrap(err, "to canonical bytes") } + if err := binary.Write(buf, binary.BigEndian, f.Timestamp); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + // Write public_key_signature_bls48581 if f.PublicKeySignatureBls48581 != nil { sigBytes, err := f.PublicKeySignatureBls48581.ToCanonicalBytes() @@ -2133,6 +2172,16 @@ func (f *FrameVote) FromCanonicalBytes(data []byte) error { ) } + // Read filter + var filterLen uint32 + if err := binary.Read(buf, binary.BigEndian, &filterLen); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + f.Filter = make([]byte, filterLen) + if _, err := buf.Read(f.Filter); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + // Read frame_number if err := binary.Read(buf, binary.BigEndian, &f.FrameNumber); err != nil { return errors.Wrap(err, "from canonical bytes") @@ -2155,6 +2204,11 @@ func (f *FrameVote) FromCanonicalBytes(data []byte) error { } f.Approve = approve != 0 + // Read timestamp + if err := binary.Read(buf, binary.BigEndian, &f.Timestamp); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + // Read public_key_signature_bls48581 var sigLen uint32 if err := binary.Read(buf, binary.BigEndian, &sigLen); err != nil { @@ -2188,6 +2242,18 @@ func (f *FrameConfirmation) ToCanonicalBytes() ([]byte, error) { return nil, errors.Wrap(err, "to canonical bytes") } + // Write filter + if err := binary.Write( + buf, + binary.BigEndian, + uint32(len(f.Filter)), + ); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + if _, err := buf.Write(f.Filter); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + // Write frame_number if err := binary.Write(buf, binary.BigEndian, f.FrameNumber); err != nil { return nil, errors.Wrap(err, "to canonical bytes") @@ -2205,6 +2271,10 @@ func (f *FrameConfirmation) ToCanonicalBytes() ([]byte, error) { return nil, errors.Wrap(err, "to canonical bytes") } + if err := binary.Write(buf, binary.BigEndian, f.Timestamp); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + // Write aggregate_signature if f.AggregateSignature != nil { sigBytes, err := f.AggregateSignature.ToCanonicalBytes() @@ -2245,6 +2315,16 @@ func (f *FrameConfirmation) FromCanonicalBytes(data []byte) error { ) } + // Read filter + var filterLen uint32 + if err := binary.Read(buf, binary.BigEndian, &filterLen); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + f.Filter = make([]byte, filterLen) + if _, err := buf.Read(f.Filter); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + // Read frame_number if err := binary.Read(buf, binary.BigEndian, &f.FrameNumber); err != nil { return errors.Wrap(err, "from canonical bytes") @@ -2260,6 +2340,11 @@ func (f *FrameConfirmation) FromCanonicalBytes(data []byte) error { return errors.Wrap(err, "from canonical bytes") } + // Read timestamp + if err := binary.Read(buf, binary.BigEndian, &f.Timestamp); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + // Read aggregate_signature var sigLen uint32 if err := binary.Read(buf, binary.BigEndian, &sigLen); err != nil { @@ -3754,8 +3839,9 @@ func (p *ProverLivenessCheck) Validate() error { return errors.Wrap(errors.New("invalid filter length"), "validate") } - // Commitment hash should be 32 bytes - if len(p.CommitmentHash) != 32 { + // Commitment hash should be 32 bytes if global, at least 32 if not + if (len(p.Filter) == 0 && len(p.CommitmentHash) != 32) || + (len(p.Filter) != 0 && len(p.CommitmentHash) >= 32) { return errors.Wrap(errors.New("invalid commitment hash length"), "validate") } @@ -3764,7 +3850,7 @@ func (p *ProverLivenessCheck) Validate() error { return errors.Wrap(errors.New("missing signature"), "validate") } - // Validate the signature + // Validate the signature payload (not the signature itself) if err := p.PublicKeySignatureBls48581.Validate(); err != nil { return errors.Wrap(err, "validate") } @@ -3772,6 +3858,17 @@ func (p *ProverLivenessCheck) Validate() error { return nil } +func (p *ProverLivenessCheck) ConstructSignaturePayload() ([]byte, error) { + clone := proto.Clone(p).(*ProverLivenessCheck) + clone.PublicKeySignatureBls48581 = nil + cloneBytes, err := clone.ToCanonicalBytes() + return cloneBytes, errors.Wrap(err, "construct signature payload") +} + +func (p *ProverLivenessCheck) GetSignatureDomain() []byte { + return slices.Concat([]byte("PROVER_LIVENESS"), p.Filter) +} + var _ ValidatableMessage = (*FrameVote)(nil) func (f *FrameVote) Validate() error { diff --git a/protobufs/global.pb.go b/protobufs/global.pb.go index 5606db27..a04fb852 100644 --- a/protobufs/global.pb.go +++ b/protobufs/global.pb.go @@ -141,6 +141,7 @@ type ProverJoin struct { PublicKeySignatureBls48581 *BLS48581SignatureWithProofOfPossession `protobuf:"bytes,3,opt,name=public_key_signature_bls48581,json=publicKeySignatureBls48581,proto3" json:"public_key_signature_bls48581,omitempty"` DelegateAddress []byte `protobuf:"bytes,4,opt,name=delegate_address,json=delegateAddress,proto3" json:"delegate_address,omitempty"` MergeTargets []*SeniorityMerge `protobuf:"bytes,5,rep,name=merge_targets,json=mergeTargets,proto3" json:"merge_targets,omitempty"` + Proof []byte `protobuf:"bytes,6,opt,name=proof,proto3" json:"proof,omitempty"` } func (x *ProverJoin) Reset() { @@ -210,6 +211,13 @@ func (x *ProverJoin) GetMergeTargets() []*SeniorityMerge { return nil } +func (x *ProverJoin) GetProof() []byte { + if x != nil { + return x.Proof + } + return nil +} + type ProverLeave struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1501,14 +1509,18 @@ type FrameVote struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // The filter for the prover's commitment in the trie + Filter []byte `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"` // The frame number being voted on - FrameNumber uint64 `protobuf:"varint,1,opt,name=frame_number,json=frameNumber,proto3" json:"frame_number,omitempty"` + FrameNumber uint64 `protobuf:"varint,2,opt,name=frame_number,json=frameNumber,proto3" json:"frame_number,omitempty"` // The proposer of the frame - Proposer []byte `protobuf:"bytes,2,opt,name=proposer,proto3" json:"proposer,omitempty"` + Proposer []byte `protobuf:"bytes,3,opt,name=proposer,proto3" json:"proposer,omitempty"` // Whether the voter approves the frame - Approve bool `protobuf:"varint,3,opt,name=approve,proto3" json:"approve,omitempty"` + Approve bool `protobuf:"varint,4,opt,name=approve,proto3" json:"approve,omitempty"` + // The timestamp when the vote was created + Timestamp int64 `protobuf:"varint,5,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // The BLS signature with the voter's address - PublicKeySignatureBls48581 *BLS48581AddressedSignature `protobuf:"bytes,4,opt,name=public_key_signature_bls48581,json=publicKeySignatureBls48581,proto3" json:"public_key_signature_bls48581,omitempty"` + PublicKeySignatureBls48581 *BLS48581AddressedSignature `protobuf:"bytes,6,opt,name=public_key_signature_bls48581,json=publicKeySignatureBls48581,proto3" json:"public_key_signature_bls48581,omitempty"` } func (x *FrameVote) Reset() { @@ -1543,6 +1555,13 @@ func (*FrameVote) Descriptor() ([]byte, []int) { return file_global_proto_rawDescGZIP(), []int{15} } +func (x *FrameVote) GetFilter() []byte { + if x != nil { + return x.Filter + } + return nil +} + func (x *FrameVote) GetFrameNumber() uint64 { if x != nil { return x.FrameNumber @@ -1564,6 +1583,13 @@ func (x *FrameVote) GetApprove() bool { return false } +func (x *FrameVote) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + func (x *FrameVote) GetPublicKeySignatureBls48581() *BLS48581AddressedSignature { if x != nil { return x.PublicKeySignatureBls48581 @@ -1576,12 +1602,16 @@ type FrameConfirmation struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // The filter for the prover's commitment in the trie + Filter []byte `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"` // The frame number that was confirmed - FrameNumber uint64 `protobuf:"varint,1,opt,name=frame_number,json=frameNumber,proto3" json:"frame_number,omitempty"` + FrameNumber uint64 `protobuf:"varint,2,opt,name=frame_number,json=frameNumber,proto3" json:"frame_number,omitempty"` // The selector (hash) of the confirmed frame - Selector []byte `protobuf:"bytes,2,opt,name=selector,proto3" json:"selector,omitempty"` + Selector []byte `protobuf:"bytes,3,opt,name=selector,proto3" json:"selector,omitempty"` + // The timestamp when the vote was created + Timestamp int64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // The aggregated BLS signature from all voters - AggregateSignature *BLS48581AggregateSignature `protobuf:"bytes,3,opt,name=aggregate_signature,json=aggregateSignature,proto3" json:"aggregate_signature,omitempty"` + AggregateSignature *BLS48581AggregateSignature `protobuf:"bytes,5,opt,name=aggregate_signature,json=aggregateSignature,proto3" json:"aggregate_signature,omitempty"` } func (x *FrameConfirmation) Reset() { @@ -1616,6 +1646,13 @@ func (*FrameConfirmation) Descriptor() ([]byte, []int) { return file_global_proto_rawDescGZIP(), []int{16} } +func (x *FrameConfirmation) GetFilter() []byte { + if x != nil { + return x.Filter + } + return nil +} + func (x *FrameConfirmation) GetFrameNumber() uint64 { if x != nil { return x.FrameNumber @@ -1630,6 +1667,13 @@ func (x *FrameConfirmation) GetSelector() []byte { return nil } +func (x *FrameConfirmation) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + func (x *FrameConfirmation) GetAggregateSignature() *BLS48581AggregateSignature { if x != nil { return x.AggregateSignature @@ -2297,6 +2341,186 @@ func (x *GetGlobalShardsResponse) GetCommitment() [][]byte { return nil } +type GetLockedAddressesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The shard address identifier, in split L2||nibbles form + ShardAddress []byte `protobuf:"bytes,1,opt,name=shard_address,json=shardAddress,proto3" json:"shard_address,omitempty"` + // The frame number of the locked address request, to disambiguate early/late + // requests + FrameNumber uint64 `protobuf:"varint,2,opt,name=frame_number,json=frameNumber,proto3" json:"frame_number,omitempty"` +} + +func (x *GetLockedAddressesRequest) Reset() { + *x = GetLockedAddressesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_global_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetLockedAddressesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetLockedAddressesRequest) ProtoMessage() {} + +func (x *GetLockedAddressesRequest) ProtoReflect() protoreflect.Message { + mi := &file_global_proto_msgTypes[29] + 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 GetLockedAddressesRequest.ProtoReflect.Descriptor instead. +func (*GetLockedAddressesRequest) Descriptor() ([]byte, []int) { + return file_global_proto_rawDescGZIP(), []int{29} +} + +func (x *GetLockedAddressesRequest) GetShardAddress() []byte { + if x != nil { + return x.ShardAddress + } + return nil +} + +func (x *GetLockedAddressesRequest) GetFrameNumber() uint64 { + if x != nil { + return x.FrameNumber + } + return 0 +} + +type LockedTransaction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The hash of the locked transaction + TransactionHash []byte `protobuf:"bytes,1,opt,name=transaction_hash,json=transactionHash,proto3" json:"transaction_hash,omitempty"` + // The shard address identifier the lock covers, in split L2||nibbles form + ShardAddresses [][]byte `protobuf:"bytes,2,rep,name=shard_addresses,json=shardAddresses,proto3" json:"shard_addresses,omitempty"` + // Whether all shard addresses impacted have committed to this value + Committed bool `protobuf:"varint,3,opt,name=committed,proto3" json:"committed,omitempty"` + // Whether the proposed frames had a winning weight witness + Filled bool `protobuf:"varint,4,opt,name=filled,proto3" json:"filled,omitempty"` +} + +func (x *LockedTransaction) Reset() { + *x = LockedTransaction{} + if protoimpl.UnsafeEnabled { + mi := &file_global_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LockedTransaction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LockedTransaction) ProtoMessage() {} + +func (x *LockedTransaction) ProtoReflect() protoreflect.Message { + mi := &file_global_proto_msgTypes[30] + 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 LockedTransaction.ProtoReflect.Descriptor instead. +func (*LockedTransaction) Descriptor() ([]byte, []int) { + return file_global_proto_rawDescGZIP(), []int{30} +} + +func (x *LockedTransaction) GetTransactionHash() []byte { + if x != nil { + return x.TransactionHash + } + return nil +} + +func (x *LockedTransaction) GetShardAddresses() [][]byte { + if x != nil { + return x.ShardAddresses + } + return nil +} + +func (x *LockedTransaction) GetCommitted() bool { + if x != nil { + return x.Committed + } + return false +} + +func (x *LockedTransaction) GetFilled() bool { + if x != nil { + return x.Filled + } + return false +} + +type GetLockedAddressesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Transactions []*LockedTransaction `protobuf:"bytes,1,rep,name=transactions,proto3" json:"transactions,omitempty"` +} + +func (x *GetLockedAddressesResponse) Reset() { + *x = GetLockedAddressesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_global_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetLockedAddressesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetLockedAddressesResponse) ProtoMessage() {} + +func (x *GetLockedAddressesResponse) ProtoReflect() protoreflect.Message { + mi := &file_global_proto_msgTypes[31] + 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 GetLockedAddressesResponse.ProtoReflect.Descriptor instead. +func (*GetLockedAddressesResponse) Descriptor() ([]byte, []int) { + return file_global_proto_rawDescGZIP(), []int{31} +} + +func (x *GetLockedAddressesResponse) GetTransactions() []*LockedTransaction { + if x != nil { + return x.Transactions + } + return nil +} + type SendMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2310,7 +2534,7 @@ type SendMessage struct { func (x *SendMessage) Reset() { *x = SendMessage{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[29] + mi := &file_global_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2323,7 +2547,7 @@ func (x *SendMessage) String() string { func (*SendMessage) ProtoMessage() {} func (x *SendMessage) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[29] + mi := &file_global_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2336,7 +2560,7 @@ func (x *SendMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SendMessage.ProtoReflect.Descriptor instead. func (*SendMessage) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{29} + return file_global_proto_rawDescGZIP(), []int{32} } func (x *SendMessage) GetPeerId() []byte { @@ -2373,7 +2597,7 @@ type ReceiveMessage struct { func (x *ReceiveMessage) Reset() { *x = ReceiveMessage{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[30] + mi := &file_global_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2386,7 +2610,7 @@ func (x *ReceiveMessage) String() string { func (*ReceiveMessage) ProtoMessage() {} func (x *ReceiveMessage) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[30] + mi := &file_global_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2399,7 +2623,7 @@ func (x *ReceiveMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use ReceiveMessage.ProtoReflect.Descriptor instead. func (*ReceiveMessage) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{30} + return file_global_proto_rawDescGZIP(), []int{33} } func (x *ReceiveMessage) GetSourcePeerId() []byte { @@ -2434,7 +2658,7 @@ type GetKeyRegistryRequest struct { func (x *GetKeyRegistryRequest) Reset() { *x = GetKeyRegistryRequest{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[31] + mi := &file_global_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2447,7 +2671,7 @@ func (x *GetKeyRegistryRequest) String() string { func (*GetKeyRegistryRequest) ProtoMessage() {} func (x *GetKeyRegistryRequest) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[31] + mi := &file_global_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2460,7 +2684,7 @@ func (x *GetKeyRegistryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetKeyRegistryRequest.ProtoReflect.Descriptor instead. func (*GetKeyRegistryRequest) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{31} + return file_global_proto_rawDescGZIP(), []int{34} } func (x *GetKeyRegistryRequest) GetIdentityKeyAddress() []byte { @@ -2482,7 +2706,7 @@ type GetKeyRegistryResponse struct { func (x *GetKeyRegistryResponse) Reset() { *x = GetKeyRegistryResponse{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[32] + mi := &file_global_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2495,7 +2719,7 @@ func (x *GetKeyRegistryResponse) String() string { func (*GetKeyRegistryResponse) ProtoMessage() {} func (x *GetKeyRegistryResponse) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[32] + mi := &file_global_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2508,7 +2732,7 @@ func (x *GetKeyRegistryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetKeyRegistryResponse.ProtoReflect.Descriptor instead. func (*GetKeyRegistryResponse) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{32} + return file_global_proto_rawDescGZIP(), []int{35} } func (x *GetKeyRegistryResponse) GetRegistry() *KeyRegistry { @@ -2536,7 +2760,7 @@ type GetKeyRegistryByProverRequest struct { func (x *GetKeyRegistryByProverRequest) Reset() { *x = GetKeyRegistryByProverRequest{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[33] + mi := &file_global_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2549,7 +2773,7 @@ func (x *GetKeyRegistryByProverRequest) String() string { func (*GetKeyRegistryByProverRequest) ProtoMessage() {} func (x *GetKeyRegistryByProverRequest) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[33] + mi := &file_global_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2562,7 +2786,7 @@ func (x *GetKeyRegistryByProverRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetKeyRegistryByProverRequest.ProtoReflect.Descriptor instead. func (*GetKeyRegistryByProverRequest) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{33} + return file_global_proto_rawDescGZIP(), []int{36} } func (x *GetKeyRegistryByProverRequest) GetProverKeyAddress() []byte { @@ -2584,7 +2808,7 @@ type GetKeyRegistryByProverResponse struct { func (x *GetKeyRegistryByProverResponse) Reset() { *x = GetKeyRegistryByProverResponse{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[34] + mi := &file_global_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2597,7 +2821,7 @@ func (x *GetKeyRegistryByProverResponse) String() string { func (*GetKeyRegistryByProverResponse) ProtoMessage() {} func (x *GetKeyRegistryByProverResponse) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[34] + mi := &file_global_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2610,7 +2834,7 @@ func (x *GetKeyRegistryByProverResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetKeyRegistryByProverResponse.ProtoReflect.Descriptor instead. func (*GetKeyRegistryByProverResponse) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{34} + return file_global_proto_rawDescGZIP(), []int{37} } func (x *GetKeyRegistryByProverResponse) GetRegistry() *KeyRegistry { @@ -2639,7 +2863,7 @@ type PutIdentityKeyRequest struct { func (x *PutIdentityKeyRequest) Reset() { *x = PutIdentityKeyRequest{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[35] + mi := &file_global_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2652,7 +2876,7 @@ func (x *PutIdentityKeyRequest) String() string { func (*PutIdentityKeyRequest) ProtoMessage() {} func (x *PutIdentityKeyRequest) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[35] + mi := &file_global_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2665,7 +2889,7 @@ func (x *PutIdentityKeyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PutIdentityKeyRequest.ProtoReflect.Descriptor instead. func (*PutIdentityKeyRequest) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{35} + return file_global_proto_rawDescGZIP(), []int{38} } func (x *PutIdentityKeyRequest) GetAddress() []byte { @@ -2693,7 +2917,7 @@ type PutIdentityKeyResponse struct { func (x *PutIdentityKeyResponse) Reset() { *x = PutIdentityKeyResponse{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[36] + mi := &file_global_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2706,7 +2930,7 @@ func (x *PutIdentityKeyResponse) String() string { func (*PutIdentityKeyResponse) ProtoMessage() {} func (x *PutIdentityKeyResponse) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[36] + mi := &file_global_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2719,7 +2943,7 @@ func (x *PutIdentityKeyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PutIdentityKeyResponse.ProtoReflect.Descriptor instead. func (*PutIdentityKeyResponse) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{36} + return file_global_proto_rawDescGZIP(), []int{39} } func (x *PutIdentityKeyResponse) GetError() string { @@ -2740,7 +2964,7 @@ type PutProvingKeyRequest struct { func (x *PutProvingKeyRequest) Reset() { *x = PutProvingKeyRequest{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[37] + mi := &file_global_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2753,7 +2977,7 @@ func (x *PutProvingKeyRequest) String() string { func (*PutProvingKeyRequest) ProtoMessage() {} func (x *PutProvingKeyRequest) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[37] + mi := &file_global_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2766,7 +2990,7 @@ func (x *PutProvingKeyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PutProvingKeyRequest.ProtoReflect.Descriptor instead. func (*PutProvingKeyRequest) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{37} + return file_global_proto_rawDescGZIP(), []int{40} } func (x *PutProvingKeyRequest) GetProvingKey() *BLS48581SignatureWithProofOfPossession { @@ -2787,7 +3011,7 @@ type PutProvingKeyResponse struct { func (x *PutProvingKeyResponse) Reset() { *x = PutProvingKeyResponse{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[38] + mi := &file_global_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2800,7 +3024,7 @@ func (x *PutProvingKeyResponse) String() string { func (*PutProvingKeyResponse) ProtoMessage() {} func (x *PutProvingKeyResponse) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[38] + mi := &file_global_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2813,7 +3037,7 @@ func (x *PutProvingKeyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PutProvingKeyResponse.ProtoReflect.Descriptor instead. func (*PutProvingKeyResponse) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{38} + return file_global_proto_rawDescGZIP(), []int{41} } func (x *PutProvingKeyResponse) GetError() string { @@ -2837,7 +3061,7 @@ type PutCrossSignatureRequest struct { func (x *PutCrossSignatureRequest) Reset() { *x = PutCrossSignatureRequest{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[39] + mi := &file_global_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2850,7 +3074,7 @@ func (x *PutCrossSignatureRequest) String() string { func (*PutCrossSignatureRequest) ProtoMessage() {} func (x *PutCrossSignatureRequest) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[39] + mi := &file_global_proto_msgTypes[42] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2863,7 +3087,7 @@ func (x *PutCrossSignatureRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PutCrossSignatureRequest.ProtoReflect.Descriptor instead. func (*PutCrossSignatureRequest) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{39} + return file_global_proto_rawDescGZIP(), []int{42} } func (x *PutCrossSignatureRequest) GetIdentityKeyAddress() []byte { @@ -2905,7 +3129,7 @@ type PutCrossSignatureResponse struct { func (x *PutCrossSignatureResponse) Reset() { *x = PutCrossSignatureResponse{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[40] + mi := &file_global_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2918,7 +3142,7 @@ func (x *PutCrossSignatureResponse) String() string { func (*PutCrossSignatureResponse) ProtoMessage() {} func (x *PutCrossSignatureResponse) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[40] + mi := &file_global_proto_msgTypes[43] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2931,7 +3155,7 @@ func (x *PutCrossSignatureResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PutCrossSignatureResponse.ProtoReflect.Descriptor instead. func (*PutCrossSignatureResponse) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{40} + return file_global_proto_rawDescGZIP(), []int{43} } func (x *PutCrossSignatureResponse) GetError() string { @@ -2953,7 +3177,7 @@ type PutSignedKeyRequest struct { func (x *PutSignedKeyRequest) Reset() { *x = PutSignedKeyRequest{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[41] + mi := &file_global_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2966,7 +3190,7 @@ func (x *PutSignedKeyRequest) String() string { func (*PutSignedKeyRequest) ProtoMessage() {} func (x *PutSignedKeyRequest) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[41] + mi := &file_global_proto_msgTypes[44] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2979,7 +3203,7 @@ func (x *PutSignedKeyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PutSignedKeyRequest.ProtoReflect.Descriptor instead. func (*PutSignedKeyRequest) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{41} + return file_global_proto_rawDescGZIP(), []int{44} } func (x *PutSignedKeyRequest) GetAddress() []byte { @@ -3007,7 +3231,7 @@ type PutSignedKeyResponse struct { func (x *PutSignedKeyResponse) Reset() { *x = PutSignedKeyResponse{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[42] + mi := &file_global_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3020,7 +3244,7 @@ func (x *PutSignedKeyResponse) String() string { func (*PutSignedKeyResponse) ProtoMessage() {} func (x *PutSignedKeyResponse) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[42] + mi := &file_global_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3033,7 +3257,7 @@ func (x *PutSignedKeyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PutSignedKeyResponse.ProtoReflect.Descriptor instead. func (*PutSignedKeyResponse) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{42} + return file_global_proto_rawDescGZIP(), []int{45} } func (x *PutSignedKeyResponse) GetError() string { @@ -3054,7 +3278,7 @@ type GetIdentityKeyRequest struct { func (x *GetIdentityKeyRequest) Reset() { *x = GetIdentityKeyRequest{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[43] + mi := &file_global_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3067,7 +3291,7 @@ func (x *GetIdentityKeyRequest) String() string { func (*GetIdentityKeyRequest) ProtoMessage() {} func (x *GetIdentityKeyRequest) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[43] + mi := &file_global_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3080,7 +3304,7 @@ func (x *GetIdentityKeyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetIdentityKeyRequest.ProtoReflect.Descriptor instead. func (*GetIdentityKeyRequest) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{43} + return file_global_proto_rawDescGZIP(), []int{46} } func (x *GetIdentityKeyRequest) GetAddress() []byte { @@ -3102,7 +3326,7 @@ type GetIdentityKeyResponse struct { func (x *GetIdentityKeyResponse) Reset() { *x = GetIdentityKeyResponse{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[44] + mi := &file_global_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3115,7 +3339,7 @@ func (x *GetIdentityKeyResponse) String() string { func (*GetIdentityKeyResponse) ProtoMessage() {} func (x *GetIdentityKeyResponse) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[44] + mi := &file_global_proto_msgTypes[47] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3128,7 +3352,7 @@ func (x *GetIdentityKeyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetIdentityKeyResponse.ProtoReflect.Descriptor instead. func (*GetIdentityKeyResponse) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{44} + return file_global_proto_rawDescGZIP(), []int{47} } func (x *GetIdentityKeyResponse) GetKey() *Ed448PublicKey { @@ -3156,7 +3380,7 @@ type GetProvingKeyRequest struct { func (x *GetProvingKeyRequest) Reset() { *x = GetProvingKeyRequest{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[45] + mi := &file_global_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3169,7 +3393,7 @@ func (x *GetProvingKeyRequest) String() string { func (*GetProvingKeyRequest) ProtoMessage() {} func (x *GetProvingKeyRequest) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[45] + mi := &file_global_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3182,7 +3406,7 @@ func (x *GetProvingKeyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProvingKeyRequest.ProtoReflect.Descriptor instead. func (*GetProvingKeyRequest) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{45} + return file_global_proto_rawDescGZIP(), []int{48} } func (x *GetProvingKeyRequest) GetAddress() []byte { @@ -3204,7 +3428,7 @@ type GetProvingKeyResponse struct { func (x *GetProvingKeyResponse) Reset() { *x = GetProvingKeyResponse{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[46] + mi := &file_global_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3217,7 +3441,7 @@ func (x *GetProvingKeyResponse) String() string { func (*GetProvingKeyResponse) ProtoMessage() {} func (x *GetProvingKeyResponse) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[46] + mi := &file_global_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3230,7 +3454,7 @@ func (x *GetProvingKeyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProvingKeyResponse.ProtoReflect.Descriptor instead. func (*GetProvingKeyResponse) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{46} + return file_global_proto_rawDescGZIP(), []int{49} } func (x *GetProvingKeyResponse) GetKey() *BLS48581SignatureWithProofOfPossession { @@ -3258,7 +3482,7 @@ type GetSignedKeyRequest struct { func (x *GetSignedKeyRequest) Reset() { *x = GetSignedKeyRequest{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[47] + mi := &file_global_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3271,7 +3495,7 @@ func (x *GetSignedKeyRequest) String() string { func (*GetSignedKeyRequest) ProtoMessage() {} func (x *GetSignedKeyRequest) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[47] + mi := &file_global_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3284,7 +3508,7 @@ func (x *GetSignedKeyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSignedKeyRequest.ProtoReflect.Descriptor instead. func (*GetSignedKeyRequest) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{47} + return file_global_proto_rawDescGZIP(), []int{50} } func (x *GetSignedKeyRequest) GetAddress() []byte { @@ -3306,7 +3530,7 @@ type GetSignedKeyResponse struct { func (x *GetSignedKeyResponse) Reset() { *x = GetSignedKeyResponse{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[48] + mi := &file_global_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3319,7 +3543,7 @@ func (x *GetSignedKeyResponse) String() string { func (*GetSignedKeyResponse) ProtoMessage() {} func (x *GetSignedKeyResponse) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[48] + mi := &file_global_proto_msgTypes[51] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3332,7 +3556,7 @@ func (x *GetSignedKeyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSignedKeyResponse.ProtoReflect.Descriptor instead. func (*GetSignedKeyResponse) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{48} + return file_global_proto_rawDescGZIP(), []int{51} } func (x *GetSignedKeyResponse) GetKey() *SignedX448Key { @@ -3361,7 +3585,7 @@ type GetSignedKeysByParentRequest struct { func (x *GetSignedKeysByParentRequest) Reset() { *x = GetSignedKeysByParentRequest{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[49] + mi := &file_global_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3374,7 +3598,7 @@ func (x *GetSignedKeysByParentRequest) String() string { func (*GetSignedKeysByParentRequest) ProtoMessage() {} func (x *GetSignedKeysByParentRequest) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[49] + mi := &file_global_proto_msgTypes[52] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3387,7 +3611,7 @@ func (x *GetSignedKeysByParentRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSignedKeysByParentRequest.ProtoReflect.Descriptor instead. func (*GetSignedKeysByParentRequest) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{49} + return file_global_proto_rawDescGZIP(), []int{52} } func (x *GetSignedKeysByParentRequest) GetParentKeyAddress() []byte { @@ -3416,7 +3640,7 @@ type GetSignedKeysByParentResponse struct { func (x *GetSignedKeysByParentResponse) Reset() { *x = GetSignedKeysByParentResponse{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[50] + mi := &file_global_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3429,7 +3653,7 @@ func (x *GetSignedKeysByParentResponse) String() string { func (*GetSignedKeysByParentResponse) ProtoMessage() {} func (x *GetSignedKeysByParentResponse) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[50] + mi := &file_global_proto_msgTypes[53] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3442,7 +3666,7 @@ func (x *GetSignedKeysByParentResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSignedKeysByParentResponse.ProtoReflect.Descriptor instead. func (*GetSignedKeysByParentResponse) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{50} + return file_global_proto_rawDescGZIP(), []int{53} } func (x *GetSignedKeysByParentResponse) GetKeys() []*SignedX448Key { @@ -3468,7 +3692,7 @@ type RangeProvingKeysRequest struct { func (x *RangeProvingKeysRequest) Reset() { *x = RangeProvingKeysRequest{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[51] + mi := &file_global_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3481,7 +3705,7 @@ func (x *RangeProvingKeysRequest) String() string { func (*RangeProvingKeysRequest) ProtoMessage() {} func (x *RangeProvingKeysRequest) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[51] + mi := &file_global_proto_msgTypes[54] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3494,7 +3718,7 @@ func (x *RangeProvingKeysRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RangeProvingKeysRequest.ProtoReflect.Descriptor instead. func (*RangeProvingKeysRequest) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{51} + return file_global_proto_rawDescGZIP(), []int{54} } type RangeProvingKeysResponse struct { @@ -3509,7 +3733,7 @@ type RangeProvingKeysResponse struct { func (x *RangeProvingKeysResponse) Reset() { *x = RangeProvingKeysResponse{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[52] + mi := &file_global_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3522,7 +3746,7 @@ func (x *RangeProvingKeysResponse) String() string { func (*RangeProvingKeysResponse) ProtoMessage() {} func (x *RangeProvingKeysResponse) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[52] + mi := &file_global_proto_msgTypes[55] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3535,7 +3759,7 @@ func (x *RangeProvingKeysResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RangeProvingKeysResponse.ProtoReflect.Descriptor instead. func (*RangeProvingKeysResponse) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{52} + return file_global_proto_rawDescGZIP(), []int{55} } func (x *RangeProvingKeysResponse) GetKey() *BLS48581SignatureWithProofOfPossession { @@ -3561,7 +3785,7 @@ type RangeIdentityKeysRequest struct { func (x *RangeIdentityKeysRequest) Reset() { *x = RangeIdentityKeysRequest{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[53] + mi := &file_global_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3574,7 +3798,7 @@ func (x *RangeIdentityKeysRequest) String() string { func (*RangeIdentityKeysRequest) ProtoMessage() {} func (x *RangeIdentityKeysRequest) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[53] + mi := &file_global_proto_msgTypes[56] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3587,7 +3811,7 @@ func (x *RangeIdentityKeysRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RangeIdentityKeysRequest.ProtoReflect.Descriptor instead. func (*RangeIdentityKeysRequest) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{53} + return file_global_proto_rawDescGZIP(), []int{56} } type RangeIdentityKeysResponse struct { @@ -3602,7 +3826,7 @@ type RangeIdentityKeysResponse struct { func (x *RangeIdentityKeysResponse) Reset() { *x = RangeIdentityKeysResponse{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[54] + mi := &file_global_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3615,7 +3839,7 @@ func (x *RangeIdentityKeysResponse) String() string { func (*RangeIdentityKeysResponse) ProtoMessage() {} func (x *RangeIdentityKeysResponse) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[54] + mi := &file_global_proto_msgTypes[57] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3628,7 +3852,7 @@ func (x *RangeIdentityKeysResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RangeIdentityKeysResponse.ProtoReflect.Descriptor instead. func (*RangeIdentityKeysResponse) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{54} + return file_global_proto_rawDescGZIP(), []int{57} } func (x *RangeIdentityKeysResponse) GetKey() *Ed448PublicKey { @@ -3657,7 +3881,7 @@ type RangeSignedKeysRequest struct { func (x *RangeSignedKeysRequest) Reset() { *x = RangeSignedKeysRequest{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[55] + mi := &file_global_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3670,7 +3894,7 @@ func (x *RangeSignedKeysRequest) String() string { func (*RangeSignedKeysRequest) ProtoMessage() {} func (x *RangeSignedKeysRequest) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[55] + mi := &file_global_proto_msgTypes[58] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3683,7 +3907,7 @@ func (x *RangeSignedKeysRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RangeSignedKeysRequest.ProtoReflect.Descriptor instead. func (*RangeSignedKeysRequest) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{55} + return file_global_proto_rawDescGZIP(), []int{58} } func (x *RangeSignedKeysRequest) GetParentKeyAddress() []byte { @@ -3712,7 +3936,7 @@ type RangeSignedKeysResponse struct { func (x *RangeSignedKeysResponse) Reset() { *x = RangeSignedKeysResponse{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[56] + mi := &file_global_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3725,7 +3949,7 @@ func (x *RangeSignedKeysResponse) String() string { func (*RangeSignedKeysResponse) ProtoMessage() {} func (x *RangeSignedKeysResponse) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[56] + mi := &file_global_proto_msgTypes[59] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3738,7 +3962,7 @@ func (x *RangeSignedKeysResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RangeSignedKeysResponse.ProtoReflect.Descriptor instead. func (*RangeSignedKeysResponse) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{56} + return file_global_proto_rawDescGZIP(), []int{59} } func (x *RangeSignedKeysResponse) GetKey() *SignedX448Key { @@ -3767,7 +3991,7 @@ type MessageKeyShard struct { func (x *MessageKeyShard) Reset() { *x = MessageKeyShard{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[57] + mi := &file_global_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3780,7 +4004,7 @@ func (x *MessageKeyShard) String() string { func (*MessageKeyShard) ProtoMessage() {} func (x *MessageKeyShard) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[57] + mi := &file_global_proto_msgTypes[60] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3793,7 +4017,7 @@ func (x *MessageKeyShard) ProtoReflect() protoreflect.Message { // Deprecated: Use MessageKeyShard.ProtoReflect.Descriptor instead. func (*MessageKeyShard) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{57} + return file_global_proto_rawDescGZIP(), []int{60} } func (x *MessageKeyShard) GetPartyIdentifier() uint32 { @@ -3828,7 +4052,7 @@ type PutMessageRequest struct { func (x *PutMessageRequest) Reset() { *x = PutMessageRequest{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[58] + mi := &file_global_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3841,7 +4065,7 @@ func (x *PutMessageRequest) String() string { func (*PutMessageRequest) ProtoMessage() {} func (x *PutMessageRequest) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[58] + mi := &file_global_proto_msgTypes[61] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3854,7 +4078,7 @@ func (x *PutMessageRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PutMessageRequest.ProtoReflect.Descriptor instead. func (*PutMessageRequest) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{58} + return file_global_proto_rawDescGZIP(), []int{61} } func (x *PutMessageRequest) GetMessageShards() []*MessageKeyShard { @@ -3887,7 +4111,7 @@ type PutMessageResponse struct { func (x *PutMessageResponse) Reset() { *x = PutMessageResponse{} if protoimpl.UnsafeEnabled { - mi := &file_global_proto_msgTypes[59] + mi := &file_global_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3900,7 +4124,7 @@ func (x *PutMessageResponse) String() string { func (*PutMessageResponse) ProtoMessage() {} func (x *PutMessageResponse) ProtoReflect() protoreflect.Message { - mi := &file_global_proto_msgTypes[59] + mi := &file_global_proto_msgTypes[62] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3913,7 +4137,7 @@ func (x *PutMessageResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PutMessageResponse.ProtoReflect.Descriptor instead. func (*PutMessageResponse) Descriptor() ([]byte, []int) { - return file_global_proto_rawDescGZIP(), []int{59} + return file_global_proto_rawDescGZIP(), []int{62} } var File_global_proto protoreflect.FileDescriptor @@ -3944,7 +4168,7 @@ var file_global_proto_rawDesc = []byte{ 0x01, 0x28, 0x0d, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x50, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0xc9, 0x02, 0x0a, 0x0a, 0x50, 0x72, 0x6f, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0xdf, 0x02, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, @@ -3965,773 +4189,812 @@ var file_global_proto_rawDesc = []byte{ 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x6e, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x52, 0x0c, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x54, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x73, 0x22, 0xc2, 0x01, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x4c, - 0x65, 0x61, 0x76, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x12, 0x21, - 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x12, 0x76, 0x0a, 0x1d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x62, 0x6c, 0x73, 0x34, 0x38, 0x35, - 0x38, 0x31, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, - 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, - 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x1a, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x42, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x22, 0xc0, 0x01, 0x0a, 0x0b, 0x50, 0x72, - 0x6f, 0x76, 0x65, 0x72, 0x50, 0x61, 0x75, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, - 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, - 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x12, 0x76, 0x0a, 0x1d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, - 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x62, 0x6c, 0x73, - 0x34, 0x38, 0x35, 0x38, 0x31, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x71, 0x75, - 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, - 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x52, 0x1a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x42, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x22, 0xc1, 0x01, 0x0a, - 0x0c, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x12, 0x16, 0x0a, - 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, - 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x76, 0x0a, 0x1d, 0x70, 0x75, 0x62, 0x6c, - 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x5f, 0x62, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, - 0x38, 0x31, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x52, 0x1a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, - 0x22, 0xc2, 0x01, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x72, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, - 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x76, 0x0a, - 0x1d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x62, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, - 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, - 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, - 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x1a, 0x70, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x6c, 0x73, - 0x34, 0x38, 0x35, 0x38, 0x31, 0x22, 0xb1, 0x01, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, - 0x74, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0f, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x12, 0x76, 0x0a, 0x1d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x62, 0x6c, 0x73, 0x34, 0x38, 0x35, - 0x38, 0x31, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, - 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, - 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x1a, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x42, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x22, 0xd7, 0x02, 0x0a, 0x0a, 0x50, 0x72, - 0x6f, 0x76, 0x65, 0x72, 0x4b, 0x69, 0x63, 0x6b, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, - 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, - 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x18, 0x6b, - 0x69, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x15, 0x6b, - 0x69, 0x63, 0x6b, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x4b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, - 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x31, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x46, 0x72, - 0x61, 0x6d, 0x65, 0x31, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, - 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x32, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x46, 0x72, - 0x61, 0x6d, 0x65, 0x32, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, - 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x57, 0x0a, 0x0f, 0x74, 0x72, - 0x61, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, - 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x50, 0x72, - 0x6f, 0x6f, 0x66, 0x52, 0x0e, 0x74, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x50, 0x72, - 0x6f, 0x6f, 0x66, 0x22, 0xc1, 0x01, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, - 0x6a, 0x65, 0x63, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, - 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, - 0x76, 0x0a, 0x1d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x62, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, - 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, - 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x1a, 0x70, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, - 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x22, 0x84, 0x0f, 0x0a, 0x0e, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x04, 0x6a, 0x6f, - 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, - 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, - 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x48, - 0x00, 0x52, 0x04, 0x6a, 0x6f, 0x69, 0x6e, 0x12, 0x3e, 0x0a, 0x05, 0x6c, 0x65, 0x61, 0x76, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, - 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, - 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x48, 0x00, - 0x52, 0x05, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x12, 0x3e, 0x0a, 0x05, 0x70, 0x61, 0x75, 0x73, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, - 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, - 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x50, 0x61, 0x75, 0x73, 0x65, 0x48, 0x00, - 0x52, 0x05, 0x70, 0x61, 0x75, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6d, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, - 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, - 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, - 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x12, 0x44, 0x0a, 0x07, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x71, 0x75, - 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, - 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x48, 0x00, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, - 0x12, 0x41, 0x0a, 0x06, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, - 0x76, 0x65, 0x72, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x6a, - 0x65, 0x63, 0x74, 0x12, 0x3b, 0x0a, 0x04, 0x6b, 0x69, 0x63, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x25, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, - 0x6f, 0x76, 0x65, 0x72, 0x4b, 0x69, 0x63, 0x6b, 0x48, 0x00, 0x52, 0x04, 0x6b, 0x69, 0x63, 0x6b, - 0x12, 0x41, 0x0a, 0x06, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, - 0x76, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x12, 0x4a, 0x0a, 0x0c, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x64, 0x65, 0x70, - 0x6c, 0x6f, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x71, 0x75, 0x69, 0x6c, - 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, - 0x48, 0x00, 0x52, 0x0b, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x12, - 0x4a, 0x0a, 0x0c, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, - 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, - 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x70, 0x62, - 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0b, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x49, 0x0a, 0x0b, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x25, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5f, 0x0a, 0x13, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, - 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x70, 0x62, 0x2e, 0x50, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x48, 0x00, 0x52, 0x12, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x56, 0x0a, 0x10, 0x6d, 0x69, 0x6e, 0x74, 0x5f, - 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0d, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x29, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x69, 0x6e, - 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0f, - 0x6d, 0x69, 0x6e, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x5e, 0x0a, 0x11, 0x68, 0x79, 0x70, 0x65, 0x72, 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x64, 0x65, - 0x70, 0x6c, 0x6f, 0x79, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x71, 0x75, 0x69, - 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x68, 0x79, 0x70, - 0x65, 0x72, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x79, 0x70, 0x65, 0x72, - 0x67, 0x72, 0x61, 0x70, 0x68, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x48, 0x00, 0x52, 0x10, 0x68, - 0x79, 0x70, 0x65, 0x72, 0x67, 0x72, 0x61, 0x70, 0x68, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x12, - 0x5e, 0x0a, 0x11, 0x68, 0x79, 0x70, 0x65, 0x72, 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x75, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x71, 0x75, 0x69, - 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x68, 0x79, 0x70, - 0x65, 0x72, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x79, 0x70, 0x65, 0x72, - 0x67, 0x72, 0x61, 0x70, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x10, 0x68, - 0x79, 0x70, 0x65, 0x72, 0x67, 0x72, 0x61, 0x70, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, - 0x49, 0x0a, 0x0a, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5f, 0x61, 0x64, 0x64, 0x18, 0x10, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, - 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x68, 0x79, 0x70, 0x65, 0x72, 0x67, 0x72, 0x61, 0x70, 0x68, - 0x2e, 0x70, 0x62, 0x2e, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x41, 0x64, 0x64, 0x48, 0x00, 0x52, - 0x09, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x41, 0x64, 0x64, 0x12, 0x52, 0x0a, 0x0d, 0x76, 0x65, - 0x72, 0x74, 0x65, 0x78, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x68, 0x79, 0x70, 0x65, 0x72, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x70, - 0x62, 0x2e, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x48, 0x00, - 0x52, 0x0c, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x52, - 0x0a, 0x0d, 0x68, 0x79, 0x70, 0x65, 0x72, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x18, - 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, - 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x68, 0x79, 0x70, 0x65, 0x72, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x79, 0x70, 0x65, 0x72, 0x65, 0x64, 0x67, 0x65, 0x41, - 0x64, 0x64, 0x48, 0x00, 0x52, 0x0c, 0x68, 0x79, 0x70, 0x65, 0x72, 0x65, 0x64, 0x67, 0x65, 0x41, - 0x64, 0x64, 0x12, 0x5b, 0x0a, 0x10, 0x68, 0x79, 0x70, 0x65, 0x72, 0x65, 0x64, 0x67, 0x65, 0x5f, - 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x71, - 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x68, - 0x79, 0x70, 0x65, 0x72, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x79, 0x70, - 0x65, 0x72, 0x65, 0x64, 0x67, 0x65, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x48, 0x00, 0x52, 0x0f, - 0x68, 0x79, 0x70, 0x65, 0x72, 0x65, 0x64, 0x67, 0x65, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, - 0x52, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x70, 0x6c, 0x6f, - 0x79, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, - 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x44, 0x65, 0x70, 0x6c, - 0x6f, 0x79, 0x48, 0x00, 0x52, 0x0d, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x44, 0x65, 0x70, - 0x6c, 0x6f, 0x79, 0x12, 0x52, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x5f, 0x75, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x71, 0x75, - 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6f, - 0x6d, 0x70, 0x75, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, - 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x4d, 0x0a, 0x0b, 0x63, 0x6f, 0x64, 0x65, 0x5f, - 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x71, - 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, - 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x44, 0x65, - 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x63, 0x6f, 0x64, 0x65, - 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x12, 0x4c, 0x0a, 0x0c, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x65, - 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, - 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, - 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x45, 0x78, - 0x65, 0x63, 0x75, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x6f, 0x64, 0x65, 0x45, 0x78, 0x65, - 0x63, 0x75, 0x74, 0x65, 0x12, 0x4f, 0x0a, 0x0d, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x66, 0x69, 0x6e, - 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x71, 0x75, - 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6f, - 0x6d, 0x70, 0x75, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x46, 0x69, 0x6e, - 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x63, 0x6f, 0x64, 0x65, 0x46, 0x69, 0x6e, - 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x63, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x42, 0x09, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x74, - 0x0a, 0x0d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, - 0x45, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x29, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x08, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x22, 0x92, 0x03, 0x0a, 0x11, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x46, - 0x72, 0x61, 0x6d, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, - 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, - 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x64, - 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x6f, - 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x70, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x2d, 0x0a, 0x12, - 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, - 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x11, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, - 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x34, 0x0a, 0x16, 0x70, - 0x72, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, - 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, 0x70, 0x72, 0x6f, - 0x76, 0x65, 0x72, 0x54, 0x72, 0x65, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, - 0x74, 0x12, 0x76, 0x0a, 0x1d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x62, 0x6c, 0x73, 0x34, 0x38, 0x35, - 0x38, 0x31, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, - 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, - 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x41, 0x67, 0x67, 0x72, 0x65, - 0x67, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x1a, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x42, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x22, 0xcf, 0x03, 0x0a, 0x0b, 0x46, 0x72, - 0x61, 0x6d, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, - 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, - 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, - 0x75, 0x6c, 0x74, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x27, 0x0a, 0x0f, - 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x73, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0c, 0x52, - 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x70, - 0x72, 0x6f, 0x76, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x72, 0x6f, - 0x76, 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x13, 0x66, 0x65, 0x65, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, - 0x70, 0x6c, 0x69, 0x65, 0x72, 0x5f, 0x76, 0x6f, 0x74, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x11, 0x66, 0x65, 0x65, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x56, - 0x6f, 0x74, 0x65, 0x12, 0x76, 0x0a, 0x1d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, + 0x67, 0x65, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xc2, 0x01, 0x0a, 0x0b, 0x50, + 0x72, 0x6f, 0x76, 0x65, 0x72, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x07, 0x66, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, + 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x76, 0x0a, 0x1d, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, + 0x62, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, + 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, + 0x31, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x52, 0x1a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x22, + 0xc0, 0x01, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x50, 0x61, 0x75, 0x73, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, + 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, + 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x76, 0x0a, 0x1d, 0x70, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x5f, 0x62, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, + 0x38, 0x35, 0x38, 0x31, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x1a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x6c, 0x73, 0x34, 0x38, 0x35, + 0x38, 0x31, 0x22, 0xc1, 0x01, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x75, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, + 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x76, + 0x0a, 0x1d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x62, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, + 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x1a, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x6c, + 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x22, 0xc2, 0x01, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x76, 0x65, + 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, + 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x12, 0x76, 0x0a, 0x1d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x62, 0x6c, 0x73, 0x34, - 0x38, 0x35, 0x38, 0x31, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x71, 0x75, 0x69, + 0x38, 0x35, 0x38, 0x31, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, - 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x41, 0x67, 0x67, - 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, + 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x1a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x42, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x22, 0x8f, 0x02, 0x0a, 0x13, - 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x4c, 0x69, 0x76, 0x65, 0x6e, 0x65, 0x73, 0x73, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, - 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, - 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x27, 0x0a, 0x0f, - 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, - 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x76, 0x0a, 0x1d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, + 0x75, 0x72, 0x65, 0x42, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x22, 0xb1, 0x01, 0x0a, 0x0c, + 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x29, 0x0a, 0x10, + 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x76, 0x0a, 0x1d, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, + 0x62, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, + 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, + 0x31, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x52, 0x1a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x22, + 0xd7, 0x02, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x4b, 0x69, 0x63, 0x6b, 0x12, 0x21, + 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x12, 0x37, 0x0a, 0x18, 0x6b, 0x69, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x76, + 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x15, 0x6b, 0x69, 0x63, 0x6b, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x76, 0x65, + 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x6f, + 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, + 0x31, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, + 0x74, 0x69, 0x6e, 0x67, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x31, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x6f, + 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, + 0x32, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, + 0x74, 0x69, 0x6e, 0x67, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x32, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, + 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, + 0x6f, 0x6f, 0x66, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, + 0x12, 0x57, 0x0a, 0x0f, 0x74, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x5f, 0x70, 0x72, + 0x6f, 0x6f, 0x66, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, + 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x76, 0x65, + 0x72, 0x73, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x0e, 0x74, 0x72, 0x61, 0x76, 0x65, + 0x72, 0x73, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xc1, 0x01, 0x0a, 0x0c, 0x50, 0x72, + 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, + 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x76, 0x0a, 0x1d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x62, 0x6c, - 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x71, + 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x1a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x22, 0xdc, 0x01, - 0x0a, 0x09, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x56, 0x6f, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x66, - 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, - 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x70, - 0x70, 0x72, 0x6f, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x61, 0x70, 0x70, - 0x72, 0x6f, 0x76, 0x65, 0x12, 0x76, 0x0a, 0x1d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, - 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x62, 0x6c, 0x73, - 0x34, 0x38, 0x35, 0x38, 0x31, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x71, 0x75, - 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, - 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x52, 0x1a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x42, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x22, 0xb8, 0x01, 0x0a, - 0x11, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, - 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x12, 0x64, 0x0a, 0x13, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x5f, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x22, 0x84, 0x0f, + 0x0a, 0x0e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x3b, 0x0a, 0x04, 0x6a, 0x6f, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, - 0x31, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x52, 0x12, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x53, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x99, 0x01, 0x0a, 0x0b, 0x47, 0x6c, 0x6f, 0x62, - 0x61, 0x6c, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x44, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, + 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, + 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x6a, 0x6f, 0x69, 0x6e, 0x12, 0x3e, 0x0a, + 0x05, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, + 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x4c, + 0x65, 0x61, 0x76, 0x65, 0x48, 0x00, 0x52, 0x05, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x12, 0x3e, 0x0a, + 0x05, 0x70, 0x61, 0x75, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, + 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x50, + 0x61, 0x75, 0x73, 0x65, 0x48, 0x00, 0x52, 0x05, 0x70, 0x61, 0x75, 0x73, 0x65, 0x12, 0x41, 0x0a, + 0x06, 0x72, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, + 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, + 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6d, 0x65, + 0x12, 0x44, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x28, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, + 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x48, 0x00, 0x52, 0x07, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x12, 0x41, 0x0a, 0x06, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, + 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x48, + 0x00, 0x52, 0x06, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x3b, 0x0a, 0x04, 0x6b, 0x69, 0x63, + 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, - 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x44, 0x0a, - 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x28, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x73, 0x22, 0x95, 0x01, 0x0a, 0x0d, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, - 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, - 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, - 0x62, 0x2e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x44, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, + 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x4b, 0x69, 0x63, 0x6b, 0x48, 0x00, + 0x52, 0x04, 0x6b, 0x69, 0x63, 0x6b, 0x12, 0x41, 0x0a, 0x06, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, + 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, + 0x00, 0x52, 0x06, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x4a, 0x0a, 0x0c, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x5f, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x25, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x48, 0x00, 0x52, 0x0b, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x44, + 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x12, 0x4a, 0x0a, 0x0c, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x71, 0x75, + 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x12, 0x49, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x70, + 0x62, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, + 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5f, 0x0a, 0x13, + 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, + 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x12, 0x70, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x56, 0x0a, + 0x10, 0x6d, 0x69, 0x6e, 0x74, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, + 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, + 0x70, 0x62, 0x2e, 0x4d, 0x69, 0x6e, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0f, 0x6d, 0x69, 0x6e, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5e, 0x0a, 0x11, 0x68, 0x79, 0x70, 0x65, 0x72, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x5f, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x68, 0x79, 0x70, 0x65, 0x72, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x70, 0x62, + 0x2e, 0x48, 0x79, 0x70, 0x65, 0x72, 0x67, 0x72, 0x61, 0x70, 0x68, 0x44, 0x65, 0x70, 0x6c, 0x6f, + 0x79, 0x48, 0x00, 0x52, 0x10, 0x68, 0x79, 0x70, 0x65, 0x72, 0x67, 0x72, 0x61, 0x70, 0x68, 0x44, + 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x12, 0x5e, 0x0a, 0x11, 0x68, 0x79, 0x70, 0x65, 0x72, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x68, 0x79, 0x70, 0x65, 0x72, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x70, 0x62, + 0x2e, 0x48, 0x79, 0x70, 0x65, 0x72, 0x67, 0x72, 0x61, 0x70, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x48, 0x00, 0x52, 0x10, 0x68, 0x79, 0x70, 0x65, 0x72, 0x67, 0x72, 0x61, 0x70, 0x68, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x49, 0x0a, 0x0a, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5f, + 0x61, 0x64, 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x71, 0x75, 0x69, 0x6c, + 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x68, 0x79, 0x70, 0x65, + 0x72, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x70, 0x62, 0x2e, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, + 0x41, 0x64, 0x64, 0x48, 0x00, 0x52, 0x09, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x41, 0x64, 0x64, + 0x12, 0x52, 0x0a, 0x0d, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x76, + 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, + 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x68, 0x79, 0x70, 0x65, 0x72, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x2e, 0x70, 0x62, 0x2e, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x52, 0x0a, 0x0d, 0x68, 0x79, 0x70, 0x65, 0x72, 0x65, 0x64, 0x67, + 0x65, 0x5f, 0x61, 0x64, 0x64, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x71, 0x75, + 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x68, 0x79, + 0x70, 0x65, 0x72, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x79, 0x70, 0x65, + 0x72, 0x65, 0x64, 0x67, 0x65, 0x41, 0x64, 0x64, 0x48, 0x00, 0x52, 0x0c, 0x68, 0x79, 0x70, 0x65, + 0x72, 0x65, 0x64, 0x67, 0x65, 0x41, 0x64, 0x64, 0x12, 0x5b, 0x0a, 0x10, 0x68, 0x79, 0x70, 0x65, + 0x72, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x13, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x68, 0x79, 0x70, 0x65, 0x72, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, + 0x70, 0x62, 0x2e, 0x48, 0x79, 0x70, 0x65, 0x72, 0x65, 0x64, 0x67, 0x65, 0x52, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x65, 0x64, 0x67, 0x65, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x52, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, + 0x5f, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, + 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, + 0x74, 0x65, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x48, 0x00, 0x52, 0x0d, 0x63, 0x6f, 0x6d, 0x70, + 0x75, 0x74, 0x65, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x12, 0x52, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, + 0x70, 0x75, 0x74, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x29, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, + 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0d, + 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x4d, 0x0a, + 0x0b, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x18, 0x16, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, + 0x43, 0x6f, 0x64, 0x65, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x00, + 0x52, 0x0a, 0x63, 0x6f, 0x64, 0x65, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x12, 0x4c, 0x0a, 0x0c, + 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x18, 0x17, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, + 0x43, 0x6f, 0x64, 0x65, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x63, + 0x6f, 0x64, 0x65, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, 0x4f, 0x0a, 0x0d, 0x63, 0x6f, + 0x64, 0x65, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x18, 0x18, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x28, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, + 0x6f, 0x64, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x63, + 0x6f, 0x64, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x63, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x09, 0x0a, 0x07, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x22, 0x74, 0x0a, 0x0d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, + 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x45, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, - 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x75, 0x6e, 0x64, 0x6c, - 0x65, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x22, 0x45, 0x0a, 0x0b, 0x47, - 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x22, 0x3a, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x46, - 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x66, - 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x69, - 0x0a, 0x13, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, - 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, - 0x2e, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x05, 0x66, 0x72, - 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x54, 0x0a, 0x17, 0x47, 0x65, 0x74, - 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, - 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, - 0x6d, 0x0a, 0x15, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x05, 0x66, 0x72, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, + 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x1c, 0x0a, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x92, 0x03, 0x0a, 0x11, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, + 0x79, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x6f, 0x72, 0x12, 0x2d, 0x0a, 0x12, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x11, + 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x12, 0x34, 0x0a, 0x16, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x72, 0x65, 0x65, + 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x14, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x54, 0x72, 0x65, 0x65, 0x43, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x76, 0x0a, 0x1d, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, + 0x62, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, + 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, + 0x31, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x52, 0x1a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x22, + 0xcf, 0x03, 0x0a, 0x0b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, + 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, + 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, + 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, + 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, + 0x74, 0x70, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x70, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0c, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x6f, 0x6f, 0x74, + 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x18, + 0x08, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, + 0x73, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x13, 0x66, 0x65, 0x65, + 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x5f, 0x76, 0x6f, 0x74, 0x65, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x66, 0x65, 0x65, 0x4d, 0x75, 0x6c, 0x74, 0x69, + 0x70, 0x6c, 0x69, 0x65, 0x72, 0x56, 0x6f, 0x74, 0x65, 0x12, 0x76, 0x0a, 0x1d, 0x70, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x5f, 0x62, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, + 0x35, 0x38, 0x31, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x1a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, + 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, + 0x31, 0x22, 0x8f, 0x02, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x4c, 0x69, 0x76, 0x65, + 0x6e, 0x65, 0x73, 0x73, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, + 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x76, 0x0a, 0x1d, 0x70, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x5f, 0x62, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, + 0x34, 0x38, 0x35, 0x38, 0x31, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x1a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, + 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x6c, 0x73, 0x34, 0x38, + 0x35, 0x38, 0x31, 0x22, 0x92, 0x02, 0x0a, 0x09, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x56, 0x6f, 0x74, + 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, + 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, + 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, + 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x72, + 0x6f, 0x76, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x61, 0x70, 0x70, 0x72, 0x6f, + 0x76, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x76, 0x0a, 0x1d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x62, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, + 0x31, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, + 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, + 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x1a, 0x70, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x42, 0x6c, 0x73, 0x34, 0x38, 0x35, 0x38, 0x31, 0x22, 0xee, 0x01, 0x0a, 0x11, 0x46, 0x72, 0x61, + 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, + 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, + 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, + 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, + 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x12, 0x64, 0x0a, 0x13, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, + 0x35, 0x38, 0x31, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x12, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x99, 0x01, 0x0a, 0x0b, 0x47, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x44, 0x0a, 0x06, 0x68, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, + 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x46, 0x72, 0x61, 0x6d, + 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, + 0x44, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x28, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x08, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x73, 0x22, 0x95, 0x01, 0x0a, 0x0d, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, + 0x72, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, - 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x46, 0x72, 0x61, 0x6d, - 0x65, 0x52, 0x05, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, - 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x4a, - 0x0a, 0x13, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x68, 0x61, 0x72, 0x64, 0x5f, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x68, 0x61, 0x72, 0x64, 0x4b, - 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0d, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x7b, 0x0a, 0x0c, 0x41, 0x70, - 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, - 0x65, 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, - 0x69, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, - 0x68, 0x61, 0x72, 0x64, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x64, 0x61, 0x74, - 0x61, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, - 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x53, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x41, 0x70, - 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x3b, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, + 0x2e, 0x70, 0x62, 0x2e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, + 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x44, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x71, 0x75, 0x69, 0x6c, + 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x75, 0x6e, + 0x64, 0x6c, 0x65, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x22, 0x45, 0x0a, + 0x0b, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x22, 0x3a, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, + 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x22, 0x69, 0x0a, 0x13, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x66, 0x72, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, + 0x70, 0x62, 0x2e, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x05, + 0x66, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x54, 0x0a, 0x17, 0x47, + 0x65, 0x74, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x21, + 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x22, 0x6d, 0x0a, 0x15, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x46, 0x72, 0x61, + 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x05, 0x66, 0x72, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x71, 0x75, 0x69, 0x6c, + 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x46, 0x72, + 0x61, 0x6d, 0x65, 0x52, 0x05, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, + 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, + 0x22, 0x4a, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x68, 0x61, 0x72, 0x64, + 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x68, 0x61, 0x72, + 0x64, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0d, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x7b, 0x0a, 0x0c, + 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, + 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x06, 0x70, 0x72, + 0x65, 0x66, 0x69, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, + 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x64, + 0x61, 0x74, 0x61, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x53, 0x0a, 0x14, 0x47, 0x65, 0x74, + 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x3b, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, 0x53, + 0x68, 0x61, 0x72, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x38, + 0x0a, 0x16, 0x47, 0x65, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x68, 0x61, 0x72, 0x64, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x6c, 0x31, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x6c, 0x31, 0x12, 0x0e, 0x0a, 0x02, 0x6c, 0x32, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x6c, 0x32, 0x22, 0x4d, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x63, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x4c, 0x6f, + 0x63, 0x6b, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x68, 0x61, 0x72, 0x64, 0x5f, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x68, 0x61, + 0x72, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, + 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x9d, 0x01, 0x0a, + 0x11, 0x4c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x12, 0x27, 0x0a, + 0x0f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0e, 0x73, 0x68, 0x61, 0x72, 0x64, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x22, 0x6e, 0x0a, 0x1a, + 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0c, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x63, + 0x6b, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x53, 0x0a, 0x0b, + 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x70, + 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x65, + 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x63, 0x69, 0x72, 0x63, 0x5f, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x63, 0x69, 0x72, 0x63, 0x49, 0x64, 0x12, 0x12, 0x0a, + 0x04, 0x63, 0x65, 0x6c, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x63, 0x65, 0x6c, + 0x6c, 0x22, 0x63, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x65, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x63, 0x69, 0x72, + 0x63, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x63, 0x69, 0x72, 0x63, + 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x65, 0x6c, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x04, 0x63, 0x65, 0x6c, 0x6c, 0x22, 0x49, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x30, 0x0a, 0x14, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x22, 0x70, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x08, 0x72, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, - 0x72, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x38, 0x0a, 0x16, - 0x47, 0x65, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x6c, 0x31, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x02, 0x6c, 0x31, 0x12, 0x0e, 0x0a, 0x02, 0x6c, 0x32, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x02, 0x6c, 0x32, 0x22, 0x4d, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x47, 0x6c, 0x6f, - 0x62, 0x61, 0x6c, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, - 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, - 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x53, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, - 0x07, 0x63, 0x69, 0x72, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, - 0x63, 0x69, 0x72, 0x63, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x65, 0x6c, 0x6c, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x63, 0x65, 0x6c, 0x6c, 0x22, 0x63, 0x0a, 0x0e, 0x52, 0x65, - 0x63, 0x65, 0x69, 0x76, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x0e, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x65, 0x65, 0x72, - 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x63, 0x69, 0x72, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x06, 0x63, 0x69, 0x72, 0x63, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x63, - 0x65, 0x6c, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x63, 0x65, 0x6c, 0x6c, 0x22, - 0x49, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x14, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x4b, 0x65, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x70, 0x0a, 0x16, 0x47, 0x65, - 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, + 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x79, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x22, 0x4d, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x79, 0x42, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x6b, + 0x65, 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x10, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x22, 0x78, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x79, 0x42, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x08, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x4d, 0x0a, 0x1d, - 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x42, 0x79, - 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, - 0x12, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x76, 0x65, - 0x72, 0x4b, 0x65, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x78, 0x0a, 0x1e, 0x47, - 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x42, 0x79, 0x50, - 0x72, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, - 0x08, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, - 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x12, - 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x7d, 0x0a, 0x15, 0x50, 0x75, 0x74, 0x49, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, - 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x4a, 0x0a, 0x0c, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, - 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, 0x50, 0x75, - 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x4b, 0x65, 0x79, 0x22, 0x2e, 0x0a, 0x16, 0x50, 0x75, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x7d, 0x0a, 0x15, + 0x50, 0x75, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x4a, 0x0a, 0x0c, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, + 0x45, 0x64, 0x34, 0x34, 0x38, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0b, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x22, 0x2e, 0x0a, 0x16, 0x50, + 0x75, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x78, 0x0a, 0x14, 0x50, + 0x75, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, + 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x53, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x57, 0x69, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x4f, 0x66, 0x50, + 0x6f, 0x73, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x22, 0x2d, 0x0a, 0x15, 0x50, 0x75, 0x74, 0x50, 0x72, 0x6f, 0x76, + 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, - 0x72, 0x72, 0x6f, 0x72, 0x22, 0x78, 0x0a, 0x14, 0x50, 0x75, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, - 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x0b, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x3f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, - 0x38, 0x35, 0x38, 0x31, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x57, 0x69, 0x74, - 0x68, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x4f, 0x66, 0x50, 0x6f, 0x73, 0x73, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x22, 0x2d, - 0x0a, 0x15, 0x50, 0x75, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x9e, 0x02, - 0x0a, 0x18, 0x50, 0x75, 0x74, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x14, 0x69, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x4b, 0x65, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2e, 0x0a, 0x13, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x4f, 0x0a, 0x25, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x6e, - 0x67, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x20, 0x69, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x4f, 0x66, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x12, 0x4f, 0x0a, - 0x25, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x6f, 0x66, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x20, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x4f, 0x66, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x22, 0x31, - 0x0a, 0x19, 0x50, 0x75, 0x74, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x22, 0x9e, 0x02, 0x0a, 0x18, 0x50, 0x75, 0x74, 0x43, 0x72, 0x6f, 0x73, + 0x73, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x30, 0x0a, 0x14, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, + 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x12, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x5f, 0x6b, + 0x65, 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x11, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x4f, 0x0a, 0x25, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, + 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x6f, 0x66, + 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x53, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x4f, 0x66, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, + 0x67, 0x4b, 0x65, 0x79, 0x12, 0x4f, 0x0a, 0x25, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x5f, + 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x6f, 0x66, + 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x53, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x4f, 0x66, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x4b, 0x65, 0x79, 0x22, 0x31, 0x0a, 0x19, 0x50, 0x75, 0x74, 0x43, 0x72, 0x6f, 0x73, + 0x73, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x69, 0x0a, 0x13, 0x50, 0x75, 0x74, 0x53, + 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x38, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, + 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x58, 0x34, 0x34, 0x38, 0x4b, 0x65, 0x79, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x22, 0x2c, 0x0a, 0x14, 0x50, 0x75, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x22, 0x69, 0x0a, 0x13, 0x50, 0x75, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, - 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x12, 0x38, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x26, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, - 0x58, 0x34, 0x34, 0x38, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x2c, 0x0a, 0x14, - 0x50, 0x75, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x31, 0x0a, 0x15, 0x47, 0x65, - 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x69, 0x0a, - 0x16, 0x47, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, - 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, - 0x64, 0x34, 0x34, 0x38, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x30, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x50, - 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x80, 0x01, 0x0a, 0x15, 0x47, - 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x3f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, - 0x38, 0x35, 0x38, 0x31, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x57, 0x69, 0x74, - 0x68, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x4f, 0x66, 0x50, 0x6f, 0x73, 0x73, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x2f, 0x0a, - 0x13, 0x47, 0x65, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x66, - 0x0a, 0x14, 0x47, 0x65, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, - 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x69, - 0x67, 0x6e, 0x65, 0x64, 0x58, 0x34, 0x34, 0x38, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x6d, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x53, 0x69, 0x67, - 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x10, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x75, 0x72, 0x70, - 0x6f, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6b, 0x65, 0x79, 0x50, 0x75, - 0x72, 0x70, 0x6f, 0x73, 0x65, 0x22, 0x71, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x53, 0x69, 0x67, 0x6e, - 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, - 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x53, - 0x69, 0x67, 0x6e, 0x65, 0x64, 0x58, 0x34, 0x34, 0x38, 0x4b, 0x65, 0x79, 0x52, 0x04, 0x6b, 0x65, - 0x79, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x19, 0x0a, 0x17, 0x52, 0x61, 0x6e, 0x67, - 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x22, 0x83, 0x01, 0x0a, 0x18, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, - 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x51, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, - 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, - 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x57, 0x69, 0x74, 0x68, 0x50, 0x72, 0x6f, - 0x6f, 0x66, 0x4f, 0x66, 0x50, 0x6f, 0x73, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x1a, 0x0a, 0x18, 0x52, 0x61, 0x6e, - 0x67, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x6c, 0x0a, 0x19, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x49, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x39, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, 0x50, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, - 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x22, 0x67, 0x0a, 0x16, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x69, 0x67, 0x6e, - 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, + 0x72, 0x22, 0x31, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x22, 0x69, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, + 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, + 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, + 0x30, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x22, 0x80, 0x01, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, + 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, + 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x53, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x57, 0x69, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x4f, 0x66, 0x50, + 0x6f, 0x73, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, + 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x22, 0x2f, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, + 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x66, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x53, 0x69, 0x67, 0x6e, + 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, 0x75, 0x69, + 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, + 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x58, 0x34, 0x34, 0x38, 0x4b, + 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x6d, 0x0a, + 0x1c, 0x47, 0x65, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x6b, 0x65, 0x79, 0x50, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x22, 0x69, 0x0a, 0x17, - 0x52, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, - 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x53, - 0x69, 0x67, 0x6e, 0x65, 0x64, 0x58, 0x34, 0x34, 0x38, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, - 0x79, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x61, 0x0a, 0x0f, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x4b, 0x65, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x70, 0x61, - 0x72, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x74, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x65, 0x6e, - 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x22, 0xb2, 0x01, 0x0a, 0x11, 0x50, - 0x75, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x51, 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x72, - 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, - 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, - 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x53, - 0x68, 0x61, 0x72, 0x64, 0x52, 0x0d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x68, 0x61, - 0x72, 0x64, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x30, 0x0a, - 0x14, 0x65, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x65, 0x70, 0x68, - 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, - 0x14, 0x0a, 0x12, 0x50, 0x75, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xee, 0x02, 0x0a, 0x0d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x72, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x47, 0x6c, - 0x6f, 0x62, 0x61, 0x6c, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, - 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, - 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x46, - 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x71, 0x75, - 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, - 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x46, 0x72, - 0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x0c, 0x47, - 0x65, 0x74, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x12, 0x2e, 0x2e, 0x71, 0x75, - 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, - 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x53, 0x68, - 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x71, 0x75, - 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, - 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x53, 0x68, - 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, 0x0f, - 0x47, 0x65, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x12, - 0x31, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x47, - 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x52, 0x0a, 0x6b, 0x65, 0x79, 0x50, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x22, 0x71, 0x0a, 0x1d, + 0x47, 0x65, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, + 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, 0x75, + 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, + 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x58, 0x34, 0x34, 0x38, + 0x4b, 0x65, 0x79, 0x52, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, + 0x19, 0x0a, 0x17, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, + 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x83, 0x01, 0x0a, 0x18, 0x52, + 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, + 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x57, 0x69, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x4f, 0x66, 0x50, 0x6f, 0x73, 0x73, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x22, 0x1a, 0x0a, 0x18, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x6c, 0x0a, 0x19, + 0x52, 0x61, 0x6e, 0x67, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, + 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x67, 0x0a, 0x16, 0x52, 0x61, + 0x6e, 0x67, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x6b, + 0x65, 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x10, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6b, 0x65, 0x79, 0x50, 0x75, 0x72, 0x70, + 0x6f, 0x73, 0x65, 0x22, 0x69, 0x0a, 0x17, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x69, 0x67, 0x6e, + 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, 0x75, + 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, + 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x58, 0x34, 0x34, 0x38, + 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x61, + 0x0a, 0x0f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x53, 0x68, 0x61, 0x72, + 0x64, 0x12, 0x29, 0x0a, 0x10, 0x70, 0x61, 0x72, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x61, 0x72, + 0x74, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, + 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4b, 0x65, + 0x79, 0x22, 0xb2, 0x01, 0x0a, 0x11, 0x50, 0x75, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x0d, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x65, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, + 0x6c, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x12, 0x65, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x14, 0x0a, 0x12, 0x50, 0x75, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xf2, 0x03, 0x0a, + 0x0d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x72, + 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x46, 0x72, 0x61, 0x6d, 0x65, + 0x12, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, + 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, - 0x65, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x8b, 0x01, 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x53, 0x68, - 0x61, 0x72, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x78, 0x0a, 0x10, 0x47, 0x65, - 0x74, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x32, - 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x70, - 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x41, - 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x70, 0x0a, 0x0c, 0x4f, 0x6e, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x60, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, - 0x26, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x6e, 0x64, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x29, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, - 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, - 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x28, 0x01, 0x30, 0x01, 0x32, 0xdf, 0x01, 0x0a, 0x0d, 0x4d, 0x69, 0x78, 0x6e, 0x65, - 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x69, 0x0a, 0x0a, 0x50, 0x75, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, + 0x64, 0x73, 0x12, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, + 0x65, 0x74, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, + 0x65, 0x74, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, + 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x12, 0x31, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, - 0x70, 0x62, 0x2e, 0x50, 0x75, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x68, 0x61, 0x72, + 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x71, 0x75, 0x69, 0x6c, + 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, + 0x68, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x81, 0x01, + 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x12, 0x34, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, - 0x2e, 0x50, 0x75, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x0b, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x12, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x27, 0x2e, 0x71, 0x75, - 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x61, 0x70, - 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x28, 0x01, 0x30, 0x01, 0x32, 0xd7, 0x0c, 0x0a, 0x12, 0x4b, 0x65, 0x79, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, - 0x75, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x79, 0x12, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, - 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, - 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, - 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x8d, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x4b, 0x65, - 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x42, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x65, - 0x72, 0x12, 0x38, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, - 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x42, 0x79, 0x50, 0x72, - 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x39, 0x2e, 0x71, 0x75, - 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, - 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x42, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x75, 0x0a, 0x0e, 0x50, 0x75, 0x74, 0x49, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x12, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, - 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, - 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x71, 0x75, 0x69, + 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x71, 0x75, 0x69, + 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, + 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x65, 0x64, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x32, 0x8b, 0x01, 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x64, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x78, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x53, + 0x68, 0x61, 0x72, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x32, 0x2e, 0x71, 0x75, 0x69, 0x6c, + 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, + 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, + 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, + 0x72, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, + 0x70, 0x0a, 0x0c, 0x4f, 0x6e, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, + 0x60, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x26, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, - 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, - 0x0d, 0x50, 0x75, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x12, 0x2f, + 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x1a, 0x29, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x52, + 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, 0x01, 0x30, + 0x01, 0x32, 0xdf, 0x01, 0x0a, 0x0d, 0x4d, 0x69, 0x78, 0x6e, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x69, 0x0a, 0x0a, 0x50, 0x75, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2d, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, + 0x0a, 0x0b, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x27, 0x2e, + 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x62, 0x2e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, + 0x01, 0x30, 0x01, 0x32, 0xd7, 0x0c, 0x0a, 0x12, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x75, 0x0a, 0x0e, 0x47, 0x65, + 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x12, 0x30, 0x2e, 0x71, + 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x74, 0x50, 0x72, - 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x74, 0x50, - 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x7e, 0x0a, 0x11, 0x50, 0x75, 0x74, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x53, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x4b, 0x65, + 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x8d, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x79, 0x42, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x38, 0x2e, 0x71, + 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x42, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x39, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, - 0x70, 0x62, 0x2e, 0x50, 0x75, 0x74, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x71, 0x75, - 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, - 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x74, 0x43, 0x72, 0x6f, 0x73, 0x73, - 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x6f, 0x0a, 0x0c, 0x50, 0x75, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, - 0x79, 0x12, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, - 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x2f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x79, 0x42, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x75, 0x0a, 0x0e, 0x50, 0x75, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x4b, 0x65, 0x79, 0x12, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, + 0x50, 0x75, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, + 0x62, 0x2e, 0x50, 0x75, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x0d, 0x50, 0x75, 0x74, 0x50, + 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x12, 0x2f, 0x2e, 0x71, 0x75, 0x69, 0x6c, + 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, + 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x71, 0x75, 0x69, + 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, + 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, + 0x67, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7e, 0x0a, 0x11, + 0x50, 0x75, 0x74, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x12, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, - 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x75, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x4b, 0x65, 0x79, 0x12, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, - 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, - 0x2e, 0x47, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x74, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, - 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, - 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x0d, 0x47, 0x65, 0x74, - 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x12, 0x2f, 0x2e, 0x71, 0x75, 0x69, - 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, - 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, - 0x67, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x71, 0x75, - 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, - 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, - 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, - 0x0c, 0x47, 0x65, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x2e, 0x2e, - 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x69, 0x67, - 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, - 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x69, 0x67, - 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x8a, - 0x01, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, - 0x42, 0x79, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x37, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x70, 0x62, 0x2e, 0x50, 0x75, 0x74, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x0c, + 0x50, 0x75, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x2e, 0x2e, 0x71, + 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x74, 0x53, 0x69, 0x67, 0x6e, + 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x71, + 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x74, 0x53, 0x69, 0x67, 0x6e, + 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x75, 0x0a, + 0x0e, 0x47, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x12, + 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x31, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, + 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, + 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x12, 0x2f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, + 0x62, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, + 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x53, + 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, - 0x79, 0x73, 0x42, 0x79, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x38, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x8a, 0x01, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x50, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x10, 0x52, - 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x73, 0x12, - 0x32, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x67, - 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, + 0x65, 0x6e, 0x74, 0x12, 0x37, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, - 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7e, 0x0a, 0x11, 0x52, 0x61, 0x6e, 0x67, - 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x33, 0x2e, - 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x49, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x52, - 0x61, 0x6e, 0x67, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, 0x0f, 0x52, 0x61, 0x6e, 0x67, - 0x65, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x31, 0x2e, 0x71, 0x75, - 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, - 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x69, 0x67, - 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, + 0x47, 0x65, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x71, + 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x69, 0x67, 0x6e, + 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x10, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, + 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x32, 0x2e, 0x71, 0x75, 0x69, + 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, + 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x76, + 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x67, 0x65, - 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x32, 0xec, 0x03, 0x0a, 0x0f, 0x44, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x56, 0x0a, 0x0f, 0x50, 0x75, 0x74, 0x49, 0x6e, 0x62, - 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, - 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x50, 0x75, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x75, - 0x0a, 0x10, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x73, 0x12, 0x2f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, - 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, - 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, - 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x06, 0x50, 0x75, 0x74, 0x48, 0x75, 0x62, 0x12, - 0x22, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x75, 0x62, - 0x50, 0x75, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x59, 0x0a, 0x06, 0x47, - 0x65, 0x74, 0x48, 0x75, 0x62, 0x12, 0x26, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, - 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, - 0x70, 0x62, 0x2e, 0x48, 0x75, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, + 0x50, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x7e, 0x0a, 0x11, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, + 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, 0x0f, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x69, 0x67, 0x6e, + 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x31, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, + 0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4b, 0x65, + 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x71, 0x75, 0x69, 0x6c, + 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x65, + 0x64, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xec, 0x03, + 0x0a, 0x0f, 0x44, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x56, 0x0a, 0x0f, 0x50, 0x75, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, + 0x62, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x75, + 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x75, 0x0a, 0x10, 0x47, 0x65, 0x74, + 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x2f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x75, 0x62, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x04, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x2f, + 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x69, 0x73, 0x70, - 0x61, 0x74, 0x63, 0x68, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x69, 0x73, - 0x70, 0x61, 0x74, 0x63, 0x68, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x42, 0x3a, 0x5a, 0x38, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x71, 0x75, 0x69, 0x6c, - 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x71, 0x75, 0x69, 0x6c, 0x69, - 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x6d, 0x6f, 0x6e, 0x6f, 0x72, 0x65, 0x70, 0x6f, 0x2f, 0x6e, - 0x6f, 0x64, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x73, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x62, 0x6f, + 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x44, 0x0a, 0x06, 0x50, 0x75, 0x74, 0x48, 0x75, 0x62, 0x12, 0x22, 0x2e, 0x71, 0x75, 0x69, + 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x75, 0x62, 0x50, 0x75, 0x74, 0x1a, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x59, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x48, 0x75, 0x62, + 0x12, 0x26, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x75, + 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x75, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x69, 0x0a, 0x04, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x2f, 0x2e, 0x71, 0x75, 0x69, 0x6c, + 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x53, + 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x71, 0x75, 0x69, + 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, + 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3a, 0x5a, 0x38, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, + 0x2f, 0x6d, 0x6f, 0x6e, 0x6f, 0x72, 0x65, 0x70, 0x6f, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -4746,7 +5009,7 @@ func file_global_proto_rawDescGZIP() []byte { return file_global_proto_rawDescData } -var file_global_proto_msgTypes = make([]protoimpl.MessageInfo, 60) +var file_global_proto_msgTypes = make([]protoimpl.MessageInfo, 63) var file_global_proto_goTypes = []interface{}{ (*LegacyProverRequest)(nil), // 0: quilibrium.node.global.pb.LegacyProverRequest (*SeniorityMerge)(nil), // 1: quilibrium.node.global.pb.SeniorityMerge @@ -4777,83 +5040,86 @@ var file_global_proto_goTypes = []interface{}{ (*GetAppShardsResponse)(nil), // 26: quilibrium.node.global.pb.GetAppShardsResponse (*GetGlobalShardsRequest)(nil), // 27: quilibrium.node.global.pb.GetGlobalShardsRequest (*GetGlobalShardsResponse)(nil), // 28: quilibrium.node.global.pb.GetGlobalShardsResponse - (*SendMessage)(nil), // 29: quilibrium.node.global.pb.SendMessage - (*ReceiveMessage)(nil), // 30: quilibrium.node.global.pb.ReceiveMessage - (*GetKeyRegistryRequest)(nil), // 31: quilibrium.node.global.pb.GetKeyRegistryRequest - (*GetKeyRegistryResponse)(nil), // 32: quilibrium.node.global.pb.GetKeyRegistryResponse - (*GetKeyRegistryByProverRequest)(nil), // 33: quilibrium.node.global.pb.GetKeyRegistryByProverRequest - (*GetKeyRegistryByProverResponse)(nil), // 34: quilibrium.node.global.pb.GetKeyRegistryByProverResponse - (*PutIdentityKeyRequest)(nil), // 35: quilibrium.node.global.pb.PutIdentityKeyRequest - (*PutIdentityKeyResponse)(nil), // 36: quilibrium.node.global.pb.PutIdentityKeyResponse - (*PutProvingKeyRequest)(nil), // 37: quilibrium.node.global.pb.PutProvingKeyRequest - (*PutProvingKeyResponse)(nil), // 38: quilibrium.node.global.pb.PutProvingKeyResponse - (*PutCrossSignatureRequest)(nil), // 39: quilibrium.node.global.pb.PutCrossSignatureRequest - (*PutCrossSignatureResponse)(nil), // 40: quilibrium.node.global.pb.PutCrossSignatureResponse - (*PutSignedKeyRequest)(nil), // 41: quilibrium.node.global.pb.PutSignedKeyRequest - (*PutSignedKeyResponse)(nil), // 42: quilibrium.node.global.pb.PutSignedKeyResponse - (*GetIdentityKeyRequest)(nil), // 43: quilibrium.node.global.pb.GetIdentityKeyRequest - (*GetIdentityKeyResponse)(nil), // 44: quilibrium.node.global.pb.GetIdentityKeyResponse - (*GetProvingKeyRequest)(nil), // 45: quilibrium.node.global.pb.GetProvingKeyRequest - (*GetProvingKeyResponse)(nil), // 46: quilibrium.node.global.pb.GetProvingKeyResponse - (*GetSignedKeyRequest)(nil), // 47: quilibrium.node.global.pb.GetSignedKeyRequest - (*GetSignedKeyResponse)(nil), // 48: quilibrium.node.global.pb.GetSignedKeyResponse - (*GetSignedKeysByParentRequest)(nil), // 49: quilibrium.node.global.pb.GetSignedKeysByParentRequest - (*GetSignedKeysByParentResponse)(nil), // 50: quilibrium.node.global.pb.GetSignedKeysByParentResponse - (*RangeProvingKeysRequest)(nil), // 51: quilibrium.node.global.pb.RangeProvingKeysRequest - (*RangeProvingKeysResponse)(nil), // 52: quilibrium.node.global.pb.RangeProvingKeysResponse - (*RangeIdentityKeysRequest)(nil), // 53: quilibrium.node.global.pb.RangeIdentityKeysRequest - (*RangeIdentityKeysResponse)(nil), // 54: quilibrium.node.global.pb.RangeIdentityKeysResponse - (*RangeSignedKeysRequest)(nil), // 55: quilibrium.node.global.pb.RangeSignedKeysRequest - (*RangeSignedKeysResponse)(nil), // 56: quilibrium.node.global.pb.RangeSignedKeysResponse - (*MessageKeyShard)(nil), // 57: quilibrium.node.global.pb.MessageKeyShard - (*PutMessageRequest)(nil), // 58: quilibrium.node.global.pb.PutMessageRequest - (*PutMessageResponse)(nil), // 59: quilibrium.node.global.pb.PutMessageResponse - (*Ed448Signature)(nil), // 60: quilibrium.node.keys.pb.Ed448Signature - (*BLS48581SignatureWithProofOfPossession)(nil), // 61: quilibrium.node.keys.pb.BLS48581SignatureWithProofOfPossession - (*BLS48581AddressedSignature)(nil), // 62: quilibrium.node.keys.pb.BLS48581AddressedSignature - (*TraversalProof)(nil), // 63: quilibrium.node.application.pb.TraversalProof - (*TokenDeploy)(nil), // 64: quilibrium.node.token.pb.TokenDeploy - (*TokenUpdate)(nil), // 65: quilibrium.node.token.pb.TokenUpdate - (*Transaction)(nil), // 66: quilibrium.node.token.pb.Transaction - (*PendingTransaction)(nil), // 67: quilibrium.node.token.pb.PendingTransaction - (*MintTransaction)(nil), // 68: quilibrium.node.token.pb.MintTransaction - (*HypergraphDeploy)(nil), // 69: quilibrium.node.hypergraph.pb.HypergraphDeploy - (*HypergraphUpdate)(nil), // 70: quilibrium.node.hypergraph.pb.HypergraphUpdate - (*VertexAdd)(nil), // 71: quilibrium.node.hypergraph.pb.VertexAdd - (*VertexRemove)(nil), // 72: quilibrium.node.hypergraph.pb.VertexRemove - (*HyperedgeAdd)(nil), // 73: quilibrium.node.hypergraph.pb.HyperedgeAdd - (*HyperedgeRemove)(nil), // 74: quilibrium.node.hypergraph.pb.HyperedgeRemove - (*ComputeDeploy)(nil), // 75: quilibrium.node.compute.pb.ComputeDeploy - (*ComputeUpdate)(nil), // 76: quilibrium.node.compute.pb.ComputeUpdate - (*CodeDeployment)(nil), // 77: quilibrium.node.compute.pb.CodeDeployment - (*CodeExecute)(nil), // 78: quilibrium.node.compute.pb.CodeExecute - (*CodeFinalize)(nil), // 79: quilibrium.node.compute.pb.CodeFinalize - (*BLS48581AggregateSignature)(nil), // 80: quilibrium.node.keys.pb.BLS48581AggregateSignature - (*KeyRegistry)(nil), // 81: quilibrium.node.keys.pb.KeyRegistry - (*Ed448PublicKey)(nil), // 82: quilibrium.node.keys.pb.Ed448PublicKey - (*SignedX448Key)(nil), // 83: quilibrium.node.keys.pb.SignedX448Key - (*Message)(nil), // 84: quilibrium.node.application.pb.Message - (*InboxMessagePut)(nil), // 85: quilibrium.node.channel.pb.InboxMessagePut - (*InboxMessageRequest)(nil), // 86: quilibrium.node.channel.pb.InboxMessageRequest - (*HubPut)(nil), // 87: quilibrium.node.channel.pb.HubPut - (*HubRequest)(nil), // 88: quilibrium.node.channel.pb.HubRequest - (*DispatchSyncRequest)(nil), // 89: quilibrium.node.channel.pb.DispatchSyncRequest - (*emptypb.Empty)(nil), // 90: google.protobuf.Empty - (*InboxMessageResponse)(nil), // 91: quilibrium.node.channel.pb.InboxMessageResponse - (*HubResponse)(nil), // 92: quilibrium.node.channel.pb.HubResponse - (*DispatchSyncResponse)(nil), // 93: quilibrium.node.channel.pb.DispatchSyncResponse + (*GetLockedAddressesRequest)(nil), // 29: quilibrium.node.global.pb.GetLockedAddressesRequest + (*LockedTransaction)(nil), // 30: quilibrium.node.global.pb.LockedTransaction + (*GetLockedAddressesResponse)(nil), // 31: quilibrium.node.global.pb.GetLockedAddressesResponse + (*SendMessage)(nil), // 32: quilibrium.node.global.pb.SendMessage + (*ReceiveMessage)(nil), // 33: quilibrium.node.global.pb.ReceiveMessage + (*GetKeyRegistryRequest)(nil), // 34: quilibrium.node.global.pb.GetKeyRegistryRequest + (*GetKeyRegistryResponse)(nil), // 35: quilibrium.node.global.pb.GetKeyRegistryResponse + (*GetKeyRegistryByProverRequest)(nil), // 36: quilibrium.node.global.pb.GetKeyRegistryByProverRequest + (*GetKeyRegistryByProverResponse)(nil), // 37: quilibrium.node.global.pb.GetKeyRegistryByProverResponse + (*PutIdentityKeyRequest)(nil), // 38: quilibrium.node.global.pb.PutIdentityKeyRequest + (*PutIdentityKeyResponse)(nil), // 39: quilibrium.node.global.pb.PutIdentityKeyResponse + (*PutProvingKeyRequest)(nil), // 40: quilibrium.node.global.pb.PutProvingKeyRequest + (*PutProvingKeyResponse)(nil), // 41: quilibrium.node.global.pb.PutProvingKeyResponse + (*PutCrossSignatureRequest)(nil), // 42: quilibrium.node.global.pb.PutCrossSignatureRequest + (*PutCrossSignatureResponse)(nil), // 43: quilibrium.node.global.pb.PutCrossSignatureResponse + (*PutSignedKeyRequest)(nil), // 44: quilibrium.node.global.pb.PutSignedKeyRequest + (*PutSignedKeyResponse)(nil), // 45: quilibrium.node.global.pb.PutSignedKeyResponse + (*GetIdentityKeyRequest)(nil), // 46: quilibrium.node.global.pb.GetIdentityKeyRequest + (*GetIdentityKeyResponse)(nil), // 47: quilibrium.node.global.pb.GetIdentityKeyResponse + (*GetProvingKeyRequest)(nil), // 48: quilibrium.node.global.pb.GetProvingKeyRequest + (*GetProvingKeyResponse)(nil), // 49: quilibrium.node.global.pb.GetProvingKeyResponse + (*GetSignedKeyRequest)(nil), // 50: quilibrium.node.global.pb.GetSignedKeyRequest + (*GetSignedKeyResponse)(nil), // 51: quilibrium.node.global.pb.GetSignedKeyResponse + (*GetSignedKeysByParentRequest)(nil), // 52: quilibrium.node.global.pb.GetSignedKeysByParentRequest + (*GetSignedKeysByParentResponse)(nil), // 53: quilibrium.node.global.pb.GetSignedKeysByParentResponse + (*RangeProvingKeysRequest)(nil), // 54: quilibrium.node.global.pb.RangeProvingKeysRequest + (*RangeProvingKeysResponse)(nil), // 55: quilibrium.node.global.pb.RangeProvingKeysResponse + (*RangeIdentityKeysRequest)(nil), // 56: quilibrium.node.global.pb.RangeIdentityKeysRequest + (*RangeIdentityKeysResponse)(nil), // 57: quilibrium.node.global.pb.RangeIdentityKeysResponse + (*RangeSignedKeysRequest)(nil), // 58: quilibrium.node.global.pb.RangeSignedKeysRequest + (*RangeSignedKeysResponse)(nil), // 59: quilibrium.node.global.pb.RangeSignedKeysResponse + (*MessageKeyShard)(nil), // 60: quilibrium.node.global.pb.MessageKeyShard + (*PutMessageRequest)(nil), // 61: quilibrium.node.global.pb.PutMessageRequest + (*PutMessageResponse)(nil), // 62: quilibrium.node.global.pb.PutMessageResponse + (*Ed448Signature)(nil), // 63: quilibrium.node.keys.pb.Ed448Signature + (*BLS48581SignatureWithProofOfPossession)(nil), // 64: quilibrium.node.keys.pb.BLS48581SignatureWithProofOfPossession + (*BLS48581AddressedSignature)(nil), // 65: quilibrium.node.keys.pb.BLS48581AddressedSignature + (*TraversalProof)(nil), // 66: quilibrium.node.application.pb.TraversalProof + (*TokenDeploy)(nil), // 67: quilibrium.node.token.pb.TokenDeploy + (*TokenUpdate)(nil), // 68: quilibrium.node.token.pb.TokenUpdate + (*Transaction)(nil), // 69: quilibrium.node.token.pb.Transaction + (*PendingTransaction)(nil), // 70: quilibrium.node.token.pb.PendingTransaction + (*MintTransaction)(nil), // 71: quilibrium.node.token.pb.MintTransaction + (*HypergraphDeploy)(nil), // 72: quilibrium.node.hypergraph.pb.HypergraphDeploy + (*HypergraphUpdate)(nil), // 73: quilibrium.node.hypergraph.pb.HypergraphUpdate + (*VertexAdd)(nil), // 74: quilibrium.node.hypergraph.pb.VertexAdd + (*VertexRemove)(nil), // 75: quilibrium.node.hypergraph.pb.VertexRemove + (*HyperedgeAdd)(nil), // 76: quilibrium.node.hypergraph.pb.HyperedgeAdd + (*HyperedgeRemove)(nil), // 77: quilibrium.node.hypergraph.pb.HyperedgeRemove + (*ComputeDeploy)(nil), // 78: quilibrium.node.compute.pb.ComputeDeploy + (*ComputeUpdate)(nil), // 79: quilibrium.node.compute.pb.ComputeUpdate + (*CodeDeployment)(nil), // 80: quilibrium.node.compute.pb.CodeDeployment + (*CodeExecute)(nil), // 81: quilibrium.node.compute.pb.CodeExecute + (*CodeFinalize)(nil), // 82: quilibrium.node.compute.pb.CodeFinalize + (*BLS48581AggregateSignature)(nil), // 83: quilibrium.node.keys.pb.BLS48581AggregateSignature + (*KeyRegistry)(nil), // 84: quilibrium.node.keys.pb.KeyRegistry + (*Ed448PublicKey)(nil), // 85: quilibrium.node.keys.pb.Ed448PublicKey + (*SignedX448Key)(nil), // 86: quilibrium.node.keys.pb.SignedX448Key + (*Message)(nil), // 87: quilibrium.node.application.pb.Message + (*InboxMessagePut)(nil), // 88: quilibrium.node.channel.pb.InboxMessagePut + (*InboxMessageRequest)(nil), // 89: quilibrium.node.channel.pb.InboxMessageRequest + (*HubPut)(nil), // 90: quilibrium.node.channel.pb.HubPut + (*HubRequest)(nil), // 91: quilibrium.node.channel.pb.HubRequest + (*DispatchSyncRequest)(nil), // 92: quilibrium.node.channel.pb.DispatchSyncRequest + (*emptypb.Empty)(nil), // 93: google.protobuf.Empty + (*InboxMessageResponse)(nil), // 94: quilibrium.node.channel.pb.InboxMessageResponse + (*HubResponse)(nil), // 95: quilibrium.node.channel.pb.HubResponse + (*DispatchSyncResponse)(nil), // 96: quilibrium.node.channel.pb.DispatchSyncResponse } var file_global_proto_depIdxs = []int32{ - 60, // 0: quilibrium.node.global.pb.LegacyProverRequest.public_key_signatures_ed448:type_name -> quilibrium.node.keys.pb.Ed448Signature - 61, // 1: quilibrium.node.global.pb.ProverJoin.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581SignatureWithProofOfPossession + 63, // 0: quilibrium.node.global.pb.LegacyProverRequest.public_key_signatures_ed448:type_name -> quilibrium.node.keys.pb.Ed448Signature + 64, // 1: quilibrium.node.global.pb.ProverJoin.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581SignatureWithProofOfPossession 1, // 2: quilibrium.node.global.pb.ProverJoin.merge_targets:type_name -> quilibrium.node.global.pb.SeniorityMerge - 62, // 3: quilibrium.node.global.pb.ProverLeave.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AddressedSignature - 62, // 4: quilibrium.node.global.pb.ProverPause.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AddressedSignature - 62, // 5: quilibrium.node.global.pb.ProverResume.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AddressedSignature - 62, // 6: quilibrium.node.global.pb.ProverConfirm.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AddressedSignature - 62, // 7: quilibrium.node.global.pb.ProverUpdate.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AddressedSignature - 63, // 8: quilibrium.node.global.pb.ProverKick.traversal_proof:type_name -> quilibrium.node.application.pb.TraversalProof - 62, // 9: quilibrium.node.global.pb.ProverReject.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AddressedSignature + 65, // 3: quilibrium.node.global.pb.ProverLeave.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AddressedSignature + 65, // 4: quilibrium.node.global.pb.ProverPause.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AddressedSignature + 65, // 5: quilibrium.node.global.pb.ProverResume.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AddressedSignature + 65, // 6: quilibrium.node.global.pb.ProverConfirm.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AddressedSignature + 65, // 7: quilibrium.node.global.pb.ProverUpdate.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AddressedSignature + 66, // 8: quilibrium.node.global.pb.ProverKick.traversal_proof:type_name -> quilibrium.node.application.pb.TraversalProof + 65, // 9: quilibrium.node.global.pb.ProverReject.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AddressedSignature 2, // 10: quilibrium.node.global.pb.MessageRequest.join:type_name -> quilibrium.node.global.pb.ProverJoin 3, // 11: quilibrium.node.global.pb.MessageRequest.leave:type_name -> quilibrium.node.global.pb.ProverLeave 4, // 12: quilibrium.node.global.pb.MessageRequest.pause:type_name -> quilibrium.node.global.pb.ProverPause @@ -4862,28 +5128,28 @@ var file_global_proto_depIdxs = []int32{ 9, // 15: quilibrium.node.global.pb.MessageRequest.reject:type_name -> quilibrium.node.global.pb.ProverReject 8, // 16: quilibrium.node.global.pb.MessageRequest.kick:type_name -> quilibrium.node.global.pb.ProverKick 7, // 17: quilibrium.node.global.pb.MessageRequest.update:type_name -> quilibrium.node.global.pb.ProverUpdate - 64, // 18: quilibrium.node.global.pb.MessageRequest.token_deploy:type_name -> quilibrium.node.token.pb.TokenDeploy - 65, // 19: quilibrium.node.global.pb.MessageRequest.token_update:type_name -> quilibrium.node.token.pb.TokenUpdate - 66, // 20: quilibrium.node.global.pb.MessageRequest.transaction:type_name -> quilibrium.node.token.pb.Transaction - 67, // 21: quilibrium.node.global.pb.MessageRequest.pending_transaction:type_name -> quilibrium.node.token.pb.PendingTransaction - 68, // 22: quilibrium.node.global.pb.MessageRequest.mint_transaction:type_name -> quilibrium.node.token.pb.MintTransaction - 69, // 23: quilibrium.node.global.pb.MessageRequest.hypergraph_deploy:type_name -> quilibrium.node.hypergraph.pb.HypergraphDeploy - 70, // 24: quilibrium.node.global.pb.MessageRequest.hypergraph_update:type_name -> quilibrium.node.hypergraph.pb.HypergraphUpdate - 71, // 25: quilibrium.node.global.pb.MessageRequest.vertex_add:type_name -> quilibrium.node.hypergraph.pb.VertexAdd - 72, // 26: quilibrium.node.global.pb.MessageRequest.vertex_remove:type_name -> quilibrium.node.hypergraph.pb.VertexRemove - 73, // 27: quilibrium.node.global.pb.MessageRequest.hyperedge_add:type_name -> quilibrium.node.hypergraph.pb.HyperedgeAdd - 74, // 28: quilibrium.node.global.pb.MessageRequest.hyperedge_remove:type_name -> quilibrium.node.hypergraph.pb.HyperedgeRemove - 75, // 29: quilibrium.node.global.pb.MessageRequest.compute_deploy:type_name -> quilibrium.node.compute.pb.ComputeDeploy - 76, // 30: quilibrium.node.global.pb.MessageRequest.compute_update:type_name -> quilibrium.node.compute.pb.ComputeUpdate - 77, // 31: quilibrium.node.global.pb.MessageRequest.code_deploy:type_name -> quilibrium.node.compute.pb.CodeDeployment - 78, // 32: quilibrium.node.global.pb.MessageRequest.code_execute:type_name -> quilibrium.node.compute.pb.CodeExecute - 79, // 33: quilibrium.node.global.pb.MessageRequest.code_finalize:type_name -> quilibrium.node.compute.pb.CodeFinalize + 67, // 18: quilibrium.node.global.pb.MessageRequest.token_deploy:type_name -> quilibrium.node.token.pb.TokenDeploy + 68, // 19: quilibrium.node.global.pb.MessageRequest.token_update:type_name -> quilibrium.node.token.pb.TokenUpdate + 69, // 20: quilibrium.node.global.pb.MessageRequest.transaction:type_name -> quilibrium.node.token.pb.Transaction + 70, // 21: quilibrium.node.global.pb.MessageRequest.pending_transaction:type_name -> quilibrium.node.token.pb.PendingTransaction + 71, // 22: quilibrium.node.global.pb.MessageRequest.mint_transaction:type_name -> quilibrium.node.token.pb.MintTransaction + 72, // 23: quilibrium.node.global.pb.MessageRequest.hypergraph_deploy:type_name -> quilibrium.node.hypergraph.pb.HypergraphDeploy + 73, // 24: quilibrium.node.global.pb.MessageRequest.hypergraph_update:type_name -> quilibrium.node.hypergraph.pb.HypergraphUpdate + 74, // 25: quilibrium.node.global.pb.MessageRequest.vertex_add:type_name -> quilibrium.node.hypergraph.pb.VertexAdd + 75, // 26: quilibrium.node.global.pb.MessageRequest.vertex_remove:type_name -> quilibrium.node.hypergraph.pb.VertexRemove + 76, // 27: quilibrium.node.global.pb.MessageRequest.hyperedge_add:type_name -> quilibrium.node.hypergraph.pb.HyperedgeAdd + 77, // 28: quilibrium.node.global.pb.MessageRequest.hyperedge_remove:type_name -> quilibrium.node.hypergraph.pb.HyperedgeRemove + 78, // 29: quilibrium.node.global.pb.MessageRequest.compute_deploy:type_name -> quilibrium.node.compute.pb.ComputeDeploy + 79, // 30: quilibrium.node.global.pb.MessageRequest.compute_update:type_name -> quilibrium.node.compute.pb.ComputeUpdate + 80, // 31: quilibrium.node.global.pb.MessageRequest.code_deploy:type_name -> quilibrium.node.compute.pb.CodeDeployment + 81, // 32: quilibrium.node.global.pb.MessageRequest.code_execute:type_name -> quilibrium.node.compute.pb.CodeExecute + 82, // 33: quilibrium.node.global.pb.MessageRequest.code_finalize:type_name -> quilibrium.node.compute.pb.CodeFinalize 10, // 34: quilibrium.node.global.pb.MessageBundle.requests:type_name -> quilibrium.node.global.pb.MessageRequest - 80, // 35: quilibrium.node.global.pb.GlobalFrameHeader.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AggregateSignature - 80, // 36: quilibrium.node.global.pb.FrameHeader.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AggregateSignature - 62, // 37: quilibrium.node.global.pb.ProverLivenessCheck.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AddressedSignature - 62, // 38: quilibrium.node.global.pb.FrameVote.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AddressedSignature - 80, // 39: quilibrium.node.global.pb.FrameConfirmation.aggregate_signature:type_name -> quilibrium.node.keys.pb.BLS48581AggregateSignature + 83, // 35: quilibrium.node.global.pb.GlobalFrameHeader.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AggregateSignature + 83, // 36: quilibrium.node.global.pb.FrameHeader.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AggregateSignature + 65, // 37: quilibrium.node.global.pb.ProverLivenessCheck.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AddressedSignature + 65, // 38: quilibrium.node.global.pb.FrameVote.public_key_signature_bls48581:type_name -> quilibrium.node.keys.pb.BLS48581AddressedSignature + 83, // 39: quilibrium.node.global.pb.FrameConfirmation.aggregate_signature:type_name -> quilibrium.node.keys.pb.BLS48581AggregateSignature 12, // 40: quilibrium.node.global.pb.GlobalFrame.header:type_name -> quilibrium.node.global.pb.GlobalFrameHeader 11, // 41: quilibrium.node.global.pb.GlobalFrame.requests:type_name -> quilibrium.node.global.pb.MessageBundle 13, // 42: quilibrium.node.global.pb.AppShardFrame.header:type_name -> quilibrium.node.global.pb.FrameHeader @@ -4891,74 +5157,77 @@ var file_global_proto_depIdxs = []int32{ 17, // 44: quilibrium.node.global.pb.GlobalFrameResponse.frame:type_name -> quilibrium.node.global.pb.GlobalFrame 18, // 45: quilibrium.node.global.pb.AppShardFrameResponse.frame:type_name -> quilibrium.node.global.pb.AppShardFrame 25, // 46: quilibrium.node.global.pb.GetAppShardsResponse.info:type_name -> quilibrium.node.global.pb.AppShardInfo - 81, // 47: quilibrium.node.global.pb.GetKeyRegistryResponse.registry:type_name -> quilibrium.node.keys.pb.KeyRegistry - 81, // 48: quilibrium.node.global.pb.GetKeyRegistryByProverResponse.registry:type_name -> quilibrium.node.keys.pb.KeyRegistry - 82, // 49: quilibrium.node.global.pb.PutIdentityKeyRequest.identity_key:type_name -> quilibrium.node.keys.pb.Ed448PublicKey - 61, // 50: quilibrium.node.global.pb.PutProvingKeyRequest.proving_key:type_name -> quilibrium.node.keys.pb.BLS48581SignatureWithProofOfPossession - 83, // 51: quilibrium.node.global.pb.PutSignedKeyRequest.key:type_name -> quilibrium.node.keys.pb.SignedX448Key - 82, // 52: quilibrium.node.global.pb.GetIdentityKeyResponse.key:type_name -> quilibrium.node.keys.pb.Ed448PublicKey - 61, // 53: quilibrium.node.global.pb.GetProvingKeyResponse.key:type_name -> quilibrium.node.keys.pb.BLS48581SignatureWithProofOfPossession - 83, // 54: quilibrium.node.global.pb.GetSignedKeyResponse.key:type_name -> quilibrium.node.keys.pb.SignedX448Key - 83, // 55: quilibrium.node.global.pb.GetSignedKeysByParentResponse.keys:type_name -> quilibrium.node.keys.pb.SignedX448Key - 61, // 56: quilibrium.node.global.pb.RangeProvingKeysResponse.key:type_name -> quilibrium.node.keys.pb.BLS48581SignatureWithProofOfPossession - 82, // 57: quilibrium.node.global.pb.RangeIdentityKeysResponse.key:type_name -> quilibrium.node.keys.pb.Ed448PublicKey - 83, // 58: quilibrium.node.global.pb.RangeSignedKeysResponse.key:type_name -> quilibrium.node.keys.pb.SignedX448Key - 57, // 59: quilibrium.node.global.pb.PutMessageRequest.message_shards:type_name -> quilibrium.node.global.pb.MessageKeyShard - 20, // 60: quilibrium.node.global.pb.GlobalService.GetGlobalFrame:input_type -> quilibrium.node.global.pb.GetGlobalFrameRequest - 24, // 61: quilibrium.node.global.pb.GlobalService.GetAppShards:input_type -> quilibrium.node.global.pb.GetAppShardsRequest - 27, // 62: quilibrium.node.global.pb.GlobalService.GetGlobalShards:input_type -> quilibrium.node.global.pb.GetGlobalShardsRequest - 22, // 63: quilibrium.node.global.pb.AppShardService.GetAppShardFrame:input_type -> quilibrium.node.global.pb.GetAppShardFrameRequest - 29, // 64: quilibrium.node.global.pb.OnionService.Connect:input_type -> quilibrium.node.global.pb.SendMessage - 58, // 65: quilibrium.node.global.pb.MixnetService.PutMessage:input_type -> quilibrium.node.global.pb.PutMessageRequest - 84, // 66: quilibrium.node.global.pb.MixnetService.RoundStream:input_type -> quilibrium.node.application.pb.Message - 31, // 67: quilibrium.node.global.pb.KeyRegistryService.GetKeyRegistry:input_type -> quilibrium.node.global.pb.GetKeyRegistryRequest - 33, // 68: quilibrium.node.global.pb.KeyRegistryService.GetKeyRegistryByProver:input_type -> quilibrium.node.global.pb.GetKeyRegistryByProverRequest - 35, // 69: quilibrium.node.global.pb.KeyRegistryService.PutIdentityKey:input_type -> quilibrium.node.global.pb.PutIdentityKeyRequest - 37, // 70: quilibrium.node.global.pb.KeyRegistryService.PutProvingKey:input_type -> quilibrium.node.global.pb.PutProvingKeyRequest - 39, // 71: quilibrium.node.global.pb.KeyRegistryService.PutCrossSignature:input_type -> quilibrium.node.global.pb.PutCrossSignatureRequest - 41, // 72: quilibrium.node.global.pb.KeyRegistryService.PutSignedKey:input_type -> quilibrium.node.global.pb.PutSignedKeyRequest - 43, // 73: quilibrium.node.global.pb.KeyRegistryService.GetIdentityKey:input_type -> quilibrium.node.global.pb.GetIdentityKeyRequest - 45, // 74: quilibrium.node.global.pb.KeyRegistryService.GetProvingKey:input_type -> quilibrium.node.global.pb.GetProvingKeyRequest - 47, // 75: quilibrium.node.global.pb.KeyRegistryService.GetSignedKey:input_type -> quilibrium.node.global.pb.GetSignedKeyRequest - 49, // 76: quilibrium.node.global.pb.KeyRegistryService.GetSignedKeysByParent:input_type -> quilibrium.node.global.pb.GetSignedKeysByParentRequest - 51, // 77: quilibrium.node.global.pb.KeyRegistryService.RangeProvingKeys:input_type -> quilibrium.node.global.pb.RangeProvingKeysRequest - 53, // 78: quilibrium.node.global.pb.KeyRegistryService.RangeIdentityKeys:input_type -> quilibrium.node.global.pb.RangeIdentityKeysRequest - 55, // 79: quilibrium.node.global.pb.KeyRegistryService.RangeSignedKeys:input_type -> quilibrium.node.global.pb.RangeSignedKeysRequest - 85, // 80: quilibrium.node.global.pb.DispatchService.PutInboxMessage:input_type -> quilibrium.node.channel.pb.InboxMessagePut - 86, // 81: quilibrium.node.global.pb.DispatchService.GetInboxMessages:input_type -> quilibrium.node.channel.pb.InboxMessageRequest - 87, // 82: quilibrium.node.global.pb.DispatchService.PutHub:input_type -> quilibrium.node.channel.pb.HubPut - 88, // 83: quilibrium.node.global.pb.DispatchService.GetHub:input_type -> quilibrium.node.channel.pb.HubRequest - 89, // 84: quilibrium.node.global.pb.DispatchService.Sync:input_type -> quilibrium.node.channel.pb.DispatchSyncRequest - 21, // 85: quilibrium.node.global.pb.GlobalService.GetGlobalFrame:output_type -> quilibrium.node.global.pb.GlobalFrameResponse - 26, // 86: quilibrium.node.global.pb.GlobalService.GetAppShards:output_type -> quilibrium.node.global.pb.GetAppShardsResponse - 28, // 87: quilibrium.node.global.pb.GlobalService.GetGlobalShards:output_type -> quilibrium.node.global.pb.GetGlobalShardsResponse - 23, // 88: quilibrium.node.global.pb.AppShardService.GetAppShardFrame:output_type -> quilibrium.node.global.pb.AppShardFrameResponse - 30, // 89: quilibrium.node.global.pb.OnionService.Connect:output_type -> quilibrium.node.global.pb.ReceiveMessage - 59, // 90: quilibrium.node.global.pb.MixnetService.PutMessage:output_type -> quilibrium.node.global.pb.PutMessageResponse - 84, // 91: quilibrium.node.global.pb.MixnetService.RoundStream:output_type -> quilibrium.node.application.pb.Message - 32, // 92: quilibrium.node.global.pb.KeyRegistryService.GetKeyRegistry:output_type -> quilibrium.node.global.pb.GetKeyRegistryResponse - 34, // 93: quilibrium.node.global.pb.KeyRegistryService.GetKeyRegistryByProver:output_type -> quilibrium.node.global.pb.GetKeyRegistryByProverResponse - 36, // 94: quilibrium.node.global.pb.KeyRegistryService.PutIdentityKey:output_type -> quilibrium.node.global.pb.PutIdentityKeyResponse - 38, // 95: quilibrium.node.global.pb.KeyRegistryService.PutProvingKey:output_type -> quilibrium.node.global.pb.PutProvingKeyResponse - 40, // 96: quilibrium.node.global.pb.KeyRegistryService.PutCrossSignature:output_type -> quilibrium.node.global.pb.PutCrossSignatureResponse - 42, // 97: quilibrium.node.global.pb.KeyRegistryService.PutSignedKey:output_type -> quilibrium.node.global.pb.PutSignedKeyResponse - 44, // 98: quilibrium.node.global.pb.KeyRegistryService.GetIdentityKey:output_type -> quilibrium.node.global.pb.GetIdentityKeyResponse - 46, // 99: quilibrium.node.global.pb.KeyRegistryService.GetProvingKey:output_type -> quilibrium.node.global.pb.GetProvingKeyResponse - 48, // 100: quilibrium.node.global.pb.KeyRegistryService.GetSignedKey:output_type -> quilibrium.node.global.pb.GetSignedKeyResponse - 50, // 101: quilibrium.node.global.pb.KeyRegistryService.GetSignedKeysByParent:output_type -> quilibrium.node.global.pb.GetSignedKeysByParentResponse - 52, // 102: quilibrium.node.global.pb.KeyRegistryService.RangeProvingKeys:output_type -> quilibrium.node.global.pb.RangeProvingKeysResponse - 54, // 103: quilibrium.node.global.pb.KeyRegistryService.RangeIdentityKeys:output_type -> quilibrium.node.global.pb.RangeIdentityKeysResponse - 56, // 104: quilibrium.node.global.pb.KeyRegistryService.RangeSignedKeys:output_type -> quilibrium.node.global.pb.RangeSignedKeysResponse - 90, // 105: quilibrium.node.global.pb.DispatchService.PutInboxMessage:output_type -> google.protobuf.Empty - 91, // 106: quilibrium.node.global.pb.DispatchService.GetInboxMessages:output_type -> quilibrium.node.channel.pb.InboxMessageResponse - 90, // 107: quilibrium.node.global.pb.DispatchService.PutHub:output_type -> google.protobuf.Empty - 92, // 108: quilibrium.node.global.pb.DispatchService.GetHub:output_type -> quilibrium.node.channel.pb.HubResponse - 93, // 109: quilibrium.node.global.pb.DispatchService.Sync:output_type -> quilibrium.node.channel.pb.DispatchSyncResponse - 85, // [85:110] is the sub-list for method output_type - 60, // [60:85] is the sub-list for method input_type - 60, // [60:60] is the sub-list for extension type_name - 60, // [60:60] is the sub-list for extension extendee - 0, // [0:60] is the sub-list for field type_name + 30, // 47: quilibrium.node.global.pb.GetLockedAddressesResponse.transactions:type_name -> quilibrium.node.global.pb.LockedTransaction + 84, // 48: quilibrium.node.global.pb.GetKeyRegistryResponse.registry:type_name -> quilibrium.node.keys.pb.KeyRegistry + 84, // 49: quilibrium.node.global.pb.GetKeyRegistryByProverResponse.registry:type_name -> quilibrium.node.keys.pb.KeyRegistry + 85, // 50: quilibrium.node.global.pb.PutIdentityKeyRequest.identity_key:type_name -> quilibrium.node.keys.pb.Ed448PublicKey + 64, // 51: quilibrium.node.global.pb.PutProvingKeyRequest.proving_key:type_name -> quilibrium.node.keys.pb.BLS48581SignatureWithProofOfPossession + 86, // 52: quilibrium.node.global.pb.PutSignedKeyRequest.key:type_name -> quilibrium.node.keys.pb.SignedX448Key + 85, // 53: quilibrium.node.global.pb.GetIdentityKeyResponse.key:type_name -> quilibrium.node.keys.pb.Ed448PublicKey + 64, // 54: quilibrium.node.global.pb.GetProvingKeyResponse.key:type_name -> quilibrium.node.keys.pb.BLS48581SignatureWithProofOfPossession + 86, // 55: quilibrium.node.global.pb.GetSignedKeyResponse.key:type_name -> quilibrium.node.keys.pb.SignedX448Key + 86, // 56: quilibrium.node.global.pb.GetSignedKeysByParentResponse.keys:type_name -> quilibrium.node.keys.pb.SignedX448Key + 64, // 57: quilibrium.node.global.pb.RangeProvingKeysResponse.key:type_name -> quilibrium.node.keys.pb.BLS48581SignatureWithProofOfPossession + 85, // 58: quilibrium.node.global.pb.RangeIdentityKeysResponse.key:type_name -> quilibrium.node.keys.pb.Ed448PublicKey + 86, // 59: quilibrium.node.global.pb.RangeSignedKeysResponse.key:type_name -> quilibrium.node.keys.pb.SignedX448Key + 60, // 60: quilibrium.node.global.pb.PutMessageRequest.message_shards:type_name -> quilibrium.node.global.pb.MessageKeyShard + 20, // 61: quilibrium.node.global.pb.GlobalService.GetGlobalFrame:input_type -> quilibrium.node.global.pb.GetGlobalFrameRequest + 24, // 62: quilibrium.node.global.pb.GlobalService.GetAppShards:input_type -> quilibrium.node.global.pb.GetAppShardsRequest + 27, // 63: quilibrium.node.global.pb.GlobalService.GetGlobalShards:input_type -> quilibrium.node.global.pb.GetGlobalShardsRequest + 29, // 64: quilibrium.node.global.pb.GlobalService.GetLockedAddresses:input_type -> quilibrium.node.global.pb.GetLockedAddressesRequest + 22, // 65: quilibrium.node.global.pb.AppShardService.GetAppShardFrame:input_type -> quilibrium.node.global.pb.GetAppShardFrameRequest + 32, // 66: quilibrium.node.global.pb.OnionService.Connect:input_type -> quilibrium.node.global.pb.SendMessage + 61, // 67: quilibrium.node.global.pb.MixnetService.PutMessage:input_type -> quilibrium.node.global.pb.PutMessageRequest + 87, // 68: quilibrium.node.global.pb.MixnetService.RoundStream:input_type -> quilibrium.node.application.pb.Message + 34, // 69: quilibrium.node.global.pb.KeyRegistryService.GetKeyRegistry:input_type -> quilibrium.node.global.pb.GetKeyRegistryRequest + 36, // 70: quilibrium.node.global.pb.KeyRegistryService.GetKeyRegistryByProver:input_type -> quilibrium.node.global.pb.GetKeyRegistryByProverRequest + 38, // 71: quilibrium.node.global.pb.KeyRegistryService.PutIdentityKey:input_type -> quilibrium.node.global.pb.PutIdentityKeyRequest + 40, // 72: quilibrium.node.global.pb.KeyRegistryService.PutProvingKey:input_type -> quilibrium.node.global.pb.PutProvingKeyRequest + 42, // 73: quilibrium.node.global.pb.KeyRegistryService.PutCrossSignature:input_type -> quilibrium.node.global.pb.PutCrossSignatureRequest + 44, // 74: quilibrium.node.global.pb.KeyRegistryService.PutSignedKey:input_type -> quilibrium.node.global.pb.PutSignedKeyRequest + 46, // 75: quilibrium.node.global.pb.KeyRegistryService.GetIdentityKey:input_type -> quilibrium.node.global.pb.GetIdentityKeyRequest + 48, // 76: quilibrium.node.global.pb.KeyRegistryService.GetProvingKey:input_type -> quilibrium.node.global.pb.GetProvingKeyRequest + 50, // 77: quilibrium.node.global.pb.KeyRegistryService.GetSignedKey:input_type -> quilibrium.node.global.pb.GetSignedKeyRequest + 52, // 78: quilibrium.node.global.pb.KeyRegistryService.GetSignedKeysByParent:input_type -> quilibrium.node.global.pb.GetSignedKeysByParentRequest + 54, // 79: quilibrium.node.global.pb.KeyRegistryService.RangeProvingKeys:input_type -> quilibrium.node.global.pb.RangeProvingKeysRequest + 56, // 80: quilibrium.node.global.pb.KeyRegistryService.RangeIdentityKeys:input_type -> quilibrium.node.global.pb.RangeIdentityKeysRequest + 58, // 81: quilibrium.node.global.pb.KeyRegistryService.RangeSignedKeys:input_type -> quilibrium.node.global.pb.RangeSignedKeysRequest + 88, // 82: quilibrium.node.global.pb.DispatchService.PutInboxMessage:input_type -> quilibrium.node.channel.pb.InboxMessagePut + 89, // 83: quilibrium.node.global.pb.DispatchService.GetInboxMessages:input_type -> quilibrium.node.channel.pb.InboxMessageRequest + 90, // 84: quilibrium.node.global.pb.DispatchService.PutHub:input_type -> quilibrium.node.channel.pb.HubPut + 91, // 85: quilibrium.node.global.pb.DispatchService.GetHub:input_type -> quilibrium.node.channel.pb.HubRequest + 92, // 86: quilibrium.node.global.pb.DispatchService.Sync:input_type -> quilibrium.node.channel.pb.DispatchSyncRequest + 21, // 87: quilibrium.node.global.pb.GlobalService.GetGlobalFrame:output_type -> quilibrium.node.global.pb.GlobalFrameResponse + 26, // 88: quilibrium.node.global.pb.GlobalService.GetAppShards:output_type -> quilibrium.node.global.pb.GetAppShardsResponse + 28, // 89: quilibrium.node.global.pb.GlobalService.GetGlobalShards:output_type -> quilibrium.node.global.pb.GetGlobalShardsResponse + 31, // 90: quilibrium.node.global.pb.GlobalService.GetLockedAddresses:output_type -> quilibrium.node.global.pb.GetLockedAddressesResponse + 23, // 91: quilibrium.node.global.pb.AppShardService.GetAppShardFrame:output_type -> quilibrium.node.global.pb.AppShardFrameResponse + 33, // 92: quilibrium.node.global.pb.OnionService.Connect:output_type -> quilibrium.node.global.pb.ReceiveMessage + 62, // 93: quilibrium.node.global.pb.MixnetService.PutMessage:output_type -> quilibrium.node.global.pb.PutMessageResponse + 87, // 94: quilibrium.node.global.pb.MixnetService.RoundStream:output_type -> quilibrium.node.application.pb.Message + 35, // 95: quilibrium.node.global.pb.KeyRegistryService.GetKeyRegistry:output_type -> quilibrium.node.global.pb.GetKeyRegistryResponse + 37, // 96: quilibrium.node.global.pb.KeyRegistryService.GetKeyRegistryByProver:output_type -> quilibrium.node.global.pb.GetKeyRegistryByProverResponse + 39, // 97: quilibrium.node.global.pb.KeyRegistryService.PutIdentityKey:output_type -> quilibrium.node.global.pb.PutIdentityKeyResponse + 41, // 98: quilibrium.node.global.pb.KeyRegistryService.PutProvingKey:output_type -> quilibrium.node.global.pb.PutProvingKeyResponse + 43, // 99: quilibrium.node.global.pb.KeyRegistryService.PutCrossSignature:output_type -> quilibrium.node.global.pb.PutCrossSignatureResponse + 45, // 100: quilibrium.node.global.pb.KeyRegistryService.PutSignedKey:output_type -> quilibrium.node.global.pb.PutSignedKeyResponse + 47, // 101: quilibrium.node.global.pb.KeyRegistryService.GetIdentityKey:output_type -> quilibrium.node.global.pb.GetIdentityKeyResponse + 49, // 102: quilibrium.node.global.pb.KeyRegistryService.GetProvingKey:output_type -> quilibrium.node.global.pb.GetProvingKeyResponse + 51, // 103: quilibrium.node.global.pb.KeyRegistryService.GetSignedKey:output_type -> quilibrium.node.global.pb.GetSignedKeyResponse + 53, // 104: quilibrium.node.global.pb.KeyRegistryService.GetSignedKeysByParent:output_type -> quilibrium.node.global.pb.GetSignedKeysByParentResponse + 55, // 105: quilibrium.node.global.pb.KeyRegistryService.RangeProvingKeys:output_type -> quilibrium.node.global.pb.RangeProvingKeysResponse + 57, // 106: quilibrium.node.global.pb.KeyRegistryService.RangeIdentityKeys:output_type -> quilibrium.node.global.pb.RangeIdentityKeysResponse + 59, // 107: quilibrium.node.global.pb.KeyRegistryService.RangeSignedKeys:output_type -> quilibrium.node.global.pb.RangeSignedKeysResponse + 93, // 108: quilibrium.node.global.pb.DispatchService.PutInboxMessage:output_type -> google.protobuf.Empty + 94, // 109: quilibrium.node.global.pb.DispatchService.GetInboxMessages:output_type -> quilibrium.node.channel.pb.InboxMessageResponse + 93, // 110: quilibrium.node.global.pb.DispatchService.PutHub:output_type -> google.protobuf.Empty + 95, // 111: quilibrium.node.global.pb.DispatchService.GetHub:output_type -> quilibrium.node.channel.pb.HubResponse + 96, // 112: quilibrium.node.global.pb.DispatchService.Sync:output_type -> quilibrium.node.channel.pb.DispatchSyncResponse + 87, // [87:113] is the sub-list for method output_type + 61, // [61:87] is the sub-list for method input_type + 61, // [61:61] is the sub-list for extension type_name + 61, // [61:61] is the sub-list for extension extendee + 0, // [0:61] is the sub-list for field type_name } func init() { file_global_proto_init() } @@ -5322,7 +5591,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SendMessage); i { + switch v := v.(*GetLockedAddressesRequest); i { case 0: return &v.state case 1: @@ -5334,7 +5603,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReceiveMessage); i { + switch v := v.(*LockedTransaction); i { case 0: return &v.state case 1: @@ -5346,7 +5615,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetKeyRegistryRequest); i { + switch v := v.(*GetLockedAddressesResponse); i { case 0: return &v.state case 1: @@ -5358,7 +5627,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetKeyRegistryResponse); i { + switch v := v.(*SendMessage); i { case 0: return &v.state case 1: @@ -5370,7 +5639,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetKeyRegistryByProverRequest); i { + switch v := v.(*ReceiveMessage); i { case 0: return &v.state case 1: @@ -5382,7 +5651,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetKeyRegistryByProverResponse); i { + switch v := v.(*GetKeyRegistryRequest); i { case 0: return &v.state case 1: @@ -5394,7 +5663,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PutIdentityKeyRequest); i { + switch v := v.(*GetKeyRegistryResponse); i { case 0: return &v.state case 1: @@ -5406,7 +5675,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PutIdentityKeyResponse); i { + switch v := v.(*GetKeyRegistryByProverRequest); i { case 0: return &v.state case 1: @@ -5418,7 +5687,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PutProvingKeyRequest); i { + switch v := v.(*GetKeyRegistryByProverResponse); i { case 0: return &v.state case 1: @@ -5430,7 +5699,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PutProvingKeyResponse); i { + switch v := v.(*PutIdentityKeyRequest); i { case 0: return &v.state case 1: @@ -5442,7 +5711,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PutCrossSignatureRequest); i { + switch v := v.(*PutIdentityKeyResponse); i { case 0: return &v.state case 1: @@ -5454,7 +5723,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PutCrossSignatureResponse); i { + switch v := v.(*PutProvingKeyRequest); i { case 0: return &v.state case 1: @@ -5466,7 +5735,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PutSignedKeyRequest); i { + switch v := v.(*PutProvingKeyResponse); i { case 0: return &v.state case 1: @@ -5478,7 +5747,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PutSignedKeyResponse); i { + switch v := v.(*PutCrossSignatureRequest); i { case 0: return &v.state case 1: @@ -5490,7 +5759,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetIdentityKeyRequest); i { + switch v := v.(*PutCrossSignatureResponse); i { case 0: return &v.state case 1: @@ -5502,7 +5771,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetIdentityKeyResponse); i { + switch v := v.(*PutSignedKeyRequest); i { case 0: return &v.state case 1: @@ -5514,7 +5783,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetProvingKeyRequest); i { + switch v := v.(*PutSignedKeyResponse); i { case 0: return &v.state case 1: @@ -5526,7 +5795,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetProvingKeyResponse); i { + switch v := v.(*GetIdentityKeyRequest); i { case 0: return &v.state case 1: @@ -5538,7 +5807,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSignedKeyRequest); i { + switch v := v.(*GetIdentityKeyResponse); i { case 0: return &v.state case 1: @@ -5550,7 +5819,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSignedKeyResponse); i { + switch v := v.(*GetProvingKeyRequest); i { case 0: return &v.state case 1: @@ -5562,7 +5831,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSignedKeysByParentRequest); i { + switch v := v.(*GetProvingKeyResponse); i { case 0: return &v.state case 1: @@ -5574,7 +5843,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSignedKeysByParentResponse); i { + switch v := v.(*GetSignedKeyRequest); i { case 0: return &v.state case 1: @@ -5586,7 +5855,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RangeProvingKeysRequest); i { + switch v := v.(*GetSignedKeyResponse); i { case 0: return &v.state case 1: @@ -5598,7 +5867,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RangeProvingKeysResponse); i { + switch v := v.(*GetSignedKeysByParentRequest); i { case 0: return &v.state case 1: @@ -5610,7 +5879,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RangeIdentityKeysRequest); i { + switch v := v.(*GetSignedKeysByParentResponse); i { case 0: return &v.state case 1: @@ -5622,7 +5891,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RangeIdentityKeysResponse); i { + switch v := v.(*RangeProvingKeysRequest); i { case 0: return &v.state case 1: @@ -5634,7 +5903,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RangeSignedKeysRequest); i { + switch v := v.(*RangeProvingKeysResponse); i { case 0: return &v.state case 1: @@ -5646,7 +5915,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RangeSignedKeysResponse); i { + switch v := v.(*RangeIdentityKeysRequest); i { case 0: return &v.state case 1: @@ -5658,7 +5927,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MessageKeyShard); i { + switch v := v.(*RangeIdentityKeysResponse); i { case 0: return &v.state case 1: @@ -5670,7 +5939,7 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PutMessageRequest); i { + switch v := v.(*RangeSignedKeysRequest); i { case 0: return &v.state case 1: @@ -5682,6 +5951,42 @@ func file_global_proto_init() { } } file_global_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RangeSignedKeysResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_global_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MessageKeyShard); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_global_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PutMessageRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_global_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PutMessageResponse); i { case 0: return &v.state @@ -5726,7 +6031,7 @@ func file_global_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_global_proto_rawDesc, NumEnums: 0, - NumMessages: 60, + NumMessages: 63, NumExtensions: 0, NumServices: 6, }, diff --git a/protobufs/global.pb.gw.go b/protobufs/global.pb.gw.go index 323a2b79..e1f9d48a 100644 --- a/protobufs/global.pb.gw.go +++ b/protobufs/global.pb.gw.go @@ -133,6 +133,40 @@ func local_request_GlobalService_GetGlobalShards_0(ctx context.Context, marshale } +func request_GlobalService_GetLockedAddresses_0(ctx context.Context, marshaler runtime.Marshaler, client GlobalServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetLockedAddressesRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.GetLockedAddresses(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_GlobalService_GetLockedAddresses_0(ctx context.Context, marshaler runtime.Marshaler, server GlobalServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetLockedAddressesRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.GetLockedAddresses(ctx, &protoReq) + return msg, metadata, err + +} + func request_AppShardService_GetAppShardFrame_0(ctx context.Context, marshaler runtime.Marshaler, client AppShardServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq GetAppShardFrameRequest var metadata runtime.ServerMetadata @@ -980,6 +1014,31 @@ func RegisterGlobalServiceHandlerServer(ctx context.Context, mux *runtime.ServeM }) + mux.Handle("POST", pattern_GlobalService_GetLockedAddresses_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/quilibrium.node.global.pb.GlobalService/GetLockedAddresses", runtime.WithHTTPPathPattern("/quilibrium.node.global.pb.GlobalService/GetLockedAddresses")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_GlobalService_GetLockedAddresses_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_GlobalService_GetLockedAddresses_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1646,6 +1705,28 @@ func RegisterGlobalServiceHandlerClient(ctx context.Context, mux *runtime.ServeM }) + mux.Handle("POST", pattern_GlobalService_GetLockedAddresses_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/quilibrium.node.global.pb.GlobalService/GetLockedAddresses", runtime.WithHTTPPathPattern("/quilibrium.node.global.pb.GlobalService/GetLockedAddresses")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_GlobalService_GetLockedAddresses_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_GlobalService_GetLockedAddresses_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1655,6 +1736,8 @@ var ( pattern_GlobalService_GetAppShards_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"quilibrium.node.global.pb.GlobalService", "GetAppShards"}, "")) pattern_GlobalService_GetGlobalShards_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"quilibrium.node.global.pb.GlobalService", "GetGlobalShards"}, "")) + + pattern_GlobalService_GetLockedAddresses_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"quilibrium.node.global.pb.GlobalService", "GetLockedAddresses"}, "")) ) var ( @@ -1663,6 +1746,8 @@ var ( forward_GlobalService_GetAppShards_0 = runtime.ForwardResponseMessage forward_GlobalService_GetGlobalShards_0 = runtime.ForwardResponseMessage + + forward_GlobalService_GetLockedAddresses_0 = runtime.ForwardResponseMessage ) // RegisterAppShardServiceHandlerFromEndpoint is same as RegisterAppShardServiceHandler but diff --git a/protobufs/global.proto b/protobufs/global.proto index af988090..1edfc69e 100644 --- a/protobufs/global.proto +++ b/protobufs/global.proto @@ -28,6 +28,7 @@ message ProverJoin { quilibrium.node.keys.pb.BLS48581SignatureWithProofOfPossession public_key_signature_bls48581 = 3; bytes delegate_address = 4; repeated SeniorityMerge merge_targets = 5; + bytes proof = 6; } message ProverLeave { @@ -204,23 +205,31 @@ message ProverLivenessCheck { } message FrameVote { + // The filter for the prover's commitment in the trie + bytes filter = 1; // The frame number being voted on - uint64 frame_number = 1; + uint64 frame_number = 2; // The proposer of the frame - bytes proposer = 2; + bytes proposer = 3; // Whether the voter approves the frame - bool approve = 3; + bool approve = 4; + // The timestamp when the vote was created + int64 timestamp = 5; // The BLS signature with the voter's address - quilibrium.node.keys.pb.BLS48581AddressedSignature public_key_signature_bls48581 = 4; + quilibrium.node.keys.pb.BLS48581AddressedSignature public_key_signature_bls48581 = 6; } message FrameConfirmation { + // The filter for the prover's commitment in the trie + bytes filter = 1; // The frame number that was confirmed - uint64 frame_number = 1; + uint64 frame_number = 2; // The selector (hash) of the confirmed frame - bytes selector = 2; + bytes selector = 3; + // The timestamp when the vote was created + int64 timestamp = 4; // The aggregated BLS signature from all voters - quilibrium.node.keys.pb.BLS48581AggregateSignature aggregate_signature = 3; + quilibrium.node.keys.pb.BLS48581AggregateSignature aggregate_signature = 5; } message GlobalFrame { @@ -283,10 +292,34 @@ message GetGlobalShardsResponse { repeated bytes commitment = 2; } +message GetLockedAddressesRequest { + // The shard address identifier, in split L2||nibbles form + bytes shard_address = 1; + // The frame number of the locked address request, to disambiguate early/late + // requests + uint64 frame_number = 2; +} + +message LockedTransaction { + // The hash of the locked transaction + bytes transaction_hash = 1; + // The shard address identifier the lock covers, in split L2||nibbles form + repeated bytes shard_addresses = 2; + // Whether all shard addresses impacted have committed to this value + bool committed = 3; + // Whether the proposed frames had a winning weight witness + bool filled = 4; +} + +message GetLockedAddressesResponse { + repeated LockedTransaction transactions = 1; +} + service GlobalService { rpc GetGlobalFrame (GetGlobalFrameRequest) returns (GlobalFrameResponse); rpc GetAppShards(GetAppShardsRequest) returns (GetAppShardsResponse); rpc GetGlobalShards(GetGlobalShardsRequest) returns (GetGlobalShardsResponse); + rpc GetLockedAddresses(GetLockedAddressesRequest) returns (GetLockedAddressesResponse); } service AppShardService { @@ -531,4 +564,4 @@ service DispatchService { // Synchronize dispatch data rpc Sync(quilibrium.node.channel.pb.DispatchSyncRequest) returns (quilibrium.node.channel.pb.DispatchSyncResponse); -} \ No newline at end of file +} diff --git a/protobufs/global_grpc.pb.go b/protobufs/global_grpc.pb.go index 398c000e..ef448422 100644 --- a/protobufs/global_grpc.pb.go +++ b/protobufs/global_grpc.pb.go @@ -20,9 +20,10 @@ import ( const _ = grpc.SupportPackageIsVersion7 const ( - GlobalService_GetGlobalFrame_FullMethodName = "/quilibrium.node.global.pb.GlobalService/GetGlobalFrame" - GlobalService_GetAppShards_FullMethodName = "/quilibrium.node.global.pb.GlobalService/GetAppShards" - GlobalService_GetGlobalShards_FullMethodName = "/quilibrium.node.global.pb.GlobalService/GetGlobalShards" + GlobalService_GetGlobalFrame_FullMethodName = "/quilibrium.node.global.pb.GlobalService/GetGlobalFrame" + GlobalService_GetAppShards_FullMethodName = "/quilibrium.node.global.pb.GlobalService/GetAppShards" + GlobalService_GetGlobalShards_FullMethodName = "/quilibrium.node.global.pb.GlobalService/GetGlobalShards" + GlobalService_GetLockedAddresses_FullMethodName = "/quilibrium.node.global.pb.GlobalService/GetLockedAddresses" ) // GlobalServiceClient is the client API for GlobalService service. @@ -32,6 +33,7 @@ type GlobalServiceClient interface { GetGlobalFrame(ctx context.Context, in *GetGlobalFrameRequest, opts ...grpc.CallOption) (*GlobalFrameResponse, error) GetAppShards(ctx context.Context, in *GetAppShardsRequest, opts ...grpc.CallOption) (*GetAppShardsResponse, error) GetGlobalShards(ctx context.Context, in *GetGlobalShardsRequest, opts ...grpc.CallOption) (*GetGlobalShardsResponse, error) + GetLockedAddresses(ctx context.Context, in *GetLockedAddressesRequest, opts ...grpc.CallOption) (*GetLockedAddressesResponse, error) } type globalServiceClient struct { @@ -69,6 +71,15 @@ func (c *globalServiceClient) GetGlobalShards(ctx context.Context, in *GetGlobal return out, nil } +func (c *globalServiceClient) GetLockedAddresses(ctx context.Context, in *GetLockedAddressesRequest, opts ...grpc.CallOption) (*GetLockedAddressesResponse, error) { + out := new(GetLockedAddressesResponse) + err := c.cc.Invoke(ctx, GlobalService_GetLockedAddresses_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // GlobalServiceServer is the server API for GlobalService service. // All implementations must embed UnimplementedGlobalServiceServer // for forward compatibility @@ -76,6 +87,7 @@ type GlobalServiceServer interface { GetGlobalFrame(context.Context, *GetGlobalFrameRequest) (*GlobalFrameResponse, error) GetAppShards(context.Context, *GetAppShardsRequest) (*GetAppShardsResponse, error) GetGlobalShards(context.Context, *GetGlobalShardsRequest) (*GetGlobalShardsResponse, error) + GetLockedAddresses(context.Context, *GetLockedAddressesRequest) (*GetLockedAddressesResponse, error) mustEmbedUnimplementedGlobalServiceServer() } @@ -92,6 +104,9 @@ func (UnimplementedGlobalServiceServer) GetAppShards(context.Context, *GetAppSha func (UnimplementedGlobalServiceServer) GetGlobalShards(context.Context, *GetGlobalShardsRequest) (*GetGlobalShardsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetGlobalShards not implemented") } +func (UnimplementedGlobalServiceServer) GetLockedAddresses(context.Context, *GetLockedAddressesRequest) (*GetLockedAddressesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetLockedAddresses not implemented") +} func (UnimplementedGlobalServiceServer) mustEmbedUnimplementedGlobalServiceServer() {} // UnsafeGlobalServiceServer may be embedded to opt out of forward compatibility for this service. @@ -159,6 +174,24 @@ func _GlobalService_GetGlobalShards_Handler(srv interface{}, ctx context.Context return interceptor(ctx, in, info, handler) } +func _GlobalService_GetLockedAddresses_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetLockedAddressesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GlobalServiceServer).GetLockedAddresses(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: GlobalService_GetLockedAddresses_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GlobalServiceServer).GetLockedAddresses(ctx, req.(*GetLockedAddressesRequest)) + } + return interceptor(ctx, in, info, handler) +} + // GlobalService_ServiceDesc is the grpc.ServiceDesc for GlobalService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -178,6 +211,10 @@ var GlobalService_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetGlobalShards", Handler: _GlobalService_GetGlobalShards_Handler, }, + { + MethodName: "GetLockedAddresses", + Handler: _GlobalService_GetLockedAddresses_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "global.proto", diff --git a/protobufs/keys.go b/protobufs/keys.go index 410a3706..78730185 100644 --- a/protobufs/keys.go +++ b/protobufs/keys.go @@ -165,6 +165,106 @@ func (s *SignedX448Key) Validate() error { return nil } +func (s *SignedDecaf448Key) Validate() error { + if s == nil { + return errors.New("nil signed decaf448 key") + } + + // Check key exists and has valid length + if s.Key == nil { + return errors.Wrap( + errors.New("nil decaf448 key"), + "validate", + ) + } + if len(s.Key.KeyValue) != 56 { + return errors.Wrap( + errors.New("invalid decaf448 key length"), + "validate", + ) + } + + // Parent key address should be 32 bytes + if len(s.ParentKeyAddress) != 32 { + return errors.Wrap( + errors.New("invalid parent key address length"), + "validate", + ) + } + + // Must have a signature + switch sig := s.Signature.(type) { + case *SignedDecaf448Key_Ed448Signature: + if sig.Ed448Signature == nil { + return errors.Wrap( + errors.New("nil ed448 signature"), + "validate", + ) + } + // Ed448Signature has its own Validate method + if err := sig.Ed448Signature.Validate(); err != nil { + return errors.Wrap( + errors.Wrap(err, "ed448 signature"), + "validate", + ) + } + case *SignedDecaf448Key_BlsSignature: + if sig.BlsSignature == nil { + return errors.Wrap( + errors.New("nil bls signature"), + "validate", + ) + } + // BLS48581Signature validation + if len(sig.BlsSignature.Signature) != 74 { + return errors.Wrap( + errors.New("invalid bls signature length"), + "validate", + ) + } + if sig.BlsSignature.PublicKey != nil && + len(sig.BlsSignature.PublicKey.KeyValue) != 585 { + return errors.Wrap( + errors.New("invalid bls public key length"), + "validate", + ) + } + case *SignedDecaf448Key_DecafSignature: + if sig.DecafSignature == nil { + return errors.Wrap( + errors.New("nil decaf signature"), + "validate", + ) + } + // Decaf448Signature validation + if len(sig.DecafSignature.Signature) != 112 { + return errors.Wrap( + errors.New("invalid decaf signature length"), + "validate", + ) + } + if sig.DecafSignature.PublicKey != nil && + len(sig.DecafSignature.PublicKey.KeyValue) != 56 { + return errors.Wrap( + errors.New("invalid decaf public key length"), + "validate", + ) + } + case nil: + return errors.Wrap( + errors.New("no signature specified"), + "validate", + ) + default: + return errors.Wrap( + errors.New("unknown signature type"), + "validate", + ) + } + + return nil +} + func (k *KeyCollection) Validate() error { if k == nil { return errors.Wrap(errors.New("nil key collection"), "validate") @@ -175,8 +275,15 @@ func (k *KeyCollection) Validate() error { return errors.Wrap(errors.New("empty key purpose"), "validate") } - // Validate all keys - for i, key := range k.Keys { + // Validate all x448 keys + for i, key := range k.X448Keys { + if err := key.Validate(); err != nil { + return errors.Wrap(errors.Wrapf(err, "key %d", i), "validate") + } + } + + // Validate all decaf448 keys + for i, key := range k.Decaf448Keys { if err := key.Validate(); err != nil { return errors.Wrap(errors.Wrapf(err, "key %d", i), "validate") } @@ -405,6 +512,124 @@ func (s *SignedX448Key) Verify( return nil } +func (s *SignedDecaf448Key) Verify( + context []byte, + blsVerifier BlsVerifier, + schnorrVerifier SchnorrVerifier, +) error { + if s == nil { + return errors.Wrap(errors.New("nil signed x448 key"), "verify") + } + + if s.Key == nil { + return errors.Wrap(errors.New("key nil"), "verify") + } + + if len(s.Key.KeyValue) != 56 { + return errors.Wrap(errors.New("invalid length for key"), "verify") + } + + if len(s.ParentKeyAddress) == 0 { + return errors.Wrap(errors.New("parent key address required"), "verify") + } + + // Verify signature and check that parent key address matches + switch sig := s.Signature.(type) { + case *SignedDecaf448Key_Ed448Signature: + if sig.Ed448Signature == nil || sig.Ed448Signature.PublicKey == nil { + return errors.Wrap( + errors.New("ed448 signature or public key nil"), + "verify", + ) + } + + // Verify the signature + if err := sig.Ed448Signature.Verify(s.Key.KeyValue, context); err != nil { + return errors.Wrap(err, "verify signature") + } + + // Check that parent key address matches the public key + addrBI, err := poseidon.HashBytes(sig.Ed448Signature.PublicKey.KeyValue) + if err != nil { + return errors.Wrap(err, "compute address from public key") + } + addressToCheck := addrBI.FillBytes(make([]byte, 32)) + if !bytes.Equal(addressToCheck, s.ParentKeyAddress) { + return errors.Wrap( + errors.New("parent key address does not match public key"), + "verify", + ) + } + + case *SignedDecaf448Key_BlsSignature: + if sig.BlsSignature == nil || sig.BlsSignature.PublicKey == nil { + return errors.Wrap( + errors.New("bls signature or public key nil"), + "verify", + ) + } + + // Verify the signature + if err := sig.BlsSignature.Verify( + s.Key.KeyValue, + context, + blsVerifier, + ); err != nil { + return errors.Wrap(err, "verify") + } + + // Check that parent key address matches the public key + addrBI, err := poseidon.HashBytes(sig.BlsSignature.PublicKey.KeyValue) + if err != nil { + return errors.Wrap(err, "verify") + } + addressToCheck := addrBI.FillBytes(make([]byte, 32)) + if !bytes.Equal(addressToCheck, s.ParentKeyAddress) { + return errors.Wrap( + errors.New("parent key address does not match public key"), + "verify", + ) + } + + case *SignedDecaf448Key_DecafSignature: + if sig.DecafSignature == nil || sig.DecafSignature.PublicKey == nil { + return errors.Wrap( + errors.New("decaf signature or public key nil"), + "verify", + ) + } + + // Verify the signature + if err := sig.DecafSignature.Verify( + s.Key.KeyValue, + context, + schnorrVerifier, + ); err != nil { + return errors.Wrap(err, "verify") + } + + // Check that parent key address matches the public key + addrBI, err := poseidon.HashBytes(sig.DecafSignature.PublicKey.KeyValue) + if err != nil { + return errors.Wrap(err, "verify") + } + addressToCheck := addrBI.FillBytes(make([]byte, 32)) + if !bytes.Equal(addressToCheck, s.ParentKeyAddress) { + return errors.Wrap( + errors.New("parent key address does not match public key"), + "verify", + ) + } + + case nil: + return errors.Wrap(errors.New("no signature"), "verify") + default: + return errors.Wrap(errors.New("unknown signature type"), "verify") + } + + return nil +} + // ToCanonicalBytes serializes an Ed448PublicKey to canonical bytes func (e *Ed448PublicKey) ToCanonicalBytes() ([]byte, error) { buf := new(bytes.Buffer) @@ -1470,6 +1695,256 @@ func (s *SignedX448Key) FromCanonicalBytes(data []byte) error { return nil } +// ToCanonicalBytes serializes a SignedDecaf448Key to canonical bytes +func (s *SignedDecaf448Key) ToCanonicalBytes() ([]byte, error) { + buf := new(bytes.Buffer) + + // Write type prefix + if err := binary.Write( + buf, + binary.BigEndian, + SignedDecaf448KeyType, + ); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + + // Write key + if s.Key != nil { + keyBytes, err := s.Key.ToCanonicalBytes() + if err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + if err := binary.Write( + buf, + binary.BigEndian, + uint32(len(keyBytes)), + ); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + if _, err := buf.Write(keyBytes); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + } else { + if err := binary.Write(buf, binary.BigEndian, uint32(0)); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + } + + // Write parent_key_address + if err := binary.Write( + buf, + binary.BigEndian, + uint32(len(s.ParentKeyAddress)), + ); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + if _, err := buf.Write(s.ParentKeyAddress); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + + // Write signature type and data + switch sig := s.Signature.(type) { + case *SignedDecaf448Key_Ed448Signature: + // Type 1 for Ed448 signature + if err := binary.Write(buf, binary.BigEndian, uint8(1)); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + sigBytes, err := sig.Ed448Signature.ToCanonicalBytes() + if err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + if err := binary.Write( + buf, + binary.BigEndian, + uint32(len(sigBytes)), + ); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + if _, err := buf.Write(sigBytes); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + case *SignedDecaf448Key_BlsSignature: + // Type 2 for BLS signature + if err := binary.Write(buf, binary.BigEndian, uint8(2)); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + sigBytes, err := sig.BlsSignature.ToCanonicalBytes() + if err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + if err := binary.Write( + buf, + binary.BigEndian, + uint32(len(sigBytes)), + ); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + if _, err := buf.Write(sigBytes); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + case *SignedDecaf448Key_DecafSignature: + // Type 3 for Decaf signature + if err := binary.Write(buf, binary.BigEndian, uint8(3)); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + sigBytes, err := sig.DecafSignature.ToCanonicalBytes() + if err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + if err := binary.Write( + buf, + binary.BigEndian, + uint32(len(sigBytes)), + ); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + if _, err := buf.Write(sigBytes); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + default: + // Type 0 for nil + if err := binary.Write(buf, binary.BigEndian, uint8(0)); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + } + + // Write created_at + if err := binary.Write(buf, binary.BigEndian, s.CreatedAt); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + + // Write expires_at + if err := binary.Write(buf, binary.BigEndian, s.ExpiresAt); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + + // Write key_purpose + purposeBytes := []byte(s.KeyPurpose) + if err := binary.Write( + buf, + binary.BigEndian, + uint32(len(purposeBytes)), + ); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + if _, err := buf.Write(purposeBytes); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + + return buf.Bytes(), nil +} + +// FromCanonicalBytes deserializes a SignedDecaf448Key from canonical bytes +func (s *SignedDecaf448Key) FromCanonicalBytes(data []byte) error { + buf := bytes.NewBuffer(data) + + // Read and verify type prefix + var typePrefix uint32 + if err := binary.Read(buf, binary.BigEndian, &typePrefix); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + if typePrefix != SignedDecaf448KeyType { + return errors.Wrap( + errors.New("invalid type prefix"), + "from canonical bytes", + ) + } + + // Read key + var keyLen uint32 + if err := binary.Read(buf, binary.BigEndian, &keyLen); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + if keyLen > 0 { + keyBytes := make([]byte, keyLen) + if _, err := buf.Read(keyBytes); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + s.Key = &Decaf448PublicKey{} + if err := s.Key.FromCanonicalBytes(keyBytes); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + } + + // Read parent_key_address + var parentKeyAddressLen uint32 + if err := binary.Read( + buf, + binary.BigEndian, + &parentKeyAddressLen, + ); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + s.ParentKeyAddress = make([]byte, parentKeyAddressLen) + if _, err := buf.Read(s.ParentKeyAddress); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + + // Read signature type + var sigType uint8 + if err := binary.Read(buf, binary.BigEndian, &sigType); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + + // Read signature data based on type + if sigType > 0 { + var sigLen uint32 + if err := binary.Read(buf, binary.BigEndian, &sigLen); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + sigBytes := make([]byte, sigLen) + if _, err := buf.Read(sigBytes); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + + switch sigType { + case 1: + ed448Sig := &Ed448Signature{} + if err := ed448Sig.FromCanonicalBytes(sigBytes); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + s.Signature = &SignedDecaf448Key_Ed448Signature{ + Ed448Signature: ed448Sig, + } + case 2: + blsSig := &BLS48581Signature{} + if err := blsSig.FromCanonicalBytes(sigBytes); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + s.Signature = &SignedDecaf448Key_BlsSignature{BlsSignature: blsSig} + case 3: + decafSig := &Decaf448Signature{} + if err := decafSig.FromCanonicalBytes(sigBytes); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + s.Signature = &SignedDecaf448Key_DecafSignature{DecafSignature: decafSig} + } + } + + // Read created_at + if err := binary.Read(buf, binary.BigEndian, &s.CreatedAt); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + + // Read expires_at + if err := binary.Read(buf, binary.BigEndian, &s.ExpiresAt); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + + // Read key_purpose + var purposeLen uint32 + if err := binary.Read(buf, binary.BigEndian, &purposeLen); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + purposeBytes := make([]byte, purposeLen) + if _, err := buf.Read(purposeBytes); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + s.KeyPurpose = string(purposeBytes) + + return nil +} + // Validate checks that all fields have valid lengths func (e *Ed448PrivateKey) Validate() error { if e == nil { @@ -1770,17 +2245,44 @@ func (k *KeyCollection) ToCanonicalBytes() ([]byte, error) { return nil, errors.Wrap(err, "to canonical bytes") } - // Write keys count + // Write x448 keys count + if err := binary.Write( + buf, + binary.BigEndian, + uint32(len(k.X448Keys)), + ); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + + // Write each x448 key + for _, key := range k.X448Keys { + keyBytes, err := key.ToCanonicalBytes() + if err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + if err := binary.Write( + buf, + binary.BigEndian, + uint32(len(keyBytes)), + ); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + if _, err := buf.Write(keyBytes); err != nil { + return nil, errors.Wrap(err, "to canonical bytes") + } + } + + // Write decaf448 keys count if err := binary.Write( buf, binary.BigEndian, - uint32(len(k.Keys)), + uint32(len(k.Decaf448Keys)), ); err != nil { return nil, errors.Wrap(err, "to canonical bytes") } - // Write each key - for _, key := range k.Keys { + // Write each decaf448 key + for _, key := range k.Decaf448Keys { keyBytes, err := key.ToCanonicalBytes() if err != nil { return nil, errors.Wrap(err, "to canonical bytes") @@ -1827,15 +2329,38 @@ func (k *KeyCollection) FromCanonicalBytes(data []byte) error { } k.KeyPurpose = string(purposeBytes) - // Read keys count - var keysCount uint32 - if err := binary.Read(buf, binary.BigEndian, &keysCount); err != nil { + // Read x448 keys count + var x448KeysCount uint32 + if err := binary.Read(buf, binary.BigEndian, &x448KeysCount); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + + // Read each key + k.X448Keys = make([]*SignedX448Key, x448KeysCount) + for i := uint32(0); i < x448KeysCount; i++ { + var keyLen uint32 + if err := binary.Read(buf, binary.BigEndian, &keyLen); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + keyBytes := make([]byte, keyLen) + if _, err := buf.Read(keyBytes); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + k.X448Keys[i] = &SignedX448Key{} + if err := k.X448Keys[i].FromCanonicalBytes(keyBytes); err != nil { + return errors.Wrap(err, "from canonical bytes") + } + } + + // Read decaf448 keys count + var decaf448KeysCount uint32 + if err := binary.Read(buf, binary.BigEndian, &decaf448KeysCount); err != nil { return errors.Wrap(err, "from canonical bytes") } // Read each key - k.Keys = make([]*SignedX448Key, keysCount) - for i := uint32(0); i < keysCount; i++ { + k.Decaf448Keys = make([]*SignedDecaf448Key, decaf448KeysCount) + for i := uint32(0); i < decaf448KeysCount; i++ { var keyLen uint32 if err := binary.Read(buf, binary.BigEndian, &keyLen); err != nil { return errors.Wrap(err, "from canonical bytes") @@ -1844,8 +2369,8 @@ func (k *KeyCollection) FromCanonicalBytes(data []byte) error { if _, err := buf.Read(keyBytes); err != nil { return errors.Wrap(err, "from canonical bytes") } - k.Keys[i] = &SignedX448Key{} - if err := k.Keys[i].FromCanonicalBytes(keyBytes); err != nil { + k.Decaf448Keys[i] = &SignedDecaf448Key{} + if err := k.Decaf448Keys[i].FromCanonicalBytes(keyBytes); err != nil { return errors.Wrap(err, "from canonical bytes") } } diff --git a/protobufs/keys.pb.go b/protobufs/keys.pb.go index 2589fdec..e7aa7bd4 100644 --- a/protobufs/keys.pb.go +++ b/protobufs/keys.pb.go @@ -1056,6 +1056,148 @@ func (*SignedX448Key_BlsSignature) isSignedX448Key_Signature() {} func (*SignedX448Key_DecafSignature) isSignedX448Key_Signature() {} +// Individual signed key with metadata +type SignedDecaf448Key struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key *Decaf448PublicKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + // The parent key that signed this + ParentKeyAddress []byte `protobuf:"bytes,2,opt,name=parent_key_address,json=parentKeyAddress,proto3" json:"parent_key_address,omitempty"` + // Signature by the parent + // + // Types that are assignable to Signature: + // + // *SignedDecaf448Key_Ed448Signature + // *SignedDecaf448Key_BlsSignature + // *SignedDecaf448Key_DecafSignature + Signature isSignedDecaf448Key_Signature `protobuf_oneof:"signature"` + // Metadata + CreatedAt uint64 `protobuf:"varint,6,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + // 0 means no expiry + ExpiresAt uint64 `protobuf:"varint,7,opt,name=expires_at,json=expiresAt,proto3" json:"expires_at,omitempty"` + // "view", "spend", "inbox", "device", "pre" + KeyPurpose string `protobuf:"bytes,8,opt,name=key_purpose,json=keyPurpose,proto3" json:"key_purpose,omitempty"` +} + +func (x *SignedDecaf448Key) Reset() { + *x = SignedDecaf448Key{} + if protoimpl.UnsafeEnabled { + mi := &file_keys_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignedDecaf448Key) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignedDecaf448Key) ProtoMessage() {} + +func (x *SignedDecaf448Key) ProtoReflect() protoreflect.Message { + mi := &file_keys_proto_msgTypes[17] + 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 SignedDecaf448Key.ProtoReflect.Descriptor instead. +func (*SignedDecaf448Key) Descriptor() ([]byte, []int) { + return file_keys_proto_rawDescGZIP(), []int{17} +} + +func (x *SignedDecaf448Key) GetKey() *Decaf448PublicKey { + if x != nil { + return x.Key + } + return nil +} + +func (x *SignedDecaf448Key) GetParentKeyAddress() []byte { + if x != nil { + return x.ParentKeyAddress + } + return nil +} + +func (m *SignedDecaf448Key) GetSignature() isSignedDecaf448Key_Signature { + if m != nil { + return m.Signature + } + return nil +} + +func (x *SignedDecaf448Key) GetEd448Signature() *Ed448Signature { + if x, ok := x.GetSignature().(*SignedDecaf448Key_Ed448Signature); ok { + return x.Ed448Signature + } + return nil +} + +func (x *SignedDecaf448Key) GetBlsSignature() *BLS48581Signature { + if x, ok := x.GetSignature().(*SignedDecaf448Key_BlsSignature); ok { + return x.BlsSignature + } + return nil +} + +func (x *SignedDecaf448Key) GetDecafSignature() *Decaf448Signature { + if x, ok := x.GetSignature().(*SignedDecaf448Key_DecafSignature); ok { + return x.DecafSignature + } + return nil +} + +func (x *SignedDecaf448Key) GetCreatedAt() uint64 { + if x != nil { + return x.CreatedAt + } + return 0 +} + +func (x *SignedDecaf448Key) GetExpiresAt() uint64 { + if x != nil { + return x.ExpiresAt + } + return 0 +} + +func (x *SignedDecaf448Key) GetKeyPurpose() string { + if x != nil { + return x.KeyPurpose + } + return "" +} + +type isSignedDecaf448Key_Signature interface { + isSignedDecaf448Key_Signature() +} + +type SignedDecaf448Key_Ed448Signature struct { + Ed448Signature *Ed448Signature `protobuf:"bytes,3,opt,name=ed448_signature,json=ed448Signature,proto3,oneof"` +} + +type SignedDecaf448Key_BlsSignature struct { + BlsSignature *BLS48581Signature `protobuf:"bytes,4,opt,name=bls_signature,json=blsSignature,proto3,oneof"` +} + +type SignedDecaf448Key_DecafSignature struct { + DecafSignature *Decaf448Signature `protobuf:"bytes,5,opt,name=decaf_signature,json=decafSignature,proto3,oneof"` +} + +func (*SignedDecaf448Key_Ed448Signature) isSignedDecaf448Key_Signature() {} + +func (*SignedDecaf448Key_BlsSignature) isSignedDecaf448Key_Signature() {} + +func (*SignedDecaf448Key_DecafSignature) isSignedDecaf448Key_Signature() {} + // A collection of keys for a specific purpose type KeyCollection struct { state protoimpl.MessageState @@ -1063,14 +1205,15 @@ type KeyCollection struct { unknownFields protoimpl.UnknownFields // "view", "spend", "inbox", "device", "pre" - KeyPurpose string `protobuf:"bytes,1,opt,name=key_purpose,json=keyPurpose,proto3" json:"key_purpose,omitempty"` - Keys []*SignedX448Key `protobuf:"bytes,2,rep,name=keys,proto3" json:"keys,omitempty"` + KeyPurpose string `protobuf:"bytes,1,opt,name=key_purpose,json=keyPurpose,proto3" json:"key_purpose,omitempty"` + X448Keys []*SignedX448Key `protobuf:"bytes,2,rep,name=x448_keys,json=x448Keys,proto3" json:"x448_keys,omitempty"` + Decaf448Keys []*SignedDecaf448Key `protobuf:"bytes,3,rep,name=decaf448_keys,json=decaf448Keys,proto3" json:"decaf448_keys,omitempty"` } func (x *KeyCollection) Reset() { *x = KeyCollection{} if protoimpl.UnsafeEnabled { - mi := &file_keys_proto_msgTypes[17] + mi := &file_keys_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1083,7 +1226,7 @@ func (x *KeyCollection) String() string { func (*KeyCollection) ProtoMessage() {} func (x *KeyCollection) ProtoReflect() protoreflect.Message { - mi := &file_keys_proto_msgTypes[17] + mi := &file_keys_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1096,7 +1239,7 @@ func (x *KeyCollection) ProtoReflect() protoreflect.Message { // Deprecated: Use KeyCollection.ProtoReflect.Descriptor instead. func (*KeyCollection) Descriptor() ([]byte, []int) { - return file_keys_proto_rawDescGZIP(), []int{17} + return file_keys_proto_rawDescGZIP(), []int{18} } func (x *KeyCollection) GetKeyPurpose() string { @@ -1106,9 +1249,16 @@ func (x *KeyCollection) GetKeyPurpose() string { return "" } -func (x *KeyCollection) GetKeys() []*SignedX448Key { +func (x *KeyCollection) GetX448Keys() []*SignedX448Key { + if x != nil { + return x.X448Keys + } + return nil +} + +func (x *KeyCollection) GetDecaf448Keys() []*SignedDecaf448Key { if x != nil { - return x.Keys + return x.Decaf448Keys } return nil } @@ -1134,7 +1284,7 @@ type KeyRegistry struct { func (x *KeyRegistry) Reset() { *x = KeyRegistry{} if protoimpl.UnsafeEnabled { - mi := &file_keys_proto_msgTypes[18] + mi := &file_keys_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1147,7 +1297,7 @@ func (x *KeyRegistry) String() string { func (*KeyRegistry) ProtoMessage() {} func (x *KeyRegistry) ProtoReflect() protoreflect.Message { - mi := &file_keys_proto_msgTypes[18] + mi := &file_keys_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1160,7 +1310,7 @@ func (x *KeyRegistry) ProtoReflect() protoreflect.Message { // Deprecated: Use KeyRegistry.ProtoReflect.Descriptor instead. func (*KeyRegistry) Descriptor() ([]byte, []int) { - return file_keys_proto_rawDescGZIP(), []int{18} + return file_keys_proto_rawDescGZIP(), []int{19} } func (x *KeyRegistry) GetIdentityKey() *Ed448PublicKey { @@ -1344,55 +1494,91 @@ var file_keys_proto_rawDesc = []byte{ 0x04, 0x52, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6b, 0x65, 0x79, 0x50, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x42, 0x0b, 0x0a, - 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x6c, 0x0a, 0x0d, 0x4b, 0x65, - 0x79, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6b, - 0x65, 0x79, 0x5f, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x6b, 0x65, 0x79, 0x50, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x04, - 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, 0x75, 0x69, - 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, - 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x58, 0x34, 0x34, 0x38, 0x4b, - 0x65, 0x79, 0x52, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x22, 0xc5, 0x04, 0x0a, 0x0b, 0x4b, 0x65, 0x79, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x12, 0x4a, 0x0a, 0x0c, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, - 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, 0x50, 0x75, - 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x4b, 0x65, 0x79, 0x12, 0x4b, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x6b, - 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, - 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, - 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x47, 0x32, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x4b, 0x65, - 0x79, 0x12, 0x55, 0x0a, 0x12, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x6f, - 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, + 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xe9, 0x03, 0x0a, 0x11, 0x53, + 0x69, 0x67, 0x6e, 0x65, 0x64, 0x44, 0x65, 0x63, 0x61, 0x66, 0x34, 0x34, 0x38, 0x4b, 0x65, 0x79, + 0x12, 0x3c, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, 0x53, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x10, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x54, 0x6f, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x58, 0x0a, 0x12, 0x70, 0x72, 0x6f, 0x76, - 0x65, 0x72, 0x5f, 0x74, 0x6f, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, - 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, - 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x52, 0x10, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x54, 0x6f, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x12, 0x5f, 0x0a, 0x0f, 0x6b, 0x65, 0x79, 0x73, 0x5f, 0x62, 0x79, 0x5f, 0x70, 0x75, - 0x72, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x71, 0x75, + 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x61, 0x66, 0x34, 0x34, 0x38, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, + 0x0a, 0x12, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x70, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x52, 0x0a, 0x0f, + 0x65, 0x64, 0x34, 0x34, 0x38, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, + 0x45, 0x64, 0x34, 0x34, 0x38, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x48, 0x00, + 0x52, 0x0e, 0x65, 0x64, 0x34, 0x34, 0x38, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x12, 0x51, 0x0a, 0x0d, 0x62, 0x6c, 0x73, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, + 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, + 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x62, 0x6c, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x12, 0x55, 0x0a, 0x0f, 0x64, 0x65, 0x63, 0x61, 0x66, 0x5f, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x71, + 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, + 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x61, 0x66, 0x34, 0x34, 0x38, 0x53, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x64, 0x65, 0x63, 0x61, + 0x66, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x78, 0x70, + 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x65, + 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6b, 0x65, 0x79, 0x5f, + 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6b, + 0x65, 0x79, 0x50, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xc6, 0x01, 0x0a, 0x0d, 0x4b, 0x65, 0x79, 0x43, 0x6f, + 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6b, 0x65, 0x79, 0x5f, + 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6b, + 0x65, 0x79, 0x50, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x09, 0x78, 0x34, 0x34, + 0x38, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, + 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, + 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x58, 0x34, 0x34, + 0x38, 0x4b, 0x65, 0x79, 0x52, 0x08, 0x78, 0x34, 0x34, 0x38, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x4f, + 0x0a, 0x0d, 0x64, 0x65, 0x63, 0x61, 0x66, 0x34, 0x34, 0x38, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, + 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x44, 0x65, 0x63, 0x61, 0x66, 0x34, 0x34, 0x38, 0x4b, 0x65, + 0x79, 0x52, 0x0c, 0x64, 0x65, 0x63, 0x61, 0x66, 0x34, 0x34, 0x38, 0x4b, 0x65, 0x79, 0x73, 0x22, + 0xc5, 0x04, 0x0a, 0x0b, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x12, + 0x4a, 0x0a, 0x0c, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, + 0x45, 0x64, 0x34, 0x34, 0x38, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0b, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x12, 0x4b, 0x0a, 0x0a, 0x70, + 0x72, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, + 0x38, 0x31, 0x47, 0x32, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x09, 0x70, + 0x72, 0x6f, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x55, 0x0a, 0x12, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x6f, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, + 0x64, 0x34, 0x34, 0x38, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x10, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x12, + 0x58, 0x0a, 0x12, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x6f, 0x5f, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, - 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x50, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x6b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x50, 0x75, 0x72, 0x70, - 0x6f, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6c, 0x61, 0x73, 0x74, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x1a, 0x68, 0x0a, 0x12, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, - 0x50, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3c, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, - 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x4b, 0x65, 0x79, 0x43, 0x6f, 0x6c, 0x6c, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, - 0x42, 0x3a, 0x5a, 0x38, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, - 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, - 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x6d, 0x6f, 0x6e, 0x6f, 0x72, 0x65, 0x70, 0x6f, 0x2f, 0x6e, 0x6f, - 0x64, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x73, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x54, + 0x6f, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x5f, 0x0a, 0x0f, 0x6b, 0x65, 0x79, + 0x73, 0x5f, 0x62, 0x79, 0x5f, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x05, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x4b, 0x65, 0x79, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x50, + 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x6b, 0x65, 0x79, + 0x73, 0x42, 0x79, 0x50, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6c, 0x61, + 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x0b, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x1a, 0x68, 0x0a, + 0x12, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x50, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x4b, + 0x65, 0x79, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x3a, 0x5a, 0x38, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x6d, 0x6f, 0x6e, 0x6f, + 0x72, 0x65, 0x70, 0x6f, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1407,7 +1593,7 @@ func file_keys_proto_rawDescGZIP() []byte { return file_keys_proto_rawDescData } -var file_keys_proto_msgTypes = make([]protoimpl.MessageInfo, 20) +var file_keys_proto_msgTypes = make([]protoimpl.MessageInfo, 21) var file_keys_proto_goTypes = []interface{}{ (*Ed448PublicKey)(nil), // 0: quilibrium.node.keys.pb.Ed448PublicKey (*Ed448PrivateKey)(nil), // 1: quilibrium.node.keys.pb.Ed448PrivateKey @@ -1426,9 +1612,10 @@ var file_keys_proto_goTypes = []interface{}{ (*Decaf448PrivateKey)(nil), // 14: quilibrium.node.keys.pb.Decaf448PrivateKey (*Decaf448Signature)(nil), // 15: quilibrium.node.keys.pb.Decaf448Signature (*SignedX448Key)(nil), // 16: quilibrium.node.keys.pb.SignedX448Key - (*KeyCollection)(nil), // 17: quilibrium.node.keys.pb.KeyCollection - (*KeyRegistry)(nil), // 18: quilibrium.node.keys.pb.KeyRegistry - nil, // 19: quilibrium.node.keys.pb.KeyRegistry.KeysByPurposeEntry + (*SignedDecaf448Key)(nil), // 17: quilibrium.node.keys.pb.SignedDecaf448Key + (*KeyCollection)(nil), // 18: quilibrium.node.keys.pb.KeyCollection + (*KeyRegistry)(nil), // 19: quilibrium.node.keys.pb.KeyRegistry + nil, // 20: quilibrium.node.keys.pb.KeyRegistry.KeysByPurposeEntry } var file_keys_proto_depIdxs = []int32{ 0, // 0: quilibrium.node.keys.pb.Ed448PrivateKey.public_key:type_name -> quilibrium.node.keys.pb.Ed448PublicKey @@ -1445,18 +1632,23 @@ var file_keys_proto_depIdxs = []int32{ 2, // 11: quilibrium.node.keys.pb.SignedX448Key.ed448_signature:type_name -> quilibrium.node.keys.pb.Ed448Signature 9, // 12: quilibrium.node.keys.pb.SignedX448Key.bls_signature:type_name -> quilibrium.node.keys.pb.BLS48581Signature 15, // 13: quilibrium.node.keys.pb.SignedX448Key.decaf_signature:type_name -> quilibrium.node.keys.pb.Decaf448Signature - 16, // 14: quilibrium.node.keys.pb.KeyCollection.keys:type_name -> quilibrium.node.keys.pb.SignedX448Key - 0, // 15: quilibrium.node.keys.pb.KeyRegistry.identity_key:type_name -> quilibrium.node.keys.pb.Ed448PublicKey - 7, // 16: quilibrium.node.keys.pb.KeyRegistry.prover_key:type_name -> quilibrium.node.keys.pb.BLS48581G2PublicKey - 2, // 17: quilibrium.node.keys.pb.KeyRegistry.identity_to_prover:type_name -> quilibrium.node.keys.pb.Ed448Signature - 9, // 18: quilibrium.node.keys.pb.KeyRegistry.prover_to_identity:type_name -> quilibrium.node.keys.pb.BLS48581Signature - 19, // 19: quilibrium.node.keys.pb.KeyRegistry.keys_by_purpose:type_name -> quilibrium.node.keys.pb.KeyRegistry.KeysByPurposeEntry - 17, // 20: quilibrium.node.keys.pb.KeyRegistry.KeysByPurposeEntry.value:type_name -> quilibrium.node.keys.pb.KeyCollection - 21, // [21:21] is the sub-list for method output_type - 21, // [21:21] is the sub-list for method input_type - 21, // [21:21] is the sub-list for extension type_name - 21, // [21:21] is the sub-list for extension extendee - 0, // [0:21] is the sub-list for field type_name + 13, // 14: quilibrium.node.keys.pb.SignedDecaf448Key.key:type_name -> quilibrium.node.keys.pb.Decaf448PublicKey + 2, // 15: quilibrium.node.keys.pb.SignedDecaf448Key.ed448_signature:type_name -> quilibrium.node.keys.pb.Ed448Signature + 9, // 16: quilibrium.node.keys.pb.SignedDecaf448Key.bls_signature:type_name -> quilibrium.node.keys.pb.BLS48581Signature + 15, // 17: quilibrium.node.keys.pb.SignedDecaf448Key.decaf_signature:type_name -> quilibrium.node.keys.pb.Decaf448Signature + 16, // 18: quilibrium.node.keys.pb.KeyCollection.x448_keys:type_name -> quilibrium.node.keys.pb.SignedX448Key + 17, // 19: quilibrium.node.keys.pb.KeyCollection.decaf448_keys:type_name -> quilibrium.node.keys.pb.SignedDecaf448Key + 0, // 20: quilibrium.node.keys.pb.KeyRegistry.identity_key:type_name -> quilibrium.node.keys.pb.Ed448PublicKey + 7, // 21: quilibrium.node.keys.pb.KeyRegistry.prover_key:type_name -> quilibrium.node.keys.pb.BLS48581G2PublicKey + 2, // 22: quilibrium.node.keys.pb.KeyRegistry.identity_to_prover:type_name -> quilibrium.node.keys.pb.Ed448Signature + 9, // 23: quilibrium.node.keys.pb.KeyRegistry.prover_to_identity:type_name -> quilibrium.node.keys.pb.BLS48581Signature + 20, // 24: quilibrium.node.keys.pb.KeyRegistry.keys_by_purpose:type_name -> quilibrium.node.keys.pb.KeyRegistry.KeysByPurposeEntry + 18, // 25: quilibrium.node.keys.pb.KeyRegistry.KeysByPurposeEntry.value:type_name -> quilibrium.node.keys.pb.KeyCollection + 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_keys_proto_init() } @@ -1670,7 +1862,7 @@ func file_keys_proto_init() { } } file_keys_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*KeyCollection); i { + switch v := v.(*SignedDecaf448Key); i { case 0: return &v.state case 1: @@ -1682,6 +1874,18 @@ func file_keys_proto_init() { } } file_keys_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*KeyCollection); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_keys_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*KeyRegistry); i { case 0: return &v.state @@ -1699,13 +1903,18 @@ func file_keys_proto_init() { (*SignedX448Key_BlsSignature)(nil), (*SignedX448Key_DecafSignature)(nil), } + file_keys_proto_msgTypes[17].OneofWrappers = []interface{}{ + (*SignedDecaf448Key_Ed448Signature)(nil), + (*SignedDecaf448Key_BlsSignature)(nil), + (*SignedDecaf448Key_DecafSignature)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_keys_proto_rawDesc, NumEnums: 0, - NumMessages: 20, + NumMessages: 21, NumExtensions: 0, NumServices: 0, }, diff --git a/protobufs/keys.proto b/protobufs/keys.proto index b3731013..7bfd1700 100644 --- a/protobufs/keys.proto +++ b/protobufs/keys.proto @@ -141,11 +141,34 @@ message SignedX448Key { string key_purpose = 8; } +// Individual signed key with metadata +message SignedDecaf448Key { + Decaf448PublicKey key = 1; + + // The parent key that signed this + bytes parent_key_address = 2; + + // Signature by the parent + oneof signature { + Ed448Signature ed448_signature = 3; + BLS48581Signature bls_signature = 4; + Decaf448Signature decaf_signature = 5; + } + + // Metadata + uint64 created_at = 6; + // 0 means no expiry + uint64 expires_at = 7; + // "view", "spend", "inbox", "device", "pre" + string key_purpose = 8; +} + // A collection of keys for a specific purpose message KeyCollection { // "view", "spend", "inbox", "device", "pre" string key_purpose = 1; - repeated SignedX448Key keys = 2; + repeated SignedX448Key x448_keys = 2; + repeated SignedDecaf448Key decaf448_keys = 3; } // Complete key registry (for querying all keys) diff --git a/protobufs/keys_test.go b/protobufs/keys_test.go index c0618311..bbbe2c8f 100644 --- a/protobufs/keys_test.go +++ b/protobufs/keys_test.go @@ -554,7 +554,7 @@ func TestKeyCollection_Serialization(t *testing.T) { name: "complete collection", collection: &KeyCollection{ KeyPurpose: "inbox", - Keys: []*SignedX448Key{ + X448Keys: []*SignedX448Key{ { Key: &X448PublicKey{ KeyValue: make([]byte, 57), @@ -584,13 +584,43 @@ func TestKeyCollection_Serialization(t *testing.T) { }, }, }, + Decaf448Keys: []*SignedDecaf448Key{ + { + Key: &Decaf448PublicKey{ + KeyValue: make([]byte, 56), + }, + ParentKeyAddress: make([]byte, 32), + Signature: &SignedDecaf448Key_Ed448Signature{ + Ed448Signature: &Ed448Signature{ + Signature: make([]byte, 114), + PublicKey: &Ed448PublicKey{ + KeyValue: make([]byte, 57), + }, + }, + }, + }, + { + Key: &Decaf448PublicKey{ + KeyValue: make([]byte, 56), + }, + ParentKeyAddress: make([]byte, 32), + Signature: &SignedDecaf448Key_BlsSignature{ + BlsSignature: &BLS48581Signature{ + Signature: make([]byte, 74), + PublicKey: &BLS48581G2PublicKey{ + KeyValue: make([]byte, 585), + }, + }, + }, + }, + }, }, }, { name: "empty collection", collection: &KeyCollection{ KeyPurpose: "device", - Keys: []*SignedX448Key{}, + X448Keys: []*SignedX448Key{}, }, }, { @@ -616,18 +646,32 @@ func TestKeyCollection_Serialization(t *testing.T) { // Compare fields assert.Equal(t, tt.collection.KeyPurpose, collection2.KeyPurpose) - if tt.collection.Keys != nil { - require.NotNil(t, collection2.Keys) - assert.Equal(t, len(tt.collection.Keys), len(collection2.Keys)) + if tt.collection.X448Keys != nil { + require.NotNil(t, collection2.X448Keys) + assert.Equal(t, len(tt.collection.X448Keys), len(collection2.X448Keys)) + + for i := range tt.collection.X448Keys { + assert.NotNil(t, collection2.X448Keys[i].Key) + assert.True(t, equalBytes(tt.collection.X448Keys[i].Key.KeyValue, collection2.X448Keys[i].Key.KeyValue)) + assert.True(t, equalBytes(tt.collection.X448Keys[i].ParentKeyAddress, collection2.X448Keys[i].ParentKeyAddress)) + } + } else { + // protobuf deserialization returns empty slice instead of nil + assert.Empty(t, collection2.X448Keys) + } + + if tt.collection.Decaf448Keys != nil { + require.NotNil(t, collection2.Decaf448Keys) + assert.Equal(t, len(tt.collection.Decaf448Keys), len(collection2.Decaf448Keys)) - for i := range tt.collection.Keys { - assert.NotNil(t, collection2.Keys[i].Key) - assert.True(t, equalBytes(tt.collection.Keys[i].Key.KeyValue, collection2.Keys[i].Key.KeyValue)) - assert.True(t, equalBytes(tt.collection.Keys[i].ParentKeyAddress, collection2.Keys[i].ParentKeyAddress)) + for i := range tt.collection.Decaf448Keys { + assert.NotNil(t, collection2.Decaf448Keys[i].Key) + assert.True(t, equalBytes(tt.collection.Decaf448Keys[i].Key.KeyValue, collection2.Decaf448Keys[i].Key.KeyValue)) + assert.True(t, equalBytes(tt.collection.Decaf448Keys[i].ParentKeyAddress, collection2.Decaf448Keys[i].ParentKeyAddress)) } } else { // protobuf deserialization returns empty slice instead of nil - assert.Empty(t, collection2.Keys) + assert.Empty(t, collection2.Decaf448Keys) } }) } @@ -662,7 +706,7 @@ func TestKeyRegistry_Serialization(t *testing.T) { KeysByPurpose: map[string]*KeyCollection{ "inbox": { KeyPurpose: "inbox", - Keys: []*SignedX448Key{ + X448Keys: []*SignedX448Key{ { Key: &X448PublicKey{ KeyValue: make([]byte, 57), @@ -682,7 +726,7 @@ func TestKeyRegistry_Serialization(t *testing.T) { }, "device": { KeyPurpose: "device", - Keys: []*SignedX448Key{ + X448Keys: []*SignedX448Key{ { Key: &X448PublicKey{ KeyValue: make([]byte, 57), @@ -758,8 +802,8 @@ func TestKeyRegistry_Serialization(t *testing.T) { collection2, ok := registry2.KeysByPurpose[purpose] require.True(t, ok) assert.Equal(t, collection.KeyPurpose, collection2.KeyPurpose) - if collection.Keys != nil { - assert.Equal(t, len(collection.Keys), len(collection2.Keys)) + if collection.X448Keys != nil { + assert.Equal(t, len(collection.X448Keys), len(collection2.X448Keys)) } } } diff --git a/protobufs/node.pb.go b/protobufs/node.pb.go index a1086cc1..85c5189d 100644 --- a/protobufs/node.pb.go +++ b/protobufs/node.pb.go @@ -1774,6 +1774,124 @@ func (*RespawnResponse) Descriptor() ([]byte, []int) { return file_node_proto_rawDescGZIP(), []int{26} } +type CreateJoinProofRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Challenge []byte `protobuf:"bytes,1,opt,name=challenge,proto3" json:"challenge,omitempty"` + Difficulty uint32 `protobuf:"varint,2,opt,name=difficulty,proto3" json:"difficulty,omitempty"` + Ids [][]byte `protobuf:"bytes,3,rep,name=ids,proto3" json:"ids,omitempty"` + ProverIndex uint32 `protobuf:"varint,4,opt,name=prover_index,json=proverIndex,proto3" json:"prover_index,omitempty"` +} + +func (x *CreateJoinProofRequest) Reset() { + *x = CreateJoinProofRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_node_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateJoinProofRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateJoinProofRequest) ProtoMessage() {} + +func (x *CreateJoinProofRequest) ProtoReflect() protoreflect.Message { + mi := &file_node_proto_msgTypes[27] + 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 CreateJoinProofRequest.ProtoReflect.Descriptor instead. +func (*CreateJoinProofRequest) Descriptor() ([]byte, []int) { + return file_node_proto_rawDescGZIP(), []int{27} +} + +func (x *CreateJoinProofRequest) GetChallenge() []byte { + if x != nil { + return x.Challenge + } + return nil +} + +func (x *CreateJoinProofRequest) GetDifficulty() uint32 { + if x != nil { + return x.Difficulty + } + return 0 +} + +func (x *CreateJoinProofRequest) GetIds() [][]byte { + if x != nil { + return x.Ids + } + return nil +} + +func (x *CreateJoinProofRequest) GetProverIndex() uint32 { + if x != nil { + return x.ProverIndex + } + return 0 +} + +type CreateJoinProofResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Response []byte `protobuf:"bytes,1,opt,name=response,proto3" json:"response,omitempty"` +} + +func (x *CreateJoinProofResponse) Reset() { + *x = CreateJoinProofResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_node_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateJoinProofResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateJoinProofResponse) ProtoMessage() {} + +func (x *CreateJoinProofResponse) ProtoReflect() protoreflect.Message { + mi := &file_node_proto_msgTypes[28] + 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 CreateJoinProofResponse.ProtoReflect.Descriptor instead. +func (*CreateJoinProofResponse) Descriptor() ([]byte, []int) { + return file_node_proto_rawDescGZIP(), []int{28} +} + +func (x *CreateJoinProofResponse) GetResponse() []byte { + if x != nil { + return x.Response + } + return nil +} + var File_node_proto protoreflect.FileDescriptor var file_node_proto_rawDesc = []byte{ @@ -2031,52 +2149,72 @@ var file_node_proto_rawDesc = []byte{ 0x73, 0x70, 0x61, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x11, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x70, 0x61, 0x77, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x9c, 0x04, 0x0a, 0x0b, 0x4e, 0x6f, 0x64, 0x65, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x65, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x50, 0x65, - 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, - 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, - 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, - 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x65, - 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x65, - 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2b, 0x2e, - 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x71, 0x75, 0x69, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x8b, 0x01, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x4a, 0x6f, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, + 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x03, 0x69, + 0x64, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x35, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, + 0x6f, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x9c, 0x04, 0x0a, + 0x0b, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x65, 0x0a, 0x0b, + 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2b, 0x2e, 0x71, 0x75, + 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x70, 0x62, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x65, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, + 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x29, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b, 0x0a, 0x0d, 0x47, 0x65, + 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2d, 0x2e, 0x71, 0x75, + 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, - 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2d, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, - 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, - 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x04, 0x53, 0x65, 0x6e, 0x64, 0x12, + 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, - 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x53, 0x0a, 0x04, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x24, 0x2e, 0x71, 0x75, 0x69, - 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x25, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7d, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x32, 0x2e, - 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x73, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x6e, 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x49, 0x50, - 0x43, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5c, 0x0a, 0x07, 0x52, 0x65, 0x73, 0x70, - 0x61, 0x77, 0x6e, 0x12, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, - 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, - 0x73, 0x70, 0x61, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x71, - 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x61, 0x77, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3a, 0x5a, 0x38, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x6d, 0x6f, 0x6e, 0x6f, 0x72, - 0x65, 0x70, 0x6f, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7d, 0x0a, 0x12, + 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x32, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, + 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xe4, 0x01, 0x0a, 0x0e, + 0x44, 0x61, 0x74, 0x61, 0x49, 0x50, 0x43, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5c, + 0x0a, 0x07, 0x52, 0x65, 0x73, 0x70, 0x61, 0x77, 0x6e, 0x12, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, + 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x61, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, + 0x70, 0x61, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x74, 0x0a, 0x0f, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, + 0x2f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x4a, 0x6f, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x4a, 0x6f, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x42, 0x3a, 0x5a, 0x38, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x71, 0x75, 0x69, + 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x71, 0x75, 0x69, 0x6c, + 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x6d, 0x6f, 0x6e, 0x6f, 0x72, 0x65, 0x70, 0x6f, 0x2f, + 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x73, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2091,7 +2229,7 @@ func file_node_proto_rawDescGZIP() []byte { return file_node_proto_rawDescData } -var file_node_proto_msgTypes = make([]protoimpl.MessageInfo, 27) +var file_node_proto_msgTypes = make([]protoimpl.MessageInfo, 29) var file_node_proto_goTypes = []interface{}{ (*GetPeerInfoRequest)(nil), // 0: quilibrium.node.node.pb.GetPeerInfoRequest (*GetNodeInfoRequest)(nil), // 1: quilibrium.node.node.pb.GetNodeInfoRequest @@ -2120,8 +2258,10 @@ var file_node_proto_goTypes = []interface{}{ (*GetTokensByAccountResponse)(nil), // 24: quilibrium.node.node.pb.GetTokensByAccountResponse (*RespawnRequest)(nil), // 25: quilibrium.node.node.pb.RespawnRequest (*RespawnResponse)(nil), // 26: quilibrium.node.node.pb.RespawnResponse - (*InboxMessage)(nil), // 27: quilibrium.node.channel.pb.InboxMessage - (*MessageBundle)(nil), // 28: quilibrium.node.global.pb.MessageBundle + (*CreateJoinProofRequest)(nil), // 27: quilibrium.node.node.pb.CreateJoinProofRequest + (*CreateJoinProofResponse)(nil), // 28: quilibrium.node.node.pb.CreateJoinProofResponse + (*InboxMessage)(nil), // 29: quilibrium.node.channel.pb.InboxMessage + (*MessageBundle)(nil), // 30: quilibrium.node.global.pb.MessageBundle } var file_node_proto_depIdxs = []int32{ 3, // 0: quilibrium.node.node.pb.PeerInfo.reachability:type_name -> quilibrium.node.node.pb.Reachability @@ -2129,8 +2269,8 @@ var file_node_proto_depIdxs = []int32{ 4, // 2: quilibrium.node.node.pb.PeerInfoResponse.peer_info:type_name -> quilibrium.node.node.pb.PeerInfo 7, // 3: quilibrium.node.node.pb.WorkerInfoResponse.worker_info:type_name -> quilibrium.node.node.pb.WorkerInfo 10, // 4: quilibrium.node.node.pb.KeyRing.keys:type_name -> quilibrium.node.node.pb.InlineKey - 27, // 5: quilibrium.node.node.pb.DeliveryData.messages:type_name -> quilibrium.node.channel.pb.InboxMessage - 28, // 6: quilibrium.node.node.pb.SendRequest.request:type_name -> quilibrium.node.global.pb.MessageBundle + 29, // 5: quilibrium.node.node.pb.DeliveryData.messages:type_name -> quilibrium.node.channel.pb.InboxMessage + 30, // 6: quilibrium.node.node.pb.SendRequest.request:type_name -> quilibrium.node.global.pb.MessageBundle 13, // 7: quilibrium.node.node.pb.SendRequest.delivery_data:type_name -> quilibrium.node.node.pb.DeliveryData 13, // 8: quilibrium.node.node.pb.SendResponse.delivery_data:type_name -> quilibrium.node.node.pb.DeliveryData 16, // 9: quilibrium.node.node.pb.AccountRef.originated_account:type_name -> quilibrium.node.node.pb.OriginatedAccountRef @@ -2146,14 +2286,16 @@ var file_node_proto_depIdxs = []int32{ 14, // 19: quilibrium.node.node.pb.NodeService.Send:input_type -> quilibrium.node.node.pb.SendRequest 23, // 20: quilibrium.node.node.pb.NodeService.GetTokensByAccount:input_type -> quilibrium.node.node.pb.GetTokensByAccountRequest 25, // 21: quilibrium.node.node.pb.DataIPCService.Respawn:input_type -> quilibrium.node.node.pb.RespawnRequest - 5, // 22: quilibrium.node.node.pb.NodeService.GetPeerInfo:output_type -> quilibrium.node.node.pb.PeerInfoResponse - 6, // 23: quilibrium.node.node.pb.NodeService.GetNodeInfo:output_type -> quilibrium.node.node.pb.NodeInfoResponse - 8, // 24: quilibrium.node.node.pb.NodeService.GetWorkerInfo:output_type -> quilibrium.node.node.pb.WorkerInfoResponse - 15, // 25: quilibrium.node.node.pb.NodeService.Send:output_type -> quilibrium.node.node.pb.SendResponse - 24, // 26: quilibrium.node.node.pb.NodeService.GetTokensByAccount:output_type -> quilibrium.node.node.pb.GetTokensByAccountResponse - 26, // 27: quilibrium.node.node.pb.DataIPCService.Respawn:output_type -> quilibrium.node.node.pb.RespawnResponse - 22, // [22:28] is the sub-list for method output_type - 16, // [16:22] is the sub-list for method input_type + 27, // 22: quilibrium.node.node.pb.DataIPCService.CreateJoinProof:input_type -> quilibrium.node.node.pb.CreateJoinProofRequest + 5, // 23: quilibrium.node.node.pb.NodeService.GetPeerInfo:output_type -> quilibrium.node.node.pb.PeerInfoResponse + 6, // 24: quilibrium.node.node.pb.NodeService.GetNodeInfo:output_type -> quilibrium.node.node.pb.NodeInfoResponse + 8, // 25: quilibrium.node.node.pb.NodeService.GetWorkerInfo:output_type -> quilibrium.node.node.pb.WorkerInfoResponse + 15, // 26: quilibrium.node.node.pb.NodeService.Send:output_type -> quilibrium.node.node.pb.SendResponse + 24, // 27: quilibrium.node.node.pb.NodeService.GetTokensByAccount:output_type -> quilibrium.node.node.pb.GetTokensByAccountResponse + 26, // 28: quilibrium.node.node.pb.DataIPCService.Respawn:output_type -> quilibrium.node.node.pb.RespawnResponse + 28, // 29: quilibrium.node.node.pb.DataIPCService.CreateJoinProof:output_type -> quilibrium.node.node.pb.CreateJoinProofResponse + 23, // [23:30] is the sub-list for method output_type + 16, // [16:23] is the sub-list for method input_type 16, // [16:16] is the sub-list for extension type_name 16, // [16:16] is the sub-list for extension extendee 0, // [0:16] is the sub-list for field type_name @@ -2491,6 +2633,30 @@ func file_node_proto_init() { return nil } } + file_node_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateJoinProofRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_node_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateJoinProofResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_node_proto_msgTypes[18].OneofWrappers = []interface{}{ (*AccountRef_OriginatedAccount)(nil), @@ -2502,7 +2668,7 @@ func file_node_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_node_proto_rawDesc, NumEnums: 0, - NumMessages: 27, + NumMessages: 29, NumExtensions: 0, NumServices: 2, }, diff --git a/protobufs/node.pb.gw.go b/protobufs/node.pb.gw.go index a78bb7f5..a7e24a70 100644 --- a/protobufs/node.pb.gw.go +++ b/protobufs/node.pb.gw.go @@ -235,6 +235,40 @@ func local_request_DataIPCService_Respawn_0(ctx context.Context, marshaler runti } +func request_DataIPCService_CreateJoinProof_0(ctx context.Context, marshaler runtime.Marshaler, client DataIPCServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq CreateJoinProofRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.CreateJoinProof(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_DataIPCService_CreateJoinProof_0(ctx context.Context, marshaler runtime.Marshaler, server DataIPCServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq CreateJoinProofRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.CreateJoinProof(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterNodeServiceHandlerServer registers the http handlers for service NodeService to "mux". // UnaryRPC :call NodeServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -400,6 +434,31 @@ func RegisterDataIPCServiceHandlerServer(ctx context.Context, mux *runtime.Serve }) + mux.Handle("POST", pattern_DataIPCService_CreateJoinProof_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/quilibrium.node.node.pb.DataIPCService/CreateJoinProof", runtime.WithHTTPPathPattern("/quilibrium.node.node.pb.DataIPCService/CreateJoinProof")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_DataIPCService_CreateJoinProof_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_DataIPCService_CreateJoinProof_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -638,13 +697,39 @@ func RegisterDataIPCServiceHandlerClient(ctx context.Context, mux *runtime.Serve }) + mux.Handle("POST", pattern_DataIPCService_CreateJoinProof_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/quilibrium.node.node.pb.DataIPCService/CreateJoinProof", runtime.WithHTTPPathPattern("/quilibrium.node.node.pb.DataIPCService/CreateJoinProof")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_DataIPCService_CreateJoinProof_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_DataIPCService_CreateJoinProof_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } var ( pattern_DataIPCService_Respawn_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"quilibrium.node.node.pb.DataIPCService", "Respawn"}, "")) + + pattern_DataIPCService_CreateJoinProof_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"quilibrium.node.node.pb.DataIPCService", "CreateJoinProof"}, "")) ) var ( forward_DataIPCService_Respawn_0 = runtime.ForwardResponseMessage + + forward_DataIPCService_CreateJoinProof_0 = runtime.ForwardResponseMessage ) diff --git a/protobufs/node.proto b/protobufs/node.proto index 30e481aa..0ca2ade7 100644 --- a/protobufs/node.proto +++ b/protobufs/node.proto @@ -215,6 +215,18 @@ message RespawnRequest { message RespawnResponse { } +message CreateJoinProofRequest { + bytes challenge = 1; + uint32 difficulty = 2; + repeated bytes ids = 3; + uint32 prover_index = 4; +} + +message CreateJoinProofResponse { + bytes response = 1; +} + service DataIPCService { rpc Respawn(RespawnRequest) returns (RespawnResponse); + rpc CreateJoinProof(CreateJoinProofRequest) returns (CreateJoinProofResponse); } diff --git a/protobufs/node_grpc.pb.go b/protobufs/node_grpc.pb.go index a94c6c9e..fb5dcf7c 100644 --- a/protobufs/node_grpc.pb.go +++ b/protobufs/node_grpc.pb.go @@ -257,7 +257,8 @@ var NodeService_ServiceDesc = grpc.ServiceDesc{ } const ( - DataIPCService_Respawn_FullMethodName = "/quilibrium.node.node.pb.DataIPCService/Respawn" + DataIPCService_Respawn_FullMethodName = "/quilibrium.node.node.pb.DataIPCService/Respawn" + DataIPCService_CreateJoinProof_FullMethodName = "/quilibrium.node.node.pb.DataIPCService/CreateJoinProof" ) // DataIPCServiceClient is the client API for DataIPCService service. @@ -265,6 +266,7 @@ const ( // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type DataIPCServiceClient interface { Respawn(ctx context.Context, in *RespawnRequest, opts ...grpc.CallOption) (*RespawnResponse, error) + CreateJoinProof(ctx context.Context, in *CreateJoinProofRequest, opts ...grpc.CallOption) (*CreateJoinProofResponse, error) } type dataIPCServiceClient struct { @@ -284,11 +286,21 @@ func (c *dataIPCServiceClient) Respawn(ctx context.Context, in *RespawnRequest, return out, nil } +func (c *dataIPCServiceClient) CreateJoinProof(ctx context.Context, in *CreateJoinProofRequest, opts ...grpc.CallOption) (*CreateJoinProofResponse, error) { + out := new(CreateJoinProofResponse) + err := c.cc.Invoke(ctx, DataIPCService_CreateJoinProof_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // DataIPCServiceServer is the server API for DataIPCService service. // All implementations must embed UnimplementedDataIPCServiceServer // for forward compatibility type DataIPCServiceServer interface { Respawn(context.Context, *RespawnRequest) (*RespawnResponse, error) + CreateJoinProof(context.Context, *CreateJoinProofRequest) (*CreateJoinProofResponse, error) mustEmbedUnimplementedDataIPCServiceServer() } @@ -299,6 +311,9 @@ type UnimplementedDataIPCServiceServer struct { func (UnimplementedDataIPCServiceServer) Respawn(context.Context, *RespawnRequest) (*RespawnResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Respawn not implemented") } +func (UnimplementedDataIPCServiceServer) CreateJoinProof(context.Context, *CreateJoinProofRequest) (*CreateJoinProofResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateJoinProof not implemented") +} func (UnimplementedDataIPCServiceServer) mustEmbedUnimplementedDataIPCServiceServer() {} // UnsafeDataIPCServiceServer may be embedded to opt out of forward compatibility for this service. @@ -330,6 +345,24 @@ func _DataIPCService_Respawn_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _DataIPCService_CreateJoinProof_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateJoinProofRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DataIPCServiceServer).CreateJoinProof(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DataIPCService_CreateJoinProof_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DataIPCServiceServer).CreateJoinProof(ctx, req.(*CreateJoinProofRequest)) + } + return interceptor(ctx, in, info, handler) +} + // DataIPCService_ServiceDesc is the grpc.ServiceDesc for DataIPCService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -341,6 +374,10 @@ var DataIPCService_ServiceDesc = grpc.ServiceDesc{ MethodName: "Respawn", Handler: _DataIPCService_Respawn_Handler, }, + { + MethodName: "CreateJoinProof", + Handler: _DataIPCService_CreateJoinProof_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "node.proto", diff --git a/types/consensus/prover_registry.go b/types/consensus/prover_registry.go index 2e095553..55efda24 100644 --- a/types/consensus/prover_registry.go +++ b/types/consensus/prover_registry.go @@ -94,6 +94,9 @@ type ProverRegistry interface { // GetProverCount returns the number of active provers for a filter/shard. GetProverCount(filter []byte) (int, error) + // GetProvers returns all provers for a filter/shard + GetProvers(filter []byte) ([]*ProverInfo, error) + // GetProversByStatus returns all provers with a specific status for a // filter/shard. GetProversByStatus(filter []byte, status ProverStatus) ([]*ProverInfo, error) diff --git a/types/consensus/signer_registry.go b/types/consensus/signer_registry.go index f358e938..f4c60fce 100644 --- a/types/consensus/signer_registry.go +++ b/types/consensus/signer_registry.go @@ -27,8 +27,11 @@ type SignerRegistry interface { provingKey *protobufs.BLS48581SignatureWithProofOfPossession, ) error - // ValidateSignedKey validates a signed X448 key - ValidateSignedKey(signedKey *protobufs.SignedX448Key) error + // ValidateSignedX448Key validates a signed X448 key + ValidateSignedX448Key(signedKey *protobufs.SignedX448Key) error + + // ValidateSignedDecaf448Key validates a signed Decaf448 key + ValidateSignedDecaf448Key(signedKey *protobufs.SignedDecaf448Key) error // PutIdentityKey stores an identity key PutIdentityKey( @@ -53,13 +56,20 @@ type SignerRegistry interface { provingKeySignatureOfIdentityKey []byte, ) error - // PutSignedKey stores a signed X448 key - PutSignedKey( + // PutSignedX448Key stores a signed X448 key + PutSignedX448Key( txn store.Transaction, address []byte, key *protobufs.SignedX448Key, ) error + // PutSignedDecaf448Key stores a signed Decaf448 key + PutSignedDecaf448Key( + txn store.Transaction, + address []byte, + key *protobufs.SignedDecaf448Key, + ) error + // GetIdentityKey retrieves an identity key by address GetIdentityKey(address []byte) (*protobufs.Ed448PublicKey, error) @@ -69,15 +79,24 @@ type SignerRegistry interface { error, ) - // GetSignedKey retrieves a signed key by address - GetSignedKey(address []byte) (*protobufs.SignedX448Key, error) + // GetSignedX448Key retrieves a signed key by address + GetSignedX448Key(address []byte) (*protobufs.SignedX448Key, error) + + // GetSignedDecaf448Key retrieves a signed key by address + GetSignedDecaf448Key(address []byte) (*protobufs.SignedDecaf448Key, error) - // GetSignedKeysByParent retrieves all signed keys for a parent key - GetSignedKeysByParent( + // GetSignedX448KeysByParent retrieves all signed keys for a parent key + GetSignedX448KeysByParent( parentKeyAddress []byte, keyPurpose string, // Optional filter by purpose ) ([]*protobufs.SignedX448Key, error) + // GetSignedDecaf448KeysByParent retrieves all signed keys for a parent key + GetSignedDecaf448KeysByParent( + parentKeyAddress []byte, + keyPurpose string, // Optional filter by purpose + ) ([]*protobufs.SignedDecaf448Key, error) + // RangeProvingKeys returns an iterator over all proving keys RangeProvingKeys() ( store.TypedIterator[*protobufs.BLS48581SignatureWithProofOfPossession], @@ -90,12 +109,21 @@ type SignerRegistry interface { error, ) - // RangeSignedKeys returns an iterator over signed keys - RangeSignedKeys( + // RangeSignedX448Keys returns an iterator over signed keys + RangeSignedX448Keys( parentKeyAddress []byte, // Optional filter keyPurpose string, // Optional filter ) ( store.TypedIterator[*protobufs.SignedX448Key], error, ) + + // RangeSignedDecaf448Keys returns an iterator over signed keys + RangeSignedDecaf448Keys( + parentKeyAddress []byte, // Optional filter + keyPurpose string, // Optional filter + ) ( + store.TypedIterator[*protobufs.SignedDecaf448Key], + error, + ) } diff --git a/types/crypto/frame_prover.go b/types/crypto/frame_prover.go index e7aa1411..beb298d1 100644 --- a/types/crypto/frame_prover.go +++ b/types/crypto/frame_prover.go @@ -54,4 +54,16 @@ type FrameProver interface { GetGlobalFrameSignaturePayload( frame *protobufs.GlobalFrameHeader, ) ([]byte, error) + CalculateMultiProof( + challenge [32]byte, + difficulty uint32, + ids [][]byte, + index uint32, + ) [516]byte + VerifyMultiProof( + challenge [32]byte, + difficulty uint32, + ids [][]byte, + allegedSolutions [][516]byte, + ) (bool, error) } diff --git a/types/execution/execution_engine.go b/types/execution/execution_engine.go index 0b820325..fed12340 100644 --- a/types/execution/execution_engine.go +++ b/types/execution/execution_engine.go @@ -29,6 +29,8 @@ type ShardExecutionEngine interface { frameNumber uint64, message []byte, ) (*protobufs.MessageRequest, error) + Lock(frameNumber uint64, address []byte, message []byte) ([][]byte, error) + Unlock() error GetCost(message []byte) (*big.Int, error) GetCapabilities() []*protobufs.Capability } diff --git a/types/execution/intrinsics/intrinsic.go b/types/execution/intrinsics/intrinsic.go index 0df77652..9d085734 100644 --- a/types/execution/intrinsics/intrinsic.go +++ b/types/execution/intrinsics/intrinsic.go @@ -26,9 +26,9 @@ type Intrinsic interface { state state.State, ) (state.State, error) // Locks addresses for writing or reading - Lock(writeAddresses [][]byte, readAddresses [][]byte) error + Lock(frameNumber uint64, input []byte) ([][]byte, error) // Unlocks addresses for writing or reading - Unlock(writeAddresses [][]byte, readAddresses [][]byte) error + Unlock() error // Performs strictly the validation of an intrinsic operation, encoded via // the ToBytes method of the given operation Validate(frameNumber uint64, input []byte) error diff --git a/types/hypergraph/hypergraph.go b/types/hypergraph/hypergraph.go index d72bdabf..eb8107ab 100644 --- a/types/hypergraph/hypergraph.go +++ b/types/hypergraph/hypergraph.go @@ -25,6 +25,12 @@ type Extrinsic struct { type Location [64]byte // 32 bytes for AppAddress + 32 bytes for DataAddress +type ShardMetadata struct { + Commitment []byte + LeafCount uint64 + Size uint64 +} + var ErrInvalidAtomType = errors.New("invalid atom type for set") var ErrInvalidLocation = errors.New("invalid location") var ErrRemoved = errors.New("removed") @@ -54,6 +60,10 @@ type Hypergraph interface { // and ascendant branches. SetCoveredPrefix(prefix []int) error + // GetMetadataAtKey is a fast path to retrieve metadata information used for + // consensus, avoiding unnecessary recomputation for lookups. + GetMetadataAtKey(pathKey []byte) ([]ShardMetadata, error) + // Vertex operations // GetVertex retrieves a vertex by its ID. Returns ErrRemoved if the vertex diff --git a/types/mocks/frame_prover.go b/types/mocks/frame_prover.go index f18a1f79..d82bb085 100644 --- a/types/mocks/frame_prover.go +++ b/types/mocks/frame_prover.go @@ -11,6 +11,26 @@ type MockFrameProver struct { mock.Mock } +func (m *MockFrameProver) CalculateMultiProof( + challenge [32]byte, + difficulty uint32, + ids [][]byte, + index uint32, +) [516]byte { + args := m.Called(challenge, difficulty, ids, index) + return args.Get(0).([516]byte) +} + +func (m *MockFrameProver) VerifyMultiProof( + challenge [32]byte, + difficulty uint32, + ids [][]byte, + allegedSolutions [][516]byte, +) (bool, error) { + args := m.Called(challenge, difficulty, ids, allegedSolutions) + return args.Bool(0), args.Error(1) +} + func (m *MockFrameProver) ProveFrameHeaderGenesis( address []byte, difficulty uint32, diff --git a/types/mocks/hypergraph.go b/types/mocks/hypergraph.go index c9ea065c..81617488 100644 --- a/types/mocks/hypergraph.go +++ b/types/mocks/hypergraph.go @@ -190,6 +190,15 @@ func (h *MockHypergraph) GetChildrenForPath( return args.Get(0).(*protobufs.GetChildrenForPathResponse), args.Error(1) } +// GetMetadataAtKey implements hypergraph.Hypergraph. +func (h *MockHypergraph) GetMetadataAtKey(pathKey []byte) ( + []hg.ShardMetadata, + error, +) { + args := h.Called(pathKey) + return args.Get(0).([]hg.ShardMetadata), args.Error(1) +} + // HyperStream implements hypergraph.Hypergraph. func (h *MockHypergraph) HyperStream( server protobufs.HypergraphComparisonService_HyperStreamServer, diff --git a/types/mocks/key_store.go b/types/mocks/key_store.go index f6c0db5a..ad35a1cc 100644 --- a/types/mocks/key_store.go +++ b/types/mocks/key_store.go @@ -91,8 +91,8 @@ func (m *MockKeyStore) GetCrossSignatureByProvingKey( return args.Get(0).([]byte), args.Error(1) } -// PutSignedKey implements store.KeyStore. -func (m *MockKeyStore) PutSignedKey( +// PutSignedX448Key implements store.KeyStore. +func (m *MockKeyStore) PutSignedX448Key( txn store.Transaction, address []byte, key *protobufs.SignedX448Key, @@ -101,16 +101,16 @@ func (m *MockKeyStore) PutSignedKey( return args.Error(0) } -// GetSignedKey implements store.KeyStore. -func (m *MockKeyStore) GetSignedKey( +// GetSignedX448Key implements store.KeyStore. +func (m *MockKeyStore) GetSignedX448Key( address []byte, ) (*protobufs.SignedX448Key, error) { args := m.Called(address) return args.Get(0).(*protobufs.SignedX448Key), args.Error(1) } -// GetSignedKeysByParent implements store.KeyStore. -func (m *MockKeyStore) GetSignedKeysByParent( +// GetSignedX448KeysByParent implements store.KeyStore. +func (m *MockKeyStore) GetSignedX448KeysByParent( parentKeyAddress []byte, keyPurpose string, ) ([]*protobufs.SignedX448Key, error) { @@ -118,8 +118,44 @@ func (m *MockKeyStore) GetSignedKeysByParent( return args.Get(0).([]*protobufs.SignedX448Key), args.Error(1) } -// DeleteSignedKey implements store.KeyStore. -func (m *MockKeyStore) DeleteSignedKey( +// DeleteSignedX448Key implements store.KeyStore. +func (m *MockKeyStore) DeleteSignedX448Key( + txn store.Transaction, + address []byte, +) error { + args := m.Called(txn, address) + return args.Error(0) +} + +// PutSignedDecaf448Key implements store.KeyStore. +func (m *MockKeyStore) PutSignedDecaf448Key( + txn store.Transaction, + address []byte, + key *protobufs.SignedDecaf448Key, +) error { + args := m.Called(txn, address, key) + return args.Error(0) +} + +// GetSignedDecaf448Key implements store.KeyStore. +func (m *MockKeyStore) GetSignedDecaf448Key( + address []byte, +) (*protobufs.SignedDecaf448Key, error) { + args := m.Called(address) + return args.Get(0).(*protobufs.SignedDecaf448Key), args.Error(1) +} + +// GetSignedDecaf448KeysByParent implements store.KeyStore. +func (m *MockKeyStore) GetSignedDecaf448KeysByParent( + parentKeyAddress []byte, + keyPurpose string, +) ([]*protobufs.SignedDecaf448Key, error) { + args := m.Called(parentKeyAddress, keyPurpose) + return args.Get(0).([]*protobufs.SignedDecaf448Key), args.Error(1) +} + +// DeleteSignedDecaf448Key implements store.KeyStore. +func (m *MockKeyStore) DeleteSignedDecaf448Key( txn store.Transaction, address []byte, ) error { @@ -169,8 +205,8 @@ func (m *MockKeyStore) RangeIdentityKeys() ( args.Error(1) } -// RangeSignedKeys implements store.KeyStore. -func (m *MockKeyStore) RangeSignedKeys( +// RangeSignedX448Keys implements store.KeyStore. +func (m *MockKeyStore) RangeSignedX448Keys( parentKeyAddress []byte, keyPurpose string, ) (store.TypedIterator[*protobufs.SignedX448Key], error) { @@ -178,3 +214,13 @@ func (m *MockKeyStore) RangeSignedKeys( return args.Get(0).(store.TypedIterator[*protobufs.SignedX448Key]), args.Error(1) } + +// RangeSignedKeys implements store.KeyStore. +func (m *MockKeyStore) RangeSignedDecaf448Keys( + parentKeyAddress []byte, + keyPurpose string, +) (store.TypedIterator[*protobufs.SignedDecaf448Key], error) { + args := m.Called(parentKeyAddress, keyPurpose) + return args.Get(0).(store.TypedIterator[*protobufs.SignedDecaf448Key]), + args.Error(1) +} diff --git a/types/mocks/prover_registry.go b/types/mocks/prover_registry.go index 273ef752..5043089d 100644 --- a/types/mocks/prover_registry.go +++ b/types/mocks/prover_registry.go @@ -10,6 +10,17 @@ type MockProverRegistry struct { mock.Mock } +var _ consensus.ProverRegistry = (*MockProverRegistry)(nil) + +// GetProvers implements consensus.ProverRegistry. +func (m *MockProverRegistry) GetProvers(filter []byte) ( + []*consensus.ProverInfo, + error, +) { + args := m.Called(filter) + return args.Get(0).([]*consensus.ProverInfo), args.Error(1) +} + // GetAllActiveAppShardProvers implements consensus.ProverRegistry. func (m *MockProverRegistry) GetAllActiveAppShardProvers() ( []*consensus.ProverInfo, diff --git a/types/mocks/shard_execution.go b/types/mocks/shard_execution.go index b564e34d..c7d58f68 100644 --- a/types/mocks/shard_execution.go +++ b/types/mocks/shard_execution.go @@ -15,6 +15,22 @@ type MockShardExecutionEngine struct { mock.Mock } +// Lock implements execution.ShardExecutionEngine. +func (m *MockShardExecutionEngine) Lock( + frameNumber uint64, + address []byte, + message []byte, +) error { + args := m.Called(frameNumber, address, message) + return args.Error(0) +} + +// Unlock implements execution.ShardExecutionEngine. +func (m *MockShardExecutionEngine) Unlock() error { + args := m.Called() + return args.Error(0) +} + // Prove implements execution.ShardExecutionEngine. func (m *MockShardExecutionEngine) Prove( domain []byte, diff --git a/types/mocks/signer_registry.go b/types/mocks/signer_registry.go index c2ed7ec5..82168df4 100644 --- a/types/mocks/signer_registry.go +++ b/types/mocks/signer_registry.go @@ -46,14 +46,22 @@ func (m *MockSignerRegistry) ValidateProvingKey( return args.Error(0) } -// ValidateSignedKey validates a signed X448 key -func (m *MockSignerRegistry) ValidateSignedKey( +// ValidateSignedX448Key validates a signed X448 key +func (m *MockSignerRegistry) ValidateSignedX448Key( signedKey *protobufs.SignedX448Key, ) error { args := m.Called(signedKey) return args.Error(0) } +// ValidateSignedDecaf448Key validates a signed Decaf448 key +func (m *MockSignerRegistry) ValidateSignedDecaf448Key( + signedKey *protobufs.SignedDecaf448Key, +) error { + args := m.Called(signedKey) + return args.Error(0) +} + // PutIdentityKey stores an identity key func (m *MockSignerRegistry) PutIdentityKey( txn store.Transaction, @@ -92,8 +100,8 @@ func (m *MockSignerRegistry) PutCrossSignature( return args.Error(0) } -// PutSignedKey stores a signed X448 key -func (m *MockSignerRegistry) PutSignedKey( +// PutSignedX448Key stores a signed X448 key +func (m *MockSignerRegistry) PutSignedX448Key( txn store.Transaction, address []byte, key *protobufs.SignedX448Key, @@ -102,6 +110,16 @@ func (m *MockSignerRegistry) PutSignedKey( return args.Error(0) } +// PutSignedDecaf448Key stores a signed Decaf448 key +func (m *MockSignerRegistry) PutSignedDecaf448Key( + txn store.Transaction, + address []byte, + key *protobufs.SignedDecaf448Key, +) error { + args := m.Called(txn, address, key) + return args.Error(0) +} + // GetIdentityKey retrieves an identity key by address func (m *MockSignerRegistry) GetIdentityKey(address []byte) ( *protobufs.Ed448PublicKey, @@ -121,8 +139,8 @@ func (m *MockSignerRegistry) GetProvingKey(address []byte) ( args.Error(1) } -// GetSignedKey retrieves a signed key by address -func (m *MockSignerRegistry) GetSignedKey(address []byte) ( +// GetSignedX448Key retrieves a signed key by address +func (m *MockSignerRegistry) GetSignedX448Key(address []byte) ( *protobufs.SignedX448Key, error, ) { @@ -130,8 +148,8 @@ func (m *MockSignerRegistry) GetSignedKey(address []byte) ( return args.Get(0).(*protobufs.SignedX448Key), args.Error(1) } -// GetSignedKeysByParent retrieves all signed keys for a parent key -func (m *MockSignerRegistry) GetSignedKeysByParent( +// GetSignedX448KeysByParent retrieves all signed keys for a parent key +func (m *MockSignerRegistry) GetSignedX448KeysByParent( parentKeyAddress []byte, keyPurpose string, ) ([]*protobufs.SignedX448Key, error) { @@ -139,6 +157,24 @@ func (m *MockSignerRegistry) GetSignedKeysByParent( return args.Get(0).([]*protobufs.SignedX448Key), args.Error(1) } +// GetSignedDecaf448Key retrieves a signed key by address +func (m *MockSignerRegistry) GetSignedDecaf448Key(address []byte) ( + *protobufs.SignedDecaf448Key, + error, +) { + args := m.Called(address) + return args.Get(0).(*protobufs.SignedDecaf448Key), args.Error(1) +} + +// GetSignedDecaf448KeysByParent retrieves all signed keys for a parent key +func (m *MockSignerRegistry) GetSignedDecaf448KeysByParent( + parentKeyAddress []byte, + keyPurpose string, +) ([]*protobufs.SignedDecaf448Key, error) { + args := m.Called(parentKeyAddress, keyPurpose) + return args.Get(0).([]*protobufs.SignedDecaf448Key), args.Error(1) +} + // RangeProvingKeys returns an iterator over all proving keys func (m *MockSignerRegistry) RangeProvingKeys() ( store.TypedIterator[*protobufs.BLS48581SignatureWithProofOfPossession], @@ -159,8 +195,8 @@ func (m *MockSignerRegistry) RangeIdentityKeys() ( args.Error(1) } -// RangeSignedKeys returns an iterator over signed keys -func (m *MockSignerRegistry) RangeSignedKeys( +// RangeSignedX448Keys returns an iterator over signed keys +func (m *MockSignerRegistry) RangeSignedX448Keys( parentKeyAddress []byte, keyPurpose string, ) (store.TypedIterator[*protobufs.SignedX448Key], error) { @@ -168,3 +204,13 @@ func (m *MockSignerRegistry) RangeSignedKeys( return args.Get(0).(store.TypedIterator[*protobufs.SignedX448Key]), args.Error(1) } + +// RangeSignedDecaf448Keys returns an iterator over signed keys +func (m *MockSignerRegistry) RangeSignedDecaf448Keys( + parentKeyAddress []byte, + keyPurpose string, +) (store.TypedIterator[*protobufs.SignedDecaf448Key], error) { + args := m.Called(parentKeyAddress, keyPurpose) + return args.Get(0).(store.TypedIterator[*protobufs.SignedDecaf448Key]), + args.Error(1) +} diff --git a/types/store/key.go b/types/store/key.go index d1a28ac7..e5fca4bb 100644 --- a/types/store/key.go +++ b/types/store/key.go @@ -37,19 +37,37 @@ type KeyStore interface { GetCrossSignatureByProvingKey(provingKeyAddress []byte) ([]byte, error) // Signed X448 key operations (supports multiple keys per type) - PutSignedKey( + PutSignedX448Key( txn Transaction, address []byte, key *protobufs.SignedX448Key, ) error - GetSignedKey( + GetSignedX448Key( address []byte, ) (*protobufs.SignedX448Key, error) - GetSignedKeysByParent( + GetSignedX448KeysByParent( parentKeyAddress []byte, keyPurpose string, // Optional filter by purpose ) ([]*protobufs.SignedX448Key, error) - DeleteSignedKey( + DeleteSignedX448Key( + txn Transaction, + address []byte, + ) error + + // Signed Decaf448 key operations (supports multiple keys per type) + PutSignedDecaf448Key( + txn Transaction, + address []byte, + key *protobufs.SignedDecaf448Key, + ) error + GetSignedDecaf448Key( + address []byte, + ) (*protobufs.SignedDecaf448Key, error) + GetSignedDecaf448KeysByParent( + parentKeyAddress []byte, + keyPurpose string, // Optional filter by purpose + ) ([]*protobufs.SignedDecaf448Key, error) + DeleteSignedDecaf448Key( txn Transaction, address []byte, ) error @@ -72,11 +90,18 @@ type KeyStore interface { TypedIterator[*protobufs.Ed448PublicKey], error, ) - RangeSignedKeys( + RangeSignedX448Keys( parentKeyAddress []byte, // Optional filter keyPurpose string, // Optional filter ) ( TypedIterator[*protobufs.SignedX448Key], error, ) + RangeSignedDecaf448Keys( + parentKeyAddress []byte, // Optional filter + keyPurpose string, // Optional filter + ) ( + TypedIterator[*protobufs.SignedDecaf448Key], + error, + ) } diff --git a/types/tries/lazy_proof_tree.go b/types/tries/lazy_proof_tree.go index cadc57c7..4a958b61 100644 --- a/types/tries/lazy_proof_tree.go +++ b/types/tries/lazy_proof_tree.go @@ -293,7 +293,7 @@ func commitNode( setType, phaseType, shardKey, - getFullPath(node.Key), + GetFullPath(node.Key), recalculate, ), nil default: @@ -612,7 +612,7 @@ func (t *LazyVectorCommitmentTree) InsertLeafSkeleton( t.PhaseType, t.ShardKey, leaf.Key, - getFullPath(leaf.Key), + GetFullPath(leaf.Key), leaf, ); err != nil { return err @@ -662,7 +662,7 @@ func (t *LazyVectorCommitmentTree) Insert( // Check if key is within the covered prefix (if one is defined) if len(t.CoveredPrefix) > 0 { - keyPath := getFullPath(key) + keyPath := GetFullPath(key) if !t.isPathWithinCoveredPrefix(keyPath) { return errors.New("key is outside covered prefix range") } @@ -706,7 +706,7 @@ func (t *LazyVectorCommitmentTree) Insert( t.PhaseType, t.ShardKey, key, - getFullPath(key), + GetFullPath(key), newNode, ) if err != nil { @@ -747,7 +747,7 @@ func (t *LazyVectorCommitmentTree) Insert( t.PhaseType, t.ShardKey, key, - getFullPath(key), + GetFullPath(key), n, ) if err != nil { @@ -789,7 +789,7 @@ func (t *LazyVectorCommitmentTree) Insert( t.PhaseType, t.ShardKey, key, - getFullPath(key), + GetFullPath(key), branch.Children[finalNewNibble], ) if err != nil { @@ -1401,7 +1401,7 @@ func (t *LazyVectorCommitmentTree) Prove(key []byte) *TraversalProof { t.SetType, t.PhaseType, t.ShardKey, - getFullPath(n.Key), + GetFullPath(n.Key), false, ) if bytes.Equal(n.Key, key) { @@ -1542,7 +1542,7 @@ func (t *LazyVectorCommitmentTree) ProveMultiple( t.SetType, t.PhaseType, t.ShardKey, - getFullPath(n.Key), + GetFullPath(n.Key), false, ) if bytes.Equal(n.Key, key) { @@ -1736,6 +1736,9 @@ func (t *LazyVectorCommitmentTree) Commit(recalculate bool) []byte { func (t *LazyVectorCommitmentTree) GetSize() *big.Int { t.treeMx.RLock() defer t.treeMx.RUnlock() + if t.Root == nil { + return big.NewInt(0) + } return t.Root.GetSize() } @@ -1787,7 +1790,7 @@ func (t *LazyVectorCommitmentTree) Delete( t.PhaseType, t.ShardKey, key, - getFullPath(key), + GetFullPath(key), ) if err != nil { log.Panic("failed to delete path", zap.Error(err)) diff --git a/types/tries/proof_tree.go b/types/tries/proof_tree.go index 7e06d7e6..6ee1b880 100644 --- a/types/tries/proof_tree.go +++ b/types/tries/proof_tree.go @@ -237,7 +237,7 @@ func getNextNibble(key []byte, pos int) int { return result & BranchMask } -func getFullPath(key []byte) []int { +func GetFullPath(key []byte) []int { var nibbles []int depth := 0 for { diff --git a/types/worker/manager.go b/types/worker/manager.go index 47e99e25..8c0e51d9 100644 --- a/types/worker/manager.go +++ b/types/worker/manager.go @@ -14,6 +14,7 @@ type WorkerManager interface { GetWorkerIdByFilter(filter []byte) (uint, error) GetFilterByWorkerId(coreId uint) ([]byte, error) RegisterWorker(info *store.WorkerInfo) error - ProposeAllocation(coreId uint, filter []byte) error + ProposeAllocations(coreIds []uint, filters [][]byte) error + DecideAllocations(reject [][]byte, confirm [][]byte) error RangeWorkers() ([]*store.WorkerInfo, error) } diff --git a/vdf/go.mod b/vdf/go.mod index 27d9f48c..3e75a443 100644 --- a/vdf/go.mod +++ b/vdf/go.mod @@ -1,6 +1,6 @@ module source.quilibrium.com/quilibrium/monorepo/vdf -go 1.23.0 +go 1.23.2 toolchain go1.23.4 @@ -19,49 +19,44 @@ replace source.quilibrium.com/quilibrium/monorepo/types => ../types replace source.quilibrium.com/quilibrium/monorepo/utils => ../utils +replace source.quilibrium.com/quilibrium/monorepo/consensus => ../consensus + require ( - github.com/cloudflare/circl v1.6.1 github.com/iden3/go-iden3-crypto v0.0.17 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.10.0 go.uber.org/zap v1.27.0 - golang.org/x/crypto v0.38.0 + golang.org/x/crypto v0.39.0 source.quilibrium.com/quilibrium/monorepo/protobufs v0.0.0-00010101000000-000000000000 source.quilibrium.com/quilibrium/monorepo/types v0.0.0-00010101000000-000000000000 ) require ( + github.com/cloudflare/circl v1.6.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect github.com/ipfs/go-cid v0.5.0 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect - github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/libp2p/go-libp2p v0.41.1 // 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 v0.15.0 // indirect + github.com/multiformats/go-multiaddr v0.16.1 // 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-varint v0.0.7 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/txaty/go-merkletree v0.2.2 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect - golang.org/x/net v0.35.0 // indirect - golang.org/x/sync v0.14.0 // indirect + golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 // indirect + golang.org/x/net v0.41.0 // indirect golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.25.0 // indirect + golang.org/x/text v0.26.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect google.golang.org/grpc v1.72.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - lukechampine.com/blake3 v1.4.0 // indirect - source.quilibrium.com/quilibrium/monorepo/utils v0.0.0-00010101000000-000000000000 // indirect + lukechampine.com/blake3 v1.4.1 // indirect + source.quilibrium.com/quilibrium/monorepo/consensus v0.0.0-00010101000000-000000000000 // indirect ) diff --git a/vdf/go.sum b/vdf/go.sum index 47971729..ce1b4c02 100644 --- a/vdf/go.sum +++ b/vdf/go.sum @@ -1,13 +1,7 @@ -github.com/agiledragon/gomonkey/v2 v2.11.0 h1:5oxSgA+tC1xuGsrIorR+sYiziYltmJyEZ9qA25b6l5U= -github.com/agiledragon/gomonkey/v2 v2.11.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= -github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -32,8 +26,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= -github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= -github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= @@ -44,8 +36,6 @@ github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9 github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= 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.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= @@ -60,8 +50,6 @@ github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0b github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/txaty/go-merkletree v0.2.2 h1:K5bHDFK+Q3KK+gEJeyTOECKuIwl/LVo4CI+cm0/p34g= -github.com/txaty/go-merkletree v0.2.2/go.mod h1:w5HPEu7ubNw5LzS+91m+1/GtuZcWHKiPU3vEGi+ThJM= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= @@ -80,18 +68,16 @@ 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.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= -golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= -golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4= -golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk= -golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= -golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 h1:bsqhLWFR6G6xiQcb+JoGqdKdRU6WzPWmK8E0jxTjzo4= +golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4= @@ -105,5 +91,5 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -lukechampine.com/blake3 v1.4.0 h1:xDbKOZCVbnZsfzM6mHSYcGRHZ3YrLDzqz8XnV4uaD5w= -lukechampine.com/blake3 v1.4.0/go.mod h1:MQJNQCTnR+kwOP/JEZSxj3MaQjp80FOFSNMMHXcSeX0= +lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= +lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo= diff --git a/vdf/vdf.go b/vdf/vdf.go index 369e13bc..02e8879c 100644 --- a/vdf/vdf.go +++ b/vdf/vdf.go @@ -30,3 +30,48 @@ func WesolowskiVerify( allegedSolution[:], ) } + +// WesolowskiSolveMulti produces a single worker-i blob ([y_i | π_i]) using ID-bound bases. +func WesolowskiSolveMulti( + challenge [32]byte, + difficulty uint32, + ids [][]byte, + i uint32, +) [516]byte { + return [516]byte( + generated.WesolowskiSolveMulti( + intSizeBits, + challenge[:], + difficulty, + ids, + i, + ), + ) +} + +// WesolowskiVerifyMulti verifies *all* workers in one shot (verifier-side aggregation). +// `allegedSolutions` must be parallel to `ids`; each entry is a 516-byte blob from WesolowskiSolveMulti. +func WesolowskiVerifyMulti( + challenge [32]byte, + difficulty uint32, + ids [][]byte, + allegedSolutions [][516]byte, +) bool { + // Convert [][516]byte -> [][]byte for the generated binding + as := make([][]byte, len(allegedSolutions)) + for idx := range allegedSolutions { + as[idx] = allegedSolutions[idx][:] + } + + if len(ids) != len(as) { + return false + } + + return generated.WesolowskiVerifyMulti( + intSizeBits, + challenge[:], + difficulty, + ids, + as, + ) +} diff --git a/vdf/vdf_test.go b/vdf/vdf_test.go index dfc9e190..ab35a4dd 100644 --- a/vdf/vdf_test.go +++ b/vdf/vdf_test.go @@ -1,7 +1,11 @@ package vdf_test import ( + "bytes" + "fmt" + "sync" "testing" + "time" "golang.org/x/crypto/sha3" "source.quilibrium.com/quilibrium/monorepo/vdf" @@ -15,39 +19,183 @@ func TestProveVerify(t *testing.T) { difficulty := uint32(160000) challenge := getChallenge("TestProveVerify") solution := vdf.WesolowskiSolve(challenge, difficulty) + now := time.Now() isOk := vdf.WesolowskiVerify(challenge, difficulty, solution) + fmt.Printf("%v\n", time.Since(now)) if !isOk { t.Fatalf("Verification failed") } } -// func TestProveRustVerifyNekro(t *testing.T) { -// difficulty := uint32(100) -// challenge := getChallenge("TestProveRustVerifyNekro") - -// for i := 0; i < 100; i++ { -// solution := vdf.WesolowskiSolve(challenge, difficulty) -// nekroVdf := nekrovdf.New(difficulty, challenge) -// isOk := nekroVdf.Verify(solution) -// if !isOk { -// t.Fatalf("Verification failed") -// } -// challenge = sha3.Sum256(solution[:]) -// } -// } - -// func TestProveNekroVerifyRust(t *testing.T) { -// difficulty := uint32(100) -// challenge := getChallenge("TestProveNekroVerifyRust") - -// for i := 0; i < 100; i++ { -// nekroVdf := nekrovdf.New(difficulty, challenge) -// nekroVdf.Execute() -// proof := nekroVdf.GetOutput() -// isOk := vdf.WesolowskiVerify(challenge, difficulty, proof) -// if !isOk { -// t.Fatalf("Verification failed") -// } -// challenge = sha3.Sum256(proof[:]) -// } -// } +func TestProveVerifyMulti_Succeeds(t *testing.T) { + difficulty := uint32(160000) + challenge := getChallenge("TestProveVerifyMulti_Succeeds") + + ids := [][]byte{ + []byte("worker-A"), + []byte("worker-B"), + []byte("worker-C"), + } + + blobs := make([][516]byte, len(ids)) + wg := sync.WaitGroup{} + for i := range ids { + wg.Add(1) + go func() { + defer wg.Done() + blobs[i] = vdf.WesolowskiSolveMulti(challenge, difficulty, ids, uint32(i)) + }() + } + wg.Wait() + + now := time.Now() + if ok := vdf.WesolowskiVerifyMulti(challenge, difficulty, ids, blobs); !ok { + t.Fatalf("Multi verification failed") + } + fmt.Printf("%v\n", time.Since(now)) + wg = sync.WaitGroup{} + + ids = [][]byte{ + []byte("worker-A"), + []byte("worker-B"), + []byte("worker-C"), + []byte("worker-D"), + []byte("worker-E"), + []byte("worker-F"), + []byte("worker-G"), + } + + blobs = make([][516]byte, len(ids)) + for i := range ids { + wg.Add(1) + go func() { + defer wg.Done() + blobs[i] = vdf.WesolowskiSolveMulti(challenge, difficulty, ids, uint32(i)) + }() + } + + wg.Wait() + + now = time.Now() + if ok := vdf.WesolowskiVerifyMulti(challenge, difficulty, ids, blobs); !ok { + t.Fatalf("Multi verification failed") + } + fmt.Printf("%v\n", time.Since(now)) +} + +func TestProveVerifyMulti_OrderInsensitive(t *testing.T) { + difficulty := uint32(50000) + challenge := getChallenge("TestProveVerifyMulti_OrderInsensitive") + + ids := [][]byte{ + []byte("alice"), + []byte("bob"), + []byte("carol"), + []byte("dave"), + } + + blobs := make([][516]byte, len(ids)) + for i := range ids { + blobs[i] = vdf.WesolowskiSolveMulti(challenge, difficulty, ids, uint32(i)) + } + + permIdx := []int{2, 0, 3, 1} + idsPerm := make([][]byte, len(ids)) + blobsPerm := make([][516]byte, len(ids)) + for i, j := range permIdx { + idsPerm[i] = ids[j] + blobsPerm[i] = blobs[j] + } + + if ok := vdf.WesolowskiVerifyMulti(challenge, difficulty, idsPerm, blobsPerm); !ok { + t.Fatalf("Multi verification failed under permutation") + } +} + +func TestProveVerifyMulti_TamperFails(t *testing.T) { + difficulty := uint32(30000) + challenge := getChallenge("TestProveVerifyMulti_TamperFails") + + ids := [][]byte{[]byte("w1"), []byte("w2")} + blobs := make([][516]byte, len(ids)) + for i := range ids { + blobs[i] = vdf.WesolowskiSolveMulti(challenge, difficulty, ids, uint32(i)) + } + + tampered := blobs + tampered[1][100] ^= 0x01 + + if ok := vdf.WesolowskiVerifyMulti(challenge, difficulty, ids, tampered); ok { + t.Fatalf("Expected tampered multi verification to fail") + } +} + +func TestProveVerifyMulti_MissingOrWrongIDsFail(t *testing.T) { + difficulty := uint32(30000) + challenge := getChallenge("TestProveVerifyMulti_MissingOrWrongIDsFail") + + ids := [][]byte{[]byte("w1"), []byte("w2"), []byte("w3")} + blobs := make([][516]byte, len(ids)) + for i := range ids { + blobs[i] = vdf.WesolowskiSolveMulti(challenge, difficulty, ids, uint32(i)) + } + + idsSubset := ids[:2] + blobsSubset := blobs[:2] + if ok := vdf.WesolowskiVerifyMulti(challenge, difficulty, idsSubset, blobsSubset); ok { + t.Fatalf("Expected subset verification to fail (b and S bound to full ID set)") + } + + idsWrong := make([][]byte, len(ids)) + copy(idsWrong, ids) + idsWrong[1] = []byte("w2-CHANGED") + if ok := vdf.WesolowskiVerifyMulti(challenge, difficulty, idsWrong, blobs); ok { + t.Fatalf("Expected verification to fail with mismatched IDs") + } + + idsExtra := append(ids, []byte("w4")) + if ok := vdf.WesolowskiVerifyMulti(challenge, difficulty, idsExtra, blobs); ok { + t.Fatalf("Expected verification to fail on mismatched lengths") + } + + idsShuffled := [][]byte{ids[2], ids[0], ids[1]} + blobsWrongPairing := [][516]byte{blobs[0], blobs[1], blobs[2]} + + // Shuffled set should still succeed, because it gets reordered + if ok := vdf.WesolowskiVerifyMulti(challenge, difficulty, idsShuffled, blobsWrongPairing); !ok { + t.Fatalf("Expected verification to succeed with wrong ID/blob pairing") + } + + if ok := vdf.WesolowskiVerifyMulti(challenge, difficulty, ids, blobs); !ok { + t.Fatalf("Original multi verification should pass") + } +} + +func TestProveVerifyMulti_DifferentChallengesFail(t *testing.T) { + difficulty := uint32(30000) + challengeA := getChallenge("A") + challengeB := getChallenge("B") + + ids := [][]byte{[]byte("wa"), []byte("wb")} + blobs := make([][516]byte, len(ids)) + for i := range ids { + blobs[i] = vdf.WesolowskiSolveMulti(challengeA, difficulty, ids, uint32(i)) + } + + // Verify against a different challenge — should fail. + if ok := vdf.WesolowskiVerifyMulti(challengeB, difficulty, ids, blobs); ok { + t.Fatalf("Expected verification to fail for different challenge") + } +} + +func TestProveVerifyMulti_Determinism(t *testing.T) { + difficulty := uint32(20000) + challenge := getChallenge("determinism-multi") + ids := [][]byte{[]byte("x"), []byte("y")} + + b1 := vdf.WesolowskiSolveMulti(challenge, difficulty, ids, 0) + b2 := vdf.WesolowskiSolveMulti(challenge, difficulty, ids, 0) + if !bytes.Equal(b1[:], b2[:]) { + t.Fatalf("Expected deterministic blob for same inputs") + } +} diff --git a/vdf/wesolowski_frame_prover.go b/vdf/wesolowski_frame_prover.go index d2d65735..b8bcd62e 100644 --- a/vdf/wesolowski_frame_prover.go +++ b/vdf/wesolowski_frame_prover.go @@ -55,6 +55,33 @@ func GetSetBitIndices(mask []byte) []uint8 { return indices } +func (w *WesolowskiFrameProver) CalculateMultiProof( + challenge [32]byte, + difficulty uint32, + ids [][]byte, + index uint32, +) [516]byte { + return WesolowskiSolveMulti(challenge, difficulty, ids, index) +} + +func (w *WesolowskiFrameProver) VerifyMultiProof( + challenge [32]byte, + difficulty uint32, + ids [][]byte, + allegedSolutions [][516]byte, +) (bool, error) { + if len(ids) != len(allegedSolutions) || len(ids) == 0 { + return false, errors.New("invalid payload") + } + + return WesolowskiVerifyMulti( + challenge, + difficulty, + ids, + allegedSolutions, + ), nil +} + func (w *WesolowskiFrameProver) ProveFrameHeaderGenesis( address []byte, difficulty uint32, diff --git a/vdf/wesolowski_frame_prover_test.go b/vdf/wesolowski_frame_prover_test.go index fa5b8e41..3f1bc61d 100644 --- a/vdf/wesolowski_frame_prover_test.go +++ b/vdf/wesolowski_frame_prover_test.go @@ -14,49 +14,6 @@ import ( "source.quilibrium.com/quilibrium/monorepo/vdf" ) -func TestMasterProve(t *testing.T) { - l, _ := zap.NewProduction() - w := vdf.NewWesolowskiFrameProver(l) - m, err := w.CreateMasterGenesisFrame([]byte{ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, bytes.Repeat([]byte{0x00}, 516), 10000) - assert.NoError(t, err) - - next, err := w.ProveMasterClockFrame( - m, - time.Now().UnixMilli(), - 10000, - []*protobufs.InclusionAggregateProof{}, - ) - assert.NoError(t, err) - err = w.VerifyMasterClockFrame(next) - assert.NoError(t, err) -} - -func TestCalculateChallengeProofDifficulty(t *testing.T) { - l, _ := zap.NewProduction() - w := vdf.NewWesolowskiFrameProver(l) - - // At 0 increments, the difficulty should be 200,000 - difficulty0 := w.CalculateChallengeProofDifficulty(0) - assert.Equal(t, uint32(200000), difficulty0) - - // At 100,000 increments, the difficulty should be 175,000 - difficulty100k := w.CalculateChallengeProofDifficulty(100000) - assert.Equal(t, uint32(175000), difficulty100k) - - // At 700,000 increments, the difficulty should be 25,000 - difficulty700k := w.CalculateChallengeProofDifficulty(700000) - assert.Equal(t, uint32(25000), difficulty700k) - - // At 800,000 increments, the difficulty should stay at 25,000 - difficulty800k := w.CalculateChallengeProofDifficulty(800000) - assert.Equal(t, uint32(25000), difficulty800k) -} - func TestProveAndVerifyFrameHeader(t *testing.T) { l, _ := zap.NewProduction() w := vdf.NewWesolowskiFrameProver(l) @@ -139,26 +96,6 @@ func TestVerifyFrameHeaderValidation(t *testing.T) { frame *protobufs.FrameHeader expectError string }{ - { - name: "missing signature", - frame: &protobufs.FrameHeader{ - Address: []byte("test"), - FrameNumber: 1, - Timestamp: time.Now().UnixMilli(), - Difficulty: 10000, - Output: bytes.Repeat([]byte{0x01}, 516), - ParentSelector: bytes.Repeat([]byte{0x00}, 32), - RequestsRoot: bytes.Repeat([]byte{0x02}, 74), - StateRoots: [][]byte{ - bytes.Repeat([]byte{0x03}, 74), - bytes.Repeat([]byte{0x04}, 74), - bytes.Repeat([]byte{0x05}, 74), - bytes.Repeat([]byte{0x06}, 74), - }, - Prover: bytes.Repeat([]byte{0x07}, 32), - }, - expectError: "no valid signature provided", - }, { name: "empty address", frame: &protobufs.FrameHeader{ @@ -361,6 +298,10 @@ func TestProveFrameHeaderMissingPreviousFrame(t *testing.T) { type MockBlsConstructor struct{} +func (m *MockBlsConstructor) Aggregate(publicKeys [][]byte, signatures [][]byte) (crypto.BlsAggregateOutput, error) { + return nil, nil +} + func (m *MockBlsConstructor) New() (crypto.Signer, []byte, error) { return &MockBlsSigner{}, bytes.Repeat([]byte{0x01}, 74), nil }