From ad7a49f85074b51717ad382d83da1f1f06c07849 Mon Sep 17 00:00:00 2001 From: Konrad Feldmeier Date: Fri, 12 Dec 2025 14:06:29 +0100 Subject: [PATCH 01/21] Add happy path ETD compilation --- go.mod | 235 ++++++----- go.sum | 824 ++++++++++++++++++++++++------------- internal/router/router.go | 1 + internal/service/crypto.go | 174 +++++++- 4 files changed, 837 insertions(+), 397 deletions(-) diff --git a/go.mod b/go.mod index e399f00..01d9bb9 100644 --- a/go.mod +++ b/go.mod @@ -1,15 +1,19 @@ module github.com/shutter-network/shutter-api -go 1.22.0 +go 1.24.0 + +toolchain go1.24.11 require ( - github.com/ethereum/go-ethereum v1.13.11 + github.com/defiweb/go-sigparser v0.6.0 + github.com/ethereum/go-ethereum v1.15.11 github.com/gin-contrib/cors v1.7.3 github.com/jackc/pgx/v5 v5.7.1 - github.com/libp2p/go-libp2p-pubsub v0.11.0 - github.com/shutter-network/contracts/v2 v2.0.0-beta.2.0.20250108084129-3b743179373a - github.com/shutter-network/rolling-shutter/rolling-shutter v0.0.7-0.20250115055236-a8f828254ba9 - github.com/stretchr/testify v1.9.0 + github.com/libp2p/go-libp2p-pubsub v0.13.1 + github.com/prometheus/client_golang v1.22.0 + github.com/shutter-network/contracts/v2 v2.0.0-beta.2.0.20250908105003-7e53b1579b04 + github.com/shutter-network/rolling-shutter/rolling-shutter v0.0.0-00010101000000-000000000000 + github.com/stretchr/testify v1.10.0 github.com/swaggo/gin-swagger v1.6.0 github.com/swaggo/swag v1.16.4 github.com/testcontainers/testcontainers-go v0.34.0 @@ -18,167 +22,196 @@ require ( require ( github.com/KyleBanks/depth v1.2.1 // indirect + github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/cosmos/gogoproto v1.4.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect + github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect - github.com/elastic/gosigar v0.14.2 // indirect + github.com/deepmap/oapi-codegen v1.9.1 // indirect + github.com/elastic/gosigar v0.14.3 // indirect + github.com/emicklei/dot v1.6.2 // indirect + github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect + github.com/ethereum/go-verkle v0.2.2 // indirect + github.com/ferranbt/fastssz v0.1.4 // indirect github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect - github.com/getsentry/sentry-go v0.18.0 // indirect + github.com/getkin/kin-openapi v0.87.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-chi/chi/v5 v5.0.10 // indirect + github.com/go-kit/kit v0.12.0 // indirect + github.com/go-kit/log v0.2.1 // indirect + github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/spec v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect - github.com/google/go-cmp v0.6.0 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/go-cmp v0.7.0 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect + github.com/google/pprof v0.0.0-20250208200701-d0013a598941 // indirect + github.com/gorilla/mux v1.8.1 // indirect + github.com/gtank/merlin v0.1.1 // 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.5-0.20210104140557-80c98217689d // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/huin/goupnp v1.3.0 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect - github.com/ipfs/boxo v0.10.0 // indirect - github.com/ipfs/go-cid v0.4.1 // indirect - github.com/ipfs/go-datastore v0.6.0 // indirect - github.com/ipfs/go-log v1.0.5 // indirect - github.com/ipfs/go-log/v2 v2.5.1 // indirect - github.com/ipld/go-ipld-prime v0.20.0 // indirect + github.com/icza/gog v0.0.0-20240529172513-3355cf65d018 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/ipfs/boxo v0.30.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/v2 v2.6.0 // indirect + github.com/ipld/go-ipld-prime v0.21.0 // indirect + github.com/jackc/chunkreader/v2 v2.0.1 // indirect + github.com/jackc/pgconn v1.14.1 // indirect + github.com/jackc/pgio v1.0.0 // indirect + github.com/jackc/pgproto3/v2 v2.3.2 // indirect + github.com/jackc/pgtype v1.14.0 // indirect + github.com/jackc/pgx/v4 v4.18.1 // indirect + github.com/jackc/puddle v1.3.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect - github.com/jbenet/goprocess v0.1.4 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/koron/go-ssdp v0.0.4 // indirect + github.com/koron/go-ssdp v0.0.5 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect - github.com/libp2p/go-flow-metrics v0.1.0 // indirect - github.com/libp2p/go-libp2p v0.35.4 // indirect + github.com/libp2p/go-flow-metrics v0.2.0 // indirect + github.com/libp2p/go-libp2p v0.41.1 // indirect github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect - github.com/libp2p/go-libp2p-kad-dht v0.25.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-libp2p-routing-helpers v0.7.2 // indirect + github.com/libp2p/go-libp2p-kad-dht v0.33.0 // indirect + github.com/libp2p/go-libp2p-kbucket v0.7.0 // indirect + github.com/libp2p/go-libp2p-record v0.3.1 // indirect + github.com/libp2p/go-libp2p-routing-helpers v0.7.5 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect - github.com/libp2p/go-nat v0.2.0 // indirect - github.com/libp2p/go-netroute v0.2.1 // indirect + github.com/libp2p/go-netroute v0.2.2 // indirect github.com/libp2p/go-reuseport v0.4.0 // indirect - github.com/libp2p/go-yamux/v4 v4.0.1 // indirect + github.com/libp2p/go-yamux/v5 v5.0.0 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect - github.com/miekg/dns v1.1.58 // 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/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/pointerstructure v1.2.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.12.4 // indirect - github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect + github.com/multiformats/go-multiaddr v0.15.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.0 // indirect github.com/multiformats/go-multihash v0.2.3 // indirect - github.com/multiformats/go-multistream v0.5.0 // indirect + github.com/multiformats/go-multistream v0.6.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect - github.com/onsi/ginkgo/v2 v2.15.0 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/oapi-codegen/runtime v1.1.1 // indirect + github.com/onsi/ginkgo/v2 v2.22.2 // indirect github.com/opencontainers/runtime-spec v1.2.0 // indirect - github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pion/datachannel v1.5.6 // indirect - github.com/pion/dtls/v2 v2.2.11 // indirect - github.com/pion/ice/v2 v2.3.25 // indirect - github.com/pion/interceptor v0.1.29 // indirect - github.com/pion/logging v0.2.2 // indirect - github.com/pion/mdns v0.0.12 // indirect + github.com/petermattis/goid v0.0.0-20230808133559-b036b712a89b // 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.4 // indirect + github.com/pion/ice/v4 v4.0.8 // indirect + github.com/pion/interceptor v0.1.37 // 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.14 // indirect - github.com/pion/rtp v1.8.6 // indirect - github.com/pion/sctp v1.8.16 // indirect - github.com/pion/sdp/v3 v3.0.9 // indirect - github.com/pion/srtp/v2 v2.0.18 // indirect + github.com/pion/rtcp v1.2.15 // indirect + github.com/pion/rtp v1.8.11 // indirect + github.com/pion/sctp v1.8.37 // indirect + github.com/pion/sdp/v3 v3.0.10 // indirect + github.com/pion/srtp/v3 v3.0.4 // indirect github.com/pion/stun v0.6.1 // indirect - github.com/pion/transport/v2 v2.2.5 // indirect - github.com/pion/turn/v2 v2.1.6 // indirect - github.com/pion/webrtc/v3 v3.2.40 // indirect + github.com/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.0 // indirect + github.com/pion/webrtc/v4 v4.0.10 // indirect github.com/polydawn/refmt v0.89.0 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.48.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect - github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/quic-go v0.44.0 // indirect - github.com/quic-go/webtransport-go v0.8.0 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.63.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.50.1 // indirect + github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect + github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect + github.com/sasha-s/go-deadlock v0.3.1 // indirect + github.com/shutter-network/shop-contracts v0.0.0-20240407151512-08ef5d8355b6 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.8.2 // indirect github.com/spf13/cast v1.5.1 // indirect - github.com/spf13/cobra v1.6.1 // indirect + github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/pflag v1.0.6 // indirect github.com/spf13/viper v1.13.0 // indirect github.com/subosito/gotenv v1.4.2 // indirect - github.com/urfave/cli/v2 v2.27.5 // indirect + github.com/tendermint/tendermint v0.37.0-rc2 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect - go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 // indirect - go.opentelemetry.io/otel/sdk v1.27.0 // indirect + github.com/wlynxg/anet v0.0.5 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 // indirect + go.opentelemetry.io/otel/sdk v1.31.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.27.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect - go.uber.org/dig v1.17.1 // indirect - go.uber.org/fx v1.22.1 // indirect - go.uber.org/mock v0.4.0 // indirect + go.uber.org/dig v1.18.0 // indirect + go.uber.org/fx v1.23.0 // indirect + go.uber.org/mock v0.5.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/mod v0.22.0 // indirect - golang.org/x/tools v0.28.0 // indirect - gonum.org/v1/gonum v0.13.0 // indirect + golang.org/x/mod v0.24.0 // indirect + golang.org/x/tools v0.33.0 // indirect + gonum.org/v1/gonum v0.16.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 // indirect + google.golang.org/grpc v1.67.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - lukechampine.com/blake3 v1.2.1 // indirect + lukechampine.com/blake3 v1.4.1 // indirect ) require ( dario.cat/mergo v1.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/bits-and-blooms/bitset v1.10.0 // indirect + github.com/bits-and-blooms/bitset v1.20.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/bytedance/sonic v1.12.6 // indirect github.com/bytedance/sonic/loader v0.2.1 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect - github.com/consensys/bavard v0.1.13 // indirect - github.com/consensys/gnark-crypto v0.12.1 // indirect + github.com/consensys/gnark-crypto v0.18.0 // indirect github.com/containerd/containerd v1.7.18 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/platforms v0.2.1 // indirect github.com/cpuguy83/dockercfg v0.3.2 // indirect - github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/deckarep/golang-set/v2 v2.1.0 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/deckarep/golang-set/v2 v2.6.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/docker v27.1.1+incompatible // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/ethereum/c-kzg-4844 v0.4.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.7 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-playground/locales v0.14.1 // indirect @@ -188,17 +221,16 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect - github.com/holiman/uint256 v1.2.4 // indirect + github.com/holiman/uint256 v1.3.2 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.8 // indirect - github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/klauspost/compress v1.18.0 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mfridman/interpolate v0.0.2 // indirect - github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect @@ -210,7 +242,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/sethvargo/go-retry v0.3.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect @@ -218,24 +250,23 @@ require ( github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/stretchr/objx v0.5.2 // indirect - github.com/supranational/blst v0.3.12 - github.com/tklauser/go-sysconf v0.3.12 // indirect - github.com/tklauser/numcpus v0.6.1 // indirect + github.com/supranational/blst v0.3.16 + github.com/tklauser/go-sysconf v0.3.13 // indirect + github.com/tklauser/numcpus v0.7.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.27.0 // indirect - go.opentelemetry.io/otel/metric v1.27.0 // indirect - go.opentelemetry.io/otel/trace v1.27.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect + go.opentelemetry.io/otel v1.35.0 // indirect + go.opentelemetry.io/otel/metric v1.35.0 // indirect + go.opentelemetry.io/otel/trace v1.35.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.12.0 // indirect - golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect - golang.org/x/net v0.33.0 // indirect - golang.org/x/sys v0.28.0 // indirect - google.golang.org/protobuf v1.36.1 // indirect + golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/sys v0.36.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - rsc.io/tmplfunc v0.0.3 // indirect ) require ( @@ -248,7 +279,7 @@ require ( github.com/rs/zerolog v1.33.0 github.com/shutter-network/shutter/shlib v0.1.19 github.com/swaggo/files v1.0.1 - golang.org/x/crypto v0.31.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/crypto v0.38.0 // indirect + golang.org/x/sync v0.14.0 // indirect + golang.org/x/text v0.25.0 // indirect ) diff --git a/go.sum b/go.sum index 2c53537..6ea7c31 100644 --- a/go.sum +++ b/go.sum @@ -51,27 +51,38 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOEl github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= -github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= +github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= -github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= +github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= +github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= +github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= +github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= 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/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= +github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= -github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU= +github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/btcsuite/btcd v0.22.0-beta h1:LTDpDKUM5EeOFBPM8IXpinEcmZ6FWfNZbE3lfrfdnWo= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcutil v1.1.2 h1:XLMbX8JQEiwMcYft2EGi8zPUkoa0abKIU6/BJSRsjzQ= +github.com/btcsuite/btcd/btcutil v1.1.2/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 h1:KdUfX2zKommPRa+PD0sWZUyXe9w277ABlgELO7H04IM= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= @@ -80,13 +91,15 @@ github.com/bytedance/sonic v1.12.6/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKz github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E= github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -99,20 +112,22 @@ github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= -github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= +github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A= -github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo= +github.com/cockroachdb/pebble v1.1.2 h1:CUh2IPtR4swHlEj48Rhfzw6l/d0qA31fItcIszQVIsA= +github.com/cockroachdb/pebble v1.1.2/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= -github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= -github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= -github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0= +github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= @@ -123,33 +138,62 @@ github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3 github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU= +github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= +github.com/cosmos/gogoproto v1.4.1 h1:WoyH+0/jbCTzpKNvyav5FL1ZTWsp1im1MxEpJEzKUB8= +github.com/cosmos/gogoproto v1.4.1/go.mod h1:Ac9lzL4vFpBMcptJROQ6dQ4M3pOEK5Z/l0Q9p+LoCr4= +github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4Y= +github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= -github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= -github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= -github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= +github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg= +github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= +github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= +github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= +github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= +github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks= +github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6VqkYlkM= +github.com/creachadair/taskgroup v0.3.2/go.mod h1:wieWwecHVzsidg2CsUnFinW1faVN4+kq+TDlRJQ0Wbk= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= 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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/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/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= -github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= -github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= -github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +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.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= +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/deepmap/oapi-codegen v1.9.1 h1:yHmEnA7jSTUMQgV+uN02WpZtwHnz2CBW3mZRIxr1vtI= +github.com/deepmap/oapi-codegen v1.9.1/go.mod h1:PLqNAhdedP8ttRpBBkzLKU3bp+Fpy+tTgeAMlztR2cw= +github.com/defiweb/go-sigparser v0.6.0 h1:HSNAZSUl8xyV+nKfWNKYVAPWLwTuASas6ohtarBbOT4= +github.com/defiweb/go-sigparser v0.6.0/go.mod h1:R1wkfsnASR2M38ZupKHoqqIfv+8HgRbZaFQI9Inr4k8= +github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8= +github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= +github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= +github.com/dgraph-io/ristretto v0.0.3 h1:jh22xisGBjrEVnRZ1DVTpBVQm0Xndu8sMl0CWDzSIBI= +github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= @@ -163,29 +207,35 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= -github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= -github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= +github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/uo= +github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= +github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A= +github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= 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/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= -github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-ethereum v1.13.11 h1:b51Dsm+rEg7anFRUMGB8hODXHvNfcRKzz9vcj8wSdUs= -github.com/ethereum/go-ethereum v1.13.11/go.mod h1:gFtlVORuUcT+UUIcJ/veCNjkuOSujCi338uSHJrYAew= +github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s= +github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs= +github.com/ethereum/go-ethereum v1.15.11 h1:JK73WKeu0WC0O1eyX+mdQAVHUV+UR1a9VB/domDngBU= +github.com/ethereum/go-ethereum v1.15.11/go.mod h1:mf8YiHIb0GR4x4TipcvBUPxJLw1mFdmxzoDi11sDRoI= +github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8= +github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ= -github.com/fjl/memsize v0.0.1/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY= +github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg= 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/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= 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/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= @@ -193,10 +243,11 @@ github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= -github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= -github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= -github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= -github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= +github.com/getkin/kin-openapi v0.87.0 h1:eeb0WBIgRiXra7ZY0Vo+jWloqvaF2kNEaxAyb+39N+E= +github.com/getkin/kin-openapi v0.87.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= +github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= +github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/cors v1.7.3 h1:hV+a5xp8hwJoTw7OY+a70FsL8JkVVFTXw9EcfrYUdns= github.com/gin-contrib/cors v1.7.3/go.mod h1:M3bcKZhxzsvI+rlRSkkxHyljJt1ESd93COUvemZ79j4= @@ -204,40 +255,63 @@ github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= +github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= +github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= +github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +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-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o= github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= +github.com/goccy/go-json v0.7.8/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -246,18 +320,21 @@ github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= +github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 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= @@ -280,12 +357,17 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= 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= @@ -294,12 +376,13 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -310,6 +393,8 @@ github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= +github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -320,12 +405,10 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo= -github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc= +github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.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= @@ -336,13 +419,22 @@ github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 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/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= 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/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0= +github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.5.0 h1:WcmKMm43DR7RdtlkEXQJyo5ws8iTp98CyhCCbOHMvNI= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= +github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= +github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= +github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= +github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= 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= @@ -352,158 +444,251 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= -github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/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/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZKHF9GxxWKDJGj8I0IqOUol//sw= -github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= +github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4= +github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= -github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= +github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/ipfs/boxo v0.10.0 h1:tdDAxq8jrsbRkYoF+5Rcqyeb91hgWe2hp7iLu7ORZLY= -github.com/ipfs/boxo v0.10.0/go.mod h1:Fg+BnfxZ0RPzR0nOodzdIq3A7KgoWAOWsEIImrIQdBM= -github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= -github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= -github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= -github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= +github.com/icza/gog v0.0.0-20240529172513-3355cf65d018 h1:5SPFJCbm/boJpqPpzA/THc44Qi4wPQI0JVKZGCfdB+8= +github.com/icza/gog v0.0.0-20240529172513-3355cf65d018/go.mod h1:DfGPW5hjxzL8lvxIU3S1/jYrehLWYdue9RDw0FFA/fI= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/influxdata/influxdb-client-go/v2 v2.4.0 h1:HGBfZYStlx3Kqvsv1h2pJixbCl/jhnFtxpKFAv9Tu5k= +github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU= +github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= +github.com/ipfs/boxo v0.30.0 h1:7afsoxPGGqfoH7Dum/wOTGUB9M5fb8HyKPMlLfBvIEQ= +github.com/ipfs/boxo v0.30.0/go.mod h1:BPqgGGyHB9rZZcPSzah2Dc9C+5Or3U1aQe7EH1H7370= +github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs= +github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= +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.3 h1:2RFdGez6bu2ZlZdI+rWfIdbQb1KudQp3VGwPtdNCmE0= github.com/ipfs/go-ipfs-util v0.0.3/go.mod h1:LHzG1a0Ig4G+iZ26UUOMjHd+lfM84LZCrn17xAKWBvs= -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/ipfs/go-log/v2 v2.6.0 h1:2Nu1KKQQ2ayonKp4MPo6pXCjqw1ULc9iohRqWV5EYqg= +github.com/ipfs/go-log/v2 v2.6.0/go.mod h1:p+Efr3qaY5YXpx9TX7MoLCSEZX5boSWj9wh86P5HJa8= +github.com/ipfs/go-test v0.2.1 h1:/D/a8xZ2JzkYqcVcV/7HYlCnc7bv/pKHQiX5TdClkPE= +github.com/ipfs/go-test v0.2.1/go.mod h1:dzu+KB9cmWjuJnXFDYJwC25T3j1GcN57byN+ixmK39M= +github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E= +github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ= +github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= +github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= +github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= +github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= +github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= +github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= +github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= +github.com/jackc/pgconn v1.14.1 h1:smbxIaZA08n6YuxEX1sDyjV/qkbtUtkH20qLkR9MUR4= +github.com/jackc/pgconn v1.14.1/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= +github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= +github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0= +github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= +github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= +github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= +github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= +github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= +github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= +github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= +github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= +github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0= +github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE= github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= +github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= -github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= -github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= +github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 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/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= -github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +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.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= -github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= -github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= -github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/koron/go-ssdp v0.0.5 h1:E1iSMxIs4WqxTbIBLtmNBeOOC+1sCIXQeqTWVnpmwhk= +github.com/koron/go-ssdp v0.0.5/go.mod h1:Qm59B7hpKpDqfyRNWRNr00jGwLdXjDyZh6y7rH6VS0w= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 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.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 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/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= 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/labstack/echo/v4 v4.6.3/go.mod h1:Hk5OiHj0kDqmFq7aHe7eDqI7CUhuCrfpupQtLGGLm7A= +github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8= +github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8= +github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= +github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= +github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= +github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= +github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= +github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ= +github.com/lestrrat-go/codegen v1.0.2/go.mod h1:JhJw6OQAuPEfVKUCLItpaVLumDGWQznd1VaXrBk9TdM= +github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++0Gf8MBnAvE= +github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc= +github.com/lestrrat-go/jwx v1.2.7/go.mod h1:bw24IXWbavc0R2RsOtpXL7RtMyP589yZ1+L7kd09ZGA= +github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= -github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= -github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.35.4 h1:FDiBUYLkueFwsuNJUZaxKRdpKvBOWU64qQPL768bSeg= -github.com/libp2p/go-libp2p v0.35.4/go.mod h1:RKCDNt30IkFipGL0tl8wQW/3zVWEGFUZo8g2gAKxwjU= +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 v0.41.1 h1:8ecNQVT5ev/jqALTvisSJeVNvXYJyK4NhQx1nNRXQZE= +github.com/libp2p/go-libp2p v0.41.1/go.mod h1:DcGTovJzQl/I7HMrby5ZRjeD0kQkGiy+9w6aEkSZpRI= 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-kad-dht v0.25.1 h1:ofFNrf6MMEy4vi3R1VbJ7LOcTn3Csh0cDcaWHTxtWNA= -github.com/libp2p/go-libp2p-kad-dht v0.25.1/go.mod h1:6za56ncRHYXX4Nc2vn8z7CZK0P4QiMcrn77acKLM2Oo= -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-pubsub v0.11.0 h1:+JvS8Kty0OiyUiN0i8H5JbaCgjnJTRnTHe4rU88dLFc= -github.com/libp2p/go-libp2p-pubsub v0.11.0/go.mod h1:QEb+hEV9WL9wCiUAnpY29FZR6W3zK8qYlaml8R4q6gQ= -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-kad-dht v0.33.0 h1:lB6JFgLpsfEKTmcy27sPFulexEZMeN40zRsmIx8aFcw= +github.com/libp2p/go-libp2p-kad-dht v0.33.0/go.mod h1:CdmNk4VeGJa9EXM9SLNyNVySEvduKvb+5rSC/H4pLAo= +github.com/libp2p/go-libp2p-kbucket v0.7.0 h1:vYDvRjkyJPeWunQXqcW2Z6E93Ywx7fX0jgzb/dGOKCs= +github.com/libp2p/go-libp2p-kbucket v0.7.0/go.mod h1:blOINGIj1yiPYlVEX0Rj9QwEkmVnz3EP8LK1dRKBC6g= +github.com/libp2p/go-libp2p-pubsub v0.13.1 h1:tV3ttzzZSCk0EtEXnxVmWIXgjVxXx+20Jwjbs/Ctzjo= +github.com/libp2p/go-libp2p-pubsub v0.13.1/go.mod h1:MKPU5vMI8RRFyTP0HfdsF9cLmL1nHAeJm44AxJGJx44= +github.com/libp2p/go-libp2p-record v0.3.1 h1:cly48Xi5GjNw5Wq+7gmjfBiG9HCzQVkiZOUZ8kUl+Fg= +github.com/libp2p/go-libp2p-record v0.3.1/go.mod h1:T8itUkLcWQLCYMqtX7Th6r7SexyUJpIyPgks757td/E= +github.com/libp2p/go-libp2p-routing-helpers v0.7.5 h1:HdwZj9NKovMx0vqq6YNPTh6aaNzey5zHD7HeLJtq6fI= +github.com/libp2p/go-libp2p-routing-helpers v0.7.5/go.mod h1:3YaxrwP0OBPDD7my3D0KxfR89FlcX/IEbxDEDfAmj98= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= -github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= -github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= -github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= -github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= +github.com/libp2p/go-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/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= -github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= +github.com/libp2p/go-yamux/v5 v5.0.0 h1:2djUh96d3Jiac/JpGkKs4TO49YhsfLopAoryfPmf+Po= +github.com/libp2p/go-yamux/v5 v5.0.0/go.mod h1:en+3cdX51U0ZslwRdRLrvQsdayFt3TSUKvBGErzpWbU= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= 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/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 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/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY= github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= -github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= +github.com/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/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= +github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94= +github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= +github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= @@ -512,9 +697,6 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.1 h1:ZhBBeX8tSlRpu/FFhXH4RC4OJzFlqsQhoHZAz4x7TIw= github.com/mitchellh/pointerstructure v1.2.1/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= -github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= -github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= -github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= @@ -528,6 +710,7 @@ github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= @@ -541,11 +724,10 @@ github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYg github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.12.4 h1:rrKqpY9h+n80EwhhC/kkcunCZZ7URIF8yN1WEUt2Hvc= -github.com/multiformats/go-multiaddr v0.12.4/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= -github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= -github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= +github.com/multiformats/go-multiaddr v0.15.0 h1:zB/HeaI/apcZiTDwhY5YqMvNVl/oQYvs3XySU+qeAVo= +github.com/multiformats/go-multiaddr v0.15.0/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0= +github.com/multiformats/go-multiaddr-dns v0.4.1 h1:whi/uCLbDS3mSEUMb1MsoT4uzUeZB0N32yzufqS0i5M= +github.com/multiformats/go-multiaddr-dns v0.4.1/go.mod h1:7hfthtB4E4pQwirrz+J0CcDUfbWzTqEzVyYKKIKpgkc= 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.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= @@ -555,21 +737,24 @@ github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI1 github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= -github.com/multiformats/go-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE= -github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA= -github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-multistream v0.6.0 h1:ZaHKbsL404720283o4c/IHQXiS6gb8qAN5EIJ4PN5EA= +github.com/multiformats/go-multistream v0.6.0/go.mod h1:MOyoG5otO24cHIg8kf9QW2/NozURlkP/rvi2FQJyCPg= 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/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= 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/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro= +github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= -github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= -github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= -github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= +github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= +github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= +github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -586,56 +771,63 @@ github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3v github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= -github.com/pion/datachannel v1.5.6 h1:1IxKJntfSlYkpUj8LlYRSWpYiTTC02nUrOE8T3DqGeg= -github.com/pion/datachannel v1.5.6/go.mod h1:1eKT6Q85pRnr2mHiWHxJwO50SfZRtWHTsNIVb/NfGW4= +github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= +github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= +github.com/petermattis/goid v0.0.0-20230808133559-b036b712a89b h1:vab8deKC4QoIfm9fJM59iuNz1ELGsuLoYYpiF+pHiG8= +github.com/petermattis/goid v0.0.0-20230808133559-b036b712a89b/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +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.11 h1:9U/dpCYl1ySttROPWJgqWKEylUdT0fXp/xst6JwY5Ks= -github.com/pion/dtls/v2 v2.2.11/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= -github.com/pion/ice/v2 v2.3.25 h1:M5rJA07dqhi3nobJIg+uPtcVjFECTrhcR3n0ns8kDZs= -github.com/pion/ice/v2 v2.3.25/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw= -github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M= -github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4= -github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/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.4 h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U= +github.com/pion/dtls/v3 v3.0.4/go.mod h1:R373CsjxWqNPf6MEkfdy3aSe9niZvL/JaKlGeFphtMg= +github.com/pion/ice/v4 v4.0.8 h1:ajNx0idNG+S+v9Phu4LSn2cs8JEfTsA1/tEjkkAVpFY= +github.com/pion/ice/v4 v4.0.8/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= +github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI= +github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= -github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= -github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk= +github.com/pion/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.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= -github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= -github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= -github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/rtp v1.8.6 h1:MTmn/b0aWWsAzux2AmP8WGllusBVw4NPYPVFFd7jUPw= -github.com/pion/rtp v1.8.6/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/sctp v1.8.13/go.mod h1:YKSgO/bO/6aOMP9LCie1DuD7m+GamiK2yIiPM6vH+GA= -github.com/pion/sctp v1.8.16 h1:PKrMs+o9EMLRvFfXq59WFsC+V8mN1wnKzqrv+3D/gYY= -github.com/pion/sctp v1.8.16/go.mod h1:P6PbDVA++OJMrVNg2AL3XtYHV4uD6dvfyOovCgMs0PE= -github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= -github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= -github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo= -github.com/pion/srtp/v2 v2.0.18/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= +github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= +github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= +github.com/pion/rtp v1.8.11 h1:17xjnY5WO5hgO6SD3/NTIUPvSFw/PbLsIJyz1r1yNIk= +github.com/pion/rtp v1.8.11/go.mod h1:8uMBJj32Pa1wwx8Fuv/AsFhn8jsgw+3rUC2PfoBZ8p4= +github.com/pion/sctp v1.8.37 h1:ZDmGPtRPX9mKCiVXtMbTWybFw3z/hVKAZgU81wcOrqs= +github.com/pion/sctp v1.8.37/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE= +github.com/pion/sdp/v3 v3.0.10 h1:6MChLE/1xYB+CjumMw+gZ9ufp2DPApuVSnDT8t5MIgA= +github.com/pion/sdp/v3 v3.0.10/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E= +github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M= +github.com/pion/srtp/v3 v3.0.4/go.mod h1:1Jx3FwDoxpRaTh1oRV8A/6G1BnFL+QI82eK4ms8EEJQ= 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/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= +github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= +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.2/go.mod h1:OJg3ojoBJopjEeECq2yJdXH9YVrUJ1uQ++NjXLOUorc= -github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= -github.com/pion/transport/v2 v2.2.5 h1:iyi25i/21gQck4hfRhomF6SktmUQjRsRW4WJdhfc3Kc= -github.com/pion/transport/v2 v2.2.5/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= -github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= -github.com/pion/transport/v3 v3.0.2 h1:r+40RJR25S9w3jbA6/5uEPTzcdn7ncyU44RWCbHkLg4= -github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37m0IlWa/D0= -github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= -github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/webrtc/v3 v3.2.40 h1:Wtfi6AZMQg+624cvCXUuSmrKWepSB7zfgYDOYqsSOVU= -github.com/pion/webrtc/v3 v3.2.40/go.mod h1:M1RAe3TNTD1tzyvqHrbVODfwdPGSXOUo/OgpoGGJqFY= +github.com/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.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM= +github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA= +github.com/pion/webrtc/v4 v4.0.10 h1:Hq/JLjhqLxi+NmCtE8lnRPDr8H4LcNvwg8OxVcdv56Q= +github.com/pion/webrtc/v4 v4.0.10/go.mod h1:ViHLVaNpiuvaH8pdiuQxuA9awuE6KVzAXx3vVWilOck= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/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/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= @@ -643,36 +835,45 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:Om github.com/pressly/goose/v3 v3.23.0 h1:57hqKos8izGek4v6D5+OXBa+Y4Rq8MU//+MmnevdpVA= github.com/pressly/goose/v3 v3.23.0/go.mod h1:rpx+D9GX/+stXmzKa+uh1DkjPnNVMdiOCV9iLdle4N8= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_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.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +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.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= -github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= +github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= -github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0= -github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek= -github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg= -github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prysmaticlabs/gohashtree v0.0.4-beta h1:H/EbCuXPeTV3lpKeXGPpEV9gsUpkqOOVnWapUyeWro4= +github.com/prysmaticlabs/gohashtree v0.0.4-beta/go.mod h1:BFdtALS+Ffhg3lGQIHv9HDWuHS8cTvHZzrHWxwOtGOs= +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.50.1 h1:unsgjFIUqW8a2oopkY7YNONpV1gYND6Nt9hnt1PN94Q= +github.com/quic-go/quic-go v0.50.1/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E= +github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 h1:4WFk6u3sOT6pLa1kQ50ZVdm8BQFgJNA117cepZxtLIg= +github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66/go.mod h1:Vp72IJajgeOL6ddqrAhmp7IM9zbTcgkQxD/YdxrVwMw= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= -github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE= github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -680,6 +881,9 @@ github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3V github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= +github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE= github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas= @@ -691,6 +895,10 @@ github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFt github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= @@ -714,12 +922,14 @@ github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go. 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/shutter-network/contracts/v2 v2.0.0-beta.2.0.20250108084129-3b743179373a h1:hWw2nJLGPZU7Rvd6YmEEDfvlTUbwZKZl5UP2ThVVNSU= -github.com/shutter-network/contracts/v2 v2.0.0-beta.2.0.20250108084129-3b743179373a/go.mod h1:V8KhVM75wyWVSzZJ6GeC9dWCjRrinIQVb7mYNP+knbg= -github.com/shutter-network/rolling-shutter/rolling-shutter v0.0.7-0.20250115055236-a8f828254ba9 h1:Y8JzqawP7uxcFe8F4Z81nxGKfMLgrXtzd7sZ6//6lvk= -github.com/shutter-network/rolling-shutter/rolling-shutter v0.0.7-0.20250115055236-a8f828254ba9/go.mod h1:luyKfmpAUsHbLP3wykbeDihL5x91cTsUybQZogkLM4s= +github.com/shutter-network/contracts/v2 v2.0.0-beta.2.0.20250908105003-7e53b1579b04 h1:DfSfDw8IqXHqz6JXkZLIcvPS4CdoeXNaDhk+HEX61rM= +github.com/shutter-network/contracts/v2 v2.0.0-beta.2.0.20250908105003-7e53b1579b04/go.mod h1:V8KhVM75wyWVSzZJ6GeC9dWCjRrinIQVb7mYNP+knbg= +github.com/shutter-network/shop-contracts v0.0.0-20240407151512-08ef5d8355b6 h1:m6Ti1/IH+GBTtGqyAX3xbh+ruUKvC+m+/uzYDUa+JDQ= +github.com/shutter-network/shop-contracts v0.0.0-20240407151512-08ef5d8355b6/go.mod h1:LEWXLRruvxq9fe2oKtJI3xfzbauhfWTjOczHN61RU+4= github.com/shutter-network/shutter/shlib v0.1.19 h1:Fm/PnxAapl5UK4JuJyF2wBh3dYB5ESztnNFcbmzNNOI= github.com/shutter-network/shutter/shlib v0.1.19/go.mod h1:miY10OJ0FKjLZTwvmG0AJNijsjsNDAk6l1tROTj8uzU= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -735,17 +945,19 @@ github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= -github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU= github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= -github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= -github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= +github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= @@ -761,12 +973,12 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/supranational/blst v0.3.12 h1:Vfas2U2CFHhniv2QkUm2OVa1+pGTdqtpqm9NnhUUbZ8= -github.com/supranational/blst v0.3.12/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/supranational/blst v0.3.16 h1:bTDadT+3fK497EvLdWRQEjiGnUtzJ7jjIUMF0jqwYhE= +github.com/supranational/blst v0.3.16/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= @@ -776,38 +988,57 @@ github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0 github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/tendermint/tendermint v0.37.0-rc2 h1:2n1em+jfbhSv6QnBj8F6KHCpbIzZCB8KgcjidJUQNlY= +github.com/tendermint/tendermint v0.37.0-rc2/go.mod h1:uYQO9DRNPeZROa9X3hJOZpYcVREDC2/HST+EiU5g2+A= +github.com/tendermint/tm-db v0.6.7 h1:fE00Cbl0jayAoqlExN6oyQJ7fR/ZtoVOmvPJ//+shu8= +github.com/tendermint/tm-db v0.6.7/go.mod h1:byQDzFkZV1syXr/ReXS808NxA2xvyuuVgXOJ/088L6I= github.com/testcontainers/testcontainers-go v0.34.0 h1:5fbgF0vIN5u+nD3IWabQwRybuB4GY8G2HHgCkbMzMHo= github.com/testcontainers/testcontainers-go v0.34.0/go.mod h1:6P/kMkQe8yqPHfPWNulFGdFHTD8HB2vLq/231xY2iPQ= -github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= -github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4= +github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4= +github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= -github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.12 h1:igJgVw1JdKH+trcLWLeLwZjU9fEfPesQ+9/e4MQ44S8= github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 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/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/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= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -815,44 +1046,47 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= -go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 h1:R9DE4kQ4k+YtfLI2ULwX82VtNQ2J8yZmA7ZIF/D+7Mc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0/go.mod h1:OQFyQVrDlbe+R7xrEyDr/2Wr67Ol0hRUgsfA+V5A95s= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= -go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik= -go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak= -go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI= -go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A= +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/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 h1:K0XaT3DwHAcV4nKLzcQvwAgSyisUghWoY20I7huthMk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0/go.mod h1:B5Ki776z/MBnVha1Nzwp5arlzBbE3+1jk+pGmaP5HME= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 h1:lUsI2TYsQw2r1IASwoROaCnjdj2cvC2+Jbxvk6nHnWU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0/go.mod h1:2HpZxxQurfGxJlJDblybejHB6RX6pmExPNe517hREw4= +go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= +go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= go.opentelemetry.io/otel/sdk/metric v1.27.0 h1:5uGNOlpXi+Hbo/DRoI31BSb1v+OGcpv2NemcCrOL8gI= go.opentelemetry.io/otel/sdk/metric v1.27.0/go.mod h1:we7jJVrYN2kh3mVBlswtPU22K0SA+769l93J6bsyvqw= -go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw= -go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= -go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= -go.uber.org/fx v1.22.1 h1:nvvln7mwyT5s1q201YE29V/BFrGor6vMiDNpU/78Mys= -go.uber.org/fx v1.22.1/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/dig v1.18.0 h1:imUL1UiY0Mg4bqbFfsRQO5G4CGRBec/ZujWTvSVp3pw= +go.uber.org/dig v1.18.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= +go.uber.org/fx v1.23.0 h1:lIr/gYWQGfTwGcSXWXu4vP5Ws6iqnNEIY+F/aFzCKTg= +go.uber.org/fx v1.23.0/go.mod h1:o/D9n+2mLP6v1EG+qsdT1O8wKopYAsqZasju97SDFCU= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= 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.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= 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= @@ -862,24 +1096,29 @@ golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+ 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-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/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-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +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-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -890,8 +1129,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI= +golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -916,11 +1155,10 @@ 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.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/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.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= -golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.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= @@ -937,6 +1175,7 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -953,24 +1192,20 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/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-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 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-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= 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= @@ -996,27 +1231,33 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ 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.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1039,13 +1280,14 @@ golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/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-20210616094352-59db8d763f22/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-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1055,48 +1297,44 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +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/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.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= +golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1108,12 +1346,14 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1125,6 +1365,7 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -1145,24 +1386,27 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -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.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= -golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= +golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= 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= @@ -1235,10 +1479,10 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20230920204549-e6e6cdab5c13 h1:vlzZttNJGVqTsRFU9AmdnrcO1Znh8Ew9kCD//yjigk0= -google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 h1:W5Xj/70xIA4x60O/IFyXivR5MGqblAb8R3w26pnD6No= -google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8/go.mod h1:vPrPUTsDCYxXWjP7clS81mZ6/803D8K4iM9Ma27VKas= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 h1:mxSlqyb8ZAHsYDCfiXN1EDdNTdvjUJSLY+OnAUtYNYA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM= +google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 h1:T6rh4haD3GVYsgEfWExoCZA2o2FmbNyKpTuAxbEFPTg= +google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:wp2WsuBYj6j8wUdo3ToZsdxxixbvQNAHqVJrTgi5E5M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 h1:QCqS/PdaHTSWGvupk2F/ehwHtGc0/GYkT+3GAcR1CCc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= 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= @@ -1258,8 +1502,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= -google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= 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= @@ -1270,22 +1514,26 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +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-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= 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.3.0/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= @@ -1305,8 +1553,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= -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= modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= @@ -1325,7 +1573,5 @@ nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYm rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= -rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/internal/router/router.go b/internal/router/router.go index 3bafb5a..7a6c9b0 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -37,6 +37,7 @@ func NewRouter( api.GET("/get_decryption_key", cryptoService.GetDecryptionKey) api.GET("/get_data_for_encryption", cryptoService.GetDataForEncryption) api.POST("/register_identity", cryptoService.RegisterIdentity) + api.POST("/compile_event_trigger_definition", cryptoService.CompileEventTriggerDefinition) api.GET("/decrypt_commitment", cryptoService.DecryptCommitment) } router.GET("/docs/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, func(c *ginSwagger.Config) { diff --git a/internal/service/crypto.go b/internal/service/crypto.go index 71a4890..a132529 100644 --- a/internal/service/crypto.go +++ b/internal/service/crypto.go @@ -1,15 +1,25 @@ package service import ( + "encoding/hex" + "math/big" "net/http" + "slices" + "strconv" + "strings" + sigparser "github.com/defiweb/go-sigparser" + ecommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/ethclient" "github.com/gin-gonic/gin" "github.com/jackc/pgx/v5/pgxpool" "github.com/rs/zerolog/log" "github.com/shutter-network/shutter-api/common" - "github.com/shutter-network/shutter-api/internal/error" + sherror "github.com/shutter-network/shutter-api/internal/error" "github.com/shutter-network/shutter-api/internal/usecase" + + shs "github.com/shutter-network/rolling-shutter/rolling-shutter/keyperimpl/shutterservice" ) type RegisterIdentityRequest struct { @@ -17,6 +27,20 @@ type RegisterIdentityRequest struct { IdentityPrefix string `json:"identityPrefix" example:"0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0"` } // @name RegisterIdentityRequest +type EventArgument struct { + Name string `json:"name" example:"amount"` + Operator string `json:"op" example:">="` + Value string `json:"value" example:"25433"` +} +type EventTriggerDefinitionRequest struct { + ABI string `json:"eventABI" example:"Transfer(indexed from address, indexed to address, amount uint256)"` + ContractAddress ecommon.Address `json:"contract" example:"0x3465a347342B72BCf800aBf814324ba4a803c32b"` + Arguments []EventArgument `json:"arguments" example:"[{\"name\": \"from\", \"operator\": \"==\", \"value\": \"0x456d9347342B72BCf800bBf117391ac2f807c6bF\"}]"` +} +type EventTriggerDefinitionResponse struct { + EventTriggerDefinition string `json:"event_trigger_definition" example:"Transfer(indexed from address, indexed to address, amount uint256)"` +} + type CryptoService struct { CryptoUsecase *usecase.CryptoUsecase } @@ -51,7 +75,7 @@ func NewCryptoService( func (svc *CryptoService) GetDecryptionKey(ctx *gin.Context) { identity, ok := ctx.GetQuery("identity") if !ok { - err := error.NewHttpError( + err := sherror.NewHttpError( "query parameter not found", "identity query parameter is required", http.StatusBadRequest, @@ -89,7 +113,7 @@ func (svc *CryptoService) GetDecryptionKey(ctx *gin.Context) { func (svc *CryptoService) GetDataForEncryption(ctx *gin.Context) { address, ok := ctx.GetQuery("address") if !ok { - err := error.NewHttpError( + err := sherror.NewHttpError( "query parameter not found", "address query parameter is required", http.StatusBadRequest, @@ -133,7 +157,7 @@ func (svc *CryptoService) RegisterIdentity(ctx *gin.Context) { var req RegisterIdentityRequest if err := ctx.ShouldBindJSON(&req); err != nil { log.Err(err).Msg("err decoding request body") - err := error.NewHttpError( + err := sherror.NewHttpError( "unable to decode request body", "", http.StatusBadRequest, @@ -171,7 +195,7 @@ func (svc *CryptoService) RegisterIdentity(ctx *gin.Context) { func (svc *CryptoService) DecryptCommitment(ctx *gin.Context) { identity, ok := ctx.GetQuery("identity") if !ok { - err := error.NewHttpError( + err := sherror.NewHttpError( "query parameter not found", "identity query parameter is required", http.StatusBadRequest, @@ -182,7 +206,7 @@ func (svc *CryptoService) DecryptCommitment(ctx *gin.Context) { encryptedCommitment, ok := ctx.GetQuery("encryptedCommitment") if !ok { - err := error.NewHttpError( + err := sherror.NewHttpError( "query parameter not found", "encrypted commitment query parameter is required", http.StatusBadRequest, @@ -200,3 +224,141 @@ func (svc *CryptoService) DecryptCommitment(ctx *gin.Context) { "message": data, }) } + +// @BasePath /api + +// EventTriggerDefinition godoc +// @Summary Allows clients to compile an event trigger definition string. +// @Description This endpoint takes an ABI snippet and some arguments to create an event trigger definition that will be understood by keypers supporting event based decryption triggers. +// @Tags Crypto +// @Produce json +// @Param request body EventDefinitionRequest true "Event ABI and operator-arguments tuples to match." +// @Success 200 {object} []byte "Success." +// @Failure 400 {object} error.Http "Invalid Event Data." +// @Failure 429 {object} error.Http "Too many requests. Rate limited." +// @Failure 500 {object} error.Http "Internal server error." +// @Security BearerAuth +// @Router /event_trigger_definition [post] + +func (svc *CryptoService) CompileEventTriggerDefinition(ctx *gin.Context) { + CompileEventTriggerDefinition(ctx) +} +func CompileEventTriggerDefinition(ctx *gin.Context) { + var req EventTriggerDefinitionRequest + if err := ctx.ShouldBindJSON(&req); err != nil { + log.Err(err).Msg("err decoding request body") + err := sherror.NewHttpError( + "unable to decode request body", + "", + http.StatusBadRequest, + ) + ctx.Error(err) + return + } + predicates, err := logPredicates(req.Arguments, req.ABI) + if err != nil { + log.Err(err).Msg("error parsing event trigger definition") + err := sherror.NewHttpError( + "unable to parse event trigger definition", + "", + http.StatusBadRequest, + ) + ctx.Error(err) + } + etd := shs.EventTriggerDefinition{ + Contract: req.ContractAddress, + LogPredicates: predicates, + } + + u := shs.EventTriggerDefinition{} + u.UnmarshalBytes(etd.MarshalBytes()) + data := EventTriggerDefinitionResponse{EventTriggerDefinition: hex.EncodeToString(etd.MarshalBytes())} + ctx.JSON(http.StatusOK, data) +} + +// aligns []byte to 32 byte +func align(val []byte) []byte { + words := (31 + len(val)) / shs.Word + x := make([]byte, shs.Word*words) + copy(x, val) + return x +} + +func logPredicates(args []EventArgument, evtABI string) ([]shs.LogPredicate, error) { + lps := []shs.LogPredicate{} + sig, err := sigparser.ParseSignature(evtABI) + if err != nil { + return lps, err + } + indexedOffset := uint64(0) + nonIndexedOffset := uint64(4) + length := uint64(0) + for _, input := range sig.Inputs { + lp := shs.LogPredicate{} + i := slices.IndexFunc( + args, + func(ea EventArgument) bool { + return ea.Name == input.Name + }) + // input is part of definition: + if i >= 0 { + arg := args[i] + // input is topic: + if input.Indexed { + val, err := hexutil.Decode(arg.Value) + if err != nil { + return lps, err + } + length = 1 + lp.ValuePredicate.Op = shs.BytesEq + lp.ValuePredicate.ByteArgs = [][]byte{align(val)} + lp.LogValueRef.Offset = indexedOffset + indexedOffset++ + // input is data argument: + } else { + if input.Type != "uint256" { + val, err := hexutil.Decode(arg.Value) + if err != nil { + return lps, err + } + + lp.ValuePredicate.Op = shs.BytesEq + lp.ValuePredicate.ByteArgs = [][]byte{align(val)} + length = uint64(len([]byte(arg.Value)) / 32) + } else { + lp.ValuePredicate.Op = opFromString(arg.Operator) + value, err := strconv.Atoi(arg.Value) + if err != nil { + return lps, err + } + lp.ValuePredicate.IntArgs = []*big.Int{big.NewInt(int64(value))} + length = 1 + } + + lp.LogValueRef.Offset = nonIndexedOffset + nonIndexedOffset += length + } + lp.LogValueRef.Length = length + lps = append(lps, lp) + } + } + return lps, nil + +} + +func opFromString(op string) shs.Op { + switch strings.ToLower(op) { + case "lt": + return shs.UintLt + case "lte": + return shs.UintLte + case "eq": + return shs.UintEq + case "gt": + return shs.UintGt + case "gte": + return shs.UintGte + default: + return shs.BytesEq + } +} From 6ac3192286d5809c7a45d8d4a70954a9c4db5a62 Mon Sep 17 00:00:00 2001 From: Konrad Feldmeier Date: Mon, 15 Dec 2025 10:51:11 +0100 Subject: [PATCH 02/21] Add input validation for common errors --- internal/service/crypto.go | 72 ++++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 6 deletions(-) diff --git a/internal/service/crypto.go b/internal/service/crypto.go index a132529..25d9114 100644 --- a/internal/service/crypto.go +++ b/internal/service/crypto.go @@ -2,6 +2,7 @@ package service import ( "encoding/hex" + "fmt" "math/big" "net/http" "slices" @@ -248,19 +249,39 @@ func CompileEventTriggerDefinition(ctx *gin.Context) { if err := ctx.ShouldBindJSON(&req); err != nil { log.Err(err).Msg("err decoding request body") err := sherror.NewHttpError( - "unable to decode request body", - "", + "unable to decode request body, JSON invalid", + err.Error(), + http.StatusBadRequest, + ) + ctx.Error(err) + } + zeroAddress := ecommon.Address{} + if req.ContractAddress == zeroAddress { + err := fmt.Errorf("Contract address empty") + log.Err(err).Msg("error creating event trigger definition") + err = sherror.NewHttpError( + "unable to parse event trigger definition", + err.Error(), + http.StatusBadRequest, + ) + ctx.Error(err) + } + if len(req.ABI) == 0 { + err := fmt.Errorf("No ABI given") + log.Err(err).Msg("error creating event trigger definition") + err = sherror.NewHttpError( + "unable to parse event trigger definition", + err.Error(), http.StatusBadRequest, ) ctx.Error(err) - return } predicates, err := logPredicates(req.Arguments, req.ABI) if err != nil { log.Err(err).Msg("error parsing event trigger definition") err := sherror.NewHttpError( "unable to parse event trigger definition", - "", + err.Error(), http.StatusBadRequest, ) ctx.Error(err) @@ -269,11 +290,25 @@ func CompileEventTriggerDefinition(ctx *gin.Context) { Contract: req.ContractAddress, LogPredicates: predicates, } + err = etd.Validate() + if err != nil { + log.Err(err).Msg("error validating event trigger definition") + err := sherror.NewHttpError( + "event trigger definition invalid", + err.Error(), + http.StatusBadRequest, + ) + ctx.Error(err) + } u := shs.EventTriggerDefinition{} u.UnmarshalBytes(etd.MarshalBytes()) data := EventTriggerDefinitionResponse{EventTriggerDefinition: hex.EncodeToString(etd.MarshalBytes())} - ctx.JSON(http.StatusOK, data) + if len(ctx.Errors) == 0 { + ctx.JSON(http.StatusOK, data) + } else { + ctx.JSON(http.StatusBadRequest, ctx.Errors.JSON()) + } } // aligns []byte to 32 byte @@ -293,6 +328,26 @@ func logPredicates(args []EventArgument, evtABI string) ([]shs.LogPredicate, err indexedOffset := uint64(0) nonIndexedOffset := uint64(4) length := uint64(0) + argnames := make([]string, len(args)) + for i, arg := range args { + found := slices.IndexFunc( + sig.Inputs, + func(par sigparser.Parameter) bool { + return par.Name == arg.Name + }) + if found < 0 { + return lps, fmt.Errorf("argument '%v' not defined in ABI", arg.Name) + } + double := slices.IndexFunc( + argnames, + func(name string) bool { + return name == arg.Name + }) + if double >= 0 { + return lps, fmt.Errorf("argument '%v' was defined more than once", arg.Name) + } + argnames[i] = arg.Name + } for _, input := range sig.Inputs { lp := shs.LogPredicate{} i := slices.IndexFunc( @@ -310,6 +365,9 @@ func logPredicates(args []EventArgument, evtABI string) ([]shs.LogPredicate, err return lps, err } length = 1 + if arg.Operator != "eq" { + return lps, fmt.Errorf("invalid operator '%v' for input '%v' of type '%v'", arg.Operator, input.Name, input.Type) + } lp.ValuePredicate.Op = shs.BytesEq lp.ValuePredicate.ByteArgs = [][]byte{align(val)} lp.LogValueRef.Offset = indexedOffset @@ -321,7 +379,9 @@ func logPredicates(args []EventArgument, evtABI string) ([]shs.LogPredicate, err if err != nil { return lps, err } - + if arg.Operator != "eq" { + return lps, fmt.Errorf("invalid operator '%v' for input '%v' of type '%v'", arg.Operator, input.Name, input.Type) + } lp.ValuePredicate.Op = shs.BytesEq lp.ValuePredicate.ByteArgs = [][]byte{align(val)} length = uint64(len([]byte(arg.Value)) / 32) From ba5a08568d2d683c0f948f502ab736dbf5536c48 Mon Sep 17 00:00:00 2001 From: Konrad Feldmeier Date: Mon, 15 Dec 2025 11:28:45 +0100 Subject: [PATCH 03/21] Add tests for CompileEventTriggerDefinition --- internal/service/crypto_test.go | 92 +++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 internal/service/crypto_test.go diff --git a/internal/service/crypto_test.go b/internal/service/crypto_test.go new file mode 100644 index 0000000..9782237 --- /dev/null +++ b/internal/service/crypto_test.go @@ -0,0 +1,92 @@ +package service + +import ( + "encoding/hex" + "encoding/json" + "math/big" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/require" + "gotest.tools/assert" + + "github.com/ethereum/go-ethereum/common" + hexutil "github.com/ethereum/go-ethereum/common/hexutil" + shs "github.com/shutter-network/rolling-shutter/rolling-shutter/keyperimpl/shutterservice" +) + +func setupRouter() *gin.Engine { + router := gin.Default() + router.POST("/test", CompileEventTriggerDefinition) + return router +} +func TestEventDecryptionValidation(t *testing.T) { + router := setupRouter() + testData := []string{ + // "grom" != "from" + `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "grom", "op": "eq", "value": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "value": "1"}]}`, + // "op: gte" illegal on indexed address + `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "gte", "value": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "value": "1"}]}`, + // argument "from" defined more than once + `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "value": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "from", "op": "eq", "value": "0x8e13976721ebff885611c8391d9b02749c1283fa"}]}`, + // invalid JSON + `{foo: "bar"}`, + // missing contract address + `{"eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "value": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "value": "1"}]}`, + // missing ABI + `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "arguments": [{"name": "from", "op": "eq", "value": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "value": "1"}]}`, + } + for _, bites := range testData { + w := httptest.NewRecorder() + req, _ := http.NewRequest("POST", "/test", strings.NewReader(bites)) + router.ServeHTTP(w, req) + assert.Check(t, w.Code != 200, "error returned 200") + } +} + +func TestEventDecryptionData(t *testing.T) { + router := setupRouter() + bites := `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "value": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "value": "1"}]}` + w := httptest.NewRecorder() + fromAsBytes, err := hexutil.Decode("0x9e13976721ebff885611c8391d9b02749c1283fa") + assert.NilError(t, err, "hex decode failed") + g := shs.EventTriggerDefinition{ + Contract: common.HexToAddress("0x4D6dD1382AA09be1d243F8960409A1ab3d913F43"), + LogPredicates: []shs.LogPredicate{ + shs.LogPredicate{ + LogValueRef: shs.LogValueRef{ + Offset: 0, + Length: 1, + }, + ValuePredicate: shs.ValuePredicate{ + Op: shs.BytesEq, + ByteArgs: [][]byte{align(fromAsBytes)}, + }, + }, + shs.LogPredicate{ + LogValueRef: shs.LogValueRef{ + Offset: 4, + Length: 1, + }, + ValuePredicate: shs.ValuePredicate{ + Op: shs.UintGte, + IntArgs: []*big.Int{big.NewInt(1)}, + }, + }}, + } + + etd := EventTriggerDefinitionResponse{ + EventTriggerDefinition: hex.EncodeToString(g.MarshalBytes()), + } + expected, err := json.Marshal(etd) + assert.NilError(t, err, "error marshalling") + + req, _ := http.NewRequest("POST", "/test", strings.NewReader(bites)) + router.ServeHTTP(w, req) + + assert.Equal(t, 200, w.Code) + require.JSONEq(t, string(expected), w.Body.String(), "roundtrip failed") +} From 2446e5681a5cdeb81688def05220830f21d199e9 Mon Sep 17 00:00:00 2001 From: Konrad Feldmeier Date: Wed, 17 Dec 2025 15:40:21 +0100 Subject: [PATCH 04/21] Fix alignment/padding --- internal/service/crypto.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/crypto.go b/internal/service/crypto.go index 25d9114..a11d289 100644 --- a/internal/service/crypto.go +++ b/internal/service/crypto.go @@ -315,7 +315,7 @@ func CompileEventTriggerDefinition(ctx *gin.Context) { func align(val []byte) []byte { words := (31 + len(val)) / shs.Word x := make([]byte, shs.Word*words) - copy(x, val) + copy(x[len(x)-len(val):], val) return x } From e025a8190bb3eb7c0e9b82b83c7a734b2f8464fe Mon Sep 17 00:00:00 2001 From: Konrad Feldmeier Date: Wed, 17 Dec 2025 15:41:47 +0100 Subject: [PATCH 05/21] Add topic0 --- internal/service/crypto.go | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/internal/service/crypto.go b/internal/service/crypto.go index a11d289..23958c3 100644 --- a/internal/service/crypto.go +++ b/internal/service/crypto.go @@ -12,6 +12,7 @@ import ( sigparser "github.com/defiweb/go-sigparser" ecommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" "github.com/gin-gonic/gin" "github.com/jackc/pgx/v5/pgxpool" @@ -244,6 +245,7 @@ func (svc *CryptoService) DecryptCommitment(ctx *gin.Context) { func (svc *CryptoService) CompileEventTriggerDefinition(ctx *gin.Context) { CompileEventTriggerDefinition(ctx) } + func CompileEventTriggerDefinition(ctx *gin.Context) { var req EventTriggerDefinitionRequest if err := ctx.ShouldBindJSON(&req); err != nil { @@ -301,8 +303,6 @@ func CompileEventTriggerDefinition(ctx *gin.Context) { ctx.Error(err) } - u := shs.EventTriggerDefinition{} - u.UnmarshalBytes(etd.MarshalBytes()) data := EventTriggerDefinitionResponse{EventTriggerDefinition: hex.EncodeToString(etd.MarshalBytes())} if len(ctx.Errors) == 0 { ctx.JSON(http.StatusOK, data) @@ -319,13 +319,35 @@ func align(val []byte) []byte { return x } +func topic0(sig sigparser.Signature) shs.LogPredicate { + var b strings.Builder + b.WriteString(sig.Name) + b.WriteString("(") + for i, input := range sig.Inputs { + b.WriteString(input.Type) + if i < len(sig.Inputs)-1 { + b.WriteString(",") + } + } + b.WriteString(")") + lp := shs.LogPredicate{} + lp.LogValueRef.Length = 1 + lp.LogValueRef.Offset = 0 + h := crypto.Keccak256([]byte(b.String())) + lp.ValuePredicate.ByteArgs = [][]byte{h} + lp.ValuePredicate.Op = shs.BytesEq + return lp +} + func logPredicates(args []EventArgument, evtABI string) ([]shs.LogPredicate, error) { lps := []shs.LogPredicate{} sig, err := sigparser.ParseSignature(evtABI) if err != nil { return lps, err } - indexedOffset := uint64(0) + lp := topic0(sig) + lps = append(lps, lp) + indexedOffset := uint64(1) nonIndexedOffset := uint64(4) length := uint64(0) argnames := make([]string, len(args)) From 49b2141a9b59b916234e3fe2935bff90be43ef30 Mon Sep 17 00:00:00 2001 From: Konrad Feldmeier Date: Wed, 17 Dec 2025 15:43:18 +0100 Subject: [PATCH 06/21] Add commandline ETD compiler --- .gitignore | 2 ++ etdc/main.go | 32 ++++++++++++++++++++++++++++++++ internal/service/crypto.go | 27 ++++++++++++++++++--------- 3 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 etdc/main.go diff --git a/.gitignore b/.gitignore index 0399b3c..1279b2c 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,5 @@ go.work.sum pgdata/ data/ + +bin/ diff --git a/etdc/main.go b/etdc/main.go new file mode 100644 index 0000000..49968bc --- /dev/null +++ b/etdc/main.go @@ -0,0 +1,32 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "os" + + "github.com/shutter-network/shutter-api/internal/service" +) + +// simple commandline compiler for EventTriggerDefinitions +// build from root folder via +// +// go build -ldflags '-w -s' -o bin/etdc ./etdc +func main() { + req, err := IngestRequest() + if err != nil { + log.Fatal(err) + } + data, errors := service.CompileEventTriggerDefinitionInternal(req) + if len(errors) > 0 { + log.Fatal(errors) + } + fmt.Println(data.EventTriggerDefinition) +} + +func IngestRequest() (service.EventTriggerDefinitionRequest, error) { + var record service.EventTriggerDefinitionRequest + err := json.NewDecoder(os.Stdin).Decode(&record) + return record, err +} diff --git a/internal/service/crypto.go b/internal/service/crypto.go index 23958c3..d0deb85 100644 --- a/internal/service/crypto.go +++ b/internal/service/crypto.go @@ -257,6 +257,19 @@ func CompileEventTriggerDefinition(ctx *gin.Context) { ) ctx.Error(err) } + resp, errors := CompileEventTriggerDefinitionInternal(req) + if len(errors) > 0 { + for _, err := range errors { + ctx.Error(err) + } + ctx.JSON(http.StatusBadRequest, ctx.Errors.JSON()) + } else { + ctx.JSON(http.StatusOK, resp) + } +} + +func CompileEventTriggerDefinitionInternal(req EventTriggerDefinitionRequest) (EventTriggerDefinitionResponse, []error) { + var errors []error zeroAddress := ecommon.Address{} if req.ContractAddress == zeroAddress { err := fmt.Errorf("Contract address empty") @@ -266,7 +279,7 @@ func CompileEventTriggerDefinition(ctx *gin.Context) { err.Error(), http.StatusBadRequest, ) - ctx.Error(err) + errors = append(errors, err) } if len(req.ABI) == 0 { err := fmt.Errorf("No ABI given") @@ -276,7 +289,7 @@ func CompileEventTriggerDefinition(ctx *gin.Context) { err.Error(), http.StatusBadRequest, ) - ctx.Error(err) + errors = append(errors, err) } predicates, err := logPredicates(req.Arguments, req.ABI) if err != nil { @@ -286,7 +299,7 @@ func CompileEventTriggerDefinition(ctx *gin.Context) { err.Error(), http.StatusBadRequest, ) - ctx.Error(err) + errors = append(errors, err) } etd := shs.EventTriggerDefinition{ Contract: req.ContractAddress, @@ -300,15 +313,11 @@ func CompileEventTriggerDefinition(ctx *gin.Context) { err.Error(), http.StatusBadRequest, ) - ctx.Error(err) + errors = append(errors, err) } data := EventTriggerDefinitionResponse{EventTriggerDefinition: hex.EncodeToString(etd.MarshalBytes())} - if len(ctx.Errors) == 0 { - ctx.JSON(http.StatusOK, data) - } else { - ctx.JSON(http.StatusBadRequest, ctx.Errors.JSON()) - } + return data, errors } // aligns []byte to 32 byte From 8d68e7532ae2cfd1e0bcf1729621f5c2077e5128 Mon Sep 17 00:00:00 2001 From: Konrad Feldmeier Date: Wed, 17 Dec 2025 15:47:59 +0100 Subject: [PATCH 07/21] Fix json example --- internal/service/crypto.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/crypto.go b/internal/service/crypto.go index d0deb85..746a842 100644 --- a/internal/service/crypto.go +++ b/internal/service/crypto.go @@ -31,13 +31,13 @@ type RegisterIdentityRequest struct { type EventArgument struct { Name string `json:"name" example:"amount"` - Operator string `json:"op" example:">="` + Operator string `json:"op" example:"gte"` Value string `json:"value" example:"25433"` } type EventTriggerDefinitionRequest struct { ABI string `json:"eventABI" example:"Transfer(indexed from address, indexed to address, amount uint256)"` ContractAddress ecommon.Address `json:"contract" example:"0x3465a347342B72BCf800aBf814324ba4a803c32b"` - Arguments []EventArgument `json:"arguments" example:"[{\"name\": \"from\", \"operator\": \"==\", \"value\": \"0x456d9347342B72BCf800bBf117391ac2f807c6bF\"}]"` + Arguments []EventArgument `json:"arguments" example:"[{\"name\": \"from\", \"op\": \"eq\", \"value\": \"0x456d9347342B72BCf800bBf117391ac2f807c6bF\"}]"` } type EventTriggerDefinitionResponse struct { EventTriggerDefinition string `json:"event_trigger_definition" example:"Transfer(indexed from address, indexed to address, amount uint256)"` From b7da27e2b56e4fc7d25939dd1999ff09b4cb097d Mon Sep 17 00:00:00 2001 From: Konrad Feldmeier Date: Thu, 18 Dec 2025 10:46:16 +0100 Subject: [PATCH 08/21] Stricter validation of values --- internal/service/crypto.go | 16 ++++++---------- internal/service/crypto_test.go | 26 +++++++++++++++++--------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/internal/service/crypto.go b/internal/service/crypto.go index 746a842..2c7db62 100644 --- a/internal/service/crypto.go +++ b/internal/service/crypto.go @@ -6,7 +6,6 @@ import ( "math/big" "net/http" "slices" - "strconv" "strings" sigparser "github.com/defiweb/go-sigparser" @@ -32,7 +31,8 @@ type RegisterIdentityRequest struct { type EventArgument struct { Name string `json:"name" example:"amount"` Operator string `json:"op" example:"gte"` - Value string `json:"value" example:"25433"` + Number int `json:"number" example:"25433"` + Bytes string `json:"bytes" example:"0xabcdef01234567"` } type EventTriggerDefinitionRequest struct { ABI string `json:"eventABI" example:"Transfer(indexed from address, indexed to address, amount uint256)"` @@ -391,7 +391,7 @@ func logPredicates(args []EventArgument, evtABI string) ([]shs.LogPredicate, err arg := args[i] // input is topic: if input.Indexed { - val, err := hexutil.Decode(arg.Value) + val, err := hexutil.Decode(arg.Bytes) if err != nil { return lps, err } @@ -406,7 +406,7 @@ func logPredicates(args []EventArgument, evtABI string) ([]shs.LogPredicate, err // input is data argument: } else { if input.Type != "uint256" { - val, err := hexutil.Decode(arg.Value) + val, err := hexutil.Decode(arg.Bytes) if err != nil { return lps, err } @@ -415,14 +415,10 @@ func logPredicates(args []EventArgument, evtABI string) ([]shs.LogPredicate, err } lp.ValuePredicate.Op = shs.BytesEq lp.ValuePredicate.ByteArgs = [][]byte{align(val)} - length = uint64(len([]byte(arg.Value)) / 32) + length = uint64(len([]byte(arg.Bytes)) / 32) } else { lp.ValuePredicate.Op = opFromString(arg.Operator) - value, err := strconv.Atoi(arg.Value) - if err != nil { - return lps, err - } - lp.ValuePredicate.IntArgs = []*big.Int{big.NewInt(int64(value))} + lp.ValuePredicate.IntArgs = []*big.Int{big.NewInt(int64(arg.Number))} length = 1 } diff --git a/internal/service/crypto_test.go b/internal/service/crypto_test.go index 9782237..9c761d3 100644 --- a/internal/service/crypto_test.go +++ b/internal/service/crypto_test.go @@ -9,6 +9,7 @@ import ( "strings" "testing" + sigparser "github.com/defiweb/go-sigparser" "github.com/gin-gonic/gin" "github.com/stretchr/testify/require" "gotest.tools/assert" @@ -27,17 +28,19 @@ func TestEventDecryptionValidation(t *testing.T) { router := setupRouter() testData := []string{ // "grom" != "from" - `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "grom", "op": "eq", "value": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "value": "1"}]}`, + `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "grom", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}`, + // "op": "gt" on "bytes" value (must be "number") + `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventABI":"event Transfer(address indexed from, address indexed to, address notify)","arguments": [{"name": "notify", "op": "gt", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"}]}`, // "op: gte" illegal on indexed address - `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "gte", "value": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "value": "1"}]}`, + `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "gte", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}`, // argument "from" defined more than once - `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "value": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "from", "op": "eq", "value": "0x8e13976721ebff885611c8391d9b02749c1283fa"}]}`, + `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "from", "op": "eq", "value": "0x8e13976721ebff885611c8391d9b02749c1283fa"}]}`, // invalid JSON `{foo: "bar"}`, // missing contract address - `{"eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "value": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "value": "1"}]}`, + `{"eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}`, // missing ABI - `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "arguments": [{"name": "from", "op": "eq", "value": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "value": "1"}]}`, + `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "arguments": [{"name": "from", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}`, } for _, bites := range testData { w := httptest.NewRecorder() @@ -49,16 +52,21 @@ func TestEventDecryptionValidation(t *testing.T) { func TestEventDecryptionData(t *testing.T) { router := setupRouter() - bites := `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "value": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "value": "1"}]}` + bites := `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}` w := httptest.NewRecorder() fromAsBytes, err := hexutil.Decode("0x9e13976721ebff885611c8391d9b02749c1283fa") assert.NilError(t, err, "hex decode failed") + var req EventTriggerDefinitionRequest + err = json.NewDecoder(strings.NewReader(bites)).Decode(&req) + assert.NilError(t, err, "invalid json") + sig, err := sigparser.ParseSignature(req.ABI) g := shs.EventTriggerDefinition{ Contract: common.HexToAddress("0x4D6dD1382AA09be1d243F8960409A1ab3d913F43"), LogPredicates: []shs.LogPredicate{ + topic0(sig), shs.LogPredicate{ LogValueRef: shs.LogValueRef{ - Offset: 0, + Offset: 1, Length: 1, }, ValuePredicate: shs.ValuePredicate{ @@ -84,8 +92,8 @@ func TestEventDecryptionData(t *testing.T) { expected, err := json.Marshal(etd) assert.NilError(t, err, "error marshalling") - req, _ := http.NewRequest("POST", "/test", strings.NewReader(bites)) - router.ServeHTTP(w, req) + request, _ := http.NewRequest("POST", "/test", strings.NewReader(bites)) + router.ServeHTTP(w, request) assert.Equal(t, 200, w.Code) require.JSONEq(t, string(expected), w.Body.String(), "roundtrip failed") From 9cff7acf53733efda61ede484180395b0fe09738 Mon Sep 17 00:00:00 2001 From: Konrad Feldmeier Date: Fri, 19 Dec 2025 09:40:07 +0100 Subject: [PATCH 09/21] Fix correct naming for event signature --- internal/service/crypto.go | 38 +++++++++++++++++++++------------ internal/service/crypto_test.go | 4 ++-- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/internal/service/crypto.go b/internal/service/crypto.go index 2c7db62..2d0ad76 100644 --- a/internal/service/crypto.go +++ b/internal/service/crypto.go @@ -35,10 +35,11 @@ type EventArgument struct { Bytes string `json:"bytes" example:"0xabcdef01234567"` } type EventTriggerDefinitionRequest struct { - ABI string `json:"eventABI" example:"Transfer(indexed from address, indexed to address, amount uint256)"` + EventSignature string `json:"event_sig" example:"Transfer(indexed from address, indexed to address, amount uint256)"` ContractAddress ecommon.Address `json:"contract" example:"0x3465a347342B72BCf800aBf814324ba4a803c32b"` Arguments []EventArgument `json:"arguments" example:"[{\"name\": \"from\", \"op\": \"eq\", \"value\": \"0x456d9347342B72BCf800bBf117391ac2f807c6bF\"}]"` -} +} // @name EventTriggerDefinitionRequest + type EventTriggerDefinitionResponse struct { EventTriggerDefinition string `json:"event_trigger_definition" example:"Transfer(indexed from address, indexed to address, amount uint256)"` } @@ -231,14 +232,23 @@ func (svc *CryptoService) DecryptCommitment(ctx *gin.Context) { // EventTriggerDefinition godoc // @Summary Allows clients to compile an event trigger definition string. -// @Description This endpoint takes an ABI snippet and some arguments to create an event trigger definition that will be understood by keypers supporting event based decryption triggers. +// @Description This endpoint takes an event signature snippet and some arguments to create an event trigger definition that will be understood by keypers +// supporting event based decryption triggers. The schema is: +// {"contract": , +// "event_sig": ( [indexed] , ...)'>, +// "arguments": []} +// The object format for the "arguments" list is: +// - "name": , +// - "op": , +// - "number": , +// - "bytes": // @Tags Crypto // @Produce json -// @Param request body EventDefinitionRequest true "Event ABI and operator-arguments tuples to match." -// @Success 200 {object} []byte "Success." -// @Failure 400 {object} error.Http "Invalid Event Data." -// @Failure 429 {object} error.Http "Too many requests. Rate limited." -// @Failure 500 {object} error.Http "Internal server error." +// @Param request body EventTriggerDefinitionRequest true "Event signature and match arguments." +// @Success 200 {object} []byte "Success." +// @Failure 400 {object} error.Http "Invalid Event Data." +// @Failure 429 {object} error.Http "Too many requests. Rate limited." +// @Failure 500 {object} error.Http "Internal server error." // @Security BearerAuth // @Router /event_trigger_definition [post] @@ -281,8 +291,8 @@ func CompileEventTriggerDefinitionInternal(req EventTriggerDefinitionRequest) (E ) errors = append(errors, err) } - if len(req.ABI) == 0 { - err := fmt.Errorf("No ABI given") + if len(req.EventSignature) == 0 { + err := fmt.Errorf("No event signature given") log.Err(err).Msg("error creating event trigger definition") err = sherror.NewHttpError( "unable to parse event trigger definition", @@ -291,7 +301,7 @@ func CompileEventTriggerDefinitionInternal(req EventTriggerDefinitionRequest) (E ) errors = append(errors, err) } - predicates, err := logPredicates(req.Arguments, req.ABI) + predicates, err := logPredicates(req.Arguments, req.EventSignature) if err != nil { log.Err(err).Msg("error parsing event trigger definition") err := sherror.NewHttpError( @@ -348,9 +358,9 @@ func topic0(sig sigparser.Signature) shs.LogPredicate { return lp } -func logPredicates(args []EventArgument, evtABI string) ([]shs.LogPredicate, error) { +func logPredicates(args []EventArgument, evtSig string) ([]shs.LogPredicate, error) { lps := []shs.LogPredicate{} - sig, err := sigparser.ParseSignature(evtABI) + sig, err := sigparser.ParseSignature(evtSig) if err != nil { return lps, err } @@ -367,7 +377,7 @@ func logPredicates(args []EventArgument, evtABI string) ([]shs.LogPredicate, err return par.Name == arg.Name }) if found < 0 { - return lps, fmt.Errorf("argument '%v' not defined in ABI", arg.Name) + return lps, fmt.Errorf("argument '%v' not defined in signature", arg.Name) } double := slices.IndexFunc( argnames, diff --git a/internal/service/crypto_test.go b/internal/service/crypto_test.go index 9c761d3..91c66e1 100644 --- a/internal/service/crypto_test.go +++ b/internal/service/crypto_test.go @@ -52,14 +52,14 @@ func TestEventDecryptionValidation(t *testing.T) { func TestEventDecryptionData(t *testing.T) { router := setupRouter() - bites := `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}` + bites := `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "event_sig":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}` w := httptest.NewRecorder() fromAsBytes, err := hexutil.Decode("0x9e13976721ebff885611c8391d9b02749c1283fa") assert.NilError(t, err, "hex decode failed") var req EventTriggerDefinitionRequest err = json.NewDecoder(strings.NewReader(bites)).Decode(&req) assert.NilError(t, err, "invalid json") - sig, err := sigparser.ParseSignature(req.ABI) + sig, err := sigparser.ParseSignature(req.EventSignature) g := shs.EventTriggerDefinition{ Contract: common.HexToAddress("0x4D6dD1382AA09be1d243F8960409A1ab3d913F43"), LogPredicates: []shs.LogPredicate{ From 1521a5a99ef821218231cab35ba10765720297ce Mon Sep 17 00:00:00 2001 From: Konrad Feldmeier Date: Fri, 19 Dec 2025 09:51:05 +0100 Subject: [PATCH 10/21] Move usecase out of service --- etdc/main.go | 8 +- internal/service/crypto.go | 226 +++---------------------------- internal/service/crypto_test.go | 21 +-- internal/usecase/eventtrigger.go | 216 +++++++++++++++++++++++++++++ 4 files changed, 249 insertions(+), 222 deletions(-) create mode 100644 internal/usecase/eventtrigger.go diff --git a/etdc/main.go b/etdc/main.go index 49968bc..ddecfff 100644 --- a/etdc/main.go +++ b/etdc/main.go @@ -6,7 +6,7 @@ import ( "log" "os" - "github.com/shutter-network/shutter-api/internal/service" + "github.com/shutter-network/shutter-api/internal/usecase" ) // simple commandline compiler for EventTriggerDefinitions @@ -18,15 +18,15 @@ func main() { if err != nil { log.Fatal(err) } - data, errors := service.CompileEventTriggerDefinitionInternal(req) + data, errors := usecase.CompileEventTriggerDefinitionInternal(req) if len(errors) > 0 { log.Fatal(errors) } fmt.Println(data.EventTriggerDefinition) } -func IngestRequest() (service.EventTriggerDefinitionRequest, error) { - var record service.EventTriggerDefinitionRequest +func IngestRequest() (usecase.EventTriggerDefinitionRequest, error) { + var record usecase.EventTriggerDefinitionRequest err := json.NewDecoder(os.Stdin).Decode(&record) return record, err } diff --git a/internal/service/crypto.go b/internal/service/crypto.go index 2d0ad76..b1b963b 100644 --- a/internal/service/crypto.go +++ b/internal/service/crypto.go @@ -1,17 +1,8 @@ package service import ( - "encoding/hex" - "fmt" - "math/big" "net/http" - "slices" - "strings" - sigparser "github.com/defiweb/go-sigparser" - ecommon "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" "github.com/gin-gonic/gin" "github.com/jackc/pgx/v5/pgxpool" @@ -19,8 +10,6 @@ import ( "github.com/shutter-network/shutter-api/common" sherror "github.com/shutter-network/shutter-api/internal/error" "github.com/shutter-network/shutter-api/internal/usecase" - - shs "github.com/shutter-network/rolling-shutter/rolling-shutter/keyperimpl/shutterservice" ) type RegisterIdentityRequest struct { @@ -28,22 +17,6 @@ type RegisterIdentityRequest struct { IdentityPrefix string `json:"identityPrefix" example:"0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0"` } // @name RegisterIdentityRequest -type EventArgument struct { - Name string `json:"name" example:"amount"` - Operator string `json:"op" example:"gte"` - Number int `json:"number" example:"25433"` - Bytes string `json:"bytes" example:"0xabcdef01234567"` -} -type EventTriggerDefinitionRequest struct { - EventSignature string `json:"event_sig" example:"Transfer(indexed from address, indexed to address, amount uint256)"` - ContractAddress ecommon.Address `json:"contract" example:"0x3465a347342B72BCf800aBf814324ba4a803c32b"` - Arguments []EventArgument `json:"arguments" example:"[{\"name\": \"from\", \"op\": \"eq\", \"value\": \"0x456d9347342B72BCf800bBf117391ac2f807c6bF\"}]"` -} // @name EventTriggerDefinitionRequest - -type EventTriggerDefinitionResponse struct { - EventTriggerDefinition string `json:"event_trigger_definition" example:"Transfer(indexed from address, indexed to address, amount uint256)"` -} - type CryptoService struct { CryptoUsecase *usecase.CryptoUsecase } @@ -257,7 +230,7 @@ func (svc *CryptoService) CompileEventTriggerDefinition(ctx *gin.Context) { } func CompileEventTriggerDefinition(ctx *gin.Context) { - var req EventTriggerDefinitionRequest + var req usecase.EventTriggerDefinitionRequest if err := ctx.ShouldBindJSON(&req); err != nil { log.Err(err).Msg("err decoding request body") err := sherror.NewHttpError( @@ -267,7 +240,7 @@ func CompileEventTriggerDefinition(ctx *gin.Context) { ) ctx.Error(err) } - resp, errors := CompileEventTriggerDefinitionInternal(req) + resp, errors := usecase.CompileEventTriggerDefinitionInternal(req) if len(errors) > 0 { for _, err := range errors { ctx.Error(err) @@ -278,184 +251,21 @@ func CompileEventTriggerDefinition(ctx *gin.Context) { } } -func CompileEventTriggerDefinitionInternal(req EventTriggerDefinitionRequest) (EventTriggerDefinitionResponse, []error) { - var errors []error - zeroAddress := ecommon.Address{} - if req.ContractAddress == zeroAddress { - err := fmt.Errorf("Contract address empty") - log.Err(err).Msg("error creating event trigger definition") - err = sherror.NewHttpError( - "unable to parse event trigger definition", - err.Error(), - http.StatusBadRequest, - ) - errors = append(errors, err) - } - if len(req.EventSignature) == 0 { - err := fmt.Errorf("No event signature given") - log.Err(err).Msg("error creating event trigger definition") - err = sherror.NewHttpError( - "unable to parse event trigger definition", - err.Error(), - http.StatusBadRequest, - ) - errors = append(errors, err) - } - predicates, err := logPredicates(req.Arguments, req.EventSignature) - if err != nil { - log.Err(err).Msg("error parsing event trigger definition") - err := sherror.NewHttpError( - "unable to parse event trigger definition", - err.Error(), - http.StatusBadRequest, - ) - errors = append(errors, err) - } - etd := shs.EventTriggerDefinition{ - Contract: req.ContractAddress, - LogPredicates: predicates, - } - err = etd.Validate() - if err != nil { - log.Err(err).Msg("error validating event trigger definition") - err := sherror.NewHttpError( - "event trigger definition invalid", - err.Error(), - http.StatusBadRequest, - ) - errors = append(errors, err) - } - - data := EventTriggerDefinitionResponse{EventTriggerDefinition: hex.EncodeToString(etd.MarshalBytes())} - return data, errors -} - -// aligns []byte to 32 byte -func align(val []byte) []byte { - words := (31 + len(val)) / shs.Word - x := make([]byte, shs.Word*words) - copy(x[len(x)-len(val):], val) - return x -} - -func topic0(sig sigparser.Signature) shs.LogPredicate { - var b strings.Builder - b.WriteString(sig.Name) - b.WriteString("(") - for i, input := range sig.Inputs { - b.WriteString(input.Type) - if i < len(sig.Inputs)-1 { - b.WriteString(",") - } - } - b.WriteString(")") - lp := shs.LogPredicate{} - lp.LogValueRef.Length = 1 - lp.LogValueRef.Offset = 0 - h := crypto.Keccak256([]byte(b.String())) - lp.ValuePredicate.ByteArgs = [][]byte{h} - lp.ValuePredicate.Op = shs.BytesEq - return lp -} - -func logPredicates(args []EventArgument, evtSig string) ([]shs.LogPredicate, error) { - lps := []shs.LogPredicate{} - sig, err := sigparser.ParseSignature(evtSig) - if err != nil { - return lps, err - } - lp := topic0(sig) - lps = append(lps, lp) - indexedOffset := uint64(1) - nonIndexedOffset := uint64(4) - length := uint64(0) - argnames := make([]string, len(args)) - for i, arg := range args { - found := slices.IndexFunc( - sig.Inputs, - func(par sigparser.Parameter) bool { - return par.Name == arg.Name - }) - if found < 0 { - return lps, fmt.Errorf("argument '%v' not defined in signature", arg.Name) - } - double := slices.IndexFunc( - argnames, - func(name string) bool { - return name == arg.Name - }) - if double >= 0 { - return lps, fmt.Errorf("argument '%v' was defined more than once", arg.Name) - } - argnames[i] = arg.Name - } - for _, input := range sig.Inputs { - lp := shs.LogPredicate{} - i := slices.IndexFunc( - args, - func(ea EventArgument) bool { - return ea.Name == input.Name - }) - // input is part of definition: - if i >= 0 { - arg := args[i] - // input is topic: - if input.Indexed { - val, err := hexutil.Decode(arg.Bytes) - if err != nil { - return lps, err - } - length = 1 - if arg.Operator != "eq" { - return lps, fmt.Errorf("invalid operator '%v' for input '%v' of type '%v'", arg.Operator, input.Name, input.Type) - } - lp.ValuePredicate.Op = shs.BytesEq - lp.ValuePredicate.ByteArgs = [][]byte{align(val)} - lp.LogValueRef.Offset = indexedOffset - indexedOffset++ - // input is data argument: - } else { - if input.Type != "uint256" { - val, err := hexutil.Decode(arg.Bytes) - if err != nil { - return lps, err - } - if arg.Operator != "eq" { - return lps, fmt.Errorf("invalid operator '%v' for input '%v' of type '%v'", arg.Operator, input.Name, input.Type) - } - lp.ValuePredicate.Op = shs.BytesEq - lp.ValuePredicate.ByteArgs = [][]byte{align(val)} - length = uint64(len([]byte(arg.Bytes)) / 32) - } else { - lp.ValuePredicate.Op = opFromString(arg.Operator) - lp.ValuePredicate.IntArgs = []*big.Int{big.NewInt(int64(arg.Number))} - length = 1 - } - - lp.LogValueRef.Offset = nonIndexedOffset - nonIndexedOffset += length - } - lp.LogValueRef.Length = length - lps = append(lps, lp) - } - } - return lps, nil - -} +// @BasePath /api +// TODO: FIXME!! doc string is just copy and paste +// RegisterEventIdentity godoc +// @Summary Allows clients to register an event trigger identity. +// @Description Allows clients to register an identity used for encryption and event trigger definition for the decryption key associated with the encrypted message. +// @Tags Crypto +// @Accepts json +// @Produce json +// @Param request body RegisterEventRequest true "Timestamp and Identity which client want to make the registration with." +// @Success 200 {object} usecase.RegisterEventResponse "Success." +// @Failure 400 {object} error.Http "Invalid Register identity request." +// @Failure 429 {object} error.Http "Too many requests. Rate limited." +// @Failure 500 {object} error.Http "Internal server error." +// @Security BearerAuth +// @Router /register_event_identity [post] -func opFromString(op string) shs.Op { - switch strings.ToLower(op) { - case "lt": - return shs.UintLt - case "lte": - return shs.UintLte - case "eq": - return shs.UintEq - case "gt": - return shs.UintGt - case "gte": - return shs.UintGte - default: - return shs.BytesEq - } +func (svc *CryptoService) RegisterEventIdentity(ctx *gin.Context) { } diff --git a/internal/service/crypto_test.go b/internal/service/crypto_test.go index 91c66e1..46849db 100644 --- a/internal/service/crypto_test.go +++ b/internal/service/crypto_test.go @@ -17,6 +17,7 @@ import ( "github.com/ethereum/go-ethereum/common" hexutil "github.com/ethereum/go-ethereum/common/hexutil" shs "github.com/shutter-network/rolling-shutter/rolling-shutter/keyperimpl/shutterservice" + "github.com/shutter-network/shutter-api/internal/usecase" ) func setupRouter() *gin.Engine { @@ -28,18 +29,18 @@ func TestEventDecryptionValidation(t *testing.T) { router := setupRouter() testData := []string{ // "grom" != "from" - `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "grom", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}`, + `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "event_sig":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "grom", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}`, // "op": "gt" on "bytes" value (must be "number") - `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventABI":"event Transfer(address indexed from, address indexed to, address notify)","arguments": [{"name": "notify", "op": "gt", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"}]}`, + `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "event_sig":"event Transfer(address indexed from, address indexed to, address notify)","arguments": [{"name": "notify", "op": "gt", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"}]}`, // "op: gte" illegal on indexed address - `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "gte", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}`, + `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "event_sig":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "gte", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}`, // argument "from" defined more than once - `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "from", "op": "eq", "value": "0x8e13976721ebff885611c8391d9b02749c1283fa"}]}`, + `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "event_sig":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "from", "op": "eq", "value": "0x8e13976721ebff885611c8391d9b02749c1283fa"}]}`, // invalid JSON `{foo: "bar"}`, // missing contract address - `{"eventABI":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}`, - // missing ABI + `{"event_sig":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}`, + // missing signature `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "arguments": [{"name": "from", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}`, } for _, bites := range testData { @@ -56,14 +57,14 @@ func TestEventDecryptionData(t *testing.T) { w := httptest.NewRecorder() fromAsBytes, err := hexutil.Decode("0x9e13976721ebff885611c8391d9b02749c1283fa") assert.NilError(t, err, "hex decode failed") - var req EventTriggerDefinitionRequest + var req usecase.EventTriggerDefinitionRequest err = json.NewDecoder(strings.NewReader(bites)).Decode(&req) assert.NilError(t, err, "invalid json") sig, err := sigparser.ParseSignature(req.EventSignature) g := shs.EventTriggerDefinition{ Contract: common.HexToAddress("0x4D6dD1382AA09be1d243F8960409A1ab3d913F43"), LogPredicates: []shs.LogPredicate{ - topic0(sig), + usecase.Topic0(sig), shs.LogPredicate{ LogValueRef: shs.LogValueRef{ Offset: 1, @@ -71,7 +72,7 @@ func TestEventDecryptionData(t *testing.T) { }, ValuePredicate: shs.ValuePredicate{ Op: shs.BytesEq, - ByteArgs: [][]byte{align(fromAsBytes)}, + ByteArgs: [][]byte{usecase.Align(fromAsBytes)}, }, }, shs.LogPredicate{ @@ -86,7 +87,7 @@ func TestEventDecryptionData(t *testing.T) { }}, } - etd := EventTriggerDefinitionResponse{ + etd := usecase.EventTriggerDefinitionResponse{ EventTriggerDefinition: hex.EncodeToString(g.MarshalBytes()), } expected, err := json.Marshal(etd) diff --git a/internal/usecase/eventtrigger.go b/internal/usecase/eventtrigger.go new file mode 100644 index 0000000..de4dfed --- /dev/null +++ b/internal/usecase/eventtrigger.go @@ -0,0 +1,216 @@ +package usecase + +import ( + "encoding/hex" + "fmt" + "math/big" + "net/http" + "slices" + "strings" + + "github.com/defiweb/go-sigparser" + ecommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" + "github.com/rs/zerolog/log" + shs "github.com/shutter-network/rolling-shutter/rolling-shutter/keyperimpl/shutterservice" + sherror "github.com/shutter-network/shutter-api/internal/error" +) + +type EventArgument struct { + Name string `json:"name" example:"amount"` + Operator string `json:"op" example:"gte"` + Number int `json:"number" example:"25433"` + Bytes string `json:"bytes" example:"0xabcdef01234567"` +} +type EventTriggerDefinitionRequest struct { + EventSignature string `json:"event_sig" example:"Transfer(indexed from address, indexed to address, amount uint256)"` + ContractAddress ecommon.Address `json:"contract" example:"0x3465a347342B72BCf800aBf814324ba4a803c32b"` + Arguments []EventArgument `json:"arguments" example:"[{\"name\": \"from\", \"op\": \"eq\", \"bytes\": \"0x456d9347342B72BCf800bBf117391ac2f807c6bF\"}]"` +} // @name EventTriggerDefinitionRequest + +type EventTriggerDefinitionResponse struct { + EventTriggerDefinition string `json:"event_trigger_definition" example:"Transfer(indexed from address, indexed to address, amount uint256)"` +} + +func CompileEventTriggerDefinitionInternal(req EventTriggerDefinitionRequest) (EventTriggerDefinitionResponse, []error) { + var errors []error + zeroAddress := ecommon.Address{} + if req.ContractAddress == zeroAddress { + err := fmt.Errorf("Contract address empty") + log.Err(err).Msg("error creating event trigger definition") + err = sherror.NewHttpError( + "unable to parse event trigger definition", + err.Error(), + http.StatusBadRequest, + ) + errors = append(errors, err) + } + if len(req.EventSignature) == 0 { + err := fmt.Errorf("No event signature given") + log.Err(err).Msg("error creating event trigger definition") + err = sherror.NewHttpError( + "unable to parse event trigger definition", + err.Error(), + http.StatusBadRequest, + ) + errors = append(errors, err) + } + predicates, err := logPredicates(req.Arguments, req.EventSignature) + if err != nil { + log.Err(err).Msg("error parsing event trigger definition") + err := sherror.NewHttpError( + "unable to parse event trigger definition", + err.Error(), + http.StatusBadRequest, + ) + errors = append(errors, err) + } + etd := shs.EventTriggerDefinition{ + Contract: req.ContractAddress, + LogPredicates: predicates, + } + err = etd.Validate() + if err != nil { + log.Err(err).Msg("error validating event trigger definition") + err := sherror.NewHttpError( + "event trigger definition invalid", + err.Error(), + http.StatusBadRequest, + ) + errors = append(errors, err) + } + + data := EventTriggerDefinitionResponse{EventTriggerDefinition: hex.EncodeToString(etd.MarshalBytes())} + return data, errors +} + +// aligns []byte to 32 byte +func Align(val []byte) []byte { + words := (31 + len(val)) / shs.Word + x := make([]byte, shs.Word*words) + copy(x[len(x)-len(val):], val) + return x +} + +func Topic0(sig sigparser.Signature) shs.LogPredicate { + var b strings.Builder + b.WriteString(sig.Name) + b.WriteString("(") + for i, input := range sig.Inputs { + b.WriteString(input.Type) + if i < len(sig.Inputs)-1 { + b.WriteString(",") + } + } + b.WriteString(")") + lp := shs.LogPredicate{} + lp.LogValueRef.Length = 1 + lp.LogValueRef.Offset = 0 + h := crypto.Keccak256([]byte(b.String())) + lp.ValuePredicate.ByteArgs = [][]byte{h} + lp.ValuePredicate.Op = shs.BytesEq + return lp +} + +func logPredicates(args []EventArgument, evtSig string) ([]shs.LogPredicate, error) { + lps := []shs.LogPredicate{} + sig, err := sigparser.ParseSignature(evtSig) + if err != nil { + return lps, err + } + lp := Topic0(sig) + lps = append(lps, lp) + indexedOffset := uint64(1) + nonIndexedOffset := uint64(4) + length := uint64(0) + argnames := make([]string, len(args)) + for i, arg := range args { + found := slices.IndexFunc( + sig.Inputs, + func(par sigparser.Parameter) bool { + return par.Name == arg.Name + }) + if found < 0 { + return lps, fmt.Errorf("argument '%v' not defined in signature", arg.Name) + } + double := slices.IndexFunc( + argnames, + func(name string) bool { + return name == arg.Name + }) + if double >= 0 { + return lps, fmt.Errorf("argument '%v' was defined more than once", arg.Name) + } + argnames[i] = arg.Name + } + for _, input := range sig.Inputs { + lp := shs.LogPredicate{} + i := slices.IndexFunc( + args, + func(ea EventArgument) bool { + return ea.Name == input.Name + }) + // input is part of definition: + if i >= 0 { + arg := args[i] + // input is topic: + if input.Indexed { + val, err := hexutil.Decode(arg.Bytes) + if err != nil { + return lps, err + } + length = 1 + if arg.Operator != "eq" { + return lps, fmt.Errorf("invalid operator '%v' for input '%v' of type '%v'", arg.Operator, input.Name, input.Type) + } + lp.ValuePredicate.Op = shs.BytesEq + lp.ValuePredicate.ByteArgs = [][]byte{Align(val)} + lp.LogValueRef.Offset = indexedOffset + indexedOffset++ + // input is data argument: + } else { + if input.Type != "uint256" { + val, err := hexutil.Decode(arg.Bytes) + if err != nil { + return lps, err + } + if arg.Operator != "eq" { + return lps, fmt.Errorf("invalid operator '%v' for input '%v' of type '%v'", arg.Operator, input.Name, input.Type) + } + lp.ValuePredicate.Op = shs.BytesEq + lp.ValuePredicate.ByteArgs = [][]byte{Align(val)} + length = uint64(len([]byte(arg.Bytes)) / 32) + } else { + lp.ValuePredicate.Op = opFromString(arg.Operator) + lp.ValuePredicate.IntArgs = []*big.Int{big.NewInt(int64(arg.Number))} + length = 1 + } + + lp.LogValueRef.Offset = nonIndexedOffset + nonIndexedOffset += length + } + lp.LogValueRef.Length = length + lps = append(lps, lp) + } + } + return lps, nil + +} + +func opFromString(op string) shs.Op { + switch strings.ToLower(op) { + case "lt": + return shs.UintLt + case "lte": + return shs.UintLte + case "eq": + return shs.UintEq + case "gt": + return shs.UintGt + case "gte": + return shs.UintGte + default: + return shs.BytesEq + } +} From 403e549d0906b1f9284a966df3e68ece0ab2e69b Mon Sep 17 00:00:00 2001 From: Konrad Feldmeier Date: Fri, 19 Dec 2025 10:55:53 +0100 Subject: [PATCH 11/21] WIP: Add event registry endpoint --- common/contract.go | 20 ++-- internal/service/crypto.go | 31 +++++- internal/usecase/crypto.go | 19 ++-- internal/usecase/eventtrigger.go | 165 +++++++++++++++++++++++++++++++ main.go | 5 +- tests/integration/README.md | 1 + tests/integration/init_test.go | 5 +- 7 files changed, 229 insertions(+), 17 deletions(-) diff --git a/common/contract.go b/common/contract.go index 464891b..5fbf625 100644 --- a/common/contract.go +++ b/common/contract.go @@ -5,18 +5,21 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/shutter-network/contracts/v2/bindings/keybroadcastcontract" "github.com/shutter-network/contracts/v2/bindings/keypersetmanager" + "github.com/shutter-network/contracts/v2/bindings/shuttereventtriggerregistryv1" "github.com/shutter-network/contracts/v2/bindings/shutterregistry" ) type Contract struct { - ShutterRegistryContract *shutterregistry.Shutterregistry - KeyperSetManagerContract *keypersetmanager.Keypersetmanager - KeyBroadcastContract *keybroadcastcontract.Keybroadcastcontract + ShutterRegistryContract *shutterregistry.Shutterregistry + ShutterEventRegistryContract *shuttereventtriggerregistryv1.Shuttereventtriggerregistryv1 + KeyperSetManagerContract *keypersetmanager.Keypersetmanager + KeyBroadcastContract *keybroadcastcontract.Keybroadcastcontract } func NewContract( ethClient *ethclient.Client, shutterRegistryContractAddress common.Address, + shutterEventRegistryContractAddress common.Address, keyperSetManagerContractAddress common.Address, keyBroadcastContractAddress common.Address, ) (*Contract, error) { @@ -25,6 +28,10 @@ func NewContract( return nil, err } + shutterEventRegistryContract, err := shuttereventtriggerregistryv1.NewShuttereventtriggerregistryv1(shutterEventRegistryContractAddress, ethClient) + if err != nil { + return nil, err + } keyperSetManagerContract, err := keypersetmanager.NewKeypersetmanager(keyperSetManagerContractAddress, ethClient) if err != nil { return nil, err @@ -35,8 +42,9 @@ func NewContract( return nil, err } return &Contract{ - ShutterRegistryContract: shutterRegistryContract, - KeyperSetManagerContract: keyperSetManagerContract, - KeyBroadcastContract: keyBroadcastContract, + ShutterRegistryContract: shutterRegistryContract, + ShutterEventRegistryContract: shutterEventRegistryContract, + KeyperSetManagerContract: keyperSetManagerContract, + KeyBroadcastContract: keyBroadcastContract, }, nil } diff --git a/internal/service/crypto.go b/internal/service/crypto.go index b1b963b..ff81e03 100644 --- a/internal/service/crypto.go +++ b/internal/service/crypto.go @@ -17,6 +17,12 @@ type RegisterIdentityRequest struct { IdentityPrefix string `json:"identityPrefix" example:"0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0"` } // @name RegisterIdentityRequest +type RegisterEventIdentityRequest struct { + EventTriggerDefinitionHex string `json:"event_trigger_definition" example:"0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0"` + IdentityPrefix string `json:"identityPrefix" example:"0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0"` + Ttl uint64 `json:"ttl" example:"100"` +} // @name RegisterEventIdentityRequest + type CryptoService struct { CryptoUsecase *usecase.CryptoUsecase } @@ -215,6 +221,7 @@ func (svc *CryptoService) DecryptCommitment(ctx *gin.Context) { // - "op": , // - "number": , // - "bytes": +// Note: the resulting condition for the trigger is a logical AND of all arguments given. // @Tags Crypto // @Produce json // @Param request body EventTriggerDefinitionRequest true "Event signature and match arguments." @@ -252,14 +259,13 @@ func CompileEventTriggerDefinition(ctx *gin.Context) { } // @BasePath /api -// TODO: FIXME!! doc string is just copy and paste // RegisterEventIdentity godoc // @Summary Allows clients to register an event trigger identity. // @Description Allows clients to register an identity used for encryption and event trigger definition for the decryption key associated with the encrypted message. // @Tags Crypto // @Accepts json // @Produce json -// @Param request body RegisterEventRequest true "Timestamp and Identity which client want to make the registration with." +// @Param request body RegisterEventIdentityRequest true "Event trigger definition, ttl and Identity which client want to make the registration with." // @Success 200 {object} usecase.RegisterEventResponse "Success." // @Failure 400 {object} error.Http "Invalid Register identity request." // @Failure 429 {object} error.Http "Too many requests. Rate limited." @@ -268,4 +274,25 @@ func CompileEventTriggerDefinition(ctx *gin.Context) { // @Router /register_event_identity [post] func (svc *CryptoService) RegisterEventIdentity(ctx *gin.Context) { + + var req RegisterEventIdentityRequest + if err := ctx.ShouldBindJSON(&req); err != nil { + log.Err(err).Msg("err decoding request body") + err := sherror.NewHttpError( + "unable to decode request body", + "", + http.StatusBadRequest, + ) + ctx.Error(err) + return + } + + data, httpErr := svc.CryptoUsecase.RegisterEventIdentity(ctx, req.EventTriggerDefinitionHex, req.IdentityPrefix, req.Ttl) + if httpErr != nil { + ctx.Error(httpErr) + return + } + ctx.JSON(http.StatusOK, gin.H{ + "message": data, + }) } diff --git a/internal/usecase/crypto.go b/internal/usecase/crypto.go index d0c3273..c73a05f 100644 --- a/internal/usecase/crypto.go +++ b/internal/usecase/crypto.go @@ -40,6 +40,10 @@ type ShutterregistryInterface interface { Register(opts *bind.TransactOpts, eon uint64, identityPrefix [32]byte, timestamp uint64) (*types.Transaction, error) } +type ShutterEventregistryInterface interface { + Register(opts *bind.TransactOpts, eon uint64, identityPrefix [32]byte, triggerDefinition []byte, ttl uint64) (*types.Transaction, error) +} + type KeyperSetManagerInterface interface { GetKeyperSetIndexByBlock(opts *bind.CallOpts, blockNumber uint64) (uint64, error) } @@ -76,13 +80,14 @@ type RegisterIdentityResponse struct { } // @name RegisterIdentityResponse type CryptoUsecase struct { - db *pgxpool.Pool - dbQuery *data.Queries - shutterRegistryContract ShutterregistryInterface - keyperSetManagerContract KeyperSetManagerInterface - keyBroadcastContract KeyBroadcastInterface - ethClient EthClientInterface - config *common.Config + db *pgxpool.Pool + dbQuery *data.Queries + shutterRegistryContract ShutterregistryInterface + shutterEventRegistryContract ShutterEventregistryInterface + keyperSetManagerContract KeyperSetManagerInterface + keyBroadcastContract KeyBroadcastInterface + ethClient EthClientInterface + config *common.Config } func NewCryptoUsecase( diff --git a/internal/usecase/eventtrigger.go b/internal/usecase/eventtrigger.go index de4dfed..9638254 100644 --- a/internal/usecase/eventtrigger.go +++ b/internal/usecase/eventtrigger.go @@ -1,6 +1,8 @@ package usecase import ( + "context" + cryptorand "crypto/rand" "encoding/hex" "fmt" "math/big" @@ -9,12 +11,17 @@ import ( "strings" "github.com/defiweb/go-sigparser" + "github.com/ethereum/go-ethereum/accounts/abi/bind" ecommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" "github.com/rs/zerolog/log" shs "github.com/shutter-network/rolling-shutter/rolling-shutter/keyperimpl/shutterservice" + "github.com/shutter-network/shutter-api/common" + httpError "github.com/shutter-network/shutter-api/internal/error" sherror "github.com/shutter-network/shutter-api/internal/error" + "github.com/shutter-network/shutter-api/metrics" + "github.com/shutter-network/shutter/shlib/shcrypto" ) type EventArgument struct { @@ -214,3 +221,161 @@ func opFromString(op string) shs.Op { return shs.BytesEq } } + +func (uc *CryptoUsecase) RegisterEventIdentity(ctx context.Context, eventTriggerDefinitionHex string, identityPrefixStringified string, ttl uint64) (*RegisterIdentityResponse, *httpError.Http) { + + var identityPrefix shcrypto.Block + + if len(identityPrefixStringified) > 0 { + trimmedIdentityPrefix := strings.TrimPrefix(identityPrefixStringified, "0x") + if len(trimmedIdentityPrefix) != 2*IdentityPrefixByteLength { + log.Warn().Msg("identity prefix should be of byte length 32") + err := httpError.NewHttpError( + "identity prefix should be of byte length 32", + "", + http.StatusBadRequest, + ) + return nil, &err + } + identityPrefixBytes, err := hex.DecodeString(trimmedIdentityPrefix) + if err != nil { + log.Err(err).Msg("err encountered while decoding identity prefix") + err := httpError.NewHttpError( + "error encountered while decoding identity prefix", + "", + http.StatusBadRequest, + ) + return nil, &err + } + identityPrefix = shcrypto.Block(identityPrefixBytes) + } else { + // generate a random one + block, err := shcrypto.RandomSigma(cryptorand.Reader) + if err != nil { + log.Err(err).Msg("err encountered while generating identity prefix") + err := httpError.NewHttpError( + "error encountered while generating identity prefix", + "", + http.StatusInternalServerError, + ) + return nil, &err + } + identityPrefix = block + } + + blockNumber, err := uc.ethClient.BlockNumber(ctx) + if err != nil { + log.Err(err).Msg("err encountered while querying for recent block") + metrics.TotalFailedRPCCalls.Inc() + err := httpError.NewHttpError( + "error encountered while querying for recent block", + "", + http.StatusInternalServerError, + ) + return nil, &err + } + + eon, err := uc.keyperSetManagerContract.GetKeyperSetIndexByBlock(nil, blockNumber) + if err != nil { + log.Err(err).Msg("err encountered while querying keyper set index") + metrics.TotalFailedRPCCalls.Inc() + err := httpError.NewHttpError( + "error encountered while querying for keyper set index", + "", + http.StatusInternalServerError, + ) + return nil, &err + } + + eonKeyBytes, err := uc.keyBroadcastContract.GetEonKey(nil, eon) + if err != nil { + log.Err(err).Msg("err encountered while querying for eon key") + metrics.TotalFailedRPCCalls.Inc() + err := httpError.NewHttpError( + "error encountered while querying for eon key", + "", + http.StatusInternalServerError, + ) + return nil, &err + } + + eonKey := &shcrypto.EonPublicKey{} + if err := eonKey.Unmarshal(eonKeyBytes); err != nil { + log.Err(err).Msg("err encountered while deserializing eon key") + err := httpError.NewHttpError( + "error encountered while querying deserializing eon key", + "", + http.StatusInternalServerError, + ) + return nil, &err + } + + chainId, err := uc.ethClient.ChainID(ctx) + if err != nil { + log.Err(err).Msg("err encountered while quering chain id") + metrics.TotalFailedRPCCalls.Inc() + err := httpError.NewHttpError( + "error encountered while querying chain id", + "", + http.StatusInternalServerError, + ) + return nil, &err + } + + newSigner, err := bind.NewKeyedTransactorWithChainID(uc.config.SigningKey, chainId) + if err != nil { + log.Err(err).Msg("err encountered while creating signer") + err := httpError.NewHttpError( + "error encountered while registering identity", + "", + http.StatusInternalServerError, + ) + return nil, &err + } + + identity := common.ComputeIdentity(identityPrefix[:], newSigner.From) + + // TODO: check for already registered + + publicAddress := crypto.PubkeyToAddress(*uc.config.PublicKey) + + opts := bind.TransactOpts{ + From: publicAddress, + Signer: newSigner.Signer, + } + + eventTriggerDefinition, err := hexutil.Decode(eventTriggerDefinitionHex) + if err != nil { + err := httpError.NewHttpError( + "could not decode event trigger definition", + "", + http.StatusBadRequest, + ) + return nil, &err + } + + tx, err := uc.shutterEventRegistryContract.Register(&opts, eon, identityPrefix, eventTriggerDefinition, ttl) + if err != nil { + log.Err(err).Msg("failed to send transaction") + metrics.TotalFailedRPCCalls.Inc() + err := httpError.NewHttpError( + "failed to register identity", + "", + http.StatusInternalServerError, + ) + return nil, &err + } + // not launching a routine to monitor the transaction + // we return the transaction hash in response to allow + // users the ability to monitor it themselves + + metrics.TotalSuccessfulIdentityRegistration.Inc() + return &RegisterIdentityResponse{ + Eon: eon, + Identity: common.PrefixWith0x(hex.EncodeToString(identity)), + IdentityPrefix: common.PrefixWith0x(hex.EncodeToString(identityPrefix[:])), + EonKey: common.PrefixWith0x(hex.EncodeToString(eonKeyBytes)), + TxHash: tx.Hash().Hex(), + }, nil + +} diff --git a/main.go b/main.go index 1544c19..6085f94 100644 --- a/main.go +++ b/main.go @@ -115,13 +115,16 @@ func main() { shutterRegistryContractAddressStringified := os.Getenv("SHUTTER_REGISTRY_CONTRACT_ADDRESS") shutterRegistryContractAddress := common.HexToAddress(shutterRegistryContractAddressStringified) + shutterEventRegistryContractAddressStringified := os.Getenv("SHUTTER_EVENT+REGISTRY_CONTRACT_ADDRESS") + shutterEventRegistryContractAddress := common.HexToAddress(shutterEventRegistryContractAddressStringified) + keyBroadcastContractAddressStringified := os.Getenv("KEY_BROADCAST_CONTRACT_ADDRESS") keyBroadcastContractAddress := common.HexToAddress(keyBroadcastContractAddressStringified) keyperSetManagerContractAddressStringified := os.Getenv("KEYPER_SET_MANAGER_CONTRACT_ADDRESS") keyperSetManagerContractAddress := common.HexToAddress(keyperSetManagerContractAddressStringified) - contract, err := shutterAPICommon.NewContract(client, shutterRegistryContractAddress, keyperSetManagerContractAddress, keyBroadcastContractAddress) + contract, err := shutterAPICommon.NewContract(client, shutterRegistryContractAddress, shutterEventRegistryContractAddress, keyperSetManagerContractAddress, keyBroadcastContractAddress) if err != nil { log.Err(err).Msg("failed to instantiate shutter contracts") return diff --git a/tests/integration/README.md b/tests/integration/README.md index 3c7a4ff..72f466e 100644 --- a/tests/integration/README.md +++ b/tests/integration/README.md @@ -12,6 +12,7 @@ Before running the tests, ensure that you have the following environment variabl - `RPC_URL` – The execution client RPC URL. - `TOTAL_BULK_REQUESTS` - Number of bulk requests for testing bulk decryption key requests - `SHUTTER_REGISTRY_CONTRACT_ADDRESS` +- `SHUTTER_EVENT_REGISTRY_CONTRACT_ADDRESS` - `KEY_BROADCAST_CONTRACT_ADDRESS` - `KEYPER_SET_MANAGER_CONTRACT_ADDRESS` - `P2P_BOOTSTRAP_ADDRESSES` - The addresses of the Keyper nodes to bootstrap the P2P network. diff --git a/tests/integration/init_test.go b/tests/integration/init_test.go index 16d571a..177a03c 100644 --- a/tests/integration/init_test.go +++ b/tests/integration/init_test.go @@ -89,13 +89,16 @@ func (s *TestShutterService) SetupSuite() { shutterRegistryContractAddressStringified := os.Getenv("SHUTTER_REGISTRY_CONTRACT_ADDRESS") shutterRegistryContractAddress := ethCommon.HexToAddress(shutterRegistryContractAddressStringified) + shutterEventRegistryContractAddressStringified := os.Getenv("SHUTTER_EVENT_REGISTRY_CONTRACT_ADDRESS") + shutterEventRegistryContractAddress := ethCommon.HexToAddress(shutterEventRegistryContractAddressStringified) + keyBroadcastContractAddressStringified := os.Getenv("KEY_BROADCAST_CONTRACT_ADDRESS") keyBroadcastContractAddress := ethCommon.HexToAddress(keyBroadcastContractAddressStringified) keyperSetManagerContractAddressStringified := os.Getenv("KEYPER_SET_MANAGER_CONTRACT_ADDRESS") keyperSetManagerContractAddress := ethCommon.HexToAddress(keyperSetManagerContractAddressStringified) - s.contract, err = common.NewContract(s.ethClient, shutterRegistryContractAddress, keyperSetManagerContractAddress, keyBroadcastContractAddress) + s.contract, err = common.NewContract(s.ethClient, shutterRegistryContractAddress, shutterEventRegistryContractAddress, keyperSetManagerContractAddress, keyBroadcastContractAddress) s.Require().NoError(err) migrationsPath := "../../migrations" From b6526c90ff96f81d4962b0a3d4858a34b2866432 Mon Sep 17 00:00:00 2001 From: Konrad Feldmeier Date: Fri, 19 Dec 2025 11:25:20 +0100 Subject: [PATCH 12/21] Usage instructions in executable source --- etdc/main.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/etdc/main.go b/etdc/main.go index ddecfff..e06b043 100644 --- a/etdc/main.go +++ b/etdc/main.go @@ -13,6 +13,22 @@ import ( // build from root folder via // // go build -ldflags '-w -s' -o bin/etdc ./etdc +// +// Usage: +// ``` +// # given request.json +// +// { +// "contract": "0x953A0425ACCee2E05f22E78999c595eD2eE7183c", +// "event_sig":"event Transfer(address indexed from, address indexed to, uint256 amount)", +// "arguments": [ +// {"name": "from", "op": "eq", "bytes": "0x812a6755975485C6E340F97dE6790B34a94D1430"}, +// {"name": "amount", "op": "gte", "number": 2}] +// } +// +// # you can call +// cat request.json | ./etdc +// # to compile func main() { req, err := IngestRequest() if err != nil { From 0ee0c3b4782c1e85723fc72d4a2457532cdc8dac Mon Sep 17 00:00:00 2001 From: Konrad Feldmeier Date: Fri, 19 Dec 2025 13:04:18 +0100 Subject: [PATCH 13/21] Add some todo's for collision checks and whitelist --- internal/usecase/crypto.go | 1 + internal/usecase/eventtrigger.go | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/internal/usecase/crypto.go b/internal/usecase/crypto.go index c73a05f..7a7358a 100644 --- a/internal/usecase/crypto.go +++ b/internal/usecase/crypto.go @@ -444,6 +444,7 @@ func (uc *CryptoUsecase) RegisterIdentity(ctx context.Context, decryptionTimesta identity := common.ComputeIdentity(identityPrefix[:], newSigner.From) + // TODO: check for already registered identities also against event based triggers! registrationData, err := uc.shutterRegistryContract.Registrations(nil, [32]byte(identity)) if err != nil { log.Err(err).Msg("err encountered while querying contract") diff --git a/internal/usecase/eventtrigger.go b/internal/usecase/eventtrigger.go index 9638254..857ddc7 100644 --- a/internal/usecase/eventtrigger.go +++ b/internal/usecase/eventtrigger.go @@ -354,6 +354,11 @@ func (uc *CryptoUsecase) RegisterEventIdentity(ctx context.Context, eventTrigger return nil, &err } + // TODO: check contract address of eventTriggerDefinition against white list (if necessary) + // whitelist from ENV - if empty assert wildcard + // - parse event trigger definition with keyper side code from keyperimpl/shutterservice.EventTriggerDefinition + // - check event trigger definition "Contract" against whitelist + tx, err := uc.shutterEventRegistryContract.Register(&opts, eon, identityPrefix, eventTriggerDefinition, ttl) if err != nil { log.Err(err).Msg("failed to send transaction") From 56b93ef902a9cbbb4991da45ded48a0807bacd4e Mon Sep 17 00:00:00 2001 From: Konrad Feldmeier Date: Fri, 19 Dec 2025 13:34:50 +0100 Subject: [PATCH 14/21] Add ttl parameter to README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b01ad23..0ce1121 100644 --- a/README.md +++ b/README.md @@ -140,7 +140,8 @@ curl -X POST https:///register_event_identity \ -H "Content-Type: application/json" \ -d '{ "eventDefinition": "0x808ba62b3fb085eae2e58888828d5aa5d0d8d3cc44dcb1750e3664468a1288c38501d8d9e5d89930656b6ce9aa13b6a311031b89963b83d95588e26e5e8a9aeef2b9c1b07740d24bbd7aef9935fde194e05aff41fe6e3529de9a4b81779ddf4bed488b753efabe29aa7407bf131a7f744f2cf0429b0a200b1d369791fae3c740d62edd422b649a41660a6f0bd4310ecad617fb8ba626970934bd473c4dcc7784fac7ed66c4576590c76e70af4f3d99ea1361669349beb8cbb3346e9cc821435d", - "identityPrefix": "0x32fdbd2ca52e171f77db2757ff6200cd8446350f927a3ad46c0565483dd8b41c" + "identityPrefix": "0x32fdbd2ca52e171f77db2757ff6200cd8446350f927a3ad46c0565483dd8b41c", + "ttl": 100 }' ``` From a6ebda689fc9b216d702f8a0e4e3b35259f662b2 Mon Sep 17 00:00:00 2001 From: Konrad Feldmeier Date: Fri, 19 Dec 2025 13:36:34 +0100 Subject: [PATCH 15/21] Add spec link to README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0ce1121..357581d 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ curl -X POST https:///register_event_identity \ }' ``` -> **Note**: The encoding of `eventDefinition` is specified [elsewhere](FIXME link missing). It is a concatenation of contract address, topic0 and the rlp encoding of the other conditions. Event definitions should be constructed by using provided tooling (WIP). +> **Note**: The encoding of `eventDefinition` is specified [in rolling-shutter](https://github.com/shutter-network/rolling-shutter/blob/main/docs/event.md). It is a concatenation of contract address, topic0 and the rlp encoding of the other conditions. Event definitions should be constructed by using provided tooling (WIP). #### Example Response ```json From ebd9e113590cff99c7198a042479394fb7330292 Mon Sep 17 00:00:00 2001 From: Konrad Feldmeier Date: Fri, 19 Dec 2025 13:41:30 +0100 Subject: [PATCH 16/21] Use valid data for triggerDefinition example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 357581d..56a9575 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ Registered event based decryption triggers are bound by a time-to-live (`ttl`). curl -X POST https:///register_event_identity \ -H "Content-Type: application/json" \ -d '{ - "eventDefinition": "0x808ba62b3fb085eae2e58888828d5aa5d0d8d3cc44dcb1750e3664468a1288c38501d8d9e5d89930656b6ce9aa13b6a311031b89963b83d95588e26e5e8a9aeef2b9c1b07740d24bbd7aef9935fde194e05aff41fe6e3529de9a4b81779ddf4bed488b753efabe29aa7407bf131a7f744f2cf0429b0a200b1d369791fae3c740d62edd422b649a41660a6f0bd4310ecad617fb8ba626970934bd473c4dcc7784fac7ed66c4576590c76e70af4f3d99ea1361669349beb8cbb3346e9cc821435d", + "triggerDefinition": "0x01f86694953a0425accee2e05f22e78999c595ed2ee7183cf84fe480e205a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efe401e205a0000000000000000000000000812a6755975485c6e340f97de6790b34a94d1430c404c20402", "identityPrefix": "0x32fdbd2ca52e171f77db2757ff6200cd8446350f927a3ad46c0565483dd8b41c", "ttl": 100 }' From d57cfdf64eb5ae5c5aff439980dbc428c4d728b9 Mon Sep 17 00:00:00 2001 From: Konrad Feldmeier Date: Fri, 19 Dec 2025 13:42:02 +0100 Subject: [PATCH 17/21] More consistent parameter naming --- internal/service/crypto.go | 4 ++-- internal/usecase/eventtrigger.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/crypto.go b/internal/service/crypto.go index ff81e03..0b97f3d 100644 --- a/internal/service/crypto.go +++ b/internal/service/crypto.go @@ -18,7 +18,7 @@ type RegisterIdentityRequest struct { } // @name RegisterIdentityRequest type RegisterEventIdentityRequest struct { - EventTriggerDefinitionHex string `json:"event_trigger_definition" example:"0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0"` + EventTriggerDefinitionHex string `json:"triggerDefinition" example:"0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0"` IdentityPrefix string `json:"identityPrefix" example:"0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0"` Ttl uint64 `json:"ttl" example:"100"` } // @name RegisterEventIdentityRequest @@ -230,7 +230,7 @@ func (svc *CryptoService) DecryptCommitment(ctx *gin.Context) { // @Failure 429 {object} error.Http "Too many requests. Rate limited." // @Failure 500 {object} error.Http "Internal server error." // @Security BearerAuth -// @Router /event_trigger_definition [post] +// @Router /compile_event_trigger_definition [post] func (svc *CryptoService) CompileEventTriggerDefinition(ctx *gin.Context) { CompileEventTriggerDefinition(ctx) diff --git a/internal/usecase/eventtrigger.go b/internal/usecase/eventtrigger.go index 857ddc7..d325cd3 100644 --- a/internal/usecase/eventtrigger.go +++ b/internal/usecase/eventtrigger.go @@ -37,7 +37,7 @@ type EventTriggerDefinitionRequest struct { } // @name EventTriggerDefinitionRequest type EventTriggerDefinitionResponse struct { - EventTriggerDefinition string `json:"event_trigger_definition" example:"Transfer(indexed from address, indexed to address, amount uint256)"` + EventTriggerDefinition string `json:"triggerDefinition" example:"Transfer(indexed from address, indexed to address, amount uint256)"` } func CompileEventTriggerDefinitionInternal(req EventTriggerDefinitionRequest) (EventTriggerDefinitionResponse, []error) { @@ -335,7 +335,7 @@ func (uc *CryptoUsecase) RegisterEventIdentity(ctx context.Context, eventTrigger identity := common.ComputeIdentity(identityPrefix[:], newSigner.From) - // TODO: check for already registered + // TODO: check for already registered identities also against time based triggers! publicAddress := crypto.PubkeyToAddress(*uc.config.PublicKey) From 62ca598af332936a43fa2f9d4c5f4c5125e822bd Mon Sep 17 00:00:00 2001 From: Konrad Feldmeier Date: Fri, 19 Dec 2025 13:50:02 +0100 Subject: [PATCH 18/21] Mention compile endpoint in README Note: it changed from 'use 3rd party tooling' but does not mention, that the provided compiler implementation is opinionated, and 3rd party tooling could provide more flexible event triggers. Namely triggers that allow for some parameters to be omitted, e.g. topic0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 56a9575..a6403b5 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ curl -X POST https:///register_event_identity \ }' ``` -> **Note**: The encoding of `eventDefinition` is specified [in rolling-shutter](https://github.com/shutter-network/rolling-shutter/blob/main/docs/event.md). It is a concatenation of contract address, topic0 and the rlp encoding of the other conditions. Event definitions should be constructed by using provided tooling (WIP). +> **Note**: The encoding of `eventDefinition` is specified [in rolling-shutter](https://github.com/shutter-network/rolling-shutter/blob/main/docs/event.md). It is a concatenation of contract address, topic0 and the rlp encoding of the other conditions. Event definitions can be constructed by using the `/compile_event_trigger_definition` endpoint (WIP: add link to swagger docs). #### Example Response ```json From 3fc762124cebbd20cea77a8bf1743a0e86454ace Mon Sep 17 00:00:00 2001 From: blockchainluffy Date: Tue, 23 Dec 2025 19:33:49 +0530 Subject: [PATCH 19/21] feat: register_event_identity endpoint and add swagger docs --- Dockerfile | 2 +- common/config.go | 21 +- common/utils.go | 6 + docker-compose.yml | 2 + docs/docs.go | 174 ++++++++++ docs/swagger.json | 174 ++++++++++ go.mod | 7 +- go.sum | 21 +- internal/router/router.go | 1 + internal/service/crypto.go | 195 ++++++------ internal/usecase/crypto.go | 16 +- internal/usecase/eventtrigger.go | 68 ++-- main.go | 16 +- tests/init_test.go | 31 +- tests/integration/init_test.go | 2 +- tests/mock/shutter_event_registry_contract.go | 16 + tests/register_event_identity_test.go | 298 ++++++++++++++++++ 17 files changed, 893 insertions(+), 157 deletions(-) create mode 100644 tests/mock/shutter_event_registry_contract.go create mode 100644 tests/register_event_identity_test.go diff --git a/Dockerfile b/Dockerfile index 4d2bd59..a1c5c2e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.22-alpine AS builder +FROM golang:1.24-alpine AS builder # Install build-essential and other necessary packages RUN apk add --no-cache build-base diff --git a/common/config.go b/common/config.go index b723967..357cc3d 100644 --- a/common/config.go +++ b/common/config.go @@ -5,17 +5,19 @@ import ( "fmt" "net/url" + "github.com/ethereum/go-ethereum/common" "github.com/shutter-network/rolling-shutter/rolling-shutter/p2p" ) type Config struct { - KeyperHTTPURL *url.URL - SigningKey *ecdsa.PrivateKey - PublicKey *ecdsa.PublicKey - P2P *p2p.Config + KeyperHTTPURL *url.URL + SigningKey *ecdsa.PrivateKey + PublicKey *ecdsa.PublicKey + P2P *p2p.Config + WhitelistedContractAddresses []common.Address } -func NewConfig(keyperHTTPUrl string, signingKey *ecdsa.PrivateKey, p2pConfig *p2p.Config) (*Config, error) { +func NewConfig(keyperHTTPUrl string, signingKey *ecdsa.PrivateKey, p2pConfig *p2p.Config, whitelistedContractAddresses []common.Address) (*Config, error) { parsedURL, err := url.Parse(keyperHTTPUrl) if err != nil { return nil, err @@ -25,9 +27,10 @@ func NewConfig(keyperHTTPUrl string, signingKey *ecdsa.PrivateKey, p2pConfig *p2 return nil, fmt.Errorf("cannot create public key") } return &Config{ - KeyperHTTPURL: parsedURL, - SigningKey: signingKey, - PublicKey: publicKey, - P2P: p2pConfig, + KeyperHTTPURL: parsedURL, + SigningKey: signingKey, + PublicKey: publicKey, + P2P: p2pConfig, + WhitelistedContractAddresses: whitelistedContractAddresses, }, nil } diff --git a/common/utils.go b/common/utils.go index 402f75b..b5fc11a 100644 --- a/common/utils.go +++ b/common/utils.go @@ -10,6 +10,12 @@ func ComputeIdentity(prefix []byte, sender common.Address) []byte { return crypto.Keccak256(imageBytes) } +func ComputeEventIdentity(prefix []byte, sender common.Address, triggerDefinition []byte) []byte { + imageBytes := append(prefix, sender.Bytes()...) + imageBytes = append(imageBytes, triggerDefinition...) + return crypto.Keccak256(imageBytes) +} + func PrefixWith0x(src string) string { return "0x" + src } diff --git a/docker-compose.yml b/docker-compose.yml index 358c823..38ab21f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -27,6 +27,8 @@ services: METRICS_ENABLED: METRICS_HOST: METRICS_PORT: + SHUTTER_EVENT_REGISTRY_CONTRACT_ADDRESS: + WHITELISTED_TRIGGER_CONTRACT_ADDRESSES: ports: - "8001:8001" - "23003:23003" diff --git a/docs/docs.go b/docs/docs.go index 8f53962..7916ad0 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -15,6 +15,60 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { + "/compile_event_trigger_definition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "This endpoint takes an event signature snippet and some arguments to create an event trigger definition that will be understood by keypers", + "produces": [ + "application/json" + ], + "tags": [ + "Crypto" + ], + "summary": "Allows clients to compile an event trigger definition string.", + "parameters": [ + { + "description": "Event signature and match arguments.", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/EventTriggerDefinitionRequest" + } + } + ], + "responses": { + "200": { + "description": "Success.", + "schema": { + "$ref": "#/definitions/usecase.EventTriggerDefinitionResponse" + } + }, + "400": { + "description": "Invalid Event Data.", + "schema": { + "$ref": "#/definitions/error.Http" + } + }, + "429": { + "description": "Too many requests. Rate limited.", + "schema": { + "$ref": "#/definitions/error.Http" + } + }, + "500": { + "description": "Internal server error.", + "schema": { + "$ref": "#/definitions/error.Http" + } + } + } + } + }, "/decrypt_commitment": { "get": { "security": [ @@ -193,6 +247,60 @@ const docTemplate = `{ } } }, + "/register_event_identity": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Allows clients to register an identity used for encryption and event trigger definition for the decryption key associated with the encrypted message.", + "produces": [ + "application/json" + ], + "tags": [ + "Crypto" + ], + "summary": "Allows clients to register an event trigger identity.", + "parameters": [ + { + "description": "Event trigger definition, ttl and Identity which client want to make the registration with.", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/RegisterEventIdentityRequest" + } + } + ], + "responses": { + "200": { + "description": "Success.", + "schema": { + "$ref": "#/definitions/RegisterIdentityResponse" + } + }, + "400": { + "description": "Invalid Register identity request.", + "schema": { + "$ref": "#/definitions/error.Http" + } + }, + "429": { + "description": "Too many requests. Rate limited.", + "schema": { + "$ref": "#/definitions/error.Http" + } + }, + "500": { + "description": "Internal server error.", + "schema": { + "$ref": "#/definitions/error.Http" + } + } + } + } + }, "/register_identity": { "post": { "security": [ @@ -249,6 +357,25 @@ const docTemplate = `{ } }, "definitions": { + "EventTriggerDefinitionRequest": { + "type": "object", + "properties": { + "arguments": { + "type": "array", + "items": { + "$ref": "#/definitions/usecase.EventArgument" + } + }, + "contract": { + "type": "string", + "example": "0x3465a347342B72BCf800aBf814324ba4a803c32b" + }, + "event_sig": { + "type": "string", + "example": "Transfer(indexed from address, indexed to address, amount uint256)" + } + } + }, "GetDataForEncryption": { "type": "object", "properties": { @@ -291,6 +418,23 @@ const docTemplate = `{ } } }, + "RegisterEventIdentityRequest": { + "type": "object", + "properties": { + "identityPrefix": { + "type": "string", + "example": "0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0" + }, + "triggerDefinition": { + "type": "string", + "example": "0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0" + }, + "ttl": { + "type": "integer", + "example": 100 + } + } + }, "RegisterIdentityRequest": { "type": "object", "properties": { @@ -342,6 +486,36 @@ const docTemplate = `{ "type": "integer" } } + }, + "usecase.EventArgument": { + "type": "object", + "properties": { + "bytes": { + "type": "string", + "example": "0xabcdef01234567" + }, + "name": { + "type": "string", + "example": "amount" + }, + "number": { + "type": "integer", + "example": 25433 + }, + "op": { + "type": "string", + "example": "gte" + } + } + }, + "usecase.EventTriggerDefinitionResponse": { + "type": "object", + "properties": { + "triggerDefinition": { + "type": "string", + "example": "0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0" + } + } } }, "securityDefinitions": { diff --git a/docs/swagger.json b/docs/swagger.json index c3549e9..74ca620 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -6,6 +6,60 @@ "contact": {} }, "paths": { + "/compile_event_trigger_definition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "This endpoint takes an event signature snippet and some arguments to create an event trigger definition that will be understood by keypers", + "produces": [ + "application/json" + ], + "tags": [ + "Crypto" + ], + "summary": "Allows clients to compile an event trigger definition string.", + "parameters": [ + { + "description": "Event signature and match arguments.", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/EventTriggerDefinitionRequest" + } + } + ], + "responses": { + "200": { + "description": "Success.", + "schema": { + "$ref": "#/definitions/usecase.EventTriggerDefinitionResponse" + } + }, + "400": { + "description": "Invalid Event Data.", + "schema": { + "$ref": "#/definitions/error.Http" + } + }, + "429": { + "description": "Too many requests. Rate limited.", + "schema": { + "$ref": "#/definitions/error.Http" + } + }, + "500": { + "description": "Internal server error.", + "schema": { + "$ref": "#/definitions/error.Http" + } + } + } + } + }, "/decrypt_commitment": { "get": { "security": [ @@ -184,6 +238,60 @@ } } }, + "/register_event_identity": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Allows clients to register an identity used for encryption and event trigger definition for the decryption key associated with the encrypted message.", + "produces": [ + "application/json" + ], + "tags": [ + "Crypto" + ], + "summary": "Allows clients to register an event trigger identity.", + "parameters": [ + { + "description": "Event trigger definition, ttl and Identity which client want to make the registration with.", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/RegisterEventIdentityRequest" + } + } + ], + "responses": { + "200": { + "description": "Success.", + "schema": { + "$ref": "#/definitions/RegisterIdentityResponse" + } + }, + "400": { + "description": "Invalid Register identity request.", + "schema": { + "$ref": "#/definitions/error.Http" + } + }, + "429": { + "description": "Too many requests. Rate limited.", + "schema": { + "$ref": "#/definitions/error.Http" + } + }, + "500": { + "description": "Internal server error.", + "schema": { + "$ref": "#/definitions/error.Http" + } + } + } + } + }, "/register_identity": { "post": { "security": [ @@ -240,6 +348,25 @@ } }, "definitions": { + "EventTriggerDefinitionRequest": { + "type": "object", + "properties": { + "arguments": { + "type": "array", + "items": { + "$ref": "#/definitions/usecase.EventArgument" + } + }, + "contract": { + "type": "string", + "example": "0x3465a347342B72BCf800aBf814324ba4a803c32b" + }, + "event_sig": { + "type": "string", + "example": "Transfer(indexed from address, indexed to address, amount uint256)" + } + } + }, "GetDataForEncryption": { "type": "object", "properties": { @@ -282,6 +409,23 @@ } } }, + "RegisterEventIdentityRequest": { + "type": "object", + "properties": { + "identityPrefix": { + "type": "string", + "example": "0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0" + }, + "triggerDefinition": { + "type": "string", + "example": "0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0" + }, + "ttl": { + "type": "integer", + "example": 100 + } + } + }, "RegisterIdentityRequest": { "type": "object", "properties": { @@ -333,6 +477,36 @@ "type": "integer" } } + }, + "usecase.EventArgument": { + "type": "object", + "properties": { + "bytes": { + "type": "string", + "example": "0xabcdef01234567" + }, + "name": { + "type": "string", + "example": "amount" + }, + "number": { + "type": "integer", + "example": 25433 + }, + "op": { + "type": "string", + "example": "gte" + } + } + }, + "usecase.EventTriggerDefinitionResponse": { + "type": "object", + "properties": { + "triggerDefinition": { + "type": "string", + "example": "0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0" + } + } } }, "securityDefinitions": { diff --git a/go.mod b/go.mod index 01d9bb9..2ada0de 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/libp2p/go-libp2p-pubsub v0.13.1 github.com/prometheus/client_golang v1.22.0 github.com/shutter-network/contracts/v2 v2.0.0-beta.2.0.20250908105003-7e53b1579b04 - github.com/shutter-network/rolling-shutter/rolling-shutter v0.0.0-00010101000000-000000000000 + github.com/shutter-network/rolling-shutter/rolling-shutter v0.0.7-0.20251208133535-1ceca5ea26d9 github.com/stretchr/testify v1.10.0 github.com/swaggo/gin-swagger v1.6.0 github.com/swaggo/swag v1.16.4 @@ -21,12 +21,14 @@ require ( ) require ( + github.com/DataDog/zstd v1.5.5 // indirect github.com/KyleBanks/depth v1.2.1 // indirect github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cockroachdb/fifo v0.0.0-20240616162244-4768e80dfb9a // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/gogoproto v1.4.1 // indirect @@ -43,6 +45,7 @@ require ( github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect github.com/getkin/kin-openapi v0.87.0 // indirect + github.com/getsentry/sentry-go v0.28.1 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-chi/chi/v5 v5.0.10 // indirect github.com/go-kit/kit v0.12.0 // indirect @@ -99,6 +102,7 @@ require ( github.com/libp2p/go-yamux/v5 v5.0.0 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect + github.com/mattn/go-runewidth v0.0.16 // 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 @@ -152,6 +156,7 @@ require ( github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/shutter-network/shop-contracts v0.0.0-20240407151512-08ef5d8355b6 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect diff --git a/go.sum b/go.sum index 6ea7c31..4e0d886 100644 --- a/go.sum +++ b/go.sum @@ -53,8 +53,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= -github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= -github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= +github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= @@ -116,8 +116,8 @@ github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= -github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= -github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= +github.com/cockroachdb/fifo v0.0.0-20240616162244-4768e80dfb9a h1:f52TdbU4D5nozMAhO9TvTJ2ZMCXtN4VIAmfrrZ0JXQ4= +github.com/cockroachdb/fifo v0.0.0-20240616162244-4768e80dfb9a/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/pebble v1.1.2 h1:CUh2IPtR4swHlEj48Rhfzw6l/d0qA31fItcIszQVIsA= @@ -245,8 +245,8 @@ github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8x github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/getkin/kin-openapi v0.87.0 h1:eeb0WBIgRiXra7ZY0Vo+jWloqvaF2kNEaxAyb+39N+E= github.com/getkin/kin-openapi v0.87.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= -github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= -github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/getsentry/sentry-go v0.28.1 h1:zzaSm/vHmGllRM6Tpx1492r0YDzauArdBfkJRtY6P5k= +github.com/getsentry/sentry-go v0.28.1/go.mod h1:1fQZ+7l7eeJ3wYi82q5Hg8GqAPgefRq+FP/QhafYVgg= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/cors v1.7.3 h1:hV+a5xp8hwJoTw7OY+a70FsL8JkVVFTXw9EcfrYUdns= @@ -669,8 +669,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 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/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY= github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg= @@ -861,8 +861,9 @@ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5X github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= @@ -924,6 +925,8 @@ github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYED github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= github.com/shutter-network/contracts/v2 v2.0.0-beta.2.0.20250908105003-7e53b1579b04 h1:DfSfDw8IqXHqz6JXkZLIcvPS4CdoeXNaDhk+HEX61rM= github.com/shutter-network/contracts/v2 v2.0.0-beta.2.0.20250908105003-7e53b1579b04/go.mod h1:V8KhVM75wyWVSzZJ6GeC9dWCjRrinIQVb7mYNP+knbg= +github.com/shutter-network/rolling-shutter/rolling-shutter v0.0.7-0.20251208133535-1ceca5ea26d9 h1:AxV/M1mTOBaf2XlfRg3aCroBtEwnd4IF26ehuBwY5ZE= +github.com/shutter-network/rolling-shutter/rolling-shutter v0.0.7-0.20251208133535-1ceca5ea26d9/go.mod h1:U01tVxIpZ1okPKkmjY9XqTiNzVQxC47u1waIPIKtx60= github.com/shutter-network/shop-contracts v0.0.0-20240407151512-08ef5d8355b6 h1:m6Ti1/IH+GBTtGqyAX3xbh+ruUKvC+m+/uzYDUa+JDQ= github.com/shutter-network/shop-contracts v0.0.0-20240407151512-08ef5d8355b6/go.mod h1:LEWXLRruvxq9fe2oKtJI3xfzbauhfWTjOczHN61RU+4= github.com/shutter-network/shutter/shlib v0.1.19 h1:Fm/PnxAapl5UK4JuJyF2wBh3dYB5ESztnNFcbmzNNOI= diff --git a/internal/router/router.go b/internal/router/router.go index 7a6c9b0..ea4054d 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -39,6 +39,7 @@ func NewRouter( api.POST("/register_identity", cryptoService.RegisterIdentity) api.POST("/compile_event_trigger_definition", cryptoService.CompileEventTriggerDefinition) api.GET("/decrypt_commitment", cryptoService.DecryptCommitment) + api.POST("/register_event_identity", cryptoService.RegisterEventIdentity) } router.GET("/docs/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, func(c *ginSwagger.Config) { c.Title = "Shutter-API" diff --git a/internal/service/crypto.go b/internal/service/crypto.go index 0b97f3d..dfa0683 100644 --- a/internal/service/crypto.go +++ b/internal/service/crypto.go @@ -34,26 +34,26 @@ func NewCryptoService( config *common.Config, ) *CryptoService { return &CryptoService{ - CryptoUsecase: usecase.NewCryptoUsecase(db, contract.ShutterRegistryContract, contract.KeyperSetManagerContract, contract.KeyBroadcastContract, ethClient, config), + CryptoUsecase: usecase.NewCryptoUsecase(db, contract.ShutterRegistryContract, contract.ShutterEventRegistryContract, contract.KeyperSetManagerContract, contract.KeyBroadcastContract, ethClient, config), } } // @BasePath /api - +// // GetDecryptionKey godoc -// @Summary Get decryption key. -// @Description Retrieves a decryption key for a given registered identity once the timestamp is reached. Decryption key is 0x padded, clients need to remove the prefix when decrypting on their end. -// @Tags Crypto -// @Produce json -// @Param identity query string true "Identity associated with the decryption key." -// @Success 200 {object} usecase.GetDecryptionKeyResponse "Success." -// @Failure 400 {object} error.Http "Invalid Get decryption key request." -// @Failure 404 {object} error.Http "Decryption key not found for the associated identity." -// @Failure 429 {object} error.Http "Too many requests. Rate limited." -// @Failure 500 {object} error.Http "Internal server error." -// @Security BearerAuth -// @Router /get_decryption_key [get] - +// +// @Summary Get decryption key. +// @Description Retrieves a decryption key for a given registered identity once the timestamp is reached. Decryption key is 0x padded, clients need to remove the prefix when decrypting on their end. +// @Tags Crypto +// @Produce json +// @Param identity query string true "Identity associated with the decryption key." +// @Success 200 {object} usecase.GetDecryptionKeyResponse "Success." +// @Failure 400 {object} error.Http "Invalid Get decryption key request." +// @Failure 404 {object} error.Http "Decryption key not found for the associated identity." +// @Failure 429 {object} error.Http "Too many requests. Rate limited." +// @Failure 500 {object} error.Http "Internal server error." +// @Security BearerAuth +// @Router /get_decryption_key [get] func (svc *CryptoService) GetDecryptionKey(ctx *gin.Context) { identity, ok := ctx.GetQuery("identity") if !ok { @@ -77,21 +77,21 @@ func (svc *CryptoService) GetDecryptionKey(ctx *gin.Context) { } // @BasePath /api - +// // GetDataForEncryption godoc -// @Summary Provides data necessary to allow encryption. -// @Description Retrieves all the necessary data required by clients for encrypting any message. -// @Tags Crypto -// @Produce json -// @Param address query string true "Ethereum address associated with the identity. If you are registering the identity yourself, pass the address of the account making the registration. If you want the API to register the identity on gnosis mainnet, pass the address: 0x228DefCF37Da29475F0EE2B9E4dfAeDc3b0746bc. For chiado pass the address: 0xb9C303443c9af84777e60D5C987AbF0c43844918" -// @Param identityPrefix query string false "Optional identity prefix. You can generate it on your end and pass it to this endpoint, or allow the API to randomly generate one for you." -// @Success 200 {object} usecase.GetDataForEncryptionResponse "Success." -// @Failure 400 {object} error.Http "Invalid Get data for encryption request." -// @Failure 429 {object} error.Http "Too many requests. Rate limited." -// @Failure 500 {object} error.Http "Internal server error." -// @Security BearerAuth -// @Router /get_data_for_encryption [get] - +// +// @Summary Provides data necessary to allow encryption. +// @Description Retrieves all the necessary data required by clients for encrypting any message. +// @Tags Crypto +// @Produce json +// @Param address query string true "Ethereum address associated with the identity. If you are registering the identity yourself, pass the address of the account making the registration. If you want the API to register the identity on gnosis mainnet, pass the address: 0x228DefCF37Da29475F0EE2B9E4dfAeDc3b0746bc. For chiado pass the address: 0xb9C303443c9af84777e60D5C987AbF0c43844918" +// @Param identityPrefix query string false "Optional identity prefix. You can generate it on your end and pass it to this endpoint, or allow the API to randomly generate one for you." +// @Success 200 {object} usecase.GetDataForEncryptionResponse "Success." +// @Failure 400 {object} error.Http "Invalid Get data for encryption request." +// @Failure 429 {object} error.Http "Too many requests. Rate limited." +// @Failure 500 {object} error.Http "Internal server error." +// @Security BearerAuth +// @Router /get_data_for_encryption [get] func (svc *CryptoService) GetDataForEncryption(ctx *gin.Context) { address, ok := ctx.GetQuery("address") if !ok { @@ -120,21 +120,21 @@ func (svc *CryptoService) GetDataForEncryption(ctx *gin.Context) { } // @BasePath /api - +// // RegisterIdentity godoc -// @Summary Allows clients to register any identity. -// @Description Allows clients to register an identity used for encryption and specify a release timestamp for the decryption key associated with the encrypted message. -// @Tags Crypto -// @Accepts json -// @Produce json -// @Param request body RegisterIdentityRequest true "Timestamp and Identity which client want to make the registration with." -// @Success 200 {object} usecase.RegisterIdentityResponse "Success." -// @Failure 400 {object} error.Http "Invalid Register identity request." -// @Failure 429 {object} error.Http "Too many requests. Rate limited." -// @Failure 500 {object} error.Http "Internal server error." -// @Security BearerAuth -// @Router /register_identity [post] - +// +// @Summary Allows clients to register any identity. +// @Description Allows clients to register an identity used for encryption and specify a release timestamp for the decryption key associated with the encrypted message. +// @Tags Crypto +// @Accepts json +// @Produce json +// @Param request body RegisterIdentityRequest true "Timestamp and Identity which client want to make the registration with." +// @Success 200 {object} usecase.RegisterIdentityResponse "Success." +// @Failure 400 {object} error.Http "Invalid Register identity request." +// @Failure 429 {object} error.Http "Too many requests. Rate limited." +// @Failure 500 {object} error.Http "Internal server error." +// @Security BearerAuth +// @Router /register_identity [post] func (svc *CryptoService) RegisterIdentity(ctx *gin.Context) { var req RegisterIdentityRequest if err := ctx.ShouldBindJSON(&req); err != nil { @@ -159,21 +159,21 @@ func (svc *CryptoService) RegisterIdentity(ctx *gin.Context) { } // @BasePath /api - +// // DecryptCommitment godoc -// @Summary Allows clients to decrypt their encrypted message. -// @Description Provides a way for clients to easily decrypt their encrypted message for which they have registered the identity for. Timestamp with which the identity was registered should have been passed for the message to be decrypted successfully. -// @Tags Crypto -// @Produce json -// @Param identity query string true "Identity used for registeration and encrypting the message." -// @Param encryptedCommitment query string true "Encrypted commitment is the clients encrypted message." -// @Success 200 {object} []byte "Success." -// @Failure 400 {object} error.Http "Invalid Decrypt commitment request." -// @Failure 429 {object} error.Http "Too many requests. Rate limited." -// @Failure 500 {object} error.Http "Internal server error." -// @Security BearerAuth -// @Router /decrypt_commitment [get] - +// +// @Summary Allows clients to decrypt their encrypted message. +// @Description Provides a way for clients to easily decrypt their encrypted message for which they have registered the identity for. Timestamp with which the identity was registered should have been passed for the message to be decrypted successfully. +// @Tags Crypto +// @Produce json +// @Param identity query string true "Identity used for registeration and encrypting the message." +// @Param encryptedCommitment query string true "Encrypted commitment is the clients encrypted message." +// @Success 200 {object} []byte "Success." +// @Failure 400 {object} error.Http "Invalid Decrypt commitment request." +// @Failure 429 {object} error.Http "Too many requests. Rate limited." +// @Failure 500 {object} error.Http "Internal server error." +// @Security BearerAuth +// @Router /decrypt_commitment [get] func (svc *CryptoService) DecryptCommitment(ctx *gin.Context) { identity, ok := ctx.GetQuery("identity") if !ok { @@ -208,30 +208,36 @@ func (svc *CryptoService) DecryptCommitment(ctx *gin.Context) { } // @BasePath /api - -// EventTriggerDefinition godoc -// @Summary Allows clients to compile an event trigger definition string. -// @Description This endpoint takes an event signature snippet and some arguments to create an event trigger definition that will be understood by keypers -// supporting event based decryption triggers. The schema is: -// {"contract": , -// "event_sig": ( [indexed] , ...)'>, -// "arguments": []} -// The object format for the "arguments" list is: -// - "name": , -// - "op": , -// - "number": , -// - "bytes": -// Note: the resulting condition for the trigger is a logical AND of all arguments given. -// @Tags Crypto -// @Produce json -// @Param request body EventTriggerDefinitionRequest true "Event signature and match arguments." -// @Success 200 {object} []byte "Success." -// @Failure 400 {object} error.Http "Invalid Event Data." -// @Failure 429 {object} error.Http "Too many requests. Rate limited." -// @Failure 500 {object} error.Http "Internal server error." -// @Security BearerAuth -// @Router /compile_event_trigger_definition [post] - +// +// # EventTriggerDefinition godoc +// +// @Summary Allows clients to compile an event trigger definition string. +// @Description This endpoint takes an event signature snippet and some arguments to create an event trigger definition that will be understood by keypers +// supporting event based decryption triggers. Example request body: +// { +// "contract": "0x3465a347342B72BCf800aBf814324ba4a803c32b", +// "event_sig": "Transfer(indexed from address, indexed to address, amount uint256)", +// "arguments": [ +// { "name": "from", "op": "eq", "bytes": "0x456d9347342B72BCf800bBf117391ac2f807c6bF" }, +// { "name": "amount", "op": "gte", "number": 25433 } +// ] +// } +// The object format for the "arguments" list is: +// - "name": +// - "op": +// - "number": +// - "bytes": +// Note: the resulting condition for the trigger is a logical AND of all arguments given. +// +// @Tags Crypto +// @Produce json +// @Param request body EventTriggerDefinitionRequest true "Event signature and match arguments." +// @Success 200 {object} usecase.EventTriggerDefinitionResponse "Success." +// @Failure 400 {object} error.Http "Invalid Event Data." +// @Failure 429 {object} error.Http "Too many requests. Rate limited." +// @Failure 500 {object} error.Http "Internal server error." +// @Security BearerAuth +// @Router /compile_event_trigger_definition [post] func (svc *CryptoService) CompileEventTriggerDefinition(ctx *gin.Context) { CompileEventTriggerDefinition(ctx) } @@ -259,20 +265,21 @@ func CompileEventTriggerDefinition(ctx *gin.Context) { } // @BasePath /api +// // RegisterEventIdentity godoc -// @Summary Allows clients to register an event trigger identity. -// @Description Allows clients to register an identity used for encryption and event trigger definition for the decryption key associated with the encrypted message. -// @Tags Crypto -// @Accepts json -// @Produce json -// @Param request body RegisterEventIdentityRequest true "Event trigger definition, ttl and Identity which client want to make the registration with." -// @Success 200 {object} usecase.RegisterEventResponse "Success." -// @Failure 400 {object} error.Http "Invalid Register identity request." -// @Failure 429 {object} error.Http "Too many requests. Rate limited." -// @Failure 500 {object} error.Http "Internal server error." -// @Security BearerAuth -// @Router /register_event_identity [post] - +// +// @Summary Allows clients to register an event trigger identity. +// @Description Allows clients to register an identity used for encryption and event trigger definition for the decryption key associated with the encrypted message. +// @Tags Crypto +// @Accepts json +// @Produce json +// @Param request body RegisterEventIdentityRequest true "Event trigger definition, ttl and Identity which client want to make the registration with." +// @Success 200 {object} usecase.RegisterIdentityResponse "Success." +// @Failure 400 {object} error.Http "Invalid Register identity request." +// @Failure 429 {object} error.Http "Too many requests. Rate limited." +// @Failure 500 {object} error.Http "Internal server error." +// @Security BearerAuth +// @Router /register_event_identity [post] func (svc *CryptoService) RegisterEventIdentity(ctx *gin.Context) { var req RegisterEventIdentityRequest diff --git a/internal/usecase/crypto.go b/internal/usecase/crypto.go index 7a7358a..6a8a79d 100644 --- a/internal/usecase/crypto.go +++ b/internal/usecase/crypto.go @@ -93,19 +93,21 @@ type CryptoUsecase struct { func NewCryptoUsecase( db *pgxpool.Pool, shutterRegistryContract ShutterregistryInterface, + shutterEventRegistryContract ShutterEventregistryInterface, keyperSetManagerContract KeyperSetManagerInterface, keyBroadcastContract KeyBroadcastInterface, ethClient EthClientInterface, config *common.Config, ) *CryptoUsecase { return &CryptoUsecase{ - db: db, - dbQuery: data.New(db), - shutterRegistryContract: shutterRegistryContract, - keyperSetManagerContract: keyperSetManagerContract, - keyBroadcastContract: keyBroadcastContract, - ethClient: ethClient, - config: config, + db: db, + dbQuery: data.New(db), + shutterRegistryContract: shutterRegistryContract, + shutterEventRegistryContract: shutterEventRegistryContract, + keyperSetManagerContract: keyperSetManagerContract, + keyBroadcastContract: keyBroadcastContract, + ethClient: ethClient, + config: config, } } diff --git a/internal/usecase/eventtrigger.go b/internal/usecase/eventtrigger.go index d325cd3..3b7f92e 100644 --- a/internal/usecase/eventtrigger.go +++ b/internal/usecase/eventtrigger.go @@ -32,12 +32,12 @@ type EventArgument struct { } type EventTriggerDefinitionRequest struct { EventSignature string `json:"event_sig" example:"Transfer(indexed from address, indexed to address, amount uint256)"` - ContractAddress ecommon.Address `json:"contract" example:"0x3465a347342B72BCf800aBf814324ba4a803c32b"` - Arguments []EventArgument `json:"arguments" example:"[{\"name\": \"from\", \"op\": \"eq\", \"bytes\": \"0x456d9347342B72BCf800bBf117391ac2f807c6bF\"}]"` + ContractAddress ecommon.Address `json:"contract" swaggertype:"string" example:"0x3465a347342B72BCf800aBf814324ba4a803c32b"` + Arguments []EventArgument `json:"arguments"` } // @name EventTriggerDefinitionRequest type EventTriggerDefinitionResponse struct { - EventTriggerDefinition string `json:"triggerDefinition" example:"Transfer(indexed from address, indexed to address, amount uint256)"` + EventTriggerDefinition string `json:"triggerDefinition" example:"0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0"` } func CompileEventTriggerDefinitionInternal(req EventTriggerDefinitionRequest) (EventTriggerDefinitionResponse, []error) { @@ -88,7 +88,7 @@ func CompileEventTriggerDefinitionInternal(req EventTriggerDefinitionRequest) (E errors = append(errors, err) } - data := EventTriggerDefinitionResponse{EventTriggerDefinition: hex.EncodeToString(etd.MarshalBytes())} + data := EventTriggerDefinitionResponse{EventTriggerDefinition: common.PrefixWith0x(hex.EncodeToString(etd.MarshalBytes()))} return data, errors } @@ -322,6 +322,49 @@ func (uc *CryptoUsecase) RegisterEventIdentity(ctx context.Context, eventTrigger return nil, &err } + eventTriggerDefinition, err := hexutil.Decode(eventTriggerDefinitionHex) + if err != nil { + err := httpError.NewHttpError( + "could not decode event trigger definition", + "", + http.StatusBadRequest, + ) + return nil, &err + } + + etd := shs.EventTriggerDefinition{} + if err := etd.UnmarshalBytes(eventTriggerDefinition); err != nil { + log.Err(err).Msg("err encountered while unmarshaling event trigger definition") + err := httpError.NewHttpError( + "could not parse event trigger definition", + "", + http.StatusBadRequest, + ) + return nil, &err + } + + // Check whitelist if it's configured + if len(uc.config.WhitelistedContractAddresses) > 0 { + isWhitelisted := false + for _, whitelistedAddr := range uc.config.WhitelistedContractAddresses { + if etd.Contract == whitelistedAddr { + isWhitelisted = true + break + } + } + if !isWhitelisted { + log.Warn(). + Str("contract_address", etd.Contract.Hex()). + Msg("contract address is not whitelisted") + err := httpError.NewHttpError( + "contract address is not whitelisted", + fmt.Sprintf("contract address %s is not in the whitelist", etd.Contract.Hex()), + http.StatusForbidden, + ) + return nil, &err + } + } + newSigner, err := bind.NewKeyedTransactorWithChainID(uc.config.SigningKey, chainId) if err != nil { log.Err(err).Msg("err encountered while creating signer") @@ -333,7 +376,7 @@ func (uc *CryptoUsecase) RegisterEventIdentity(ctx context.Context, eventTrigger return nil, &err } - identity := common.ComputeIdentity(identityPrefix[:], newSigner.From) + identity := common.ComputeEventIdentity(identityPrefix[:], newSigner.From, eventTriggerDefinition) // TODO: check for already registered identities also against time based triggers! @@ -344,21 +387,6 @@ func (uc *CryptoUsecase) RegisterEventIdentity(ctx context.Context, eventTrigger Signer: newSigner.Signer, } - eventTriggerDefinition, err := hexutil.Decode(eventTriggerDefinitionHex) - if err != nil { - err := httpError.NewHttpError( - "could not decode event trigger definition", - "", - http.StatusBadRequest, - ) - return nil, &err - } - - // TODO: check contract address of eventTriggerDefinition against white list (if necessary) - // whitelist from ENV - if empty assert wildcard - // - parse event trigger definition with keyper side code from keyperimpl/shutterservice.EventTriggerDefinition - // - check event trigger definition "Contract" against whitelist - tx, err := uc.shutterEventRegistryContract.Register(&opts, eon, identityPrefix, eventTriggerDefinition, ttl) if err != nil { log.Err(err).Msg("failed to send transaction") diff --git a/main.go b/main.go index 6085f94..afcdff9 100644 --- a/main.go +++ b/main.go @@ -115,7 +115,7 @@ func main() { shutterRegistryContractAddressStringified := os.Getenv("SHUTTER_REGISTRY_CONTRACT_ADDRESS") shutterRegistryContractAddress := common.HexToAddress(shutterRegistryContractAddressStringified) - shutterEventRegistryContractAddressStringified := os.Getenv("SHUTTER_EVENT+REGISTRY_CONTRACT_ADDRESS") + shutterEventRegistryContractAddressStringified := os.Getenv("SHUTTER_EVENT_REGISTRY_CONTRACT_ADDRESS") shutterEventRegistryContractAddress := common.HexToAddress(shutterEventRegistryContractAddressStringified) keyBroadcastContractAddressStringified := os.Getenv("KEY_BROADCAST_CONTRACT_ADDRESS") @@ -182,7 +182,19 @@ func main() { p2pConfig.Environment = env.Environment(p2pEnviroment) p2pConfig.DiscoveryNamespace = os.Getenv("P2P_DISCOVERY_NAMESPACE") - config, err := shutterAPICommon.NewConfig(keyperHTTPUrl, signingKey, &p2pConfig) + var whitelistedContractAddresses []common.Address + whitelistedAddressesStr := os.Getenv("WHITELISTED_TRIGGER_CONTRACT_ADDRESSES") + if whitelistedAddressesStr != "" { + addressStrings := strings.Split(whitelistedAddressesStr, ",") + for _, addrStr := range addressStrings { + addrStr = strings.TrimSpace(addrStr) + if addrStr != "" { + whitelistedContractAddresses = append(whitelistedContractAddresses, common.HexToAddress(addrStr)) + } + } + } + + config, err := shutterAPICommon.NewConfig(keyperHTTPUrl, signingKey, &p2pConfig, whitelistedContractAddresses) if err != nil { log.Err(err).Msg("unable to parse keyper http url") return diff --git a/tests/init_test.go b/tests/init_test.go index 795f31e..c360aa7 100644 --- a/tests/init_test.go +++ b/tests/init_test.go @@ -5,6 +5,7 @@ import ( "net/url" "testing" + ecommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/rs/zerolog/log" "github.com/shutter-network/shutter-api/common" @@ -18,14 +19,15 @@ const GnosisMainnetChainID = 100 type TestShutterService struct { suite.Suite - testDB *common.TestDatabase - dbQuery *data.Queries - cryptoUsecase *usecase.CryptoUsecase - config *common.Config - shutterRegistryContract *mock.MockShutterregistry - keyperSetManagerContract *mock.MockKeyperSetManager - keyBroadcastContract *mock.MockKeyBroadcast - ethClient *mock.MockEthClient + testDB *common.TestDatabase + dbQuery *data.Queries + cryptoUsecase *usecase.CryptoUsecase + config *common.Config + shutterRegistryContract *mock.MockShutterregistry + shutterEventRegistryContract *mock.MockShutterEventRegistry + keyperSetManagerContract *mock.MockKeyperSetManager + keyBroadcastContract *mock.MockKeyBroadcast + ethClient *mock.MockEthClient } func TestShutterServiceSuite(t *testing.T) { @@ -49,19 +51,22 @@ func (s *TestShutterService) SetupSuite() { return } s.config = &common.Config{ - KeyperHTTPURL: parsedURL, - SigningKey: privateKey, - PublicKey: publicKey, + KeyperHTTPURL: parsedURL, + SigningKey: privateKey, + PublicKey: publicKey, + WhitelistedContractAddresses: []ecommon.Address{}, } s.shutterRegistryContract = new(mock.MockShutterregistry) + s.shutterEventRegistryContract = new(mock.MockShutterEventRegistry) s.keyBroadcastContract = new(mock.MockKeyBroadcast) s.keyperSetManagerContract = new(mock.MockKeyperSetManager) s.ethClient = new(mock.MockEthClient) - s.cryptoUsecase = usecase.NewCryptoUsecase(s.testDB.DbInstance, s.shutterRegistryContract, s.keyperSetManagerContract, s.keyBroadcastContract, s.ethClient, s.config) + s.cryptoUsecase = usecase.NewCryptoUsecase(s.testDB.DbInstance, s.shutterRegistryContract, s.shutterEventRegistryContract, s.keyperSetManagerContract, s.keyBroadcastContract, s.ethClient, s.config) } func (s *TestShutterService) BeforeTest(suiteName, testName string) { s.shutterRegistryContract.ExpectedCalls = nil + s.shutterEventRegistryContract.ExpectedCalls = nil s.keyBroadcastContract.ExpectedCalls = nil s.keyperSetManagerContract.ExpectedCalls = nil s.ethClient.ExpectedCalls = nil @@ -81,4 +86,4 @@ func generateRandomETHAccount() (*ecdsa.PrivateKey, *ecdsa.PublicKey, string, er address := crypto.PubkeyToAddress(*publicKeyECDSA).Hex() return privateKey, publicKeyECDSA, address, nil -} \ No newline at end of file +} diff --git a/tests/integration/init_test.go b/tests/integration/init_test.go index 177a03c..ac5c45a 100644 --- a/tests/integration/init_test.go +++ b/tests/integration/init_test.go @@ -79,7 +79,7 @@ func (s *TestShutterService) SetupSuite() { p2pConfig.Environment = env.Environment(p2pEnviroment) p2pConfig.DiscoveryNamespace = os.Getenv("P2P_DISCOVERY_NAMESPACE") - s.config, err = common.NewConfig(keyperHTTPUrl, signingKey, &p2pConfig) + s.config, err = common.NewConfig(keyperHTTPUrl, signingKey, &p2pConfig, []ethCommon.Address{}) s.Require().NoError(err) rpc_url := os.Getenv("RPC_URL") diff --git a/tests/mock/shutter_event_registry_contract.go b/tests/mock/shutter_event_registry_contract.go new file mode 100644 index 0000000..f72519f --- /dev/null +++ b/tests/mock/shutter_event_registry_contract.go @@ -0,0 +1,16 @@ +package mock + +import ( + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/mock" +) + +type MockShutterEventRegistry struct { + mock.Mock +} + +func (m *MockShutterEventRegistry) Register(opts *bind.TransactOpts, eon uint64, identityPrefix [32]byte, triggerDefinition []byte, ttl uint64) (*types.Transaction, error) { + args := m.Called(opts, eon, identityPrefix, triggerDefinition, ttl) + return args.Get(0).(*types.Transaction), args.Error(1) +} diff --git a/tests/register_event_identity_test.go b/tests/register_event_identity_test.go new file mode 100644 index 0000000..b8485b4 --- /dev/null +++ b/tests/register_event_identity_test.go @@ -0,0 +1,298 @@ +package tests + +import ( + "context" + "encoding/hex" + "math/big" + "math/rand" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/shutter-network/shutter-api/common" + "github.com/stretchr/testify/mock" +) + +func (s *TestShutterService) TestRegisterEventIdentity() { + ctx := context.Background() + ttl := uint64(100) + identityPrefix, err := generateRandomBytes(32) + s.Require().NoError(err) + identityPrefixStringified := hex.EncodeToString(identityPrefix) + blockNumber := rand.Uint64() + + eon := rand.Uint64() + + // Hardcoded valid event trigger definition + eventTriggerDefinitionHex := "0x01f86694953a0425accee2e05f22e78999c595ed2ee7183cf84fe480e205a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efe401e205a0000000000000000000000000812a6755975485c6e340f97de6790b34a94d1430c404c20402" + eventTriggerDefinitionBytes, err := hexutil.Decode(eventTriggerDefinitionHex) + s.Require().NoError(err) + + newSigner, err := bind.NewKeyedTransactorWithChainID(s.config.SigningKey, big.NewInt(GnosisMainnetChainID)) + s.Require().NoError(err) + + identity := common.ComputeEventIdentity(identityPrefix[:], newSigner.From, eventTriggerDefinitionBytes) + + eonPublicKey, _, _ := s.makeKeys(identity) + + randomTx := generateRandomTransaction() + + s.ethClient. + On("BlockNumber", ctx). + Return(blockNumber, nil). + Once() + + s.keyperSetManagerContract. + On("GetKeyperSetIndexByBlock", nil, blockNumber). + Return(eon, nil). + Once() + + s.keyBroadcastContract. + On("GetEonKey", nil, eon). + Return(eonPublicKey.Marshal(), nil). + Once() + + s.ethClient. + On("ChainID", ctx). + Return(big.NewInt(GnosisMainnetChainID), nil). + Once() + + s.shutterEventRegistryContract. + On("Register", mock.Anything, eon, [32]byte(identityPrefix), eventTriggerDefinitionBytes, ttl). + Return(randomTx, nil). + Once() + + data, err := s.cryptoUsecase.RegisterEventIdentity(ctx, eventTriggerDefinitionHex, identityPrefixStringified, ttl) + s.Require().Nil(err) + + s.Require().Equal(data.Eon, eon) + s.Require().Equal(common.PrefixWith0x(hex.EncodeToString(identity)), data.Identity) + s.Require().Equal(common.PrefixWith0x(hex.EncodeToString(identityPrefix)), data.IdentityPrefix) + s.Require().Equal(data.EonKey, common.PrefixWith0x(hex.EncodeToString(eonPublicKey.Marshal()))) + s.Require().Equal(randomTx.Hash().Hex(), data.TxHash) +} + +func (s *TestShutterService) TestRegisterEventIdentity_InvalidIdentityPrefix() { + ctx := context.Background() + ttl := uint64(100) + eventTriggerDefinitionHex := "0x01f86694953a0425accee2e05f22e78999c595ed2ee7183cf84fe480e205a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efe401e205a0000000000000000000000000812a6755975485c6e340f97de6790b34a94d1430c404c20402" + + // Test with invalid identity prefix length + invalidIdentityPrefix := "0x1234" // Too short + + _, err := s.cryptoUsecase.RegisterEventIdentity(ctx, eventTriggerDefinitionHex, invalidIdentityPrefix, ttl) + s.Require().NotNil(err) + + // Verify the exact error message + s.Require().Equal("identity prefix should be of byte length 32", err.Description) + s.Require().Equal(400, err.StatusCode) +} + +func (s *TestShutterService) TestRegisterEventIdentity_InvalidEventTriggerDefinition() { + ctx := context.Background() + ttl := uint64(100) + identityPrefix, err := generateRandomBytes(32) + s.Require().NoError(err) + identityPrefixStringified := hex.EncodeToString(identityPrefix) + blockNumber := rand.Uint64() + eon := rand.Uint64() + + newSigner, err := bind.NewKeyedTransactorWithChainID(s.config.SigningKey, big.NewInt(GnosisMainnetChainID)) + s.Require().NoError(err) + + // Test with invalid hex string + invalidEventTriggerDefinitionHex := "0xinvalid" + // Note: Since the endpoint will fail at hex decoding, identity computation never happens + // But we still need to set up the mock. Use a dummy valid trigger definition for mock setup. + dummyTriggerBytes, _ := hexutil.Decode("0x01f86694953a0425accee2e05f22e78999c595ed2ee7183cf84fe480e205a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efe401e205a0000000000000000000000000812a6755975485c6e340f97de6790b34a94d1430c404c20402") + identity := common.ComputeEventIdentity(identityPrefix[:], newSigner.From, dummyTriggerBytes) + + eonPublicKey, _, _ := s.makeKeys(identity) + + s.ethClient. + On("BlockNumber", ctx). + Return(blockNumber, nil). + Once() + + s.keyperSetManagerContract. + On("GetKeyperSetIndexByBlock", nil, blockNumber). + Return(eon, nil). + Once() + + s.keyBroadcastContract. + On("GetEonKey", nil, eon). + Return(eonPublicKey.Marshal(), nil). + Once() + + s.ethClient. + On("ChainID", ctx). + Return(big.NewInt(GnosisMainnetChainID), nil). + Once() + + _, httpErr := s.cryptoUsecase.RegisterEventIdentity(ctx, invalidEventTriggerDefinitionHex, identityPrefixStringified, ttl) + s.Require().NotNil(httpErr) + + // Verify the exact error message + s.Require().Equal("could not decode event trigger definition", httpErr.Description) + s.Require().Equal(400, httpErr.StatusCode) +} + +func (s *TestShutterService) TestRegisterEventIdentity_TriggerDefinitionWithout0xPrefix() { + ctx := context.Background() + ttl := uint64(100) + identityPrefix, err := generateRandomBytes(32) + s.Require().NoError(err) + identityPrefixStringified := hex.EncodeToString(identityPrefix) + blockNumber := rand.Uint64() + eon := rand.Uint64() + + newSigner, err := bind.NewKeyedTransactorWithChainID(s.config.SigningKey, big.NewInt(GnosisMainnetChainID)) + s.Require().NoError(err) + + eventTriggerDefinitionHexWithoutPrefix := "01f86694953a0425accee2e05f22e78999c595ed2ee7183cf84fe480e205a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efe401e205a0000000000000000000000000812a6755975485c6e340f97de6790b34a94d1430c404c20402" + // Decode the trigger definition to compute identity (endpoint will decode it with 0x prefix) + eventTriggerDefinitionBytes, err := hexutil.Decode("0x" + eventTriggerDefinitionHexWithoutPrefix) + s.Require().NoError(err) + identity := common.ComputeEventIdentity(identityPrefix[:], newSigner.From, eventTriggerDefinitionBytes) + + eonPublicKey, _, _ := s.makeKeys(identity) + + s.ethClient. + On("BlockNumber", ctx). + Return(blockNumber, nil). + Once() + + s.keyperSetManagerContract. + On("GetKeyperSetIndexByBlock", nil, blockNumber). + Return(eon, nil). + Once() + + s.keyBroadcastContract. + On("GetEonKey", nil, eon). + Return(eonPublicKey.Marshal(), nil). + Once() + + s.ethClient. + On("ChainID", ctx). + Return(big.NewInt(GnosisMainnetChainID), nil). + Once() + + _, httpErr := s.cryptoUsecase.RegisterEventIdentity(ctx, eventTriggerDefinitionHexWithoutPrefix, identityPrefixStringified, ttl) + s.Require().NotNil(httpErr) + + // Verify the exact error message + s.Require().Equal("could not decode event trigger definition", httpErr.Description) + s.Require().Equal(400, httpErr.StatusCode) +} + +func (s *TestShutterService) TestRegisterEventIdentity_ZeroBytesEventTriggerDefinition() { + ctx := context.Background() + ttl := uint64(100) + identityPrefix, err := generateRandomBytes(32) + s.Require().NoError(err) + identityPrefixStringified := hex.EncodeToString(identityPrefix) + blockNumber := rand.Uint64() + eon := rand.Uint64() + + newSigner, err := bind.NewKeyedTransactorWithChainID(s.config.SigningKey, big.NewInt(GnosisMainnetChainID)) + s.Require().NoError(err) + + // Create a zero-filled hex string (128 hex chars = 64 bytes) + zeroEventTriggerDefinitionHex := "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + // Decode the zero bytes to compute identity (endpoint will decode it before computing identity) + zeroBytes, err := hexutil.Decode(zeroEventTriggerDefinitionHex) + s.Require().NoError(err) + identity := common.ComputeEventIdentity(identityPrefix[:], newSigner.From, zeroBytes) + + eonPublicKey, _, _ := s.makeKeys(identity) + + s.ethClient. + On("BlockNumber", ctx). + Return(blockNumber, nil). + Once() + + s.keyperSetManagerContract. + On("GetKeyperSetIndexByBlock", nil, blockNumber). + Return(eon, nil). + Once() + + s.keyBroadcastContract. + On("GetEonKey", nil, eon). + Return(eonPublicKey.Marshal(), nil). + Once() + + s.ethClient. + On("ChainID", ctx). + Return(big.NewInt(GnosisMainnetChainID), nil). + Once() + + _, httpErr := s.cryptoUsecase.RegisterEventIdentity(ctx, zeroEventTriggerDefinitionHex, identityPrefixStringified, ttl) + s.Require().NotNil(httpErr) + + // Verify the exact error message + s.Require().Equal("could not parse event trigger definition", httpErr.Description) + s.Require().Equal(400, httpErr.StatusCode) +} + +func (s *TestShutterService) TestRegisterEventIdentity_EmptyIdentityPrefix() { + ctx := context.Background() + ttl := uint64(100) + blockNumber := rand.Uint64() + eon := rand.Uint64() + + // Hardcoded valid event trigger definition + eventTriggerDefinitionHex := "0x01f86694953a0425accee2e05f22e78999c595ed2ee7183cf84fe480e205a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efe401e205a0000000000000000000000000812a6755975485c6e340f97de6790b34a94d1430c404c20402" + eventTriggerDefinitionBytes, err := hexutil.Decode(eventTriggerDefinitionHex) + s.Require().NoError(err) + + // Generate a random identity prefix that will be used to compute identity + // Note: The function will generate its own random prefix, but we need to set up mocks + // So we'll use a predictable prefix for the identity computation in mocks + randomIdentityPrefix, err := generateRandomBytes(32) + s.Require().NoError(err) + + newSigner, err := bind.NewKeyedTransactorWithChainID(s.config.SigningKey, big.NewInt(GnosisMainnetChainID)) + s.Require().NoError(err) + // Compute identity with event trigger definition to match the new implementation + identity := common.ComputeEventIdentity(randomIdentityPrefix[:], newSigner.From, eventTriggerDefinitionBytes) + + eonPublicKey, _, _ := s.makeKeys(identity) + + randomTx := generateRandomTransaction() + + s.ethClient. + On("BlockNumber", ctx). + Return(blockNumber, nil). + Once() + + s.keyperSetManagerContract. + On("GetKeyperSetIndexByBlock", nil, blockNumber). + Return(eon, nil). + Once() + + s.keyBroadcastContract. + On("GetEonKey", nil, eon). + Return(eonPublicKey.Marshal(), nil). + Once() + + s.ethClient. + On("ChainID", ctx). + Return(big.NewInt(GnosisMainnetChainID), nil). + Once() + + // Mock will be called with the generated identity prefix (we can't predict it, so use mock.MatchedBy) + s.shutterEventRegistryContract. + On("Register", mock.Anything, eon, mock.MatchedBy(func(prefix [32]byte) bool { + return true + }), eventTriggerDefinitionBytes, ttl). + Return(randomTx, nil). + Once() + + data, err := s.cryptoUsecase.RegisterEventIdentity(ctx, eventTriggerDefinitionHex, "", ttl) + s.Require().Nil(err) + + s.Require().Equal(data.Eon, eon) + s.Require().NotEqual(data.IdentityPrefix, "") + s.Require().NotEqual(data.Identity, "") + s.Require().Equal(data.EonKey, common.PrefixWith0x(hex.EncodeToString(eonPublicKey.Marshal()))) + s.Require().Equal(randomTx.Hash().Hex(), data.TxHash) +} From 8b76656672352161973d41fb1e1738a4e3222364 Mon Sep 17 00:00:00 2001 From: blockchainluffy Date: Wed, 24 Dec 2025 14:22:49 +0530 Subject: [PATCH 20/21] feat: ttl getter endpoint, already registered identity checks, update get_data_for_encryption endpoint --- .gitignore | 3 +- docs/docs.go | 82 +++++++- docs/swagger.json | 82 +++++++- docs/swagger.yaml | 176 +++++++++++++++++- internal/data/event_registrations.sql.go | 93 +++++++++ internal/data/models.sqlc.gen.go | 15 +- .../data/sql/queries/event_registrations.sql | 21 +++ .../data/sql/schemas/event_registrations.sql | 13 ++ internal/router/router.go | 1 + internal/service/crypto.go | 72 ++++++- internal/usecase/crypto.go | 22 ++- internal/usecase/eventtrigger.go | 107 ++++++++++- ..._add_event_identity_registration_table.sql | 19 ++ tests/encryption_test.go | 4 +- ..._add_event_identity_registration_table.sql | 19 ++ tests/register_event_identity_test.go | 121 +++++++++++- 16 files changed, 831 insertions(+), 19 deletions(-) create mode 100644 internal/data/event_registrations.sql.go create mode 100644 internal/data/sql/queries/event_registrations.sql create mode 100644 internal/data/sql/schemas/event_registrations.sql create mode 100644 migrations/20251223124122_add_event_identity_registration_table.sql create mode 100644 tests/migrations/20251223124122_add_event_identity_registration_table.sql diff --git a/.gitignore b/.gitignore index 1279b2c..0c0c980 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,6 @@ go.work.sum .env .envrc pgdata/ - -data/ +.DS_Store bin/ diff --git a/docs/docs.go b/docs/docs.go index 7916ad0..e6d78ad 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -138,7 +138,7 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Retrieves all the necessary data required by clients for encrypting any message.", + "description": "Retrieves all the necessary data required by clients for encrypting any message. Supports both time-based and event-based identity computation. If triggerDefinition is provided, the identity will be computed for event-based triggers. Otherwise, it uses time-based identity computation.", "produces": [ "application/json" ], @@ -159,6 +159,12 @@ const docTemplate = `{ "description": "Optional identity prefix. You can generate it on your end and pass it to this endpoint, or allow the API to randomly generate one for you.", "name": "identityPrefix", "in": "query" + }, + { + "type": "string", + "description": "Optional event trigger definition (hex-encoded with 0x prefix). If provided, identity will be computed for event-based triggers. This parameter is strictly for event-based triggers.", + "name": "triggerDefinition", + "in": "query" } ], "responses": { @@ -247,6 +253,71 @@ const docTemplate = `{ } } }, + "/get_event_trigger_ttl": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieves the time-to-live (TTL) for a given event identity registration.", + "produces": [ + "application/json" + ], + "tags": [ + "Crypto" + ], + "summary": "Get event identity registration TTL.", + "parameters": [ + { + "type": "integer", + "description": "Eon number associated with the event identity registration.", + "name": "eon", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Identity associated with the event identity registration.", + "name": "identity", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "Success.", + "schema": { + "$ref": "#/definitions/GetEventIdentityRegistrationTTL" + } + }, + "400": { + "description": "Invalid Get event identity registration TTL request.", + "schema": { + "$ref": "#/definitions/error.Http" + } + }, + "404": { + "description": "Event identity registration not found.", + "schema": { + "$ref": "#/definitions/error.Http" + } + }, + "429": { + "description": "Too many requests. Rate limited.", + "schema": { + "$ref": "#/definitions/error.Http" + } + }, + "500": { + "description": "Internal server error.", + "schema": { + "$ref": "#/definitions/error.Http" + } + } + } + } + }, "/register_event_identity": { "post": { "security": [ @@ -418,6 +489,15 @@ const docTemplate = `{ } } }, + "GetEventIdentityRegistrationTTL": { + "type": "object", + "properties": { + "ttl": { + "type": "integer", + "example": 100 + } + } + }, "RegisterEventIdentityRequest": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 74ca620..cadd609 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -129,7 +129,7 @@ "BearerAuth": [] } ], - "description": "Retrieves all the necessary data required by clients for encrypting any message.", + "description": "Retrieves all the necessary data required by clients for encrypting any message. Supports both time-based and event-based identity computation. If triggerDefinition is provided, the identity will be computed for event-based triggers. Otherwise, it uses time-based identity computation.", "produces": [ "application/json" ], @@ -150,6 +150,12 @@ "description": "Optional identity prefix. You can generate it on your end and pass it to this endpoint, or allow the API to randomly generate one for you.", "name": "identityPrefix", "in": "query" + }, + { + "type": "string", + "description": "Optional event trigger definition (hex-encoded with 0x prefix). If provided, identity will be computed for event-based triggers. This parameter is strictly for event-based triggers.", + "name": "triggerDefinition", + "in": "query" } ], "responses": { @@ -238,6 +244,71 @@ } } }, + "/get_event_trigger_ttl": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieves the time-to-live (TTL) for a given event identity registration.", + "produces": [ + "application/json" + ], + "tags": [ + "Crypto" + ], + "summary": "Get event identity registration TTL.", + "parameters": [ + { + "type": "integer", + "description": "Eon number associated with the event identity registration.", + "name": "eon", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Identity associated with the event identity registration.", + "name": "identity", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "Success.", + "schema": { + "$ref": "#/definitions/GetEventIdentityRegistrationTTL" + } + }, + "400": { + "description": "Invalid Get event identity registration TTL request.", + "schema": { + "$ref": "#/definitions/error.Http" + } + }, + "404": { + "description": "Event identity registration not found.", + "schema": { + "$ref": "#/definitions/error.Http" + } + }, + "429": { + "description": "Too many requests. Rate limited.", + "schema": { + "$ref": "#/definitions/error.Http" + } + }, + "500": { + "description": "Internal server error.", + "schema": { + "$ref": "#/definitions/error.Http" + } + } + } + } + }, "/register_event_identity": { "post": { "security": [ @@ -409,6 +480,15 @@ } } }, + "GetEventIdentityRegistrationTTL": { + "type": "object", + "properties": { + "ttl": { + "type": "integer", + "example": 100 + } + } + }, "RegisterEventIdentityRequest": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 1938000..51d79a2 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,4 +1,17 @@ definitions: + EventTriggerDefinitionRequest: + properties: + arguments: + items: + $ref: '#/definitions/usecase.EventArgument' + type: array + contract: + example: 0x3465a347342B72BCf800aBf814324ba4a803c32b + type: string + event_sig: + example: Transfer(indexed from address, indexed to address, amount uint256) + type: string + type: object GetDataForEncryption: properties: eon: @@ -29,6 +42,24 @@ definitions: example: 0x8c232eae4f957259e9d6b68301d529e9851b8642874c8f59d2bd0fb84a570c75 type: string type: object + GetEventIdentityRegistrationTTL: + properties: + ttl: + example: 100 + type: integer + type: object + RegisterEventIdentityRequest: + properties: + identityPrefix: + example: 0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0 + type: string + triggerDefinition: + example: 0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0 + type: string + ttl: + example: 100 + type: integer + type: object RegisterIdentityRequest: properties: decryptionTimestamp: @@ -65,6 +96,27 @@ definitions: statusCode: type: integer type: object + usecase.EventArgument: + properties: + bytes: + example: "0xabcdef01234567" + type: string + name: + example: amount + type: string + number: + example: 25433 + type: integer + op: + example: gte + type: string + type: object + usecase.EventTriggerDefinitionResponse: + properties: + triggerDefinition: + example: 0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0 + type: string + type: object info: contact: {} description: Shutter API is an encryption and decryption API that allows clients @@ -74,6 +126,41 @@ info: release the decryption keys. title: Shutter API paths: + /compile_event_trigger_definition: + post: + description: This endpoint takes an event signature snippet and some arguments + to create an event trigger definition that will be understood by keypers + parameters: + - description: Event signature and match arguments. + in: body + name: request + required: true + schema: + $ref: '#/definitions/EventTriggerDefinitionRequest' + produces: + - application/json + responses: + "200": + description: Success. + schema: + $ref: '#/definitions/usecase.EventTriggerDefinitionResponse' + "400": + description: Invalid Event Data. + schema: + $ref: '#/definitions/error.Http' + "429": + description: Too many requests. Rate limited. + schema: + $ref: '#/definitions/error.Http' + "500": + description: Internal server error. + schema: + $ref: '#/definitions/error.Http' + security: + - BearerAuth: [] + summary: Allows clients to compile an event trigger definition string. + tags: + - Crypto /decrypt_commitment: get: description: Provides a way for clients to easily decrypt their encrypted message @@ -120,7 +207,9 @@ paths: /get_data_for_encryption: get: description: Retrieves all the necessary data required by clients for encrypting - any message. + any message. Supports both time-based and event-based identity computation. + If triggerDefinition is provided, the identity will be computed for event-based + triggers. Otherwise, it uses time-based identity computation. parameters: - description: 'Ethereum address associated with the identity. If you are registering the identity yourself, pass the address of the account making the registration. @@ -137,6 +226,12 @@ paths: in: query name: identityPrefix type: string + - description: Optional event trigger definition (hex-encoded with 0x prefix). + If provided, identity will be computed for event-based triggers. This parameter + is strictly for event-based triggers. + in: query + name: triggerDefinition + type: string produces: - application/json responses: @@ -200,6 +295,85 @@ paths: summary: Get decryption key. tags: - Crypto + /get_event_trigger_ttl: + get: + description: Retrieves the time-to-live (TTL) for a given event identity registration. + parameters: + - description: Eon number associated with the event identity registration. + in: query + name: eon + required: true + type: integer + - description: Identity associated with the event identity registration. + in: query + name: identity + required: true + type: string + produces: + - application/json + responses: + "200": + description: Success. + schema: + $ref: '#/definitions/GetEventIdentityRegistrationTTL' + "400": + description: Invalid Get event identity registration TTL request. + schema: + $ref: '#/definitions/error.Http' + "404": + description: Event identity registration not found. + schema: + $ref: '#/definitions/error.Http' + "429": + description: Too many requests. Rate limited. + schema: + $ref: '#/definitions/error.Http' + "500": + description: Internal server error. + schema: + $ref: '#/definitions/error.Http' + security: + - BearerAuth: [] + summary: Get event identity registration TTL. + tags: + - Crypto + /register_event_identity: + post: + description: Allows clients to register an identity used for encryption and + event trigger definition for the decryption key associated with the encrypted + message. + parameters: + - description: Event trigger definition, ttl and Identity which client want + to make the registration with. + in: body + name: request + required: true + schema: + $ref: '#/definitions/RegisterEventIdentityRequest' + produces: + - application/json + responses: + "200": + description: Success. + schema: + $ref: '#/definitions/RegisterIdentityResponse' + "400": + description: Invalid Register identity request. + schema: + $ref: '#/definitions/error.Http' + "429": + description: Too many requests. Rate limited. + schema: + $ref: '#/definitions/error.Http' + "500": + description: Internal server error. + schema: + $ref: '#/definitions/error.Http' + security: + - BearerAuth: [] + summary: Allows clients to register an event trigger identity. + tags: + - Crypto /register_identity: post: description: Allows clients to register an identity used for encryption and diff --git a/internal/data/event_registrations.sql.go b/internal/data/event_registrations.sql.go new file mode 100644 index 0000000..6d9763f --- /dev/null +++ b/internal/data/event_registrations.sql.go @@ -0,0 +1,93 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.22.0 +// source: event_registrations.sql + +package data + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getEventIdentityRegistration = `-- name: GetEventIdentityRegistration :one +SELECT eon, identity, identity_prefix, eon_key, event_trigger_definition, ttl, tx_hash, created_at FROM event_identity_registration +WHERE eon = $1 AND identity = $2 +` + +type GetEventIdentityRegistrationParams struct { + Eon int64 + Identity []byte +} + +func (q *Queries) GetEventIdentityRegistration(ctx context.Context, arg GetEventIdentityRegistrationParams) (EventIdentityRegistration, error) { + row := q.db.QueryRow(ctx, getEventIdentityRegistration, arg.Eon, arg.Identity) + var i EventIdentityRegistration + err := row.Scan( + &i.Eon, + &i.Identity, + &i.IdentityPrefix, + &i.EonKey, + &i.EventTriggerDefinition, + &i.Ttl, + &i.TxHash, + &i.CreatedAt, + ) + return i, err +} + +const getEventIdentityRegistrationTTL = `-- name: GetEventIdentityRegistrationTTL :one +SELECT ttl FROM event_identity_registration +WHERE eon = $1 AND identity = $2 +` + +type GetEventIdentityRegistrationTTLParams struct { + Eon int64 + Identity []byte +} + +func (q *Queries) GetEventIdentityRegistrationTTL(ctx context.Context, arg GetEventIdentityRegistrationTTLParams) (pgtype.Int8, error) { + row := q.db.QueryRow(ctx, getEventIdentityRegistrationTTL, arg.Eon, arg.Identity) + var ttl pgtype.Int8 + err := row.Scan(&ttl) + return ttl, err +} + +const insertEventIdentityRegistration = `-- name: InsertEventIdentityRegistration :exec + +INSERT INTO event_identity_registration ( + eon, + identity, + identity_prefix, + eon_key, + event_trigger_definition, + ttl, + tx_hash +) VALUES ($1, $2, $3, $4, $5, $6, $7) +ON CONFLICT (eon, identity) DO NOTHING +` + +type InsertEventIdentityRegistrationParams struct { + Eon int64 + Identity []byte + IdentityPrefix []byte + EonKey []byte + EventTriggerDefinition []byte + Ttl pgtype.Int8 + TxHash []byte +} + +// write sql queries here +func (q *Queries) InsertEventIdentityRegistration(ctx context.Context, arg InsertEventIdentityRegistrationParams) error { + _, err := q.db.Exec(ctx, insertEventIdentityRegistration, + arg.Eon, + arg.Identity, + arg.IdentityPrefix, + arg.EonKey, + arg.EventTriggerDefinition, + arg.Ttl, + arg.TxHash, + ) + return err +} diff --git a/internal/data/models.sqlc.gen.go b/internal/data/models.sqlc.gen.go index 6c3122e..a4e1275 100644 --- a/internal/data/models.sqlc.gen.go +++ b/internal/data/models.sqlc.gen.go @@ -4,10 +4,23 @@ package data -import () +import ( + "github.com/jackc/pgx/v5/pgtype" +) type DecryptionKey struct { Eon int64 EpochID []byte DecryptionKey []byte } + +type EventIdentityRegistration struct { + Eon int64 + Identity []byte + IdentityPrefix []byte + EonKey []byte + EventTriggerDefinition []byte + Ttl pgtype.Int8 + TxHash []byte + CreatedAt pgtype.Timestamp +} diff --git a/internal/data/sql/queries/event_registrations.sql b/internal/data/sql/queries/event_registrations.sql new file mode 100644 index 0000000..62f328d --- /dev/null +++ b/internal/data/sql/queries/event_registrations.sql @@ -0,0 +1,21 @@ +-- write sql queries here + +-- name: InsertEventIdentityRegistration :exec +INSERT INTO event_identity_registration ( + eon, + identity, + identity_prefix, + eon_key, + event_trigger_definition, + ttl, + tx_hash +) VALUES ($1, $2, $3, $4, $5, $6, $7) +ON CONFLICT (eon, identity) DO NOTHING; + +-- name: GetEventIdentityRegistration :one +SELECT * FROM event_identity_registration +WHERE eon = $1 AND identity = $2; + +-- name: GetEventIdentityRegistrationTTL :one +SELECT ttl FROM event_identity_registration +WHERE eon = $1 AND identity = $2; \ No newline at end of file diff --git a/internal/data/sql/schemas/event_registrations.sql b/internal/data/sql/schemas/event_registrations.sql new file mode 100644 index 0000000..bca25c5 --- /dev/null +++ b/internal/data/sql/schemas/event_registrations.sql @@ -0,0 +1,13 @@ +-- write schema definitions here + +CREATE TABLE event_identity_registration ( + eon bigint, + identity bytea, + identity_prefix bytea, + eon_key bytea, + event_trigger_definition bytea, + ttl bigint, + tx_hash bytea, + created_at TIMESTAMP DEFAULT NOW(), + PRIMARY KEY (eon, identity) +); \ No newline at end of file diff --git a/internal/router/router.go b/internal/router/router.go index ea4054d..0c26447 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -40,6 +40,7 @@ func NewRouter( api.POST("/compile_event_trigger_definition", cryptoService.CompileEventTriggerDefinition) api.GET("/decrypt_commitment", cryptoService.DecryptCommitment) api.POST("/register_event_identity", cryptoService.RegisterEventIdentity) + api.GET("/get_event_trigger_ttl", cryptoService.GetEventIdentityRegistrationTTL) } router.GET("/docs/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, func(c *ginSwagger.Config) { c.Title = "Shutter-API" diff --git a/internal/service/crypto.go b/internal/service/crypto.go index dfa0683..7618c3c 100644 --- a/internal/service/crypto.go +++ b/internal/service/crypto.go @@ -2,6 +2,7 @@ package service import ( "net/http" + "strconv" "github.com/ethereum/go-ethereum/ethclient" "github.com/gin-gonic/gin" @@ -81,11 +82,12 @@ func (svc *CryptoService) GetDecryptionKey(ctx *gin.Context) { // GetDataForEncryption godoc // // @Summary Provides data necessary to allow encryption. -// @Description Retrieves all the necessary data required by clients for encrypting any message. +// @Description Retrieves all the necessary data required by clients for encrypting any message. Supports both time-based and event-based identity computation. If triggerDefinition is provided, the identity will be computed for event-based triggers. Otherwise, it uses time-based identity computation. // @Tags Crypto // @Produce json // @Param address query string true "Ethereum address associated with the identity. If you are registering the identity yourself, pass the address of the account making the registration. If you want the API to register the identity on gnosis mainnet, pass the address: 0x228DefCF37Da29475F0EE2B9E4dfAeDc3b0746bc. For chiado pass the address: 0xb9C303443c9af84777e60D5C987AbF0c43844918" // @Param identityPrefix query string false "Optional identity prefix. You can generate it on your end and pass it to this endpoint, or allow the API to randomly generate one for you." +// @Param triggerDefinition query string false "Optional event trigger definition (hex-encoded with 0x prefix). If provided, identity will be computed for event-based triggers. This parameter is strictly for event-based triggers." // @Success 200 {object} usecase.GetDataForEncryptionResponse "Success." // @Failure 400 {object} error.Http "Invalid Get data for encryption request." // @Failure 429 {object} error.Http "Too many requests. Rate limited." @@ -109,7 +111,12 @@ func (svc *CryptoService) GetDataForEncryption(ctx *gin.Context) { identityPrefix = "" } - data, httpErr := svc.CryptoUsecase.GetDataForEncryption(ctx, address, identityPrefix) + triggerDefinition, ok := ctx.GetQuery("triggerDefinition") + if !ok { + triggerDefinition = "" + } + + data, httpErr := svc.CryptoUsecase.GetDataForEncryption(ctx, address, identityPrefix, triggerDefinition) if httpErr != nil { ctx.Error(httpErr) return @@ -303,3 +310,64 @@ func (svc *CryptoService) RegisterEventIdentity(ctx *gin.Context) { "message": data, }) } + +// @BasePath /api +// +// GetEventIdentityRegistrationTTL godoc +// +// @Summary Get event identity registration TTL. +// @Description Retrieves the time-to-live (TTL) for a given event identity registration. +// @Tags Crypto +// @Produce json +// @Param eon query uint64 true "Eon number associated with the event identity registration." +// @Param identity query string true "Identity associated with the event identity registration." +// @Success 200 {object} usecase.GetEventIdentityRegistrationTTLResponse "Success." +// @Failure 400 {object} error.Http "Invalid Get event identity registration TTL request." +// @Failure 404 {object} error.Http "Event identity registration not found." +// @Failure 429 {object} error.Http "Too many requests. Rate limited." +// @Failure 500 {object} error.Http "Internal server error." +// @Security BearerAuth +// @Router /get_event_trigger_ttl [get] +func (svc *CryptoService) GetEventIdentityRegistrationTTL(ctx *gin.Context) { + eonStr, ok := ctx.GetQuery("eon") + if !ok { + err := sherror.NewHttpError( + "query parameter not found", + "eon query parameter is required", + http.StatusBadRequest, + ) + ctx.Error(err) + return + } + + eon, err := strconv.ParseUint(eonStr, 10, 64) + if err != nil { + err := sherror.NewHttpError( + "invalid eon parameter", + "eon must be a valid unsigned integer", + http.StatusBadRequest, + ) + ctx.Error(err) + return + } + + identity, ok := ctx.GetQuery("identity") + if !ok { + err := sherror.NewHttpError( + "query parameter not found", + "identity query parameter is required", + http.StatusBadRequest, + ) + ctx.Error(err) + return + } + + data, httpErr := svc.CryptoUsecase.GetEventIdentityRegistrationTTL(ctx, eon, identity) + if httpErr != nil { + ctx.Error(httpErr) + return + } + ctx.JSON(http.StatusOK, gin.H{ + "message": data, + }) +} diff --git a/internal/usecase/crypto.go b/internal/usecase/crypto.go index 6a8a79d..25b60ec 100644 --- a/internal/usecase/crypto.go +++ b/internal/usecase/crypto.go @@ -14,6 +14,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" ethCommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/jackc/pgx/v5" @@ -217,7 +218,7 @@ func (uc *CryptoUsecase) GetDecryptionKey(ctx context.Context, identity string) }, nil } -func (uc *CryptoUsecase) GetDataForEncryption(ctx context.Context, address string, identityPrefixStringified string) (*GetDataForEncryptionResponse, *httpError.Http) { +func (uc *CryptoUsecase) GetDataForEncryption(ctx context.Context, address string, identityPrefixStringified string, triggerDefinitionHex string) (*GetDataForEncryptionResponse, *httpError.Http) { if !ethCommon.IsHexAddress(address) { log.Warn().Str("address", address).Msg("invalid address") err := httpError.NewHttpError( @@ -313,7 +314,24 @@ func (uc *CryptoUsecase) GetDataForEncryption(ctx context.Context, address strin return nil, &err } - identity := common.ComputeIdentity(identityPrefix[:], ethCommon.HexToAddress(address)) + var identity []byte + if len(triggerDefinitionHex) > 0 { + // Event-based identity computation: hash(prefix + sender + triggerDefinition) + triggerDefinitionBytes, err := hexutil.Decode(triggerDefinitionHex) + if err != nil { + log.Err(err).Msg("err encountered while decoding trigger definition") + err := httpError.NewHttpError( + "error encountered while decoding trigger definition", + "", + http.StatusBadRequest, + ) + return nil, &err + } + identity = common.ComputeEventIdentity(identityPrefix[:], ethCommon.HexToAddress(address), triggerDefinitionBytes) + } else { + // Time-based identity computation: hash(prefix + sender) + identity = common.ComputeIdentity(identityPrefix[:], ethCommon.HexToAddress(address)) + } epochID := shcrypto.ComputeEpochID(identity) return &GetDataForEncryptionResponse{ Eon: eon, diff --git a/internal/usecase/eventtrigger.go b/internal/usecase/eventtrigger.go index 3b7f92e..86d2fc9 100644 --- a/internal/usecase/eventtrigger.go +++ b/internal/usecase/eventtrigger.go @@ -15,9 +15,12 @@ import ( ecommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgtype" "github.com/rs/zerolog/log" shs "github.com/shutter-network/rolling-shutter/rolling-shutter/keyperimpl/shutterservice" "github.com/shutter-network/shutter-api/common" + "github.com/shutter-network/shutter-api/internal/data" httpError "github.com/shutter-network/shutter-api/internal/error" sherror "github.com/shutter-network/shutter-api/internal/error" "github.com/shutter-network/shutter-api/metrics" @@ -40,6 +43,10 @@ type EventTriggerDefinitionResponse struct { EventTriggerDefinition string `json:"triggerDefinition" example:"0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0"` } +type GetEventIdentityRegistrationTTLResponse struct { + TTL uint64 `json:"ttl" example:"100"` +} // @name GetEventIdentityRegistrationTTL + func CompileEventTriggerDefinitionInternal(req EventTriggerDefinitionRequest) (EventTriggerDefinitionResponse, []error) { var errors []error zeroAddress := ecommon.Address{} @@ -378,7 +385,28 @@ func (uc *CryptoUsecase) RegisterEventIdentity(ctx context.Context, eventTrigger identity := common.ComputeEventIdentity(identityPrefix[:], newSigner.From, eventTriggerDefinition) - // TODO: check for already registered identities also against time based triggers! + _, err = uc.dbQuery.GetEventIdentityRegistration(ctx, data.GetEventIdentityRegistrationParams{ + Eon: int64(eon), + Identity: identity, + }) + if err == nil { + log.Warn().Msg("event identity already registered") + err := httpError.NewHttpError( + "event identity already registered", + "", + http.StatusBadRequest, + ) + return nil, &err + } else if err != pgx.ErrNoRows { + // Unexpected database error + log.Err(err).Msg("err encountered while querying event identity registration") + err := httpError.NewHttpError( + "error encountered while checking event identity registration", + "", + http.StatusInternalServerError, + ) + return nil, &err + } publicAddress := crypto.PubkeyToAddress(*uc.config.PublicKey) @@ -402,6 +430,23 @@ func (uc *CryptoUsecase) RegisterEventIdentity(ctx context.Context, eventTrigger // we return the transaction hash in response to allow // users the ability to monitor it themselves + // Store the registration in database + txHashBytes := tx.Hash().Bytes() + err = uc.dbQuery.InsertEventIdentityRegistration(ctx, data.InsertEventIdentityRegistrationParams{ + Eon: int64(eon), + Identity: identity, + IdentityPrefix: identityPrefix[:], + EonKey: eonKeyBytes, + EventTriggerDefinition: eventTriggerDefinition, + Ttl: pgtype.Int8{Int64: int64(ttl), Valid: true}, + TxHash: txHashBytes, + }) + if err != nil { + log.Err(err).Msg("err encountered while storing event identity registration") + // Note: Transaction already sent, so we log the error but don't fail the request + // The registration is on-chain even if DB insert fails + } + metrics.TotalSuccessfulIdentityRegistration.Inc() return &RegisterIdentityResponse{ Eon: eon, @@ -412,3 +457,63 @@ func (uc *CryptoUsecase) RegisterEventIdentity(ctx context.Context, eventTrigger }, nil } + +func (uc *CryptoUsecase) GetEventIdentityRegistrationTTL(ctx context.Context, eon uint64, identity string) (*GetEventIdentityRegistrationTTLResponse, *httpError.Http) { + identityBytes, err := hex.DecodeString(strings.TrimPrefix(identity, "0x")) + if err != nil { + log.Err(err).Msg("err encountered while decoding identity") + err := httpError.NewHttpError( + "error encountered while decoding identity", + "", + http.StatusBadRequest, + ) + return nil, &err + } + + if len(identityBytes) != 32 { + log.Err(err).Msg("identity should be of length 32") + err := httpError.NewHttpError( + "identity should be of length 32", + "", + http.StatusBadRequest, + ) + return nil, &err + } + + ttl, err := uc.dbQuery.GetEventIdentityRegistrationTTL(ctx, data.GetEventIdentityRegistrationTTLParams{ + Eon: int64(eon), + Identity: identityBytes, + }) + if err != nil { + if err == pgx.ErrNoRows { + log.Debug().Uint64("eon", eon).Str("identity", identity).Msg("event identity registration not found") + err := httpError.NewHttpError( + "event identity registration not found", + "", + http.StatusNotFound, + ) + return nil, &err + } + log.Err(err).Msg("err encountered while querying event identity registration TTL") + err := httpError.NewHttpError( + "error encountered while querying event identity registration TTL", + "", + http.StatusInternalServerError, + ) + return nil, &err + } + + if !ttl.Valid { + log.Warn().Uint64("eon", eon).Str("identity", identity).Msg("ttl is null for event identity registration") + err := httpError.NewHttpError( + "ttl not set for event identity registration", + "", + http.StatusBadRequest, + ) + return nil, &err + } + + return &GetEventIdentityRegistrationTTLResponse{ + TTL: uint64(ttl.Int64), + }, nil +} diff --git a/migrations/20251223124122_add_event_identity_registration_table.sql b/migrations/20251223124122_add_event_identity_registration_table.sql new file mode 100644 index 0000000..f86c85a --- /dev/null +++ b/migrations/20251223124122_add_event_identity_registration_table.sql @@ -0,0 +1,19 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE event_identity_registration ( + eon bigint, + identity bytea, + identity_prefix bytea, + eon_key bytea, + event_trigger_definition bytea, + ttl bigint, + tx_hash bytea, + created_at TIMESTAMP DEFAULT NOW(), + PRIMARY KEY (eon, identity) +); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP TABLE event_identity_registration; +-- +goose StatementEnd diff --git a/tests/encryption_test.go b/tests/encryption_test.go index cd4499e..e773f88 100644 --- a/tests/encryption_test.go +++ b/tests/encryption_test.go @@ -102,7 +102,7 @@ func (s *TestShutterService) TestGetDataForEncryption() { Return(eonPublicKey.Marshal(), nil). Once() - data, err := s.cryptoUsecase.GetDataForEncryption(ctx, sender, identityPrefixStringified) + data, err := s.cryptoUsecase.GetDataForEncryption(ctx, sender, identityPrefixStringified, "") s.Require().Nil(err) s.Require().Equal(data.Eon, eon) @@ -139,6 +139,6 @@ func (s *TestShutterService) TestGetDataForEncryptionInvalidSender() { Return(eonPublicKey.Marshal(), nil). Once() - _, err = s.cryptoUsecase.GetDataForEncryption(ctx, sender, identityPrefixStringified) + _, err = s.cryptoUsecase.GetDataForEncryption(ctx, sender, identityPrefixStringified, "") s.Require().Error(err) } \ No newline at end of file diff --git a/tests/migrations/20251223124122_add_event_identity_registration_table.sql b/tests/migrations/20251223124122_add_event_identity_registration_table.sql new file mode 100644 index 0000000..f86c85a --- /dev/null +++ b/tests/migrations/20251223124122_add_event_identity_registration_table.sql @@ -0,0 +1,19 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE event_identity_registration ( + eon bigint, + identity bytea, + identity_prefix bytea, + eon_key bytea, + event_trigger_definition bytea, + ttl bigint, + tx_hash bytea, + created_at TIMESTAMP DEFAULT NOW(), + PRIMARY KEY (eon, identity) +); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP TABLE event_identity_registration; +-- +goose StatementEnd diff --git a/tests/register_event_identity_test.go b/tests/register_event_identity_test.go index b8485b4..a42eeb1 100644 --- a/tests/register_event_identity_test.go +++ b/tests/register_event_identity_test.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/shutter-network/shutter-api/common" + "github.com/shutter-network/shutter-api/internal/data" "github.com/stretchr/testify/mock" ) @@ -61,14 +62,29 @@ func (s *TestShutterService) TestRegisterEventIdentity() { Return(randomTx, nil). Once() - data, err := s.cryptoUsecase.RegisterEventIdentity(ctx, eventTriggerDefinitionHex, identityPrefixStringified, ttl) + response, err := s.cryptoUsecase.RegisterEventIdentity(ctx, eventTriggerDefinitionHex, identityPrefixStringified, ttl) s.Require().Nil(err) - s.Require().Equal(data.Eon, eon) - s.Require().Equal(common.PrefixWith0x(hex.EncodeToString(identity)), data.Identity) - s.Require().Equal(common.PrefixWith0x(hex.EncodeToString(identityPrefix)), data.IdentityPrefix) - s.Require().Equal(data.EonKey, common.PrefixWith0x(hex.EncodeToString(eonPublicKey.Marshal()))) - s.Require().Equal(randomTx.Hash().Hex(), data.TxHash) + s.Require().Equal(response.Eon, eon) + s.Require().Equal(common.PrefixWith0x(hex.EncodeToString(identity)), response.Identity) + s.Require().Equal(common.PrefixWith0x(hex.EncodeToString(identityPrefix)), response.IdentityPrefix) + s.Require().Equal(response.EonKey, common.PrefixWith0x(hex.EncodeToString(eonPublicKey.Marshal()))) + s.Require().Equal(randomTx.Hash().Hex(), response.TxHash) + + // Verify the registration was stored in the database + dbRegistration, dbErr := s.dbQuery.GetEventIdentityRegistration(ctx, data.GetEventIdentityRegistrationParams{ + Eon: int64(eon), + Identity: identity, + }) + s.Require().NoError(dbErr) + s.Require().Equal(int64(eon), dbRegistration.Eon) + s.Require().Equal(identity, dbRegistration.Identity) + s.Require().Equal(identityPrefix, dbRegistration.IdentityPrefix) + s.Require().Equal(eonPublicKey.Marshal(), dbRegistration.EonKey) + s.Require().Equal(eventTriggerDefinitionBytes, dbRegistration.EventTriggerDefinition) + s.Require().True(dbRegistration.Ttl.Valid) + s.Require().Equal(int64(ttl), dbRegistration.Ttl.Int64) + s.Require().Equal(randomTx.Hash().Bytes(), dbRegistration.TxHash) } func (s *TestShutterService) TestRegisterEventIdentity_InvalidIdentityPrefix() { @@ -296,3 +312,96 @@ func (s *TestShutterService) TestRegisterEventIdentity_EmptyIdentityPrefix() { s.Require().Equal(data.EonKey, common.PrefixWith0x(hex.EncodeToString(eonPublicKey.Marshal()))) s.Require().Equal(randomTx.Hash().Hex(), data.TxHash) } + +func (s *TestShutterService) TestRegisterEventIdentity_AlreadyRegistered() { + ctx := context.Background() + ttl := uint64(100) + identityPrefix, err := generateRandomBytes(32) + s.Require().NoError(err) + identityPrefixStringified := hex.EncodeToString(identityPrefix) + blockNumber := rand.Uint64() + + eon := rand.Uint64() + + // Hardcoded valid event trigger definition + eventTriggerDefinitionHex := "0x01f86694953a0425accee2e05f22e78999c595ed2ee7183cf84fe480e205a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efe401e205a0000000000000000000000000812a6755975485c6e340f97de6790b34a94d1430c404c20402" + eventTriggerDefinitionBytes, err := hexutil.Decode(eventTriggerDefinitionHex) + s.Require().NoError(err) + + newSigner, err := bind.NewKeyedTransactorWithChainID(s.config.SigningKey, big.NewInt(GnosisMainnetChainID)) + s.Require().NoError(err) + + identity := common.ComputeEventIdentity(identityPrefix[:], newSigner.From, eventTriggerDefinitionBytes) + + eonPublicKey, _, _ := s.makeKeys(identity) + + randomTx := generateRandomTransaction() + + // First registration - set up mocks + s.ethClient. + On("BlockNumber", ctx). + Return(blockNumber, nil). + Once() + + s.keyperSetManagerContract. + On("GetKeyperSetIndexByBlock", nil, blockNumber). + Return(eon, nil). + Once() + + s.keyBroadcastContract. + On("GetEonKey", nil, eon). + Return(eonPublicKey.Marshal(), nil). + Once() + + s.ethClient. + On("ChainID", ctx). + Return(big.NewInt(GnosisMainnetChainID), nil). + Once() + + s.shutterEventRegistryContract. + On("Register", mock.Anything, eon, [32]byte(identityPrefix), eventTriggerDefinitionBytes, ttl). + Return(randomTx, nil). + Once() + + // First registration should succeed + response, err := s.cryptoUsecase.RegisterEventIdentity(ctx, eventTriggerDefinitionHex, identityPrefixStringified, ttl) + s.Require().Nil(err) + s.Require().Equal(response.Eon, eon) + s.Require().Equal(common.PrefixWith0x(hex.EncodeToString(identity)), response.Identity) + + // Verify the registration was stored in the database + dbRegistration, dbErr := s.dbQuery.GetEventIdentityRegistration(ctx, data.GetEventIdentityRegistrationParams{ + Eon: int64(eon), + Identity: identity, + }) + s.Require().NoError(dbErr) + s.Require().Equal(int64(eon), dbRegistration.Eon) + s.Require().Equal(identity, dbRegistration.Identity) + + // Second registration attempt - set up mocks again + s.ethClient. + On("BlockNumber", ctx). + Return(blockNumber, nil). + Once() + + s.keyperSetManagerContract. + On("GetKeyperSetIndexByBlock", nil, blockNumber). + Return(eon, nil). + Once() + + s.keyBroadcastContract. + On("GetEonKey", nil, eon). + Return(eonPublicKey.Marshal(), nil). + Once() + + s.ethClient. + On("ChainID", ctx). + Return(big.NewInt(GnosisMainnetChainID), nil). + Once() + + // Second registration should fail with "event identity already registered" + _, httpErr := s.cryptoUsecase.RegisterEventIdentity(ctx, eventTriggerDefinitionHex, identityPrefixStringified, ttl) + s.Require().NotNil(httpErr) + s.Require().Equal("event identity already registered", httpErr.Description) + s.Require().Equal(400, httpErr.StatusCode) +} From 069f89f37abecaa88b19fa01c9b7998a5d9eefc3 Mon Sep 17 00:00:00 2001 From: blockchainluffy Date: Fri, 26 Dec 2025 15:41:03 +0530 Subject: [PATCH 21/21] feat: add rate limiting and update checks for already registered identity --- .env.example | 4 +- README.md | 131 +++++++++++++++--- docker-compose.rate_limit.yaml | 42 ++++++ docs/docs.go | 33 +++-- docs/swagger.json | 33 +++-- docs/swagger.yaml | 35 +++-- etdc/main.go | 2 +- internal/data/event_registrations.sql.go | 85 ++++++++---- internal/data/models.sqlc.gen.go | 4 +- .../data/sql/queries/event_registrations.sql | 31 +++-- .../data/sql/schemas/event_registrations.sql | 20 +-- internal/router/router.go | 2 +- internal/service/crypto.go | 87 +++++++----- internal/service/crypto_test.go | 12 +- internal/usecase/crypto.go | 2 + internal/usecase/eventtrigger.go | 103 +++++++++----- ..._add_event_identity_registration_table.sql | 18 +-- ..._add_event_identity_registration_table.sql | 18 +-- tests/mock/eth_client.go | 10 ++ tests/register_event_identity_test.go | 80 +++++++++-- 20 files changed, 532 insertions(+), 220 deletions(-) diff --git a/.env.example b/.env.example index 87631e9..b409735 100644 --- a/.env.example +++ b/.env.example @@ -21,4 +21,6 @@ P2P_PORT= LOG_LEVEL= METRICS_ENABLED=true METRICS_HOST="[::]" -METRICS_PORT=4000 \ No newline at end of file +METRICS_PORT=4000 +SHUTTER_EVENT_REGISTRY_CONTRACT_ADDRESS= +WHITELISTED_TRIGGER_CONTRACT_ADDRESSES= \ No newline at end of file diff --git a/README.md b/README.md index a6403b5..a510c00 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,16 @@ This guide will help you integrate Shutter's Commit and Reveal Scheme into your 1. [Overview](#overview) 2. [Prerequisites](#prerequisites) 3. [Endpoints](#endpoints) - - [Register an Identity with a Decryption Trigger](#1-register-an-identity-with-a-decryption-trigger) - - [Retrieve the Encryption Data](#2-retrieve-the-encryption-data) - - [Retrieve the Decryption Key](#3-retrieve-the-decryption-key) - - [Decrypt Commitments](#4-decrypt-commitments) + - [Identity Registration](#1-identity-registration) + - [Register an Identity with Time-based Decryption Triggers](#1a-register-an-identity-with-time-based-decryption-triggers) + - [Compile an Event Trigger Definition](#1b-compile-an-event-trigger-definition) + - [Register an Identity with Event-based Decryption Triggers](#1c-register-an-identity-with-event-based-decryption-triggers) + - [Get Event Trigger Identity Registration Expiration Block](#1d-get-event-trigger-identity-registration-expiration-block) + - [Encryption Operations](#2-encryption-operations) + - [Retrieve the Encryption Data](#2a-retrieve-the-encryption-data) + - [Decryption Operations](#3-decryption-operations) + - [Retrieve the Decryption Key](#3a-retrieve-the-decryption-key) + - [Decrypt Commitments](#3b-decrypt-commitments) 4. [Future features](#future-features) 5. [FAQs](#faqs) 6. [Swagger Documentation](#swagger-documentation) @@ -39,9 +45,11 @@ The Shutter system leverages threshold encryption, distributed cryptographic ope - **API**: An API that simplifies interaction with the Shutter system by exposing endpoints for encryption and decryption operations. This documentation will guide you through: -- Setting up identities and time-based decryption triggers. +- Setting up identities with time-based or event-based decryption triggers. +- Compiling event trigger definitions for event-based triggers. - Retrieving encryption data and decryption keys. - Decrypting encrypted commitments. +- Querying event identity registration expiration block. --- @@ -65,6 +73,9 @@ This documentation will guide you through: For unauthorized access, the API on Gnosis Mainnet is rate limited with these limits per endpoint and remote ip: - `/register_identity` 5 requests per 24 hours + - `/compile_event_trigger_definition` 20 requests per 24 hours + - `/register_event_identity` 5 requests per 24 hours + - `/get_event_trigger_expiration_block` 20 requests per 24 hours - `/get_data_for_encryption` 10 requests per 24 hours - `/get_decryption_key` 20 requests per 24 hours - `/decrypt_commitment` 10 requests per 24 hours @@ -76,6 +87,9 @@ If you need higher limits, contact [loring@brainbot.com](mailto:loring@brainbot. Authorized requests have these limits: - `/register_identity` 500 requests per 24 hours + - `/compile_event_trigger_definition` 2000 requests per 24 hours + - `/register_event_identity` 500 requests per 24 hours + - `/get_event_trigger_expiration_block` 2000 requests per 24 hours - `/get_data_for_encryption` 1000 requests per 24 hours - `/get_decryption_key` 2000 requests per 24 hours - `/decrypt_commitment` 1000 requests per 24 hours @@ -88,7 +102,9 @@ Use the `/check_authentication` endpoint, to test your API key. ## Endpoints -### 1.A Register an Identity with Time-based Decryption Triggers +### 1. Identity Registration + +#### 1.A Register an Identity with Time-based Decryption Triggers To begin using the Shutter system, register an identity and specify a time-based decryption trigger. This step links an identity to a decryption key and sets the release conditions for the key to a Unix timestamp. @@ -118,18 +134,62 @@ curl -X POST https:///register_identity \ } ``` -### 1.B Register an Identity with Event-based Decryption Triggers [WIP] +### 1.B Compile an Event Trigger Definition -An alternative is the upcoming feature of "event-based" decryption triggers. This is very similar to the time-based release conditions discussed above. However here the decryption key is produced only when a specific EVM event has been observed by the keypers. +Before registering an identity with event-based decryption triggers, you need to compile an event trigger definition. This endpoint takes an event signature and arguments to create an event trigger definition that will be understood by keypers supporting event-based decryption triggers. -The trigger condition is specified by a `contract address` (mandatory), the event's `topic-0` (mandatory) and a number of additional topic- or data-matchers. Event data can be matched as `byte-equals` or numeric comparisons (`<, <=, ==, >=, >`) over an uint256-cast of the specified event data fields. +The trigger condition is specified by a `contract address` (mandatory), the event's signature (mandatory), and a number of additional arguments. Event data can be matched as `byte-equals` or numeric comparisons (`lt, lte, eq, gte, gt`) over an uint256-cast of the specified event data fields. -Registered event based decryption triggers are bound by a time-to-live (`ttl`). The decryption keys are only released once and only if +Refer to the `/compile_event_trigger_definition` endpoint in the Swagger documentation for details on parameters and responses. + +#### Example Request +```bash +curl -X POST https:///compile_event_trigger_definition \ +-H "Content-Type: application/json" \ +-d '{ + "contract": "0x3465a347342B72BCf800aBf814324ba4a803c32b", + "eventSig": "Transfer(indexed from address, indexed to address, amount uint256)", + "arguments": [ + { + "name": "from", + "op": "eq", + "bytes": "0x456d9347342B72BCf800bBf117391ac2f807c6bF" + }, + { + "name": "amount", + "op": "gte", + "number": 25433 + } + ] +}' +``` + +#### Example Response +```json +{ + "trigger_definition": "0x01f86694953a0425accee2e05f22e78999c595ed2ee7183cf84fe480e205a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efe401e205a0000000000000000000000000812a6755975485c6e340f97de6790b34a94d1430c404c20402" +} +``` + +> **Note**: The object format for the "arguments" list is: +> - `name`: The matching argument name from the event signature +> - `op`: One of `lt`, `lte`, `eq`, `gte`, `gt` for comparison operations +> - `number`: Integer argument for numeric comparisons +> - `bytes`: Hex-encoded byte argument for non-numeric matches with `op == "eq"` +> +> The resulting condition for the trigger is a logical AND of all arguments given. + +### 1.C Register an Identity with Event-based Decryption Triggers + +An alternative to time-based decryption triggers is "event-based" decryption triggers. This is very similar to the time-based release conditions discussed above. However, here the decryption key is produced only when a specific EVM event has been observed by the keypers. + +The trigger condition is specified by a compiled event trigger definition (created using `/compile_event_trigger_definition`). Registered event-based decryption triggers are bound by a time-to-live (`ttl`). The decryption keys are only released once and only if: - the release condition has not been met before (since registration) - the `ttl` timer has not run out, and - *all* conditions of the trigger definition were fulfilled. +Refer to the `/register_event_identity` endpoint in the Swagger documentation for details on parameters and responses. > **Note**: When registering identities through our API, the API account address is used to compute the identity that will be returned. If you want to use your own address, you need to submit the registration directly to the registry contract. The contract's definition can be found here: > [ShutterEventRegistry.sol](https://github.com/shutter-network/contracts/blob/main/src/shutter-service/ShutterEventTriggerRegistry.sol#L35-L40) @@ -145,30 +205,61 @@ curl -X POST https:///register_event_identity \ }' ``` -> **Note**: The encoding of `eventDefinition` is specified [in rolling-shutter](https://github.com/shutter-network/rolling-shutter/blob/main/docs/event.md). It is a concatenation of contract address, topic0 and the rlp encoding of the other conditions. Event definitions can be constructed by using the `/compile_event_trigger_definition` endpoint (WIP: add link to swagger docs). - #### Example Response ```json { "eon": 1, "eon_key": "0x9348cbe5372c1b467bfe60d6c678bbe1aed74a90b93f857b2db1b6a5dac5cd95", "identity": "0xdfb9b97b2ff057a1fdff173e10e974ffb16c28105f0524b33e8a6906c6c81dc0", - "identityPrefix": "0x32fdbd2ca52e171f77db2757ff6200cd8446350f927a3ad46c0565483dd8b41c", + "identity_prefix": "0x32fdbd2ca52e171f77db2757ff6200cd8446350f927a3ad46c0565483dd8b41c", "tx_hash": "0xf7cb7ef13edee67735bba17d5ff84546a1ac7547b3d2a9f1d15e4d1b2e9f303c" } ``` -### 2. Retrieve the Encryption Data +> **Note**: The encoding of `triggerDefinition` is specified [in rolling-shutter](https://github.com/shutter-network/rolling-shutter/blob/main/docs/event.md). It is a concatenation of contract address, topic0 and the RLP encoding of the other conditions. Event definitions should be constructed using the `/compile_event_trigger_definition` endpoint. + +### 1.D Get Event Trigger Identity Registration Expiration Block + +Retrieve the expiration block number for a given event trigger identity registration. This endpoint allows you to check the expiration block number for an event-based identity registration. + +Refer to the `/get_event_trigger_expiration_block` endpoint in the Swagger documentation for details on parameters and responses. + +#### Example Request +```bash +curl -X GET "https:///get_event_trigger_expiration_block?eon=1&identityPrefix=0x32fdbd2ca52e171f77db2757ff6200cd8446350f927a3ad46c0565483dd8b41c&address=0x228DefCF37Da29475F0EE2B9E4dfAeDc3b0746bc" +``` + +#### Example Response +```json +{ + "expiration_block_number": 5678967 +} +``` + +> **Note**: If the event identity registration is not found, the endpoint will return a 404 error. + +### 2. Encryption Operations + +#### 2.A Retrieve the Encryption Data To encrypt commitments, obtain the encryption data associated with your identity. Use the `/get_data_for_encryption` endpoint to retrieve all necessary encryption data. +This endpoint supports both time-based and event-based identity computation: +- For **Time-based**: Omit the `triggerDefinition` parameter. +- For **Event-based**: Provide the `triggerDefinition` parameter (hex-encoded with 0x prefix) as well to compute identity for event-based triggers. + Refer to the Swagger documentation for specifics on this endpoint. -#### Example Request +#### Example Request (Time-based) ```bash curl -X GET "https:///get_data_for_encryption?address=0xb9C303443c9af84777e60D5C987AbF0c43844918&identityPrefix=0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0" ``` +#### Example Request (Event-based) +```bash +curl -X GET "https:///get_data_for_encryption?address=0xb9C303443c9af84777e60D5C987AbF0c43844918&identityPrefix=0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0&triggerDefinition=0x01f86694953a0425accee2e05f22e78999c595ed2ee7183cf84fe480e205a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efe401e205a0000000000000000000000000812a6755975485c6e340f97de6790b34a94d1430c404c20402" +``` + #### Example Response ```json { @@ -270,7 +361,9 @@ const encryptedCommitment = await encryptData(message, eonPublicKey, identityPre console.log("Encrypted Commitment:", encryptedCommitment); ``` -### 3. Retrieve the Decryption Key +### 3. Decryption Operations + +#### 3.A Retrieve the Decryption Key After the decryption trigger conditions are met (i.e., the specified timestamp has passed), retrieve the decryption key using the `/get_decryption_key` endpoint. @@ -290,7 +383,7 @@ curl -X GET "https:///get_decryption_key?identity=0x8c232eae4f9572 } ``` -### 4. Decrypt Commitments +#### 3.B Decrypt Commitments Once you have the decryption key, use it to decrypt commitments encrypted with the Shutter system. The `/decrypt_commitment` endpoint enables this process. @@ -314,8 +407,8 @@ The decrypted message is returned in its hex format. To get the initial message, ## Future Features -- **Event-Based and Block-Based Triggers** - Future versions of the Shutter system will support event-based and block-based decryption triggers for enhanced functionality. +- **Block-Based Triggers** + Future versions of the Shutter system will support block-based decryption triggers for enhanced functionality. - **Real-Time Notifications** Planned updates include WebSocket-based notifications for real-time key releases, improving user experience and interactivity. diff --git a/docker-compose.rate_limit.yaml b/docker-compose.rate_limit.yaml index 50a8cb7..c7529aa 100644 --- a/docker-compose.rate_limit.yaml +++ b/docker-compose.rate_limit.yaml @@ -74,6 +74,27 @@ services: caddy.rate_limit_0.zone_3.match.path: "*/decrypt_commitment*" caddy.rate_limit_0.zone_3.match.method: GET + caddy.rate_limit_0.zone_4: compile_event_trigger_definition__unauthorized + caddy.rate_limit_0.zone_4.key: "{remote_host}" + caddy.rate_limit_0.zone_4.events: 20 + caddy.rate_limit_0.zone_4.window: 1d + caddy.rate_limit_0.zone_4.match.path: "*/compile_event_trigger_definition*" + caddy.rate_limit_0.zone_4.match.method: POST + + caddy.rate_limit_0.zone_5: register_event_identity__unauthorized + caddy.rate_limit_0.zone_5.key: "{remote_host}" + caddy.rate_limit_0.zone_5.events: 5 + caddy.rate_limit_0.zone_5.window: 1d + caddy.rate_limit_0.zone_5.match.path: "*/register_event_identity*" + caddy.rate_limit_0.zone_5.match.method: POST + + caddy.rate_limit_0.zone_6: get_event_trigger_expiration_block__unauthorized + caddy.rate_limit_0.zone_6.key: "{remote_host}" + caddy.rate_limit_0.zone_6.events: 20 + caddy.rate_limit_0.zone_6.window: 1d + caddy.rate_limit_0.zone_6.match.path: "*/get_event_trigger_expiration_block*" + caddy.rate_limit_0.zone_6.match.method: GET + # Rate limits with api key caddy.rate_limit_1: "@withApiKey" caddy.rate_limit_1.log_key: " " @@ -106,6 +127,27 @@ services: caddy.rate_limit_1.zone_3.match.path: "*/decrypt_commitment*" caddy.rate_limit_1.zone_3.match.method: GET + caddy.rate_limit_1.zone_4: compile_event_trigger_definition__authorized + caddy.rate_limit_1.zone_4.key: "{header.Authorization}" + caddy.rate_limit_1.zone_4.events: 2000 + caddy.rate_limit_1.zone_4.window: 1d + caddy.rate_limit_1.zone_4.match.path: "*/compile_event_trigger_definition*" + caddy.rate_limit_1.zone_4.match.method: POST + + caddy.rate_limit_1.zone_5: register_event_identity__authorized + caddy.rate_limit_1.zone_5.key: "{header.Authorization}" + caddy.rate_limit_1.zone_5.events: 500 + caddy.rate_limit_1.zone_5.window: 1d + caddy.rate_limit_1.zone_5.match.path: "*/register_event_identity*" + caddy.rate_limit_1.zone_5.match.method: POST + + caddy.rate_limit_1.zone_6: get_event_trigger_expiration_block__authorized + caddy.rate_limit_1.zone_6.key: "{header.Authorization}" + caddy.rate_limit_1.zone_6.events: 2000 + caddy.rate_limit_1.zone_6.window: 1d + caddy.rate_limit_1.zone_6.match.path: "*/get_event_trigger_expiration_block*" + caddy.rate_limit_1.zone_6.match.method: GET + caddy: build: context: . diff --git a/docs/docs.go b/docs/docs.go index e6d78ad..edd21b0 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -253,21 +253,21 @@ const docTemplate = `{ } } }, - "/get_event_trigger_ttl": { + "/get_event_trigger_expiration_block": { "get": { "security": [ { "BearerAuth": [] } ], - "description": "Retrieves the time-to-live (TTL) for a given event identity registration.", + "description": "Retrieves the expiration block number for a given event identity registration.", "produces": [ "application/json" ], "tags": [ "Crypto" ], - "summary": "Get event identity registration TTL.", + "summary": "Get event identity registration expiration block number.", "parameters": [ { "type": "integer", @@ -278,8 +278,15 @@ const docTemplate = `{ }, { "type": "string", - "description": "Identity associated with the event identity registration.", - "name": "identity", + "description": "Identity prefix associated with the event identity registration.", + "name": "identityPrefix", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Ethereum address associated with the identity. For gnosis mainnet, pass the address: 0x228DefCF37Da29475F0EE2B9E4dfAeDc3b0746bc. For chiado pass the address: 0xb9C303443c9af84777e60D5C987AbF0c43844918", + "name": "address", "in": "query", "required": true } @@ -288,11 +295,11 @@ const docTemplate = `{ "200": { "description": "Success.", "schema": { - "$ref": "#/definitions/GetEventIdentityRegistrationTTL" + "$ref": "#/definitions/GetEventTriggerExpirationBlock" } }, "400": { - "description": "Invalid Get event identity registration TTL request.", + "description": "Invalid Get event identity registration expiration block number request.", "schema": { "$ref": "#/definitions/error.Http" } @@ -441,9 +448,9 @@ const docTemplate = `{ "type": "string", "example": "0x3465a347342B72BCf800aBf814324ba4a803c32b" }, - "event_sig": { + "eventSig": { "type": "string", - "example": "Transfer(indexed from address, indexed to address, amount uint256)" + "example": "Transfer(address indexed from, address indexed to, uint256 amount)" } } }, @@ -489,12 +496,12 @@ const docTemplate = `{ } } }, - "GetEventIdentityRegistrationTTL": { + "GetEventTriggerExpirationBlock": { "type": "object", "properties": { - "ttl": { + "expiration_block_number": { "type": "integer", - "example": 100 + "example": 12345678 } } }, @@ -591,7 +598,7 @@ const docTemplate = `{ "usecase.EventTriggerDefinitionResponse": { "type": "object", "properties": { - "triggerDefinition": { + "trigger_definition": { "type": "string", "example": "0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0" } diff --git a/docs/swagger.json b/docs/swagger.json index cadd609..ecf86fc 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -244,21 +244,21 @@ } } }, - "/get_event_trigger_ttl": { + "/get_event_trigger_expiration_block": { "get": { "security": [ { "BearerAuth": [] } ], - "description": "Retrieves the time-to-live (TTL) for a given event identity registration.", + "description": "Retrieves the expiration block number for a given event identity registration.", "produces": [ "application/json" ], "tags": [ "Crypto" ], - "summary": "Get event identity registration TTL.", + "summary": "Get event identity registration expiration block number.", "parameters": [ { "type": "integer", @@ -269,8 +269,15 @@ }, { "type": "string", - "description": "Identity associated with the event identity registration.", - "name": "identity", + "description": "Identity prefix associated with the event identity registration.", + "name": "identityPrefix", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Ethereum address associated with the identity. For gnosis mainnet, pass the address: 0x228DefCF37Da29475F0EE2B9E4dfAeDc3b0746bc. For chiado pass the address: 0xb9C303443c9af84777e60D5C987AbF0c43844918", + "name": "address", "in": "query", "required": true } @@ -279,11 +286,11 @@ "200": { "description": "Success.", "schema": { - "$ref": "#/definitions/GetEventIdentityRegistrationTTL" + "$ref": "#/definitions/GetEventTriggerExpirationBlock" } }, "400": { - "description": "Invalid Get event identity registration TTL request.", + "description": "Invalid Get event identity registration expiration block number request.", "schema": { "$ref": "#/definitions/error.Http" } @@ -432,9 +439,9 @@ "type": "string", "example": "0x3465a347342B72BCf800aBf814324ba4a803c32b" }, - "event_sig": { + "eventSig": { "type": "string", - "example": "Transfer(indexed from address, indexed to address, amount uint256)" + "example": "Transfer(address indexed from, address indexed to, uint256 amount)" } } }, @@ -480,12 +487,12 @@ } } }, - "GetEventIdentityRegistrationTTL": { + "GetEventTriggerExpirationBlock": { "type": "object", "properties": { - "ttl": { + "expiration_block_number": { "type": "integer", - "example": 100 + "example": 12345678 } } }, @@ -582,7 +589,7 @@ "usecase.EventTriggerDefinitionResponse": { "type": "object", "properties": { - "triggerDefinition": { + "trigger_definition": { "type": "string", "example": "0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0" } diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 51d79a2..54a7c90 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -8,8 +8,8 @@ definitions: contract: example: 0x3465a347342B72BCf800aBf814324ba4a803c32b type: string - event_sig: - example: Transfer(indexed from address, indexed to address, amount uint256) + eventSig: + example: Transfer(address indexed from, address indexed to, uint256 amount) type: string type: object GetDataForEncryption: @@ -42,10 +42,10 @@ definitions: example: 0x8c232eae4f957259e9d6b68301d529e9851b8642874c8f59d2bd0fb84a570c75 type: string type: object - GetEventIdentityRegistrationTTL: + GetEventTriggerExpirationBlock: properties: - ttl: - example: 100 + expiration_block_number: + example: 12345678 type: integer type: object RegisterEventIdentityRequest: @@ -113,7 +113,7 @@ definitions: type: object usecase.EventTriggerDefinitionResponse: properties: - triggerDefinition: + trigger_definition: example: 0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0 type: string type: object @@ -295,18 +295,26 @@ paths: summary: Get decryption key. tags: - Crypto - /get_event_trigger_ttl: + /get_event_trigger_expiration_block: get: - description: Retrieves the time-to-live (TTL) for a given event identity registration. + description: Retrieves the expiration block number for a given event identity + registration. parameters: - description: Eon number associated with the event identity registration. in: query name: eon required: true type: integer - - description: Identity associated with the event identity registration. + - description: Identity prefix associated with the event identity registration. in: query - name: identity + name: identityPrefix + required: true + type: string + - description: 'Ethereum address associated with the identity. For gnosis mainnet, + pass the address: 0x228DefCF37Da29475F0EE2B9E4dfAeDc3b0746bc. For chiado + pass the address: 0xb9C303443c9af84777e60D5C987AbF0c43844918' + in: query + name: address required: true type: string produces: @@ -315,9 +323,10 @@ paths: "200": description: Success. schema: - $ref: '#/definitions/GetEventIdentityRegistrationTTL' + $ref: '#/definitions/GetEventTriggerExpirationBlock' "400": - description: Invalid Get event identity registration TTL request. + description: Invalid Get event identity registration expiration block number + request. schema: $ref: '#/definitions/error.Http' "404": @@ -334,7 +343,7 @@ paths: $ref: '#/definitions/error.Http' security: - BearerAuth: [] - summary: Get event identity registration TTL. + summary: Get event identity registration expiration block number. tags: - Crypto /register_event_identity: diff --git a/etdc/main.go b/etdc/main.go index e06b043..5612428 100644 --- a/etdc/main.go +++ b/etdc/main.go @@ -20,7 +20,7 @@ import ( // // { // "contract": "0x953A0425ACCee2E05f22E78999c595eD2eE7183c", -// "event_sig":"event Transfer(address indexed from, address indexed to, uint256 amount)", +// "eventSig":"event Transfer(address indexed from, address indexed to, uint256 amount)", // "arguments": [ // {"name": "from", "op": "eq", "bytes": "0x812a6755975485C6E340F97dE6790B34a94D1430"}, // {"name": "amount", "op": "gte", "number": 2}] diff --git a/internal/data/event_registrations.sql.go b/internal/data/event_registrations.sql.go index 6d9763f..5c396be 100644 --- a/internal/data/event_registrations.sql.go +++ b/internal/data/event_registrations.sql.go @@ -7,51 +7,60 @@ package data import ( "context" - - "github.com/jackc/pgx/v5/pgtype" ) const getEventIdentityRegistration = `-- name: GetEventIdentityRegistration :one -SELECT eon, identity, identity_prefix, eon_key, event_trigger_definition, ttl, tx_hash, created_at FROM event_identity_registration -WHERE eon = $1 AND identity = $2 +SELECT + eon, + identity, + identity_prefix, + sender, + event_trigger_definition, + COALESCE(expiration_block_number, 0) AS expiration_block_number, + tx_hash, + created_at +FROM event_identity_registration +WHERE eon = $1 AND identity_prefix = $2 AND sender = $3 ` type GetEventIdentityRegistrationParams struct { - Eon int64 - Identity []byte + Eon int64 + IdentityPrefix []byte + Sender string } func (q *Queries) GetEventIdentityRegistration(ctx context.Context, arg GetEventIdentityRegistrationParams) (EventIdentityRegistration, error) { - row := q.db.QueryRow(ctx, getEventIdentityRegistration, arg.Eon, arg.Identity) + row := q.db.QueryRow(ctx, getEventIdentityRegistration, arg.Eon, arg.IdentityPrefix, arg.Sender) var i EventIdentityRegistration err := row.Scan( &i.Eon, &i.Identity, &i.IdentityPrefix, - &i.EonKey, + &i.Sender, &i.EventTriggerDefinition, - &i.Ttl, + &i.ExpirationBlockNumber, &i.TxHash, &i.CreatedAt, ) return i, err } -const getEventIdentityRegistrationTTL = `-- name: GetEventIdentityRegistrationTTL :one -SELECT ttl FROM event_identity_registration -WHERE eon = $1 AND identity = $2 +const getEventTriggerExpirationBlockNumber = `-- name: GetEventTriggerExpirationBlockNumber :one +SELECT COALESCE(expiration_block_number, 0) FROM event_identity_registration +WHERE eon = $1 AND identity_prefix = $2 AND sender = $3 ` -type GetEventIdentityRegistrationTTLParams struct { - Eon int64 - Identity []byte +type GetEventTriggerExpirationBlockNumberParams struct { + Eon int64 + IdentityPrefix []byte + Sender string } -func (q *Queries) GetEventIdentityRegistrationTTL(ctx context.Context, arg GetEventIdentityRegistrationTTLParams) (pgtype.Int8, error) { - row := q.db.QueryRow(ctx, getEventIdentityRegistrationTTL, arg.Eon, arg.Identity) - var ttl pgtype.Int8 - err := row.Scan(&ttl) - return ttl, err +func (q *Queries) GetEventTriggerExpirationBlockNumber(ctx context.Context, arg GetEventTriggerExpirationBlockNumberParams) (int64, error) { + row := q.db.QueryRow(ctx, getEventTriggerExpirationBlockNumber, arg.Eon, arg.IdentityPrefix, arg.Sender) + var expiration_block_number int64 + err := row.Scan(&expiration_block_number) + return expiration_block_number, err } const insertEventIdentityRegistration = `-- name: InsertEventIdentityRegistration :exec @@ -60,21 +69,19 @@ INSERT INTO event_identity_registration ( eon, identity, identity_prefix, - eon_key, + sender, event_trigger_definition, - ttl, tx_hash -) VALUES ($1, $2, $3, $4, $5, $6, $7) -ON CONFLICT (eon, identity) DO NOTHING +) VALUES ($1, $2, $3, $4, $5, $6) +ON CONFLICT (eon, identity_prefix, sender) DO NOTHING ` type InsertEventIdentityRegistrationParams struct { Eon int64 Identity []byte IdentityPrefix []byte - EonKey []byte + Sender string EventTriggerDefinition []byte - Ttl pgtype.Int8 TxHash []byte } @@ -84,10 +91,32 @@ func (q *Queries) InsertEventIdentityRegistration(ctx context.Context, arg Inser arg.Eon, arg.Identity, arg.IdentityPrefix, - arg.EonKey, + arg.Sender, arg.EventTriggerDefinition, - arg.Ttl, arg.TxHash, ) return err } + +const updateEventIdentityRegistrationExpirationBlockNumber = `-- name: UpdateEventIdentityRegistrationExpirationBlockNumber :exec +UPDATE event_identity_registration +SET expiration_block_number = $1 +WHERE eon = $2 AND identity_prefix = $3 AND sender = $4 +` + +type UpdateEventIdentityRegistrationExpirationBlockNumberParams struct { + ExpirationBlockNumber int64 + Eon int64 + IdentityPrefix []byte + Sender string +} + +func (q *Queries) UpdateEventIdentityRegistrationExpirationBlockNumber(ctx context.Context, arg UpdateEventIdentityRegistrationExpirationBlockNumberParams) error { + _, err := q.db.Exec(ctx, updateEventIdentityRegistrationExpirationBlockNumber, + arg.ExpirationBlockNumber, + arg.Eon, + arg.IdentityPrefix, + arg.Sender, + ) + return err +} diff --git a/internal/data/models.sqlc.gen.go b/internal/data/models.sqlc.gen.go index a4e1275..a52fefe 100644 --- a/internal/data/models.sqlc.gen.go +++ b/internal/data/models.sqlc.gen.go @@ -18,9 +18,9 @@ type EventIdentityRegistration struct { Eon int64 Identity []byte IdentityPrefix []byte - EonKey []byte + Sender string EventTriggerDefinition []byte - Ttl pgtype.Int8 + ExpirationBlockNumber int64 TxHash []byte CreatedAt pgtype.Timestamp } diff --git a/internal/data/sql/queries/event_registrations.sql b/internal/data/sql/queries/event_registrations.sql index 62f328d..9607164 100644 --- a/internal/data/sql/queries/event_registrations.sql +++ b/internal/data/sql/queries/event_registrations.sql @@ -5,17 +5,30 @@ INSERT INTO event_identity_registration ( eon, identity, identity_prefix, - eon_key, + sender, event_trigger_definition, - ttl, tx_hash -) VALUES ($1, $2, $3, $4, $5, $6, $7) -ON CONFLICT (eon, identity) DO NOTHING; +) VALUES ($1, $2, $3, $4, $5, $6) +ON CONFLICT (eon, identity_prefix, sender) DO NOTHING; -- name: GetEventIdentityRegistration :one -SELECT * FROM event_identity_registration -WHERE eon = $1 AND identity = $2; +SELECT + eon, + identity, + identity_prefix, + sender, + event_trigger_definition, + COALESCE(expiration_block_number, 0) AS expiration_block_number, + tx_hash, + created_at +FROM event_identity_registration +WHERE eon = $1 AND identity_prefix = $2 AND sender = $3; + +-- name: GetEventTriggerExpirationBlockNumber :one +SELECT COALESCE(expiration_block_number, 0) FROM event_identity_registration +WHERE eon = $1 AND identity_prefix = $2 AND sender = $3; --- name: GetEventIdentityRegistrationTTL :one -SELECT ttl FROM event_identity_registration -WHERE eon = $1 AND identity = $2; \ No newline at end of file +-- name: UpdateEventIdentityRegistrationExpirationBlockNumber :exec +UPDATE event_identity_registration +SET expiration_block_number = $1 +WHERE eon = $2 AND identity_prefix = $3 AND sender = $4; diff --git a/internal/data/sql/schemas/event_registrations.sql b/internal/data/sql/schemas/event_registrations.sql index bca25c5..f422293 100644 --- a/internal/data/sql/schemas/event_registrations.sql +++ b/internal/data/sql/schemas/event_registrations.sql @@ -1,13 +1,13 @@ -- write schema definitions here CREATE TABLE event_identity_registration ( - eon bigint, - identity bytea, - identity_prefix bytea, - eon_key bytea, - event_trigger_definition bytea, - ttl bigint, - tx_hash bytea, - created_at TIMESTAMP DEFAULT NOW(), - PRIMARY KEY (eon, identity) -); \ No newline at end of file + eon bigint NOT NULL, + identity bytea NOT NULL, + identity_prefix bytea NOT NULL, + sender text NOT NULL, + event_trigger_definition bytea NOT NULL, + expiration_block_number bigint, + tx_hash bytea NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT NOW(), + PRIMARY KEY (eon, identity_prefix, sender) +); diff --git a/internal/router/router.go b/internal/router/router.go index 0c26447..8097892 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -40,7 +40,7 @@ func NewRouter( api.POST("/compile_event_trigger_definition", cryptoService.CompileEventTriggerDefinition) api.GET("/decrypt_commitment", cryptoService.DecryptCommitment) api.POST("/register_event_identity", cryptoService.RegisterEventIdentity) - api.GET("/get_event_trigger_ttl", cryptoService.GetEventIdentityRegistrationTTL) + api.GET("/get_event_trigger_expiration_block", cryptoService.GetEventTriggerExpirationBlock) } router.GET("/docs/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, func(c *ginSwagger.Config) { c.Title = "Shutter-API" diff --git a/internal/service/crypto.go b/internal/service/crypto.go index 7618c3c..e6a6024 100644 --- a/internal/service/crypto.go +++ b/internal/service/crypto.go @@ -216,35 +216,34 @@ func (svc *CryptoService) DecryptCommitment(ctx *gin.Context) { // @BasePath /api // -// # EventTriggerDefinition godoc +// EventTriggerDefinition godoc // -// @Summary Allows clients to compile an event trigger definition string. -// @Description This endpoint takes an event signature snippet and some arguments to create an event trigger definition that will be understood by keypers -// supporting event based decryption triggers. Example request body: -// { -// "contract": "0x3465a347342B72BCf800aBf814324ba4a803c32b", -// "event_sig": "Transfer(indexed from address, indexed to address, amount uint256)", -// "arguments": [ -// { "name": "from", "op": "eq", "bytes": "0x456d9347342B72BCf800bBf117391ac2f807c6bF" }, -// { "name": "amount", "op": "gte", "number": 25433 } -// ] -// } -// The object format for the "arguments" list is: -// - "name": -// - "op": -// - "number": -// - "bytes": -// Note: the resulting condition for the trigger is a logical AND of all arguments given. +// @Summary Allows clients to compile an event trigger definition string. +// @Description This endpoint takes an event signature snippet and some arguments to create an event trigger definition that will be understood by keypers +// supporting event based decryption triggers. Example request body: +// { +// "contract": "0x953A0425ACCee2E05f22E78999c595eD2eE7183c", +// "eventSig":"event Transfer(address indexed from, address indexed to, uint256 amount)", +// "arguments": [ +// {"name": "from", "op": "eq", "bytes": "0x812a6755975485C6E340F97dE6790B34a94D1430"}, +// {"name": "amount", "op": "gte", "number": 2}] +// } +// The object format for the "arguments" list is: +// - "name": +// - "op": +// - "number": +// - "bytes": +// Note: the resulting condition for the trigger is a logical AND of all arguments given. // -// @Tags Crypto -// @Produce json -// @Param request body EventTriggerDefinitionRequest true "Event signature and match arguments." -// @Success 200 {object} usecase.EventTriggerDefinitionResponse "Success." -// @Failure 400 {object} error.Http "Invalid Event Data." -// @Failure 429 {object} error.Http "Too many requests. Rate limited." -// @Failure 500 {object} error.Http "Internal server error." -// @Security BearerAuth -// @Router /compile_event_trigger_definition [post] +// @Tags Crypto +// @Produce json +// @Param request body EventTriggerDefinitionRequest true "Event signature and match arguments." +// @Success 200 {object} usecase.EventTriggerDefinitionResponse "Success." +// @Failure 400 {object} error.Http "Invalid Event Data." +// @Failure 429 {object} error.Http "Too many requests. Rate limited." +// @Failure 500 {object} error.Http "Internal server error." +// @Security BearerAuth +// @Router /compile_event_trigger_definition [post] func (svc *CryptoService) CompileEventTriggerDefinition(ctx *gin.Context) { CompileEventTriggerDefinition(ctx) } @@ -313,22 +312,23 @@ func (svc *CryptoService) RegisterEventIdentity(ctx *gin.Context) { // @BasePath /api // -// GetEventIdentityRegistrationTTL godoc +// GetEventTriggerExpirationBlock godoc // -// @Summary Get event identity registration TTL. -// @Description Retrieves the time-to-live (TTL) for a given event identity registration. +// @Summary Get event identity registration expiration block number. +// @Description Retrieves the expiration block number for a given event identity registration. // @Tags Crypto // @Produce json // @Param eon query uint64 true "Eon number associated with the event identity registration." -// @Param identity query string true "Identity associated with the event identity registration." -// @Success 200 {object} usecase.GetEventIdentityRegistrationTTLResponse "Success." -// @Failure 400 {object} error.Http "Invalid Get event identity registration TTL request." +// @Param identityPrefix query string true "Identity prefix associated with the event identity registration." +// @Param address query string true "Ethereum address associated with the identity. For gnosis mainnet, pass the address: 0x228DefCF37Da29475F0EE2B9E4dfAeDc3b0746bc. For chiado pass the address: 0xb9C303443c9af84777e60D5C987AbF0c43844918" +// @Success 200 {object} usecase.GetEventTriggerExpirationBlockResponse "Success." +// @Failure 400 {object} error.Http "Invalid Get event identity registration expiration block number request." // @Failure 404 {object} error.Http "Event identity registration not found." // @Failure 429 {object} error.Http "Too many requests. Rate limited." // @Failure 500 {object} error.Http "Internal server error." // @Security BearerAuth -// @Router /get_event_trigger_ttl [get] -func (svc *CryptoService) GetEventIdentityRegistrationTTL(ctx *gin.Context) { +// @Router /get_event_trigger_expiration_block [get] +func (svc *CryptoService) GetEventTriggerExpirationBlock(ctx *gin.Context) { eonStr, ok := ctx.GetQuery("eon") if !ok { err := sherror.NewHttpError( @@ -351,18 +351,29 @@ func (svc *CryptoService) GetEventIdentityRegistrationTTL(ctx *gin.Context) { return } - identity, ok := ctx.GetQuery("identity") + identityPrefix, ok := ctx.GetQuery("identityPrefix") if !ok { err := sherror.NewHttpError( "query parameter not found", - "identity query parameter is required", + "identityPrefix query parameter is required", + http.StatusBadRequest, + ) + ctx.Error(err) + return + } + + address, ok := ctx.GetQuery("address") + if !ok { + err := sherror.NewHttpError( + "query parameter not found", + "address query parameter is required", http.StatusBadRequest, ) ctx.Error(err) return } - data, httpErr := svc.CryptoUsecase.GetEventIdentityRegistrationTTL(ctx, eon, identity) + data, httpErr := svc.CryptoUsecase.GetEventTriggerExpirationBlock(ctx, eon, identityPrefix, address) if httpErr != nil { ctx.Error(httpErr) return diff --git a/internal/service/crypto_test.go b/internal/service/crypto_test.go index 46849db..f1e7e8e 100644 --- a/internal/service/crypto_test.go +++ b/internal/service/crypto_test.go @@ -29,17 +29,17 @@ func TestEventDecryptionValidation(t *testing.T) { router := setupRouter() testData := []string{ // "grom" != "from" - `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "event_sig":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "grom", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}`, + `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventSig":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "grom", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}`, // "op": "gt" on "bytes" value (must be "number") - `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "event_sig":"event Transfer(address indexed from, address indexed to, address notify)","arguments": [{"name": "notify", "op": "gt", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"}]}`, + `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventSig":"event Transfer(address indexed from, address indexed to, address notify)","arguments": [{"name": "notify", "op": "gt", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"}]}`, // "op: gte" illegal on indexed address - `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "event_sig":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "gte", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}`, + `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventSig":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "gte", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}`, // argument "from" defined more than once - `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "event_sig":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "from", "op": "eq", "value": "0x8e13976721ebff885611c8391d9b02749c1283fa"}]}`, + `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventSig":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "from", "op": "eq", "value": "0x8e13976721ebff885611c8391d9b02749c1283fa"}]}`, // invalid JSON `{foo: "bar"}`, // missing contract address - `{"event_sig":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}`, + `{"eventSig":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}`, // missing signature `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "arguments": [{"name": "from", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}`, } @@ -53,7 +53,7 @@ func TestEventDecryptionValidation(t *testing.T) { func TestEventDecryptionData(t *testing.T) { router := setupRouter() - bites := `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "event_sig":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}` + bites := `{"contract": "0x4d6dd1382aa09be1d243f8960409a1ab3d913f43", "eventSig":"event Transfer(address indexed from, address indexed to, uint256 amount)","arguments": [{"name": "from", "op": "eq", "bytes": "0x9e13976721ebff885611c8391d9b02749c1283fa"},{"name": "amount", "op": "gte", "number": 1}]}` w := httptest.NewRecorder() fromAsBytes, err := hexutil.Decode("0x9e13976721ebff885611c8391d9b02749c1283fa") assert.NilError(t, err, "hex decode failed") diff --git a/internal/usecase/crypto.go b/internal/usecase/crypto.go index 25b60ec..14e5cc6 100644 --- a/internal/usecase/crypto.go +++ b/internal/usecase/crypto.go @@ -13,6 +13,7 @@ import ( cryptorand "crypto/rand" "github.com/ethereum/go-ethereum/accounts/abi/bind" + ecommon "github.com/ethereum/go-ethereum/common" ethCommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" @@ -56,6 +57,7 @@ type KeyBroadcastInterface interface { type EthClientInterface interface { BlockNumber(ctx context.Context) (uint64, error) ChainID(ctx context.Context) (*big.Int, error) + TransactionReceipt(ctx context.Context, txHash ecommon.Hash) (*types.Receipt, error) } type GetDecryptionKeyResponse struct { diff --git a/internal/usecase/eventtrigger.go b/internal/usecase/eventtrigger.go index 86d2fc9..12f0356 100644 --- a/internal/usecase/eventtrigger.go +++ b/internal/usecase/eventtrigger.go @@ -9,6 +9,7 @@ import ( "net/http" "slices" "strings" + "time" "github.com/defiweb/go-sigparser" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -16,7 +17,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" "github.com/jackc/pgx/v5" - "github.com/jackc/pgx/v5/pgtype" "github.com/rs/zerolog/log" shs "github.com/shutter-network/rolling-shutter/rolling-shutter/keyperimpl/shutterservice" "github.com/shutter-network/shutter-api/common" @@ -34,18 +34,18 @@ type EventArgument struct { Bytes string `json:"bytes" example:"0xabcdef01234567"` } type EventTriggerDefinitionRequest struct { - EventSignature string `json:"event_sig" example:"Transfer(indexed from address, indexed to address, amount uint256)"` + EventSignature string `json:"eventSig" example:"Transfer(address indexed from, address indexed to, uint256 amount)"` ContractAddress ecommon.Address `json:"contract" swaggertype:"string" example:"0x3465a347342B72BCf800aBf814324ba4a803c32b"` Arguments []EventArgument `json:"arguments"` } // @name EventTriggerDefinitionRequest type EventTriggerDefinitionResponse struct { - EventTriggerDefinition string `json:"triggerDefinition" example:"0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0"` + EventTriggerDefinition string `json:"trigger_definition" example:"0x79bc8f6b4fcb02c651d6a702b7ad965c7fca19e94a9646d21ae90c8b54c030a0"` } -type GetEventIdentityRegistrationTTLResponse struct { - TTL uint64 `json:"ttl" example:"100"` -} // @name GetEventIdentityRegistrationTTL +type GetEventTriggerExpirationBlockResponse struct { + ExpirationBlockNumber uint64 `json:"expiration_block_number" example:"12345678"` +} // @name GetEventTriggerExpirationBlock func CompileEventTriggerDefinitionInternal(req EventTriggerDefinitionRequest) (EventTriggerDefinitionResponse, []error) { var errors []error @@ -386,8 +386,9 @@ func (uc *CryptoUsecase) RegisterEventIdentity(ctx context.Context, eventTrigger identity := common.ComputeEventIdentity(identityPrefix[:], newSigner.From, eventTriggerDefinition) _, err = uc.dbQuery.GetEventIdentityRegistration(ctx, data.GetEventIdentityRegistrationParams{ - Eon: int64(eon), - Identity: identity, + Eon: int64(eon), + IdentityPrefix: identityPrefix[:], + Sender: newSigner.From.Hex(), }) if err == nil { log.Warn().Msg("event identity already registered") @@ -436,9 +437,8 @@ func (uc *CryptoUsecase) RegisterEventIdentity(ctx context.Context, eventTrigger Eon: int64(eon), Identity: identity, IdentityPrefix: identityPrefix[:], - EonKey: eonKeyBytes, + Sender: newSigner.From.Hex(), EventTriggerDefinition: eventTriggerDefinition, - Ttl: pgtype.Int8{Int64: int64(ttl), Valid: true}, TxHash: txHashBytes, }) if err != nil { @@ -447,6 +447,8 @@ func (uc *CryptoUsecase) RegisterEventIdentity(ctx context.Context, eventTrigger // The registration is on-chain even if DB insert fails } + go uc.updateEventIdentityExpirationBlockNumber(tx.Hash(), eon, identityPrefix[:], newSigner.From.Hex(), ttl) + metrics.TotalSuccessfulIdentityRegistration.Inc() return &RegisterIdentityResponse{ Eon: eon, @@ -458,35 +460,76 @@ func (uc *CryptoUsecase) RegisterEventIdentity(ctx context.Context, eventTrigger } -func (uc *CryptoUsecase) GetEventIdentityRegistrationTTL(ctx context.Context, eon uint64, identity string) (*GetEventIdentityRegistrationTTLResponse, *httpError.Http) { - identityBytes, err := hex.DecodeString(strings.TrimPrefix(identity, "0x")) +func (uc *CryptoUsecase) updateEventIdentityExpirationBlockNumber(txHash ecommon.Hash, eon uint64, identityPrefix []byte, sender string, ttl uint64) { + ctx := context.Background() + ticker := time.NewTicker(1 * time.Second) + defer ticker.Stop() + + for { + receipt, err := uc.ethClient.TransactionReceipt(ctx, txHash) + if err == nil { + if receipt.Status == 0 { + log.Error().Str("tx_hash", txHash.Hex()).Msg("event identity registration transaction failed") + return + } + + expirationBlockNumber := receipt.BlockNumber.Uint64() + ttl + err = uc.dbQuery.UpdateEventIdentityRegistrationExpirationBlockNumber(ctx, data.UpdateEventIdentityRegistrationExpirationBlockNumberParams{ + ExpirationBlockNumber: int64(expirationBlockNumber), + Eon: int64(eon), + IdentityPrefix: identityPrefix, + Sender: sender, + }) + if err != nil { + log.Err(err).Str("tx_hash", txHash.Hex()).Msg("failed to update expiration block number") + } + return + } + + <-ticker.C + } +} + +func (uc *CryptoUsecase) GetEventTriggerExpirationBlock(ctx context.Context, eon uint64, identityPrefix string, sender string) (*GetEventTriggerExpirationBlockResponse, *httpError.Http) { + identityPrefixBytes, err := hex.DecodeString(strings.TrimPrefix(identityPrefix, "0x")) if err != nil { - log.Err(err).Msg("err encountered while decoding identity") + log.Err(err).Msg("err encountered while decoding identity prefix") + err := httpError.NewHttpError( + "error encountered while decoding identity prefix", + "", + http.StatusBadRequest, + ) + return nil, &err + } + + if len(identityPrefixBytes) != 32 { + log.Err(err).Msg("identity prefix should be of length 32") err := httpError.NewHttpError( - "error encountered while decoding identity", + "identity prefix should be of length 32", "", http.StatusBadRequest, ) return nil, &err } - if len(identityBytes) != 32 { - log.Err(err).Msg("identity should be of length 32") + if !ecommon.IsHexAddress(sender) { + log.Err(err).Msg("invalid address") err := httpError.NewHttpError( - "identity should be of length 32", + "invalid address", "", http.StatusBadRequest, ) return nil, &err } - ttl, err := uc.dbQuery.GetEventIdentityRegistrationTTL(ctx, data.GetEventIdentityRegistrationTTLParams{ - Eon: int64(eon), - Identity: identityBytes, + expirationBlockNumber, err := uc.dbQuery.GetEventTriggerExpirationBlockNumber(ctx, data.GetEventTriggerExpirationBlockNumberParams{ + Eon: int64(eon), + IdentityPrefix: identityPrefixBytes, + Sender: sender, }) if err != nil { if err == pgx.ErrNoRows { - log.Debug().Uint64("eon", eon).Str("identity", identity).Msg("event identity registration not found") + log.Debug().Uint64("eon", eon).Str("identityPrefix", identityPrefix).Str("sender", sender).Msg("event identity registration not found") err := httpError.NewHttpError( "event identity registration not found", "", @@ -494,26 +537,16 @@ func (uc *CryptoUsecase) GetEventIdentityRegistrationTTL(ctx context.Context, eo ) return nil, &err } - log.Err(err).Msg("err encountered while querying event identity registration TTL") + log.Err(err).Msg("err encountered while querying event identity registration expiration block number") err := httpError.NewHttpError( - "error encountered while querying event identity registration TTL", + "error encountered while querying event identity registration expiration block number", "", http.StatusInternalServerError, ) return nil, &err } - if !ttl.Valid { - log.Warn().Uint64("eon", eon).Str("identity", identity).Msg("ttl is null for event identity registration") - err := httpError.NewHttpError( - "ttl not set for event identity registration", - "", - http.StatusBadRequest, - ) - return nil, &err - } - - return &GetEventIdentityRegistrationTTLResponse{ - TTL: uint64(ttl.Int64), + return &GetEventTriggerExpirationBlockResponse{ + ExpirationBlockNumber: uint64(expirationBlockNumber), }, nil } diff --git a/migrations/20251223124122_add_event_identity_registration_table.sql b/migrations/20251223124122_add_event_identity_registration_table.sql index f86c85a..087cfc7 100644 --- a/migrations/20251223124122_add_event_identity_registration_table.sql +++ b/migrations/20251223124122_add_event_identity_registration_table.sql @@ -1,15 +1,15 @@ -- +goose Up -- +goose StatementBegin CREATE TABLE event_identity_registration ( - eon bigint, - identity bytea, - identity_prefix bytea, - eon_key bytea, - event_trigger_definition bytea, - ttl bigint, - tx_hash bytea, - created_at TIMESTAMP DEFAULT NOW(), - PRIMARY KEY (eon, identity) + eon bigint NOT NULL, + identity bytea NOT NULL, + identity_prefix bytea NOT NULL, + sender text NOT NULL, + event_trigger_definition bytea NOT NULL, + expiration_block_number bigint, + tx_hash bytea NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT NOW(), + PRIMARY KEY (eon, identity_prefix, sender) ); -- +goose StatementEnd diff --git a/tests/migrations/20251223124122_add_event_identity_registration_table.sql b/tests/migrations/20251223124122_add_event_identity_registration_table.sql index f86c85a..087cfc7 100644 --- a/tests/migrations/20251223124122_add_event_identity_registration_table.sql +++ b/tests/migrations/20251223124122_add_event_identity_registration_table.sql @@ -1,15 +1,15 @@ -- +goose Up -- +goose StatementBegin CREATE TABLE event_identity_registration ( - eon bigint, - identity bytea, - identity_prefix bytea, - eon_key bytea, - event_trigger_definition bytea, - ttl bigint, - tx_hash bytea, - created_at TIMESTAMP DEFAULT NOW(), - PRIMARY KEY (eon, identity) + eon bigint NOT NULL, + identity bytea NOT NULL, + identity_prefix bytea NOT NULL, + sender text NOT NULL, + event_trigger_definition bytea NOT NULL, + expiration_block_number bigint, + tx_hash bytea NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT NOW(), + PRIMARY KEY (eon, identity_prefix, sender) ); -- +goose StatementEnd diff --git a/tests/mock/eth_client.go b/tests/mock/eth_client.go index 495b120..f1acfa2 100644 --- a/tests/mock/eth_client.go +++ b/tests/mock/eth_client.go @@ -4,6 +4,8 @@ import ( "context" "math/big" + ecommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/mock" ) @@ -20,3 +22,11 @@ func (m *MockEthClient) ChainID(ctx context.Context) (*big.Int, error) { args := m.Called(ctx) return args.Get(0).(*big.Int), args.Error(1) } + +func (m *MockEthClient) TransactionReceipt(ctx context.Context, txHash ecommon.Hash) (*types.Receipt, error) { + args := m.Called(ctx, txHash) + if args.Get(0) == nil { + return nil, args.Error(1) + } + return args.Get(0).(*types.Receipt), args.Error(1) +} \ No newline at end of file diff --git a/tests/register_event_identity_test.go b/tests/register_event_identity_test.go index a42eeb1..a2a43f5 100644 --- a/tests/register_event_identity_test.go +++ b/tests/register_event_identity_test.go @@ -5,9 +5,11 @@ import ( "encoding/hex" "math/big" "math/rand" + "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" "github.com/shutter-network/shutter-api/common" "github.com/shutter-network/shutter-api/internal/data" "github.com/stretchr/testify/mock" @@ -19,7 +21,7 @@ func (s *TestShutterService) TestRegisterEventIdentity() { identityPrefix, err := generateRandomBytes(32) s.Require().NoError(err) identityPrefixStringified := hex.EncodeToString(identityPrefix) - blockNumber := rand.Uint64() + blockNumber := uint64(1000000) eon := rand.Uint64() @@ -62,6 +64,20 @@ func (s *TestShutterService) TestRegisterEventIdentity() { Return(randomTx, nil). Once() + // Mock transaction receipt - use a different block number for the receipt + txBlockNumber := blockNumber + 5 // Transaction mined in a later block + receipt := &types.Receipt{ + Status: types.ReceiptStatusSuccessful, + BlockNumber: big.NewInt(int64(txBlockNumber)), + } + + s.ethClient. + On("TransactionReceipt", mock.Anything, randomTx.Hash()). + Return(receipt, nil). + Once() + + expectedExpirationBlockNumber := int64(txBlockNumber + ttl) + response, err := s.cryptoUsecase.RegisterEventIdentity(ctx, eventTriggerDefinitionHex, identityPrefixStringified, ttl) s.Require().Nil(err) @@ -73,17 +89,25 @@ func (s *TestShutterService) TestRegisterEventIdentity() { // Verify the registration was stored in the database dbRegistration, dbErr := s.dbQuery.GetEventIdentityRegistration(ctx, data.GetEventIdentityRegistrationParams{ - Eon: int64(eon), - Identity: identity, + Eon: int64(eon), + IdentityPrefix: identityPrefix, + Sender: newSigner.From.Hex(), }) + for i := 0; i < 50 && (dbErr != nil || dbRegistration.ExpirationBlockNumber != expectedExpirationBlockNumber); i++ { + time.Sleep(20 * time.Millisecond) + dbRegistration, dbErr = s.dbQuery.GetEventIdentityRegistration(ctx, data.GetEventIdentityRegistrationParams{ + Eon: int64(eon), + IdentityPrefix: identityPrefix, + Sender: newSigner.From.Hex(), + }) + } s.Require().NoError(dbErr) s.Require().Equal(int64(eon), dbRegistration.Eon) s.Require().Equal(identity, dbRegistration.Identity) s.Require().Equal(identityPrefix, dbRegistration.IdentityPrefix) - s.Require().Equal(eonPublicKey.Marshal(), dbRegistration.EonKey) + s.Require().Equal(newSigner.From.Hex(), dbRegistration.Sender) s.Require().Equal(eventTriggerDefinitionBytes, dbRegistration.EventTriggerDefinition) - s.Require().True(dbRegistration.Ttl.Valid) - s.Require().Equal(int64(ttl), dbRegistration.Ttl.Int64) + s.Require().Equal(expectedExpirationBlockNumber, dbRegistration.ExpirationBlockNumber) s.Require().Equal(randomTx.Hash().Bytes(), dbRegistration.TxHash) } @@ -109,7 +133,8 @@ func (s *TestShutterService) TestRegisterEventIdentity_InvalidEventTriggerDefini identityPrefix, err := generateRandomBytes(32) s.Require().NoError(err) identityPrefixStringified := hex.EncodeToString(identityPrefix) - blockNumber := rand.Uint64() + // Use a reasonable block number that won't overflow when converted to int64 + blockNumber := uint64(1000000) eon := rand.Uint64() newSigner, err := bind.NewKeyedTransactorWithChainID(s.config.SigningKey, big.NewInt(GnosisMainnetChainID)) @@ -158,7 +183,8 @@ func (s *TestShutterService) TestRegisterEventIdentity_TriggerDefinitionWithout0 identityPrefix, err := generateRandomBytes(32) s.Require().NoError(err) identityPrefixStringified := hex.EncodeToString(identityPrefix) - blockNumber := rand.Uint64() + // Use a reasonable block number that won't overflow when converted to int64 + blockNumber := uint64(1000000) eon := rand.Uint64() newSigner, err := bind.NewKeyedTransactorWithChainID(s.config.SigningKey, big.NewInt(GnosisMainnetChainID)) @@ -206,7 +232,8 @@ func (s *TestShutterService) TestRegisterEventIdentity_ZeroBytesEventTriggerDefi identityPrefix, err := generateRandomBytes(32) s.Require().NoError(err) identityPrefixStringified := hex.EncodeToString(identityPrefix) - blockNumber := rand.Uint64() + // Use a reasonable block number that won't overflow when converted to int64 + blockNumber := uint64(1000000) eon := rand.Uint64() newSigner, err := bind.NewKeyedTransactorWithChainID(s.config.SigningKey, big.NewInt(GnosisMainnetChainID)) @@ -252,7 +279,8 @@ func (s *TestShutterService) TestRegisterEventIdentity_ZeroBytesEventTriggerDefi func (s *TestShutterService) TestRegisterEventIdentity_EmptyIdentityPrefix() { ctx := context.Background() ttl := uint64(100) - blockNumber := rand.Uint64() + // Use a reasonable block number that won't overflow when converted to int64 + blockNumber := uint64(1000000) eon := rand.Uint64() // Hardcoded valid event trigger definition @@ -303,6 +331,18 @@ func (s *TestShutterService) TestRegisterEventIdentity_EmptyIdentityPrefix() { Return(randomTx, nil). Once() + // Mock transaction receipt + txBlockNumber := blockNumber + 5 + receipt := &types.Receipt{ + Status: types.ReceiptStatusSuccessful, + BlockNumber: big.NewInt(int64(txBlockNumber)), + } + + s.ethClient. + On("TransactionReceipt", mock.Anything, randomTx.Hash()). + Return(receipt, nil). + Once() + data, err := s.cryptoUsecase.RegisterEventIdentity(ctx, eventTriggerDefinitionHex, "", ttl) s.Require().Nil(err) @@ -319,7 +359,8 @@ func (s *TestShutterService) TestRegisterEventIdentity_AlreadyRegistered() { identityPrefix, err := generateRandomBytes(32) s.Require().NoError(err) identityPrefixStringified := hex.EncodeToString(identityPrefix) - blockNumber := rand.Uint64() + // Use a reasonable block number that won't overflow when converted to int64 + blockNumber := uint64(1000000) eon := rand.Uint64() @@ -363,6 +404,18 @@ func (s *TestShutterService) TestRegisterEventIdentity_AlreadyRegistered() { Return(randomTx, nil). Once() + // Mock transaction receipt + txBlockNumber := blockNumber + 5 + receipt := &types.Receipt{ + Status: types.ReceiptStatusSuccessful, + BlockNumber: big.NewInt(int64(txBlockNumber)), + } + + s.ethClient. + On("TransactionReceipt", mock.Anything, randomTx.Hash()). + Return(receipt, nil). + Once() + // First registration should succeed response, err := s.cryptoUsecase.RegisterEventIdentity(ctx, eventTriggerDefinitionHex, identityPrefixStringified, ttl) s.Require().Nil(err) @@ -371,8 +424,9 @@ func (s *TestShutterService) TestRegisterEventIdentity_AlreadyRegistered() { // Verify the registration was stored in the database dbRegistration, dbErr := s.dbQuery.GetEventIdentityRegistration(ctx, data.GetEventIdentityRegistrationParams{ - Eon: int64(eon), - Identity: identity, + Eon: int64(eon), + IdentityPrefix: identityPrefix, + Sender: newSigner.From.Hex(), }) s.Require().NoError(dbErr) s.Require().Equal(int64(eon), dbRegistration.Eon)