diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 37ee2f90..3559cac5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ jobs: lint_test: uses: babylonlabs-io/.github/.github/workflows/reusable_go_lint_test.yml@v0.6.0 with: - run-unit-tests: false + run-unit-tests: true run-integration-tests: false run-lint: false run-build: true diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 1525ee3b..442dec48 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -11,7 +11,7 @@ jobs: lint_test: uses: babylonlabs-io/.github/.github/workflows/reusable_go_lint_test.yml@v0.6.0 with: - run-unit-tests: false + run-unit-tests: true run-integration-tests: false run-lint: false diff --git a/cmd/staking-api-service/main.go b/cmd/staking-api-service/main.go index d0e66d3b..3b42b5b8 100644 --- a/cmd/staking-api-service/main.go +++ b/cmd/staking-api-service/main.go @@ -13,9 +13,9 @@ import ( "github.com/babylonlabs-io/staking-api-service/internal/shared/http/clients" "github.com/babylonlabs-io/staking-api-service/internal/shared/observability/healthcheck" "github.com/babylonlabs-io/staking-api-service/internal/shared/observability/metrics" - queueclients "github.com/babylonlabs-io/staking-api-service/internal/shared/queue/clients" "github.com/babylonlabs-io/staking-api-service/internal/shared/services" "github.com/babylonlabs-io/staking-api-service/internal/shared/types" + v2queue "github.com/babylonlabs-io/staking-api-service/internal/v2/queue" "github.com/joho/godotenv" "github.com/rs/zerolog/log" ) @@ -83,13 +83,13 @@ func main() { } // Start the event queue processing - queueClients := queueclients.New(ctx, cfg.Queue, services) + v2queues := v2queue.New(cfg.Queue, services) // Check if the scripts flag is set if cli.GetReplayFlag() { log.Info().Msg("Replay flag is set. Starting replay of unprocessable messages.") - err := scripts.ReplayUnprocessableMessages(ctx, cfg, queueClients, dbClients.SharedDBClient) + err := scripts.ReplayUnprocessableMessages(ctx, cfg, v2queues, dbClients.SharedDBClient) if err != nil { log.Fatal().Err(err).Msg("error while replaying unprocessable messages") } @@ -103,9 +103,9 @@ func main() { return } - queueClients.StartReceivingMessages() + v2queues.StartReceivingMessages() - healthcheckErr := healthcheck.StartHealthCheckCron(ctx, queueClients, cfg.Server.HealthCheckInterval) + healthcheckErr := healthcheck.StartHealthCheckCron(ctx, v2queues, cfg.Server.HealthCheckInterval) if healthcheckErr != nil { log.Fatal().Err(healthcheckErr).Msg("error while starting health check cron") } diff --git a/cmd/staking-api-service/scripts/replay_unprocessed_messages.go b/cmd/staking-api-service/scripts/replay_unprocessed_messages.go index 42cec480..f9e3cdf6 100644 --- a/cmd/staking-api-service/scripts/replay_unprocessed_messages.go +++ b/cmd/staking-api-service/scripts/replay_unprocessed_messages.go @@ -8,7 +8,7 @@ import ( "github.com/babylonlabs-io/staking-api-service/internal/shared/config" dbclient "github.com/babylonlabs-io/staking-api-service/internal/shared/db/client" - queueclients "github.com/babylonlabs-io/staking-api-service/internal/shared/queue/clients" + v2queue "github.com/babylonlabs-io/staking-api-service/internal/v2/queue" queueClient "github.com/babylonlabs-io/staking-queue-client/client" "github.com/rs/zerolog/log" ) @@ -17,7 +17,7 @@ type GenericEvent struct { EventType queueClient.EventType `json:"event_type"` } -func ReplayUnprocessableMessages(ctx context.Context, cfg *config.Config, queues *queueclients.QueueClients, db dbclient.DBClient) (err error) { +func ReplayUnprocessableMessages(ctx context.Context, cfg *config.Config, queues *v2queue.Queues, db dbclient.DBClient) (err error) { // Fetch unprocessable messages unprocessableMessages, err := db.FindUnprocessableMessages(ctx) if err != nil { @@ -55,20 +55,12 @@ func ReplayUnprocessableMessages(ctx context.Context, cfg *config.Config, queues } // processEventMessage processes the event message based on its EventType. -func processEventMessage(ctx context.Context, queues *queueclients.QueueClients, event GenericEvent, messageBody string) error { +func processEventMessage(ctx context.Context, queues *v2queue.Queues, event GenericEvent, messageBody string) error { switch event.EventType { case queueClient.ActiveStakingEventType: - return queues.V1QueueClient.ActiveStakingQueueClient.SendMessage(ctx, messageBody) + return queues.ActiveStakingQueueClient.SendMessage(ctx, messageBody) case queueClient.UnbondingStakingEventType: - return queues.V1QueueClient.UnbondingStakingQueueClient.SendMessage(ctx, messageBody) - case queueClient.WithdrawStakingEventType: - return queues.V1QueueClient.WithdrawStakingQueueClient.SendMessage(ctx, messageBody) - case queueClient.ExpiredStakingEventType: - return queues.V1QueueClient.ExpiredStakingQueueClient.SendMessage(ctx, messageBody) - case queueClient.StatsEventType: - return queues.V1QueueClient.StatsQueueClient.SendMessage(ctx, messageBody) - case queueClient.BtcInfoEventType: - return queues.V1QueueClient.BtcInfoQueueClient.SendMessage(ctx, messageBody) + return queues.UnbondingStakingQueueClient.SendMessage(ctx, messageBody) default: return fmt.Errorf("unknown event type: %v", event.EventType) } diff --git a/go.mod b/go.mod index a9e1c8dc..07516fa5 100644 --- a/go.mod +++ b/go.mod @@ -7,12 +7,11 @@ toolchain go1.23.3 require ( github.com/babylonlabs-io/babylon v0.17.2 github.com/babylonlabs-io/networks/parameters v0.2.2 - github.com/babylonlabs-io/staking-queue-client v0.4.7-0.20241129112518-b417aa03ec62 + github.com/babylonlabs-io/staking-queue-client v0.4.7-0.20241203052145-e50972fc19c9 github.com/btcsuite/btcd v0.24.2 github.com/btcsuite/btcd/btcec/v2 v2.3.2 github.com/btcsuite/btcd/btcutil v1.1.6 github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 - github.com/rabbitmq/amqp091-go v1.9.0 github.com/robfig/cron/v3 v3.0.1 github.com/spf13/viper v1.19.0 github.com/swaggo/swag v1.16.3 @@ -20,12 +19,7 @@ require ( ) require ( - cloud.google.com/go v0.112.1 // indirect - cloud.google.com/go/compute/metadata v0.5.0 // indirect - cloud.google.com/go/iam v1.1.6 // indirect - cloud.google.com/go/storage v1.38.0 // indirect cosmossdk.io/api v0.7.5 // indirect - cosmossdk.io/client/v2 v2.0.0-beta.1 // indirect cosmossdk.io/collections v0.4.0 // indirect cosmossdk.io/core v0.11.1 // indirect cosmossdk.io/depinject v1.0.0 // indirect @@ -33,32 +27,19 @@ require ( cosmossdk.io/log v1.4.1 // indirect cosmossdk.io/math v1.4.0 // indirect cosmossdk.io/store v1.1.0 // indirect - cosmossdk.io/x/circuit v0.1.1 // indirect - cosmossdk.io/x/evidence v0.1.1 // indirect - cosmossdk.io/x/feegrant v0.1.1 // indirect - cosmossdk.io/x/nft v0.1.1 // indirect cosmossdk.io/x/tx v0.13.4 // indirect - cosmossdk.io/x/upgrade v0.1.4 // indirect filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect - github.com/CosmWasm/wasmd v0.53.0 // indirect - github.com/CosmWasm/wasmvm/v2 v2.1.3 // indirect github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/DataDog/zstd v1.5.5 // indirect github.com/KyleBanks/depth v1.2.1 // indirect github.com/aead/siphash v1.0.1 // indirect - github.com/aws/aws-sdk-go v1.44.312 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect - github.com/bits-and-blooms/bitset v1.10.0 // indirect - github.com/boljen/go-bitmap v0.0.0-20151001105940-23cd2fb0ce7d // indirect github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect github.com/cenkalti/backoff/v4 v4.2.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/chzyer/readline v1.5.1 // indirect - github.com/cockroachdb/apd/v2 v2.0.2 // indirect github.com/cockroachdb/errors v1.11.3 // indirect github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect @@ -75,10 +56,6 @@ require ( github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/gogoproto v1.7.0 // indirect github.com/cosmos/iavl v1.2.0 // indirect - github.com/cosmos/ibc-go/modules/apps/callbacks v0.2.1-0.20231113120333-342c00b0f8bd // indirect - github.com/cosmos/ibc-go/modules/capability v1.0.1 // indirect - github.com/cosmos/ibc-go/modules/light-clients/08-wasm v0.0.0-20240429153234-e1e6da7e4ead // indirect - github.com/cosmos/ibc-go/v8 v8.4.0 // indirect github.com/cosmos/ics23/go v0.10.0 // indirect github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect github.com/danieljoos/wincred v1.1.2 // indirect @@ -88,97 +65,70 @@ require ( github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/dgraph-io/badger/v4 v4.3.0 // indirect github.com/dgraph-io/ristretto v0.1.2-0.20240116140435-c67e07994f91 // indirect - github.com/distribution/reference v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.6.0 // indirect github.com/emicklei/dot v1.6.1 // indirect - github.com/fatih/color v1.15.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/getsentry/sentry-go v0.27.0 // indirect github.com/go-kit/kit v0.13.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.4.1 // indirect - github.com/go-logr/stdr v1.2.2 // 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/gobwas/httphead v0.1.0 // indirect + github.com/gobwas/pool v0.2.1 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.3 // indirect github.com/google/flatbuffers v1.12.1 // indirect github.com/google/go-cmp v0.6.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/google/orderedcode v0.0.1 // indirect - github.com/google/s2a-go v0.1.7 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.3 // indirect github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect - github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-getter v1.7.5 // indirect - github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-metrics v0.5.3 // indirect - github.com/hashicorp/go-plugin v1.5.2 // indirect - github.com/hashicorp/go-safetemp v1.0.0 // indirect - github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/go-uuid v1.0.2 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect - github.com/hashicorp/yamux v0.1.1 // indirect github.com/hdevalence/ed25519consensus v0.1.0 // indirect - github.com/huandu/skiplist v1.2.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jinzhu/copier v0.3.5 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/kkdai/bstream v1.0.0 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect - github.com/lib/pq v1.10.9 // indirect github.com/linxGnu/grocksdb v1.9.3 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/manifoldco/promptui v0.9.0 // indirect - github.com/minio/highwayhash v1.0.3 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/mtibben/percent v0.2.1 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect - github.com/oklog/run v1.1.0 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.60.1 // indirect github.com/prometheus/procfs v0.15.1 // indirect + github.com/rabbitmq/amqp091-go v1.9.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/sasha-s/go-deadlock v0.3.5 // indirect - github.com/shamaton/msgpack/v2 v2.2.0 // indirect github.com/stretchr/objx v0.5.2 // indirect - github.com/supranational/blst v0.3.11 // indirect github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/tidwall/btree v1.7.0 // indirect - github.com/ulikunitz/xz v0.5.11 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect @@ -187,25 +137,16 @@ require ( github.com/zondax/ledger-go v0.14.3 // indirect go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect golang.org/x/crypto v0.28.0 // indirect golang.org/x/net v0.30.0 // indirect - golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/term v0.25.0 // indirect - golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect - google.golang.org/api v0.171.0 // indirect google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect google.golang.org/grpc v1.67.1 // indirect google.golang.org/protobuf v1.35.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gotest.tools/v3 v3.5.1 // indirect nhooyr.io/websocket v1.8.6 // indirect pgregory.net/rapid v1.1.0 // indirect @@ -233,7 +174,7 @@ require ( github.com/spf13/cast v1.7.0 // indirect github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.9.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/swaggo/http-swagger v1.3.4 go.mongodb.org/mongo-driver v1.14.0 diff --git a/go.sum b/go.sum index 716c0327..74929979 100644 --- a/go.sum +++ b/go.sum @@ -1,187 +1,14 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= -cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= -cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= -cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= -cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= -cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= -cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= -cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= -cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= -cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= -cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= -cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= -cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= -cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= -cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= -cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= -cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= -cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= -cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= -cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= -cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= -cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= -cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= -cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= -cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= -cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= -cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= -cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= -cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= -cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= -cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= -cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= -cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= -cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= -cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= -cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= -cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= -cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= -cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= -cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= -cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= -cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= -cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= -cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= -cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= -cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= -cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= -cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= -cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= -cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= -cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= -cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= -cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= -cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= -cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= -cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= -cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= -cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= -cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= -cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= -cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= -cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= -cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= -cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= -cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= -cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= -cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= -cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= -cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= -cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= -cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= -cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= -cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= -cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= -cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= -cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= -cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= -cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= -cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= -cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= -cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= -cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= -cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= -cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= -cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= -cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= -cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= -cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= -cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= -cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= -cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= -cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= -cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= -cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= -cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= -cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= -cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= -cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= -cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= -cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= -cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= -cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= -cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= -cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= -cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= -cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= -cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= cloud.google.com/go/storage v1.38.0 h1:Az68ZRGlnNTpIBbLjSMIV2BDcwwXYlRlQzis0llkpJg= cloud.google.com/go/storage v1.38.0/go.mod h1:tlUADB0mAb9BgYls9lq+8MGkfzOXuLrnHXlpHmvFJoY= -cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= -cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= -cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= -cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= -cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= -cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= -cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= -cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= -cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= -cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= -cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= cosmossdk.io/api v0.7.5 h1:eMPTReoNmGUm8DeiQL9DyM8sYDjEhWzL1+nLbI9DqtQ= cosmossdk.io/api v0.7.5/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= cosmossdk.io/client/v2 v2.0.0-beta.1 h1:XkHh1lhrLYIT9zKl7cIOXUXg2hdhtjTPBUfqERNA1/Q= @@ -219,8 +46,6 @@ github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMb github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o= github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/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/CosmWasm/wasmd v0.53.0 h1:kdaoAi20bIb4VCsxw9pRaT2g5PpIp82Wqrr9DRVN9ao= @@ -234,17 +59,10 @@ github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwS github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= 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/adlio/schema v1.3.6 h1:k1/zc2jNfeiZBA5aFTRy37jlBIuCkXCm0XmvpzCKI9I= -github.com/adlio/schema v1.3.6/go.mod h1:qkxwLgPBd1FgLRHYVCmQT/rrBr3JH38J9LjmVzWNudg= github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= @@ -262,7 +80,6 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.44.312 h1:llrElfzeqG/YOLFFKjg1xNpZCFJ2xraIi3PqSuP+95k= github.com/aws/aws-sdk-go v1.44.312/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= @@ -272,7 +89,8 @@ github.com/babylonlabs-io/networks/parameters v0.2.2 h1:TCu39fZvjX5f6ZZrjhYe54M6 github.com/babylonlabs-io/networks/parameters v0.2.2/go.mod h1:iEJVOzaLsE33vpP7J4u+CRGfkSIfErUAwRmgCFCBpyI= github.com/babylonlabs-io/staking-queue-client v0.4.7-0.20241129112518-b417aa03ec62 h1:lMj/YjQMUCaynl4EBOZIqQNvTX7muiNKhHeell2PRU4= github.com/babylonlabs-io/staking-queue-client v0.4.7-0.20241129112518-b417aa03ec62/go.mod h1:n3fr3c+9LNiJlyETmcrVk94Zn76rAADhGZKxX+rVf+Q= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/babylonlabs-io/staking-queue-client v0.4.7-0.20241203052145-e50972fc19c9 h1:4UGpRPm5oxj3P8QNrGrkiQtlQYTAgsWzXJFi8oD7zpY= +github.com/babylonlabs-io/staking-queue-client v0.4.7-0.20241203052145-e50972fc19c9/go.mod h1:n3fr3c+9LNiJlyETmcrVk94Zn76rAADhGZKxX+rVf+Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -314,38 +132,27 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= -github.com/bufbuild/protocompile v0.6.0 h1:Uu7WiSQ6Yj9DbkdnOe7U4mNKp58y9WDMKDn28/ZlunY= -github.com/bufbuild/protocompile v0.6.0/go.mod h1:YNP35qEYoYGme7QMtz5SBCoN4kL4g12jTtjuzRNdjpE= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= -github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= -github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= -github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 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/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= @@ -372,8 +179,6 @@ github.com/cometbft/cometbft v0.38.15 h1:5veFd8k1uXM27PBg9sMO3hAfRJ3vbh4OmmLf6cV github.com/cometbft/cometbft v0.38.15/go.mod h1:+wh6ap6xctVG+JOHwbl8pPKZ0GeqdPYqISu7F4b43cQ= github.com/cometbft/cometbft-db v0.15.0 h1:VLtsRt8udD4jHCyjvrsTBpgz83qne5hnL245AcPJVRk= github.com/cometbft/cometbft-db v0.15.0/go.mod h1:EBrFs1GDRiTqrWXYi4v90Awf/gcdD5ExzdPbg4X8+mk= -github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= -github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= @@ -436,10 +241,6 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WA github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= -github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 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= @@ -455,15 +256,11 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s 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/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= @@ -491,15 +288,12 @@ github.com/go-chi/chi v1.5.5 h1:vOB/HbEMt9QqBqErz07QehcOKHaWFtuj87tTDVz2qXE= github.com/go-chi/chi v1.5.5/go.mod h1:C9JqLr3tIYjDOZpzn+BCuxY8z8vmca43EeMgyZt7irw= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-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.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU= github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg= -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.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -507,7 +301,6 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/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/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -553,18 +346,10 @@ github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6x github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 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/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -572,7 +357,6 @@ github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -583,12 +367,10 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD 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.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= 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.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 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= @@ -602,16 +384,10 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.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.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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= @@ -619,55 +395,20 @@ github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= -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/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= -github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= 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= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -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-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0/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/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= -github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= @@ -742,14 +483,11 @@ github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbg github.com/hdevalence/ed25519consensus v0.1.0 h1:jtBwzzcHuTmFrQN6xQZn6CQEO/V9f7HsjsjeEZ6auqU= github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= -github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= github.com/huandu/skiplist v1.2.0 h1:gox56QD77HzSC0w+Ws3MH3iie755GBJU1OER3h5VsYw= github.com/huandu/skiplist v1.2.0/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -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/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= @@ -759,15 +497,11 @@ github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLf github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jhump/protoreflect v1.15.3 h1:6SFRuqU45u9hIZPJAoZ8c28T3nK64BNdp9w6jFonzls= -github.com/jhump/protoreflect v1.15.3/go.mod h1:4ORHmSBmlCW8fh3xHmJMGyul1zNqZK4Elxc8qKP+p1k= github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= @@ -784,8 +518,6 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.10/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/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= @@ -796,7 +528,6 @@ github.com/kkdai/bstream v1.0.0 h1:Se5gHwgp2VT2uHfDrkbbgbgEvV9cimLELwrPJctSjg8= github.com/kkdai/bstream v1.0.0/go.mod h1:FDnDOHt5Yx4p3FaHcioFT0QjDOtgUpvjeZqAs+NVZZA= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -828,20 +559,16 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12/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.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 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.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= @@ -913,10 +640,6 @@ github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdM github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= 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-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= -github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= -github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss= -github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -925,8 +648,6 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= -github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= @@ -1022,15 +743,12 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= 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= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= @@ -1084,12 +802,10 @@ github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI= github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/unrolled/secure v1.14.0 h1:u9vJTU/pR4Bny0ntLUMxdfLtmIRGvQf2sEFuA0TG9AE= @@ -1107,11 +823,8 @@ github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gi github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= -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/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U= github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= @@ -1125,13 +838,7 @@ go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 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.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= 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/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= @@ -1142,33 +849,26 @@ go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= -go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= 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.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= 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.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.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/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-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-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1178,14 +878,6 @@ golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= 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= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -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-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8= golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= @@ -1195,25 +887,13 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.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.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= @@ -1230,81 +910,31 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 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= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 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-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-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1313,14 +943,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/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.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1336,9 +960,6 @@ golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7w 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-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1348,99 +969,49 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/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-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/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-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/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-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/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-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= -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.5/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.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 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= @@ -1449,61 +1020,18 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 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-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-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= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -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= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -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-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-20201224043029-2b0845dc783e/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.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -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.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= @@ -1511,178 +1039,25 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T 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= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= -google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= -google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= -google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= google.golang.org/api v0.171.0 h1:w174hnBPqut76FzW5Qaupt7zY8Kql6fiVjgys4f58sU= google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200324203455-a04cca1dde73/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= -google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= -google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= -google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= -google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= @@ -1694,45 +1069,22 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= 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.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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= @@ -1746,7 +1098,6 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba 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.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= @@ -1758,7 +1109,6 @@ gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8 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/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= @@ -1786,19 +1136,12 @@ gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -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= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw= pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= -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= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/internal/indexer/types/delegation_state.go b/internal/indexer/types/delegation_state.go index 3060759d..2f9b692e 100644 --- a/internal/indexer/types/delegation_state.go +++ b/internal/indexer/types/delegation_state.go @@ -13,6 +13,10 @@ const ( StateSlashed DelegationState = "SLASHED" ) +func (s DelegationState) String() string { + return string(s) +} + type DelegationSubState string const ( diff --git a/internal/shared/observability/healthcheck/healthcheck.go b/internal/shared/observability/healthcheck/healthcheck.go index 903e9ef5..2cd5cf1e 100644 --- a/internal/shared/observability/healthcheck/healthcheck.go +++ b/internal/shared/observability/healthcheck/healthcheck.go @@ -5,8 +5,7 @@ import ( "fmt" "github.com/babylonlabs-io/staking-api-service/internal/shared/observability/metrics" - queueclient "github.com/babylonlabs-io/staking-api-service/internal/shared/queue/client" - queueclients "github.com/babylonlabs-io/staking-api-service/internal/shared/queue/clients" + v2queue "github.com/babylonlabs-io/staking-api-service/internal/v2/queue" "github.com/robfig/cron/v3" "github.com/rs/zerolog" "github.com/rs/zerolog/log" @@ -18,7 +17,7 @@ func SetLogger(customLogger zerolog.Logger) { logger = customLogger } -func StartHealthCheckCron(ctx context.Context, queueClients *queueclients.QueueClients, cronTime int) error { +func StartHealthCheckCron(ctx context.Context, queues *v2queue.Queues, cronTime int) error { c := cron.New() logger.Info().Msg("Initiated Health Check Cron") @@ -29,7 +28,7 @@ func StartHealthCheckCron(ctx context.Context, queueClients *queueclients.QueueC cronSpec := fmt.Sprintf("@every %ds", cronTime) _, err := c.AddFunc(cronSpec, func() { - queueHealthCheck(queueClients.V1QueueClient) + queueHealthCheck(queues) }) if err != nil { @@ -47,8 +46,8 @@ func StartHealthCheckCron(ctx context.Context, queueClients *queueclients.QueueC return nil } -func queueHealthCheck(queueClient queueclient.QueueClient) { - if err := queueClient.IsConnectionHealthy(); err != nil { +func queueHealthCheck(queues *v2queue.Queues) { + if err := queues.IsConnectionHealthy(); err != nil { logger.Error().Err(err).Msg("One or more queue connections are not healthy.") // Record service unavailable in metrics metrics.RecordServiceCrash("queue") diff --git a/internal/shared/queue/REAME.md b/internal/shared/queue/REAME.md deleted file mode 100644 index 2c52d864..00000000 --- a/internal/shared/queue/REAME.md +++ /dev/null @@ -1,33 +0,0 @@ -# Event Message Processing Guidelines - -In our system, message delivery adheres to three foundational principles to ensure robust and reliable event handling: - -1. **Guarantee of Message Delivery**: No message will be lost. -2. **Handling Out-of-Order Messages**: Messages may arrive in an unexpected order. -3. **Duplicate Message Management**: The system can receive duplicate messages. - -When designing or implementing handlers, adherence to these principles is paramount. This ensures that event processing is resilient, idempotent, and consistent. - -## Implementation Example: ActiveStakingHandler - -The `ActiveStakingHandler` exemplifies our approach to preserving these rules through careful design and strategic method ordering. - -### Design Rationale - -This handler prioritizes event processing integrity, especially in scenarios involving service interruptions. By positioning the `SaveActiveStakingDelegation` operation at the end, we mitigate risks associated with partial processing due to unexpected system restarts or failures. - -### Problem Addressed - -Interruptions after a state update but before completion of all intended operations could lead to requeued messages being incorrectly assumed as fully processed. This misassumption risks omitting unexecuted operations, compromising data integrity and processing completeness. - -### Solution Strategy - -To counteract this, we ensure that state-changing operations occur only after all checks and preparatory actions have succeeded. If a message is reprocessed, the system reattempts all operations, safeguarding against lost actions. This approach demands each component be capable of handling duplicates and out-of-order messages effectively. - -## TL;DR: Event Processing Steps - -1. **Eligibility Verification**: Initially, verify the event's relevance and timeliness. Disregard or requeue messages as appropriate based on their current applicability. -2. **Custom Logic Execution**: Implement your specific logic (e.g., statistics calculations, expiration checks) with resilience to duplication and out-of-order scenarios. -3. **State Alteration**: Conclude with state-changing actions, ensuring no prior steps are skipped or lost due to message reprocessing. - -By following these guidelines, handlers within the system maintain a high degree of resilience and data integrity, even in the face of challenges like service interruptions and message anomalies. diff --git a/internal/shared/queue/client/client.go b/internal/shared/queue/client/client.go deleted file mode 100644 index 744a3954..00000000 --- a/internal/shared/queue/client/client.go +++ /dev/null @@ -1,55 +0,0 @@ -package queueclient - -import ( - "context" - "net/http" - "time" - - "github.com/babylonlabs-io/staking-api-service/internal/shared/observability/tracing" - "github.com/babylonlabs-io/staking-api-service/internal/shared/services" - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - - "github.com/babylonlabs-io/staking-queue-client/client" - queueConfig "github.com/babylonlabs-io/staking-queue-client/config" - "github.com/rs/zerolog/log" -) - -type Queue struct { - ProcessingTimeout time.Duration - MaxRetryAttempts int32 - StatsQueueClient client.QueueClient -} - -func New(ctx context.Context, cfg *queueConfig.QueueConfig, service *services.Services) *Queue { - statsQueueClient, err := client.NewQueueClient( - cfg, client.StakingStatsQueueName, - ) - if err != nil { - log.Fatal().Err(err).Msg("error while creating StatsQueueClient") - } - - return &Queue{ - ProcessingTimeout: cfg.QueueProcessingTimeout, - MaxRetryAttempts: cfg.MsgMaxRetryAttempts, - StatsQueueClient: statsQueueClient, - } -} - -func attachLoggerContext(ctx context.Context, message client.QueueMessage, queueClient client.QueueClient) context.Context { - ctx = tracing.AttachTracingIntoContext(ctx) - - traceId := ctx.Value(tracing.TraceIdKey) - return log.With(). - Str("receipt", message.Receipt). - Str("queueName", queueClient.GetQueueName()). - Interface("traceId", traceId). - Logger().WithContext(ctx) -} - -func recordErrorLog(err *types.Error) { - if err.StatusCode >= http.StatusInternalServerError { - log.Error().Err(err).Msg("event processing failed with 5xx error") - } else { - log.Warn().Err(err).Msg("event processing failed with 4xx error") - } -} diff --git a/internal/shared/queue/client/interface.go b/internal/shared/queue/client/interface.go deleted file mode 100644 index d6a1efb5..00000000 --- a/internal/shared/queue/client/interface.go +++ /dev/null @@ -1,7 +0,0 @@ -package queueclient - -type QueueClient interface { - StartReceivingMessages() - StopReceivingMessages() - IsConnectionHealthy() error -} diff --git a/internal/shared/queue/client/message.go b/internal/shared/queue/client/message.go deleted file mode 100644 index 9c878790..00000000 --- a/internal/shared/queue/client/message.go +++ /dev/null @@ -1,92 +0,0 @@ -package queueclient - -import ( - "context" - "net/http" - "time" - - "github.com/babylonlabs-io/staking-api-service/internal/shared/observability/metrics" - "github.com/babylonlabs-io/staking-api-service/internal/shared/observability/tracing" - queuehandler "github.com/babylonlabs-io/staking-api-service/internal/shared/queue/handler" - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - "github.com/babylonlabs-io/staking-queue-client/client" - "github.com/rs/zerolog/log" -) - -func StartQueueMessageProcessing( - queueClient client.QueueClient, - handler queuehandler.MessageHandler, unprocessableHandler queuehandler.UnprocessableMessageHandler, - maxRetryAttempts int32, processingTimeout time.Duration, -) { - messagesChan, err := queueClient.ReceiveMessages() - log.Info().Str("queueName", queueClient.GetQueueName()).Msg("start receiving messages from queue") - if err != nil { - log.Fatal().Err(err).Str("queueName", queueClient.GetQueueName()).Msg("error setting up message channel from queue") - } - - go func() { - for message := range messagesChan { - attempts := message.GetRetryAttempts() - // For each message, create a new context with a deadline or timeout - ctx, cancel := context.WithTimeout(context.Background(), processingTimeout) - ctx = attachLoggerContext(ctx, message, queueClient) - // Attach the tracingInfo for the message processing - _, err := tracing.WrapWithSpan[any](ctx, "message_processing", func() (any, *types.Error) { - timer := metrics.StartEventProcessingDurationTimer(queueClient.GetQueueName(), attempts) - // Process the message - err := handler(ctx, message.Body) - if err != nil { - timer(err.StatusCode) - } else { - timer(http.StatusOK) - } - return nil, err - }) - if err != nil { - recordErrorLog(err) - // We will retry the message if it has not exceeded the max retry attempts - // otherwise, we will dump the message into db for manual inspection and remove from the queue - if attempts > maxRetryAttempts { - log.Ctx(ctx).Error().Err(err). - Msg("exceeded retry attempts, message will be dumped into db for manual inspection") - metrics.RecordUnprocessableEntity(queueClient.GetQueueName()) - saveUnprocessableMsgErr := unprocessableHandler(ctx, message.Body, message.Receipt) - if saveUnprocessableMsgErr != nil { - log.Ctx(ctx).Error().Err(saveUnprocessableMsgErr). - Msg("error while saving unprocessable message") - metrics.RecordQueueOperationFailure("unprocessableHandler", queueClient.GetQueueName()) - cancel() - continue - } - } else { - log.Ctx(ctx).Error().Err(err). - Msg("error while processing message from queue, will be requeued") - reQueueErr := queueClient.ReQueueMessage(ctx, message) - if reQueueErr != nil { - log.Ctx(ctx).Error().Err(reQueueErr). - Msg("error while requeuing message") - metrics.RecordQueueOperationFailure("reQueueMessage", queueClient.GetQueueName()) - } - cancel() - continue - } - } - - delErr := queueClient.DeleteMessage(message.Receipt) - if delErr != nil { - log.Ctx(ctx).Error().Err(delErr). - Msg("error while deleting message from queue") - metrics.RecordQueueOperationFailure("deleteMessage", queueClient.GetQueueName()) - } - - tracingInfo := ctx.Value(tracing.TracingInfoKey) - logEvent := log.Ctx(ctx).Debug() - if tracingInfo != nil { - logEvent = logEvent.Interface("tracingInfo", tracingInfo) - } - logEvent.Msg("message processed successfully") - cancel() - } - log.Info().Str("queueName", queueClient.GetQueueName()).Msg("stopped receiving messages from queue") - }() -} diff --git a/internal/shared/queue/clients/clients.go b/internal/shared/queue/clients/clients.go deleted file mode 100644 index 90deabdd..00000000 --- a/internal/shared/queue/clients/clients.go +++ /dev/null @@ -1,42 +0,0 @@ -package queueclients - -import ( - "context" - - queueclient "github.com/babylonlabs-io/staking-api-service/internal/shared/queue/client" - queuehandler "github.com/babylonlabs-io/staking-api-service/internal/shared/queue/handler" - queuehandlers "github.com/babylonlabs-io/staking-api-service/internal/shared/queue/handlers" - "github.com/babylonlabs-io/staking-api-service/internal/shared/services" - v1queueclient "github.com/babylonlabs-io/staking-api-service/internal/v1/queue/client" - v2queueclient "github.com/babylonlabs-io/staking-api-service/internal/v2/queue/client" - queueConfig "github.com/babylonlabs-io/staking-queue-client/config" - "github.com/rs/zerolog/log" -) - -type QueueClients struct { - V1QueueClient *v1queueclient.V1QueueClient - V2QueueClient *v2queueclient.V2QueueClient -} - -func New(ctx context.Context, cfg *queueConfig.QueueConfig, services *services.Services) *QueueClients { - queueClient := queueclient.New(ctx, cfg, services) - queueHandler := queuehandler.New(queueClient.StatsQueueClient.SendMessage) - queueHandlers, err := queuehandlers.New(services, queueHandler) - if err != nil { - log.Fatal().Err(err).Msg("error while setting up queue handlers") - } - - v1QueueClient := v1queueclient.New(cfg, queueHandlers.V1QueueHandler, queueClient) - v2QueueClient := v2queueclient.New(cfg, queueHandlers.V2QueueHandler, queueClient) - - return &QueueClients{ - V1QueueClient: v1QueueClient, - V2QueueClient: v2QueueClient, - } -} - -func (q *QueueClients) StartReceivingMessages() { - log.Printf("Starting to receive messages from queue clients") - q.V1QueueClient.StartReceivingMessages() - q.V2QueueClient.StartReceivingMessages() -} diff --git a/internal/shared/queue/handler/handler.go b/internal/shared/queue/handler/handler.go deleted file mode 100644 index 1f92b055..00000000 --- a/internal/shared/queue/handler/handler.go +++ /dev/null @@ -1,42 +0,0 @@ -package queuehandler - -import ( - "context" - "encoding/json" - "net/http" - - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - queueclient "github.com/babylonlabs-io/staking-queue-client/client" - "github.com/rs/zerolog/log" -) - -type QueueHandler struct { - emitStatsEvent func(ctx context.Context, messageBody string) error -} - -type MessageHandler func(ctx context.Context, messageBody string) *types.Error -type UnprocessableMessageHandler func(ctx context.Context, messageBody, receipt string) *types.Error - -func New( - emitStatsEvent func(ctx context.Context, messageBody string) error, -) *QueueHandler { - return &QueueHandler{ - emitStatsEvent: emitStatsEvent, - } -} - -func (qh *QueueHandler) EmitStatsEvent(ctx context.Context, statsEvent queueclient.StatsEvent) *types.Error { - jsonData, err := json.Marshal(statsEvent) - if err != nil { - log.Ctx(ctx).Err(err).Msg("Failed to marshal the stats event") - return types.NewError(http.StatusBadRequest, types.BadRequest, err) - } - - err = qh.emitStatsEvent(ctx, string(jsonData)) - - if err != nil { - log.Ctx(ctx).Err(err).Msg("Failed to emit the stats event") - return types.NewError(http.StatusInternalServerError, types.InternalServiceError, err) - } - return nil -} diff --git a/internal/shared/queue/handlers/handlers.go b/internal/shared/queue/handlers/handlers.go deleted file mode 100644 index 2ad98b99..00000000 --- a/internal/shared/queue/handlers/handlers.go +++ /dev/null @@ -1,20 +0,0 @@ -package queuehandlers - -import ( - queuehandler "github.com/babylonlabs-io/staking-api-service/internal/shared/queue/handler" - "github.com/babylonlabs-io/staking-api-service/internal/shared/services" - v1queuehandler "github.com/babylonlabs-io/staking-api-service/internal/v1/queue/handler" - v2queuehandler "github.com/babylonlabs-io/staking-api-service/internal/v2/queue/handler" -) - -type QueueHandlers struct { - V1QueueHandler *v1queuehandler.V1QueueHandler - V2QueueHandler *v2queuehandler.V2QueueHandler -} - -func New(services *services.Services, queueHandler *queuehandler.QueueHandler) (*QueueHandlers, error) { - return &QueueHandlers{ - V1QueueHandler: v1queuehandler.New(queueHandler, services.V1Service), - V2QueueHandler: v2queuehandler.New(queueHandler, services.V2Service), - }, nil -} diff --git a/internal/v1/queue/client/client.go b/internal/v1/queue/client/client.go deleted file mode 100644 index 2618bfc5..00000000 --- a/internal/v1/queue/client/client.go +++ /dev/null @@ -1,63 +0,0 @@ -package v1queueclient - -import ( - queueclient "github.com/babylonlabs-io/staking-api-service/internal/shared/queue/client" - v1queuehandler "github.com/babylonlabs-io/staking-api-service/internal/v1/queue/handler" - client "github.com/babylonlabs-io/staking-queue-client/client" - queueConfig "github.com/babylonlabs-io/staking-queue-client/config" - "github.com/rs/zerolog/log" -) - -type V1QueueClient struct { - *queueclient.Queue - Handler *v1queuehandler.V1QueueHandler - ActiveStakingQueueClient client.QueueClient - ExpiredStakingQueueClient client.QueueClient - UnbondingStakingQueueClient client.QueueClient - WithdrawStakingQueueClient client.QueueClient - BtcInfoQueueClient client.QueueClient -} - -func New(cfg *queueConfig.QueueConfig, handler *v1queuehandler.V1QueueHandler, queueClient *queueclient.Queue) *V1QueueClient { - activeStakingQueueClient, err := client.NewQueueClient( - cfg, client.ActiveStakingQueueName, - ) - if err != nil { - log.Fatal().Err(err).Msg("error while creating ActiveStakingQueueClient") - } - - expiredStakingQueueClient, err := client.NewQueueClient( - cfg, client.ExpiredStakingQueueName, - ) - if err != nil { - log.Fatal().Err(err).Msg("error while creating ExpiredStakingQueueClient") - } - - unbondingStakingQueueClient, err := client.NewQueueClient( - cfg, client.UnbondingStakingQueueName, - ) - if err != nil { - log.Fatal().Err(err).Msg("error while creating UnbondingStakingQueueClient") - } - withdrawStakingQueueClient, err := client.NewQueueClient( - cfg, client.WithdrawStakingQueueName, - ) - if err != nil { - log.Fatal().Err(err).Msg("error while creating WithdrawStakingQueueClient") - } - btcInfoQueueClient, err := client.NewQueueClient( - cfg, client.BtcInfoQueueName, - ) - if err != nil { - log.Fatal().Err(err).Msg("error while creating BtcInfoQueueClient") - } - return &V1QueueClient{ - Queue: queueClient, - Handler: handler, - ActiveStakingQueueClient: activeStakingQueueClient, - ExpiredStakingQueueClient: expiredStakingQueueClient, - UnbondingStakingQueueClient: unbondingStakingQueueClient, - WithdrawStakingQueueClient: withdrawStakingQueueClient, - BtcInfoQueueClient: btcInfoQueueClient, - } -} diff --git a/internal/v1/queue/client/health.go b/internal/v1/queue/client/health.go deleted file mode 100644 index eb1d5399..00000000 --- a/internal/v1/queue/client/health.go +++ /dev/null @@ -1,35 +0,0 @@ -package v1queueclient - -import ( - "context" - "fmt" - "strings" - "time" - - "github.com/babylonlabs-io/staking-queue-client/client" -) - -func (q *V1QueueClient) IsConnectionHealthy() error { - var errorMessages []string - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - checkQueue := func(name string, client client.QueueClient) { - if err := client.Ping(ctx); err != nil { - errorMessages = append(errorMessages, fmt.Sprintf("%s is not healthy: %v", name, err)) - } - } - - checkQueue("ActiveStakingQueueClient", q.ActiveStakingQueueClient) - checkQueue("ExpiredStakingQueueClient", q.ExpiredStakingQueueClient) - checkQueue("UnbondingStakingQueueClient", q.UnbondingStakingQueueClient) - checkQueue("WithdrawStakingQueueClient", q.WithdrawStakingQueueClient) - checkQueue("StatsQueueClient", q.StatsQueueClient) - checkQueue("BtcInfoQueueClient", q.BtcInfoQueueClient) - - if len(errorMessages) > 0 { - return fmt.Errorf(strings.Join(errorMessages, "; ")) - } - return nil -} diff --git a/internal/v1/queue/client/message.go b/internal/v1/queue/client/message.go deleted file mode 100644 index a65c1ae7..00000000 --- a/internal/v1/queue/client/message.go +++ /dev/null @@ -1,88 +0,0 @@ -package v1queueclient - -import ( - queueclient "github.com/babylonlabs-io/staking-api-service/internal/shared/queue/client" - "github.com/rs/zerolog/log" -) - -func (q *V1QueueClient) StartReceivingMessages() { - log.Printf("Starting to receive messages from v1 queues") - // start processing messages from the active staking queue - queueclient.StartQueueMessageProcessing( - q.ActiveStakingQueueClient, - q.Handler.ActiveStakingHandler, q.Handler.HandleUnprocessedMessage, - q.MaxRetryAttempts, q.ProcessingTimeout, - ) - log.Printf("Starting to receive messages from expired staking queue") - queueclient.StartQueueMessageProcessing( - q.ExpiredStakingQueueClient, - q.Handler.ExpiredStakingHandler, q.Handler.HandleUnprocessedMessage, - q.MaxRetryAttempts, q.ProcessingTimeout, - ) - log.Printf("Starting to receive messages from unbonding staking queue") - queueclient.StartQueueMessageProcessing( - q.UnbondingStakingQueueClient, - q.Handler.UnbondingStakingHandler, q.Handler.HandleUnprocessedMessage, - q.MaxRetryAttempts, q.ProcessingTimeout, - ) - log.Printf("Starting to receive messages from withdraw staking queue") - queueclient.StartQueueMessageProcessing( - q.WithdrawStakingQueueClient, - q.Handler.WithdrawStakingHandler, q.Handler.HandleUnprocessedMessage, - q.MaxRetryAttempts, q.ProcessingTimeout, - ) - log.Printf("Starting to receive messages from stats queue") - queueclient.StartQueueMessageProcessing( - q.StatsQueueClient, - q.Handler.StatsHandler, q.Handler.HandleUnprocessedMessage, - q.MaxRetryAttempts, q.ProcessingTimeout, - ) - log.Printf("Starting to receive messages from btc info queue") - queueclient.StartQueueMessageProcessing( - q.BtcInfoQueueClient, - q.Handler.BtcInfoHandler, q.Handler.HandleUnprocessedMessage, - q.MaxRetryAttempts, q.ProcessingTimeout, - ) - // ...add more queues here -} - -// Turn off all message processing -func (q *V1QueueClient) StopReceivingMessages() { - activeQueueErr := q.ActiveStakingQueueClient.Stop() - if activeQueueErr != nil { - log.Error().Err(activeQueueErr). - Str("queueName", q.ActiveStakingQueueClient.GetQueueName()). - Msg("error while stopping queue") - } - expiredQueueErr := q.ExpiredStakingQueueClient.Stop() - if expiredQueueErr != nil { - log.Error().Err(expiredQueueErr). - Str("queueName", q.ExpiredStakingQueueClient.GetQueueName()). - Msg("error while stopping queue") - } - unbondingQueueErr := q.UnbondingStakingQueueClient.Stop() - if unbondingQueueErr != nil { - log.Error().Err(unbondingQueueErr). - Str("queueName", q.UnbondingStakingQueueClient.GetQueueName()). - Msg("error while stopping queue") - } - withdrawnQueueErr := q.WithdrawStakingQueueClient.Stop() - if withdrawnQueueErr != nil { - log.Error().Err(withdrawnQueueErr). - Str("queueName", q.WithdrawStakingQueueClient.GetQueueName()). - Msg("error while stopping queue") - } - statsQueueErr := q.StatsQueueClient.Stop() - if statsQueueErr != nil { - log.Error().Err(statsQueueErr). - Str("queueName", q.StatsQueueClient.GetQueueName()). - Msg("error while stopping queue") - } - btcInfoQueueErr := q.BtcInfoQueueClient.Stop() - if btcInfoQueueErr != nil { - log.Error().Err(btcInfoQueueErr). - Str("queueName", q.BtcInfoQueueClient.GetQueueName()). - Msg("error while stopping queue") - } - // ...add more queues here -} diff --git a/internal/v1/queue/handler/active_staking.go b/internal/v1/queue/handler/active_staking.go deleted file mode 100644 index 373eb397..00000000 --- a/internal/v1/queue/handler/active_staking.go +++ /dev/null @@ -1,76 +0,0 @@ -package v1queuehandler - -import ( - "context" - "encoding/json" - "net/http" - - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - queueClient "github.com/babylonlabs-io/staking-queue-client/client" - "github.com/rs/zerolog/log" -) - -// ActiveStakingHandler handles the active staking event -// This handler is designed to be idempotent, capable of handling duplicate messages gracefully. -// It can also resume from the next step if a previous step fails, ensuring robustness in the event processing workflow. -func (h *V1QueueHandler) ActiveStakingHandler(ctx context.Context, messageBody string) *types.Error { - // Parse the message body into ActiveStakingEvent - var activeStakingEvent queueClient.ActiveStakingEvent - err := json.Unmarshal([]byte(messageBody), &activeStakingEvent) - if err != nil { - log.Ctx(ctx).Error().Err(err).Msg("Failed to unmarshal the message body into ActiveStakingEvent") - return types.NewError(http.StatusBadRequest, types.BadRequest, err) - } - - // Check if delegation already exists - exist, delError := h.Service.IsDelegationPresent(ctx, activeStakingEvent.StakingTxHashHex) - if delError != nil { - return delError - } - if exist { - // Ignore the message as the delegation already exists. This is a duplicate message - log.Ctx(ctx).Debug().Str("StakingTxHashHex", activeStakingEvent.StakingTxHashHex). - Msg("delegation already exists") - return nil - } - - // Perform the async metadata calculation by emit the stats event - statsError := h.EmitStatsEvent(ctx, queueClient.NewStatsEvent( - activeStakingEvent.StakingTxHashHex, - activeStakingEvent.StakerPkHex, - activeStakingEvent.FinalityProviderPkHex, - activeStakingEvent.StakingValue, - types.Active.ToString(), - activeStakingEvent.IsOverflow, - )) - if statsError != nil { - log.Ctx(ctx).Error().Err(statsError).Msg("Failed to emit stats event for active staking") - return statsError - } - - // Perform the async timelock expire check - expireCheckError := h.Service.ProcessExpireCheck( - ctx, activeStakingEvent.StakingTxHashHex, - activeStakingEvent.StakingStartHeight, - activeStakingEvent.StakingTimeLock, - types.ActiveTxType, - ) - if expireCheckError != nil { - return expireCheckError - } - - // Save the active staking delegation. This is the final step in the active staking event processing - // Please refer to the README.md for the details on the active staking event processing workflow - saveErr := h.Service.SaveActiveStakingDelegation( - ctx, activeStakingEvent.StakingTxHashHex, activeStakingEvent.StakerPkHex, - activeStakingEvent.FinalityProviderPkHex, activeStakingEvent.StakingValue, - activeStakingEvent.StakingStartHeight, activeStakingEvent.StakingStartTimestamp, - activeStakingEvent.StakingTimeLock, activeStakingEvent.StakingOutputIndex, - activeStakingEvent.StakingTxHex, activeStakingEvent.IsOverflow, - ) - if saveErr != nil { - return saveErr - } - - return nil -} diff --git a/internal/v1/queue/handler/btc_info.go b/internal/v1/queue/handler/btc_info.go deleted file mode 100644 index a6bc9de3..00000000 --- a/internal/v1/queue/handler/btc_info.go +++ /dev/null @@ -1,29 +0,0 @@ -package v1queuehandler - -import ( - "context" - "encoding/json" - "net/http" - - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - queueClient "github.com/babylonlabs-io/staking-queue-client/client" - "github.com/rs/zerolog/log" -) - -func (h *V1QueueHandler) BtcInfoHandler(ctx context.Context, messageBody string) *types.Error { - var btcInfo queueClient.BtcInfoEvent - err := json.Unmarshal([]byte(messageBody), &btcInfo) - if err != nil { - log.Ctx(ctx).Error().Err(err).Msg("Failed to unmarshal the message body into btcInfo") - return types.NewError(http.StatusBadRequest, types.BadRequest, err) - } - - statsErr := h.Service.ProcessBtcInfoStats( - ctx, btcInfo.Height, btcInfo.ConfirmedTvl, btcInfo.UnconfirmedTvl, - ) - if statsErr != nil { - log.Error().Err(statsErr).Msg("Failed to process unconfirmed tvl stats") - return types.NewInternalServiceError(statsErr) - } - return nil -} diff --git a/internal/v1/queue/handler/expired_staking.go b/internal/v1/queue/handler/expired_staking.go deleted file mode 100644 index f7da1b59..00000000 --- a/internal/v1/queue/handler/expired_staking.go +++ /dev/null @@ -1,49 +0,0 @@ -package v1queuehandler - -import ( - "context" - "encoding/json" - "net/http" - - queueClient "github.com/babylonlabs-io/staking-queue-client/client" - "github.com/rs/zerolog/log" - - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - "github.com/babylonlabs-io/staking-api-service/internal/shared/utils" -) - -func (h *V1QueueHandler) ExpiredStakingHandler(ctx context.Context, messageBody string) *types.Error { - var expiredStakingEvent queueClient.ExpiredStakingEvent - err := json.Unmarshal([]byte(messageBody), &expiredStakingEvent) - if err != nil { - log.Ctx(ctx).Error().Err(err).Msg("Failed to unmarshal the message body into expiredStakingEvent") - return types.NewError(http.StatusBadRequest, types.BadRequest, err) - } - - // Check if the delegation is in the right state to process the unbonded(timelock expire) event - del, delErr := h.Service.GetDelegation(ctx, expiredStakingEvent.StakingTxHashHex) - // Requeue if found any error. Including not found error - if delErr != nil { - return delErr - } - state := types.DelegationState(del.State) - if utils.Contains(utils.OutdatedStatesForUnbonded(), state) { - // Ignore the message as the delegation state already passed the unbonded state. This is an outdated duplication - log.Ctx(ctx).Debug().Str("StakingTxHashHex", expiredStakingEvent.StakingTxHashHex). - Msg("delegation state is outdated for unbonded event") - return nil - } - - txType, err := types.StakingTxTypeFromString(expiredStakingEvent.TxType) - if err != nil { - log.Ctx(ctx).Error().Err(err).Str("TxType", expiredStakingEvent.TxType).Msg("Failed to convert TxType from string") - return types.NewError(http.StatusBadRequest, types.BadRequest, err) - } - - transitionErr := h.Service.TransitionToUnbondedState(ctx, txType, expiredStakingEvent.StakingTxHashHex) - if transitionErr != nil { - return transitionErr - } - - return nil -} diff --git a/internal/v1/queue/handler/handler.go b/internal/v1/queue/handler/handler.go deleted file mode 100644 index 33273c54..00000000 --- a/internal/v1/queue/handler/handler.go +++ /dev/null @@ -1,25 +0,0 @@ -package v1queuehandler - -import ( - "context" - - queuehandler "github.com/babylonlabs-io/staking-api-service/internal/shared/queue/handler" - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - v1service "github.com/babylonlabs-io/staking-api-service/internal/v1/service" -) - -type V1QueueHandler struct { - *queuehandler.QueueHandler - Service v1service.V1ServiceProvider -} - -func New(queueHandler *queuehandler.QueueHandler, service v1service.V1ServiceProvider) *V1QueueHandler { - return &V1QueueHandler{ - QueueHandler: queueHandler, - Service: service, - } -} - -func (qh *V1QueueHandler) HandleUnprocessedMessage(ctx context.Context, messageBody, receipt string) *types.Error { - return qh.Service.SaveUnprocessableMessages(ctx, messageBody, receipt) -} diff --git a/internal/v1/queue/handler/stats.go b/internal/v1/queue/handler/stats.go deleted file mode 100644 index 690e1b72..00000000 --- a/internal/v1/queue/handler/stats.go +++ /dev/null @@ -1,89 +0,0 @@ -package v1queuehandler - -import ( - "context" - "encoding/json" - "net/http" - - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - queueClient "github.com/babylonlabs-io/staking-queue-client/client" - "github.com/rs/zerolog/log" -) - -// StatsHandler handles the processing of stats event from the message queue. -// This handler is responsible for processing non-critical events such as -// statistics calculations and other metadata-related tasks. -// It performs the following operations: -// 1. If the event corresponds to an active delegation, it transforms the staker's public key -// into corresponding BTC addresses for lookup purposes, and saves them to the database. -// 2. Executes the staking statistics calculation using the provided event data. -// -// If any step fails, it logs the error and returns a corresponding error response. -// which will be sent back to the message queue for later retry -func (h *V1QueueHandler) StatsHandler(ctx context.Context, messageBody string) *types.Error { - var statsEvent queueClient.StatsEvent - err := json.Unmarshal([]byte(messageBody), &statsEvent) - if err != nil { - log.Ctx(ctx).Error().Err(err).Msg("Failed to unmarshal the message body into statsEvent") - return types.NewError(http.StatusBadRequest, types.BadRequest, err) - } - - state, err := types.FromStringToDelegationState(statsEvent.State) - if err != nil { - log.Ctx(ctx).Error().Err(err).Msg("Failed to convert statsEvent.State to DelegationState") - return types.NewError(http.StatusBadRequest, types.BadRequest, err) - } - // For backwards compatibility reason, we will check msg version to determine - // if we need to look up the overflow status from db - // in version 1, we added the new field IsOverflow to the event - // Below code will be removed after service being fully rollout - isOverflow := statsEvent.IsOverflow - if statsEvent.SchemaVersion < 1 { - // Look up the overflow status from the database - overflow, overflowErr := h.Service.GetDelegation(ctx, statsEvent.GetStakingTxHashHex()) - if overflowErr != nil { - log.Ctx(ctx).Error().Err(overflowErr).Msg("Failed to get overflow status") - return overflowErr - } - isOverflow = overflow.IsOverflow - } - - // Perform the address lookup conversion - addressLookupErr := h.performAddressLookupConversion(ctx, statsEvent.StakerPkHex, state) - if addressLookupErr != nil { - return addressLookupErr - } - - // Perform the stats calculation only if the event is not an overflow event - if !isOverflow { - // Perform the stats calculation - statsErr := h.Service.ProcessStakingStatsCalculation( - ctx, statsEvent.StakingTxHashHex, - statsEvent.StakerPkHex, - statsEvent.FinalityProviderPkHex, - state, - statsEvent.StakingValue, - ) - if statsErr != nil { - log.Ctx(ctx).Error().Err(statsErr).Msg("Failed to process staking stats calculation") - return statsErr - } - } - return nil -} - -// Convert the staker's public key into corresponding BTC addresses for -// database lookup. This is performed only for active delegation events to -// prevent duplicated database writes. -func (h *V1QueueHandler) performAddressLookupConversion(ctx context.Context, stakerPkHex string, state types.DelegationState) *types.Error { - // Perform the address lookup conversion only for active delegation events - // to prevent duplicated database writes - if state == types.Active { - addErr := h.Service.ProcessAndSaveBtcAddresses(ctx, stakerPkHex) - if addErr != nil { - log.Ctx(ctx).Error().Err(addErr).Msg("Failed to process and save btc addresses") - return addErr - } - } - return nil -} diff --git a/internal/v1/queue/handler/unbonding.go b/internal/v1/queue/handler/unbonding.go deleted file mode 100644 index 7d1ecefb..00000000 --- a/internal/v1/queue/handler/unbonding.go +++ /dev/null @@ -1,75 +0,0 @@ -package v1queuehandler - -import ( - "context" - "encoding/json" - "net/http" - - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - "github.com/babylonlabs-io/staking-api-service/internal/shared/utils" - queueClient "github.com/babylonlabs-io/staking-queue-client/client" - "github.com/rs/zerolog/log" -) - -func (h *V1QueueHandler) UnbondingStakingHandler(ctx context.Context, messageBody string) *types.Error { - var unbondingStakingEvent queueClient.UnbondingStakingEvent - err := json.Unmarshal([]byte(messageBody), &unbondingStakingEvent) - if err != nil { - log.Ctx(ctx).Error().Err(err).Msg("Failed to unmarshal the message body into unbondingStakingEvent") - return types.NewError(http.StatusBadRequest, types.BadRequest, err) - } - - // Check if the delegation is in the right state to process the unbonding event - del, delErr := h.Service.GetDelegation(ctx, unbondingStakingEvent.StakingTxHashHex) - // Requeue if found any error. Including not found error - if delErr != nil { - return delErr - } - state := types.DelegationState(del.State) - if utils.Contains(utils.OutdatedStatesForUnbonding(), state) { - // Ignore the message as the delegation state already passed the unbonding state. This is an outdated duplication - log.Ctx(ctx).Debug().Str("StakingTxHashHex", unbondingStakingEvent.StakingTxHashHex). - Msg("delegation state is outdated for unbonding event") - return nil - } - - expireCheckErr := h.Service.ProcessExpireCheck( - ctx, unbondingStakingEvent.StakingTxHashHex, - unbondingStakingEvent.UnbondingStartHeight, - unbondingStakingEvent.UnbondingTimeLock, - types.UnbondingTxType, - ) - if expireCheckErr != nil { - return expireCheckErr - } - - // Perform the async stats calculation by emit the stats event - // NOTE: We no longer perform the stats calculation for timelock expired event - // This is based on the assumption that phase 1 launch date + min timelock will be over the lauch of phase 2 date - statsError := h.EmitStatsEvent(ctx, queueClient.NewStatsEvent( - del.StakingTxHashHex, - del.StakerPkHex, - del.FinalityProviderPkHex, - del.StakingValue, - types.Unbonded.ToString(), - del.IsOverflow, - )) - if statsError != nil { - log.Ctx(ctx).Error().Err(statsError).Str("stakingTxHashHex", del.StakingTxHashHex). - Msg("Failed to emit stats event for unbonding staking") - return statsError - } - - // Save the unbonding staking delegation. This is the final step in the unbonding staking event processing - // Please refer to the README.md for the details on the unbonding staking event processing workflow - transitionErr := h.Service.TransitionToUnbondingState( - ctx, unbondingStakingEvent.StakingTxHashHex, unbondingStakingEvent.UnbondingStartHeight, - unbondingStakingEvent.UnbondingTimeLock, unbondingStakingEvent.UnbondingOutputIndex, - unbondingStakingEvent.UnbondingTxHex, unbondingStakingEvent.UnbondingStartTimestamp, - ) - if transitionErr != nil { - return transitionErr - } - - return nil -} diff --git a/internal/v1/queue/handler/withdraw.go b/internal/v1/queue/handler/withdraw.go deleted file mode 100644 index 2bd97108..00000000 --- a/internal/v1/queue/handler/withdraw.go +++ /dev/null @@ -1,57 +0,0 @@ -package v1queuehandler - -import ( - "context" - "encoding/json" - "net/http" - - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - "github.com/babylonlabs-io/staking-api-service/internal/shared/utils" - queueClient "github.com/babylonlabs-io/staking-queue-client/client" - "github.com/rs/zerolog/log" -) - -func (h *V1QueueHandler) WithdrawStakingHandler(ctx context.Context, messageBody string) *types.Error { - var withdrawnStakingEvent queueClient.WithdrawStakingEvent - err := json.Unmarshal([]byte(messageBody), &withdrawnStakingEvent) - if err != nil { - log.Ctx(ctx).Error().Err(err).Msg("Failed to unmarshal the message body into withdrawnStakingEvent") - return types.NewError(http.StatusBadRequest, types.BadRequest, err) - } - - // Check if the delegation is in the right state to process the withdrawn event. - del, delErr := h.Service.GetDelegation(ctx, withdrawnStakingEvent.StakingTxHashHex) - // Requeue if found any error. Including not found error - if delErr != nil { - return delErr - } - state := types.DelegationState(del.State) - - stakingTxHashHex := withdrawnStakingEvent.GetStakingTxHashHex() - - if utils.Contains(utils.OutdatedStatesForWithdraw(), state) { - // Ignore the message as the delegation state is withdrawn. Nothing to do anymore - log.Ctx(ctx).Debug().Str("stakingTxHashHex", stakingTxHashHex). - Msg("delegation state is outdated for withdrawn event") - return nil - } - // Requeue if the current state is not in the qualified states to transition to withdrawn - // We will wait for the unbonded message to be processed first. - if !utils.Contains(utils.QualifiedStatesToWithdraw(), state) { - errMsg := "delegation is not in the qualified state to transition to withdrawn" - log.Ctx(ctx).Warn().Str("stakingTxHashHex", stakingTxHashHex). - Str("state", state.ToString()).Msg(errMsg) - return types.NewErrorWithMsg(http.StatusForbidden, types.Forbidden, errMsg) - } - - // Transition to withdrawn state - // Please refer to the README.md for the details on the event processing workflow - transitionErr := h.Service.TransitionToWithdrawnState( - ctx, withdrawnStakingEvent.StakingTxHashHex, - ) - if transitionErr != nil { - return transitionErr - } - - return nil -} diff --git a/internal/v2/db/client/interface.go b/internal/v2/db/client/interface.go index 61665cdf..d94a570b 100644 --- a/internal/v2/db/client/interface.go +++ b/internal/v2/db/client/interface.go @@ -11,6 +11,7 @@ type V2DBClient interface { dbclient.DBClient GetOverallStats(ctx context.Context) (*v2dbmodel.V2OverallStatsDocument, error) GetStakerStats(ctx context.Context, stakerPKHex string) (*v2dbmodel.V2StakerStatsDocument, error) + GetFinalityProviderStats(ctx context.Context) ([]*v2dbmodel.V2FinalityProviderStatsDocument, error) GetOrCreateStatsLock( ctx context.Context, stakingTxHashHex string, state string, ) (*v2dbmodel.V2StatsLockDocument, error) @@ -26,4 +27,11 @@ type V2DBClient interface { SubtractStakerStats( ctx context.Context, stakingTxHashHex, stakerPkHex string, amount uint64, ) error + IncrementFinalityProviderStats( + ctx context.Context, stakingTxHashHex string, fpPkHexes []string, amount uint64, + ) error + SubtractFinalityProviderStats( + ctx context.Context, stakingTxHashHex string, fpPkHexes []string, amount uint64, + ) error + GetActiveStakersCount(ctx context.Context) (int64, error) } diff --git a/internal/v2/db/client/stats.go b/internal/v2/db/client/stats.go index d997b08d..c0ac33c7 100644 --- a/internal/v2/db/client/stats.go +++ b/internal/v2/db/client/stats.go @@ -307,3 +307,139 @@ func (v2dbclient *V2Database) GetStakerStats( } return &result, nil } + +func (v2dbclient *V2Database) GetActiveStakersCount(ctx context.Context) (int64, error) { + client := v2dbclient.Client. + Database(v2dbclient.DbName). + Collection(dbmodel.V2StakerStatsCollection) + + filter := bson.M{ + "active_delegations": bson.M{ + "$gt": 0, + }, + } + + count, err := client.CountDocuments(ctx, filter) + if err != nil { + return 0, fmt.Errorf("failed to count active stakers: %w", err) + } + + return count, nil +} + +func (v2dbclient *V2Database) IncrementFinalityProviderStats( + ctx context.Context, + stakingTxHashHex string, + fpPkHexes []string, + amount uint64, +) error { + // Create bulk write operations for each FP + var operations []mongo.WriteModel + for _, fpPkHex := range fpPkHexes { + operation := mongo.NewUpdateOneModel(). + SetFilter(bson.M{"_id": fpPkHex}). + SetUpdate(bson.M{ + "$inc": bson.M{ + "active_tvl": int64(amount), + "total_tvl": int64(amount), + "active_delegations": 1, + "total_delegations": 1, + }, + }). + SetUpsert(true) + operations = append(operations, operation) + } + + return v2dbclient.updateFinalityProviderStats( + ctx, + types.Active.ToString(), + stakingTxHashHex, + operations, + ) +} + +func (v2dbclient *V2Database) SubtractFinalityProviderStats( + ctx context.Context, + stakingTxHashHex string, + fpPkHexes []string, + amount uint64, +) error { + // Create bulk write operations for each FP + var operations []mongo.WriteModel + for _, fpPkHex := range fpPkHexes { + operation := mongo.NewUpdateOneModel(). + SetFilter(bson.M{"_id": fpPkHex}). + SetUpdate(bson.M{ + "$inc": bson.M{ + "active_tvl": -int64(amount), + "active_delegations": -1, + }, + }). + SetUpsert(true) + operations = append(operations, operation) + } + + return v2dbclient.updateFinalityProviderStats( + ctx, + types.Unbonded.ToString(), + stakingTxHashHex, + operations, + ) +} + +func (v2dbclient *V2Database) updateFinalityProviderStats( + ctx context.Context, + state string, + stakingTxHashHex string, + operations []mongo.WriteModel, +) error { + client := v2dbclient.Client.Database(v2dbclient.DbName).Collection(dbmodel.V2FinalityProviderStatsCollection) + + session, sessionErr := v2dbclient.Client.StartSession() + if sessionErr != nil { + return sessionErr + } + defer session.EndSession(ctx) + + transactionWork := func(sessCtx mongo.SessionContext) (interface{}, error) { + // Single lock for the entire operation + err := v2dbclient.updateStatsLockByFieldName( + sessCtx, + stakingTxHashHex, + state, + "finality_provider_stats", + ) + if err != nil { + return nil, err + } + + // Execute all updates in a single bulk write + opts := options.BulkWrite().SetOrdered(true) + _, err = client.BulkWrite(sessCtx, operations, opts) + if err != nil { + return nil, err + } + + return nil, nil + } + + _, txErr := session.WithTransaction(ctx, transactionWork) + return txErr +} + +func (v2dbclient *V2Database) GetFinalityProviderStats( + ctx context.Context, +) ([]*v2dbmodel.V2FinalityProviderStatsDocument, error) { + client := v2dbclient.Client.Database(v2dbclient.DbName).Collection(dbmodel.V2FinalityProviderStatsCollection) + cursor, err := client.Find(ctx, bson.M{}) + if err != nil { + return nil, err + } + defer cursor.Close(ctx) + + var results []*v2dbmodel.V2FinalityProviderStatsDocument + if err := cursor.All(ctx, &results); err != nil { + return nil, err + } + return results, nil +} diff --git a/internal/v2/db/model/stats.go b/internal/v2/db/model/stats.go index 03db1d8f..9e3555bd 100644 --- a/internal/v2/db/model/stats.go +++ b/internal/v2/db/model/stats.go @@ -1,7 +1,5 @@ package v2dbmodel -import dbmodel "github.com/babylonlabs-io/staking-api-service/internal/shared/db/model" - // StatsLockDocument represents the document in the stats lock collection // It's used as a lock to prevent concurrent stats calculation for the same staking tx hash // As well as to prevent the same staking tx hash + txType to be processed multiple times @@ -41,21 +39,22 @@ type V2StakerStatsDocument struct { TotalDelegations int64 `bson:"total_delegations"` } -// StakerStatsByStakerPagination is used to paginate the top stakers by active tvl -// ActiveTvl is used as the sorting key, whereas StakerPkHex is used as the secondary sorting key -type V2StakerStatsByStakerPagination struct { - StakerPkHex string `json:"staker_pk_hex"` - ActiveTvl int64 `json:"active_tvl"` +type V2FinalityProviderStatsDocument struct { + FinalityProviderPkHex string `bson:"_id"` + ActiveTvl int64 `bson:"active_tvl"` + TotalTvl int64 `bson:"total_tvl"` + ActiveDelegations int64 `bson:"active_delegations"` + TotalDelegations int64 `bson:"total_delegations"` } -func BuildV2StakerStatsByStakerPaginationToken(d *V2StakerStatsDocument) (string, error) { - page := V2StakerStatsByStakerPagination{ - StakerPkHex: d.StakerPkHex, - ActiveTvl: d.ActiveTvl, - } - token, err := dbmodel.GetPaginationToken(page) - if err != nil { - return "", err +type V2FpSlashingLockDocument struct { + FinalityProviderPkHex string `bson:"_id"` // + IsProcessed bool `bson:"is_processed"` // true when processing is complete +} + +func NewV2FpSlashingLockDocument(fpBtcPkHex string) *V2FpSlashingLockDocument { + return &V2FpSlashingLockDocument{ + FinalityProviderPkHex: fpBtcPkHex, + IsProcessed: false, } - return token, nil } diff --git a/internal/v2/queue/client/client.go b/internal/v2/queue/client/client.go deleted file mode 100644 index efb6e1a1..00000000 --- a/internal/v2/queue/client/client.go +++ /dev/null @@ -1,35 +0,0 @@ -package v2queueclient - -import ( - queueclient "github.com/babylonlabs-io/staking-api-service/internal/shared/queue/client" - v2queuehandler "github.com/babylonlabs-io/staking-api-service/internal/v2/queue/handler" - client "github.com/babylonlabs-io/staking-queue-client/client" - queueConfig "github.com/babylonlabs-io/staking-queue-client/config" - "github.com/rs/zerolog/log" -) - -type V2QueueClient struct { - *queueclient.Queue - Handler *v2queuehandler.V2QueueHandler - ActiveStakingEventQueueClient client.QueueClient - UnbondingEventQueueClient client.QueueClient -} - -func New(cfg *queueConfig.QueueConfig, handler *v2queuehandler.V2QueueHandler, queueClient *queueclient.Queue) *V2QueueClient { - activeStakingEventQueueClient, err := client.NewQueueClient(cfg, client.ActiveStakingQueueName) - if err != nil { - log.Fatal().Err(err).Msg("error while creating ActiveStakingEventQueue") - } - - unbondingEventQueueClient, err := client.NewQueueClient(cfg, client.UnbondingStakingQueueName) - if err != nil { - log.Fatal().Err(err).Msg("error while creating UnbondingEventQueue") - } - - return &V2QueueClient{ - Queue: queueClient, - Handler: handler, - ActiveStakingEventQueueClient: activeStakingEventQueueClient, - UnbondingEventQueueClient: unbondingEventQueueClient, - } -} diff --git a/internal/v2/queue/client/health.go b/internal/v2/queue/client/health.go deleted file mode 100644 index a0822837..00000000 --- a/internal/v2/queue/client/health.go +++ /dev/null @@ -1,31 +0,0 @@ -package v2queueclient - -import ( - "context" - "fmt" - "strings" - "time" - - "github.com/babylonlabs-io/staking-queue-client/client" -) - -func (q *V2QueueClient) IsConnectionHealthy() error { - var errorMessages []string - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - checkQueue := func(name string, client client.QueueClient) { - if err := client.Ping(ctx); err != nil { - errorMessages = append(errorMessages, fmt.Sprintf("%s is not healthy: %v", name, err)) - } - } - - checkQueue("ActiveStakingEventQueueClient", q.ActiveStakingEventQueueClient) - checkQueue("UnbondingEventQueueClient", q.UnbondingEventQueueClient) - - if len(errorMessages) > 0 { - return fmt.Errorf(strings.Join(errorMessages, "; ")) - } - return nil -} diff --git a/internal/v2/queue/client/message.go b/internal/v2/queue/client/message.go deleted file mode 100644 index acce6879..00000000 --- a/internal/v2/queue/client/message.go +++ /dev/null @@ -1,43 +0,0 @@ -package v2queueclient - -import ( - queueclient "github.com/babylonlabs-io/staking-api-service/internal/shared/queue/client" - "github.com/rs/zerolog/log" -) - -func (q *V2QueueClient) StartReceivingMessages() { - log.Printf("Starting to receive messages from v2 queues") - // start processing messages from the active staking queue - queueclient.StartQueueMessageProcessing( - q.ActiveStakingEventQueueClient, - q.Handler.ActiveStakingHandler, - q.Handler.HandleUnprocessedMessage, - q.MaxRetryAttempts, - q.ProcessingTimeout, - ) - log.Printf("Starting to receive messages from unbonding staking queue") - queueclient.StartQueueMessageProcessing( - q.UnbondingEventQueueClient, - q.Handler.UnbondingStakingHandler, - q.Handler.HandleUnprocessedMessage, - q.MaxRetryAttempts, - q.ProcessingTimeout, - ) - // ...add more queues here -} - -func (q *V2QueueClient) StopReceivingMessages() { - activeQueueErr := q.ActiveStakingEventQueueClient.Stop() - if activeQueueErr != nil { - log.Error().Err(activeQueueErr). - Str("queueName", q.ActiveStakingEventQueueClient.GetQueueName()). - Msg("error while stopping queue") - } - unbondingQueueErr := q.UnbondingEventQueueClient.Stop() - if unbondingQueueErr != nil { - log.Error().Err(unbondingQueueErr). - Str("queueName", q.UnbondingEventQueueClient.GetQueueName()). - Msg("error while stopping queue") - } - // ...add more queues here -} diff --git a/internal/v2/queue/handler/handler.go b/internal/v2/queue/handler/handler.go index c86fdd91..cfaea2b4 100644 --- a/internal/v2/queue/handler/handler.go +++ b/internal/v2/queue/handler/handler.go @@ -3,23 +3,23 @@ package v2queuehandler import ( "context" - queuehandler "github.com/babylonlabs-io/staking-api-service/internal/shared/queue/handler" + "github.com/babylonlabs-io/staking-api-service/internal/shared/services" "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - v2service "github.com/babylonlabs-io/staking-api-service/internal/v2/service" ) type V2QueueHandler struct { - *queuehandler.QueueHandler - Service v2service.V2ServiceProvider + Services *services.Services } -func New(queueHandler *queuehandler.QueueHandler, service v2service.V2ServiceProvider) *V2QueueHandler { +type MessageHandler func(ctx context.Context, messageBody string) *types.Error +type UnprocessableMessageHandler func(ctx context.Context, messageBody, receipt string) *types.Error + +func NewV2QueueHandler(services *services.Services) *V2QueueHandler { return &V2QueueHandler{ - QueueHandler: queueHandler, - Service: service, + Services: services, } } func (qh *V2QueueHandler) HandleUnprocessedMessage(ctx context.Context, messageBody, receipt string) *types.Error { - return qh.Service.SaveUnprocessableMessages(ctx, messageBody, receipt) + return qh.Services.SharedService.SaveUnprocessableMessages(ctx, messageBody, receipt) } diff --git a/internal/v2/queue/handler/staking.go b/internal/v2/queue/handler/stats.go similarity index 63% rename from internal/v2/queue/handler/staking.go rename to internal/v2/queue/handler/stats.go index 9b17eb2a..7f9b0dcd 100644 --- a/internal/v2/queue/handler/staking.go +++ b/internal/v2/queue/handler/stats.go @@ -21,24 +21,19 @@ func (h *V2QueueHandler) ActiveStakingHandler(ctx context.Context, messageBody s } // Mark as v1 delegation as transitioned if it exists - if err := h.Service.MarkV1DelegationAsTransitioned(ctx, activeStakingEvent.StakingTxHashHex); err != nil { + if err := h.Services.V2Service.MarkV1DelegationAsTransitioned(ctx, activeStakingEvent.StakingTxHashHex); err != nil { log.Ctx(ctx).Error().Err(err).Msg("Failed to mark v1 delegation as transitioned") return err } - // Perform the address lookup conversion - addressLookupErr := h.performAddressLookupConversion(ctx, activeStakingEvent.StakerBtcPkHex, types.Active) - if addressLookupErr != nil { - return addressLookupErr - } + // TODO: Perform the address lookup conversion + // https://github.com/babylonlabs-io/staking-api-service/issues/162 - // Perform the stats calculation - statsErr := h.Service.ProcessStakingStatsCalculation( + statsErr := h.Services.V2Service.ProcessActiveDelegationStats( ctx, activeStakingEvent.StakingTxHashHex, activeStakingEvent.StakerBtcPkHex, activeStakingEvent.FinalityProviderBtcPksHex, - types.Active, activeStakingEvent.StakingAmount, ) if statsErr != nil { @@ -59,12 +54,11 @@ func (h *V2QueueHandler) UnbondingStakingHandler(ctx context.Context, messageBod } // Perform the stats calculation - statsErr := h.Service.ProcessStakingStatsCalculation( + statsErr := h.Services.V2Service.ProcessUnbondingDelegationStats( ctx, unbondingStakingEvent.StakingTxHashHex, unbondingStakingEvent.StakerBtcPkHex, unbondingStakingEvent.FinalityProviderBtcPksHex, - types.Unbonding, unbondingStakingEvent.StakingAmount, ) if statsErr != nil { @@ -73,19 +67,3 @@ func (h *V2QueueHandler) UnbondingStakingHandler(ctx context.Context, messageBod } return nil } - -// Convert the staker's public key into corresponding BTC addresses for -// database lookup. This is performed only for active delegation events to -// prevent duplicated database writes. -func (h *V2QueueHandler) performAddressLookupConversion(ctx context.Context, stakerPkHex string, state types.DelegationState) *types.Error { - // Perform the address lookup conversion only for active delegation events - // to prevent duplicated database writes - if state == types.Active { - addErr := h.Service.ProcessAndSaveBtcAddresses(ctx, stakerPkHex) - if addErr != nil { - log.Ctx(ctx).Error().Err(addErr).Msg("Failed to process and save btc addresses") - return addErr - } - } - return nil -} diff --git a/internal/v2/queue/queue.go b/internal/v2/queue/queue.go new file mode 100644 index 00000000..0deda0df --- /dev/null +++ b/internal/v2/queue/queue.go @@ -0,0 +1,203 @@ +package queue + +import ( + "context" + "fmt" + "net/http" + "strings" + "time" + + "github.com/babylonlabs-io/staking-api-service/internal/shared/observability/metrics" + "github.com/babylonlabs-io/staking-api-service/internal/shared/observability/tracing" + "github.com/babylonlabs-io/staking-api-service/internal/shared/services" + "github.com/babylonlabs-io/staking-api-service/internal/shared/types" + v2queuehandler "github.com/babylonlabs-io/staking-api-service/internal/v2/queue/handler" + "github.com/babylonlabs-io/staking-queue-client/client" + queueConfig "github.com/babylonlabs-io/staking-queue-client/config" + "github.com/rs/zerolog/log" +) + +type Queues struct { + Handlers *v2queuehandler.V2QueueHandler + processingTimeout time.Duration + maxRetryAttempts int32 + ActiveStakingQueueClient client.QueueClient + UnbondingStakingQueueClient client.QueueClient +} + +func New(cfg *queueConfig.QueueConfig, service *services.Services) *Queues { + activeStakingQueueClient, err := client.NewQueueClient( + cfg, client.ActiveStakingQueueName, + ) + if err != nil { + log.Fatal().Err(err).Msg("error while creating ActiveStakingQueueClient") + } + + unbondingStakingQueueClient, err := client.NewQueueClient( + cfg, client.UnbondingStakingQueueName, + ) + if err != nil { + log.Fatal().Err(err).Msg("error while creating UnbondingStakingQueueClient") + } + + handlers := v2queuehandler.NewV2QueueHandler(service) + return &Queues{ + Handlers: handlers, + processingTimeout: time.Duration(cfg.QueueProcessingTimeout) * time.Second, + maxRetryAttempts: cfg.MsgMaxRetryAttempts, + ActiveStakingQueueClient: activeStakingQueueClient, + UnbondingStakingQueueClient: unbondingStakingQueueClient, + } +} + +// Start all message processing +func (q *Queues) StartReceivingMessages() { + // start processing messages from the active staking queue + startQueueMessageProcessing( + q.ActiveStakingQueueClient, + q.Handlers.ActiveStakingHandler, q.Handlers.HandleUnprocessedMessage, + q.maxRetryAttempts, q.processingTimeout, + ) + startQueueMessageProcessing( + q.UnbondingStakingQueueClient, + q.Handlers.UnbondingStakingHandler, q.Handlers.HandleUnprocessedMessage, + q.maxRetryAttempts, q.processingTimeout, + ) + // ...add more queues here +} + +// Turn off all message processing +func (q *Queues) StopReceivingMessages() { + activeQueueErr := q.ActiveStakingQueueClient.Stop() + if activeQueueErr != nil { + log.Error().Err(activeQueueErr). + Str("queueName", q.ActiveStakingQueueClient.GetQueueName()). + Msg("error while stopping queue") + } + unbondingQueueErr := q.UnbondingStakingQueueClient.Stop() + if unbondingQueueErr != nil { + log.Error().Err(unbondingQueueErr). + Str("queueName", q.UnbondingStakingQueueClient.GetQueueName()). + Msg("error while stopping queue") + } + // ...add more queues here +} + +func startQueueMessageProcessing( + queueClient client.QueueClient, + handler v2queuehandler.MessageHandler, + unprocessableHandler v2queuehandler.UnprocessableMessageHandler, + maxRetryAttempts int32, processingTimeout time.Duration, +) { + messagesChan, err := queueClient.ReceiveMessages() + log.Info().Str("queueName", queueClient.GetQueueName()).Msg("start receiving messages from queue") + if err != nil { + log.Fatal().Err(err).Str("queueName", queueClient.GetQueueName()).Msg("error setting up message channel from queue") + } + + go func() { + for message := range messagesChan { + attempts := message.GetRetryAttempts() + // For each message, create a new context with a deadline or timeout + ctx, cancel := context.WithTimeout(context.Background(), processingTimeout) + ctx = attachLoggerContext(ctx, message, queueClient) + // Attach the tracingInfo for the message processing + _, err := tracing.WrapWithSpan[any](ctx, "message_processing", func() (any, *types.Error) { + timer := metrics.StartEventProcessingDurationTimer(queueClient.GetQueueName(), attempts) + // Process the message + err := handler(ctx, message.Body) + if err != nil { + timer(err.StatusCode) + } else { + timer(http.StatusOK) + } + return nil, err + }) + if err != nil { + recordErrorLog(err) + // We will retry the message if it has not exceeded the max retry attempts + // otherwise, we will dump the message into db for manual inspection and remove from the queue + if attempts > maxRetryAttempts { + log.Ctx(ctx).Error().Err(err). + Msg("exceeded retry attempts, message will be dumped into db for manual inspection") + metrics.RecordUnprocessableEntity(queueClient.GetQueueName()) + saveUnprocessableMsgErr := unprocessableHandler(ctx, message.Body, message.Receipt) + if saveUnprocessableMsgErr != nil { + log.Ctx(ctx).Error().Err(saveUnprocessableMsgErr). + Msg("error while saving unprocessable message") + metrics.RecordQueueOperationFailure("unprocessableHandler", queueClient.GetQueueName()) + cancel() + continue + } + } else { + log.Ctx(ctx).Error().Err(err). + Msg("error while processing message from queue, will be requeued") + reQueueErr := queueClient.ReQueueMessage(ctx, message) + if reQueueErr != nil { + log.Ctx(ctx).Error().Err(reQueueErr). + Msg("error while requeuing message") + metrics.RecordQueueOperationFailure("reQueueMessage", queueClient.GetQueueName()) + } + cancel() + continue + } + } + + delErr := queueClient.DeleteMessage(message.Receipt) + if delErr != nil { + log.Ctx(ctx).Error().Err(delErr). + Msg("error while deleting message from queue") + metrics.RecordQueueOperationFailure("deleteMessage", queueClient.GetQueueName()) + } + + tracingInfo := ctx.Value(tracing.TracingInfoKey) + logEvent := log.Ctx(ctx).Debug() + if tracingInfo != nil { + logEvent = logEvent.Interface("tracingInfo", tracingInfo) + } + logEvent.Msg("message processed successfully") + cancel() + } + log.Info().Str("queueName", queueClient.GetQueueName()).Msg("stopped receiving messages from queue") + }() +} + +func attachLoggerContext(ctx context.Context, message client.QueueMessage, queueClient client.QueueClient) context.Context { + ctx = tracing.AttachTracingIntoContext(ctx) + + traceId := ctx.Value(tracing.TraceIdKey) + return log.With(). + Str("receipt", message.Receipt). + Str("queueName", queueClient.GetQueueName()). + Interface("traceId", traceId). + Logger().WithContext(ctx) +} + +func recordErrorLog(err *types.Error) { + if err.StatusCode >= http.StatusInternalServerError { + log.Error().Err(err).Msg("event processing failed with 5xx error") + } else { + log.Warn().Err(err).Msg("event processing failed with 4xx error") + } +} + +func (q *Queues) IsConnectionHealthy() error { + var errorMessages []string + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + checkQueue := func(name string, client client.QueueClient) { + if err := client.Ping(ctx); err != nil { + errorMessages = append(errorMessages, fmt.Sprintf("%s is not healthy: %v", name, err)) + } + } + + checkQueue("ActiveStakingQueueClient", q.ActiveStakingQueueClient) + checkQueue("UnbondingStakingQueueClient", q.UnbondingStakingQueueClient) + + if len(errorMessages) > 0 { + return fmt.Errorf(strings.Join(errorMessages, "; ")) + } + return nil +} diff --git a/internal/v2/service/delegation.go b/internal/v2/service/delegation.go index 5fb13d7c..5dd0335c 100644 --- a/internal/v2/service/delegation.go +++ b/internal/v2/service/delegation.go @@ -146,22 +146,6 @@ func getUnbondingSignatures(covenantSignatures []indexerdbmodel.CovenantSignatur return covenantSignaturesPublic } -func (s *V2Service) IsDelegationPresent(ctx context.Context, txHashHex string) (bool, *types.Error) { - delegation, err := s.DbClients.IndexerDBClient.GetDelegation(ctx, txHashHex) - if err != nil { - if db.IsNotFoundError(err) { - return false, nil - } - log.Ctx(ctx).Error().Err(err).Msg("Failed to find delegation by tx hash hex") - return false, types.NewInternalServiceError(err) - } - if delegation != nil { - return true, nil - } - - return false, nil -} - func (s *V2Service) SaveUnprocessableMessages(ctx context.Context, messageBody, receipt string) *types.Error { err := s.DbClients.V2DBClient.SaveUnprocessableMessage(ctx, messageBody, receipt) if err != nil { diff --git a/internal/v2/service/finality_provider.go b/internal/v2/service/finality_provider.go index 7d9dbc12..4e4b997e 100644 --- a/internal/v2/service/finality_provider.go +++ b/internal/v2/service/finality_provider.go @@ -7,6 +7,7 @@ import ( indexerdbmodel "github.com/babylonlabs-io/staking-api-service/internal/indexer/db/model" "github.com/babylonlabs-io/staking-api-service/internal/shared/db" "github.com/babylonlabs-io/staking-api-service/internal/shared/types" + v2dbmodel "github.com/babylonlabs-io/staking-api-service/internal/v2/db/model" "github.com/rs/zerolog/log" ) @@ -23,39 +24,72 @@ type FinalityProvidersStatsPublic struct { FinalityProviders []FinalityProviderStatsPublic `json:"finality_providers"` } -func mapToFinalityProviderStatsPublic(provider indexerdbmodel.IndexerFinalityProviderDetails) *FinalityProviderStatsPublic { +func mapToFinalityProviderStatsPublic( + provider indexerdbmodel.IndexerFinalityProviderDetails, + fpStats *v2dbmodel.V2FinalityProviderStatsDocument, +) *FinalityProviderStatsPublic { return &FinalityProviderStatsPublic{ BtcPk: provider.BtcPk, State: types.FinalityProviderQueryingState(provider.State), Description: types.FinalityProviderDescription(provider.Description), Commission: provider.Commission, - ActiveTvl: 0, - ActiveDelegations: 0, + ActiveTvl: fpStats.ActiveTvl, + ActiveDelegations: fpStats.ActiveDelegations, } } -// GetFinalityProviders gets a list of finality providers with stats +// GetFinalityProvidersWithStats retrieves all finality providers and their associated statistics func (s *V2Service) GetFinalityProvidersWithStats( ctx context.Context, ) ([]*FinalityProviderStatsPublic, *types.Error) { - fps, err := s.DbClients.IndexerDBClient.GetFinalityProviders(ctx) + finalityProviders, err := s.DbClients.IndexerDBClient.GetFinalityProviders(ctx) if err != nil { if db.IsNotFoundError(err) { - log.Ctx(ctx).Warn().Err(err).Msg("Finality providers not found") + log.Ctx(ctx).Warn().Err(err).Msg("No finality providers found") return nil, types.NewErrorWithMsg( - http.StatusNotFound, types.NotFound, "finality providers not found, please retry", + http.StatusNotFound, + types.NotFound, + "finality providers not found, please retry", ) } return nil, types.NewErrorWithMsg( - http.StatusInternalServerError, types.InternalServiceError, "failed to get finality providers", + http.StatusInternalServerError, + types.InternalServiceError, + "failed to get finality providers", ) } - // TODO: Call the FP stats service to get the stats for compose the response - providersPublic := make([]*FinalityProviderStatsPublic, 0, len(fps)) + providerStats, err := s.DbClients.V2DBClient.GetFinalityProviderStats(ctx) + if err != nil { + return nil, types.NewErrorWithMsg( + http.StatusInternalServerError, + types.InternalServiceError, + "failed to get finality provider stats", + ) + } - for _, provider := range fps { - providersPublic = append(providersPublic, mapToFinalityProviderStatsPublic(*provider)) + statsLookup := make(map[string]*v2dbmodel.V2FinalityProviderStatsDocument) + for _, stats := range providerStats { + statsLookup[stats.FinalityProviderPkHex] = stats + } + + finalityProvidersWithStats := make([]*FinalityProviderStatsPublic, 0, len(finalityProviders)) + + for _, provider := range finalityProviders { + providerStats, hasStats := statsLookup[provider.BtcPk] + if !hasStats { + providerStats = &v2dbmodel.V2FinalityProviderStatsDocument{ + ActiveTvl: 0, + ActiveDelegations: 0, + } + log.Ctx(ctx).Debug(). + Str("finality_provider_pk_hex", provider.BtcPk). + Msg("Initializing finality provider with default stats") + } + finalityProvidersWithStats = append( + finalityProvidersWithStats, + mapToFinalityProviderStatsPublic(*provider, providerStats), + ) } - return providersPublic, nil + return finalityProvidersWithStats, nil } diff --git a/internal/v2/service/interface.go b/internal/v2/service/interface.go index 3f4ad5d3..80686225 100644 --- a/internal/v2/service/interface.go +++ b/internal/v2/service/interface.go @@ -11,18 +11,13 @@ type V2ServiceProvider interface { []*FinalityProviderStatsPublic, *types.Error, ) GetNetworkInfo(ctx context.Context) (*NetworkInfoPublic, *types.Error) - IsDelegationPresent(ctx context.Context, txHashHex string) (bool, *types.Error) GetDelegation(ctx context.Context, stakingTxHashHex string) (*StakerDelegationPublic, *types.Error) GetDelegations(ctx context.Context, stakerPKHex string, paginationKey string) ([]*StakerDelegationPublic, string, *types.Error) MarkV1DelegationAsTransitioned(ctx context.Context, stakingTxHashHex string) *types.Error GetOverallStats(ctx context.Context) (*OverallStatsPublic, *types.Error) GetStakerStats(ctx context.Context, stakerPKHex string) (*StakerStatsPublic, *types.Error) ProcessAndSaveBtcAddresses(ctx context.Context, stakerPkHex string) *types.Error - ProcessStakingStatsCalculation( - ctx context.Context, - stakingTxHashHex, stakerPkHex string, - finalityProviderBtcPksHex []string, - state types.DelegationState, amount uint64, - ) *types.Error SaveUnprocessableMessages(ctx context.Context, messageBody, receipt string) *types.Error + ProcessActiveDelegationStats(ctx context.Context, stakingTxHashHex, stakerPkHex string, fpBtcPkHexes []string, amount uint64) *types.Error + ProcessUnbondingDelegationStats(ctx context.Context, stakingTxHashHex, stakerPkHex string, fpBtcPkHexes []string, amount uint64) *types.Error } diff --git a/internal/v2/service/stats.go b/internal/v2/service/stats.go index 2b38b17d..9ea17bf4 100644 --- a/internal/v2/service/stats.go +++ b/internal/v2/service/stats.go @@ -2,21 +2,22 @@ package v2service import ( "context" - "fmt" - "net/http" + indexerdbmodel "github.com/babylonlabs-io/staking-api-service/internal/indexer/db/model" "github.com/babylonlabs-io/staking-api-service/internal/shared/db" "github.com/babylonlabs-io/staking-api-service/internal/shared/types" "github.com/rs/zerolog/log" ) type OverallStatsPublic struct { - ActiveTvl int64 `json:"active_tvl"` - TotalTvl int64 `json:"total_tvl"` - ActiveDelegations int64 `json:"active_delegations"` - TotalDelegations int64 `json:"total_delegations"` - ActiveStakers uint64 `json:"active_stakers"` - TotalStakers uint64 `json:"total_stakers"` + ActiveTvl int64 `json:"active_tvl"` + TotalTvl int64 `json:"total_tvl"` + ActiveDelegations int64 `json:"active_delegations"` + TotalDelegations int64 `json:"total_delegations"` + ActiveStakers uint64 `json:"active_stakers"` + TotalStakers uint64 `json:"total_stakers"` + ActiveFinalityProviders uint64 `json:"active_finality_providers"` + TotalFinalityProviders uint64 `json:"total_finality_providers"` } type StakerStatsPublic struct { @@ -34,12 +35,36 @@ func (s *V2Service) GetOverallStats(ctx context.Context) (*OverallStatsPublic, * return nil, types.NewInternalServiceError(err) } + // TODO: count fetch will affect the performance of the API + activeStakersCount, err := s.DbClients.V2DBClient.GetActiveStakersCount(ctx) + if err != nil { + log.Ctx(ctx).Error().Err(err).Msg("error while fetching active stakers count") + return nil, types.NewInternalServiceError(err) + } + + // TODO: ideally this should not be fetched from the indexer db + finalityProviders, err := s.DbClients.IndexerDBClient.GetFinalityProviders(ctx) + if err != nil { + log.Ctx(ctx).Error().Err(err).Msg("error while fetching finality providers") + return nil, types.NewInternalServiceError(err) + } + + activeFinalityProvidersCount := 0 + for _, fp := range finalityProviders { + if fp.State == indexerdbmodel.FinalityProviderStatus_FINALITY_PROVIDER_STATUS_ACTIVE { + activeFinalityProvidersCount++ + } + } + return &OverallStatsPublic{ - ActiveTvl: overallStats.ActiveTvl, - TotalTvl: overallStats.TotalTvl, - ActiveDelegations: overallStats.ActiveDelegations, - TotalDelegations: overallStats.TotalDelegations, - TotalStakers: overallStats.TotalStakers, + ActiveTvl: overallStats.ActiveTvl, + TotalTvl: overallStats.TotalTvl, + ActiveDelegations: overallStats.ActiveDelegations, + TotalDelegations: overallStats.TotalDelegations, + ActiveStakers: uint64(activeStakersCount), + TotalStakers: overallStats.TotalStakers, + ActiveFinalityProviders: uint64(activeFinalityProvidersCount), + TotalFinalityProviders: uint64(len(finalityProviders)), }, nil } @@ -59,106 +84,130 @@ func (s *V2Service) GetStakerStats(ctx context.Context, stakerPKHex string) (*St }, nil } -// ProcessStakingStatsCalculation calculates the staking stats and updates the database. -// This method tolerates duplicated calls, only the first call will be processed. -func (s *V2Service) ProcessStakingStatsCalculation( - ctx context.Context, - stakingTxHashHex, stakerPkHex string, - finalityProviderBtcPksHex []string, - state types.DelegationState, amount uint64, -) *types.Error { +// ProcessActiveDelegationStats calculates the active delegation stats and updates the database. +func (s *V2Service) ProcessActiveDelegationStats(ctx context.Context, stakingTxHashHex, stakerPkHex string, fpBtcPkHexes []string, amount uint64) *types.Error { // Fetch existing or initialize the stats lock document if not exist statsLockDocument, err := s.DbClients.V2DBClient.GetOrCreateStatsLock( - ctx, stakingTxHashHex, state.ToString(), + ctx, stakingTxHashHex, types.Active.ToString(), ) if err != nil { log.Ctx(ctx).Error().Err(err).Str("stakingTxHashHex", stakingTxHashHex). Msg("error while fetching stats lock document") return types.NewInternalServiceError(err) } - switch state { - case types.Active: - // TODO: Add finality provider stats calculation - - if !statsLockDocument.StakerStats { - // Convert the staker public key to multiple BTC addresses and save - // them in the database. - if addressConversionErr := s.ProcessAndSaveBtcAddresses( - ctx, stakerPkHex, - ); addressConversionErr != nil { - log.Ctx(ctx).Error().Err(addressConversionErr). - Str("stakingTxHashHex", stakingTxHashHex). - Msg("error while processing and saving btc addresses") - return types.NewInternalServiceError(addressConversionErr) - } - err = s.DbClients.V2DBClient.IncrementStakerStats( - ctx, stakingTxHashHex, stakerPkHex, amount, - ) - if err != nil { - if db.IsNotFoundError(err) { - return nil - } - log.Ctx(ctx).Error().Err(err).Str("stakingTxHashHex", stakingTxHashHex). - Msg("error while incrementing staker stats") - return types.NewInternalServiceError(err) + + if !statsLockDocument.FinalityProviderStats { + err = s.DbClients.V2DBClient.IncrementFinalityProviderStats( + ctx, stakingTxHashHex, fpBtcPkHexes, amount, + ) + if err != nil { + if db.IsNotFoundError(err) { + return nil } + log.Ctx(ctx).Error().Err(err).Str("stakingTxHashHex", stakingTxHashHex). + Msg("error while incrementing finality stats") + return types.NewInternalServiceError(err) } + } - // Add to the overall stats - // The overall stats should be the last to be updated as it has dependency - // on staker stats. - if !statsLockDocument.OverallStats { - err = s.DbClients.V2DBClient.IncrementOverallStats( - ctx, stakingTxHashHex, stakerPkHex, amount, - ) - if err != nil { - if db.IsNotFoundError(err) { - // This is a duplicate call, ignore it - return nil - } - log.Ctx(ctx).Error().Err(err).Str("stakingTxHashHex", stakingTxHashHex). - Msg("error while incrementing overall stats") - return types.NewInternalServiceError(err) + if !statsLockDocument.StakerStats { + err = s.DbClients.V2DBClient.IncrementStakerStats( + ctx, stakingTxHashHex, stakerPkHex, amount, + ) + if err != nil { + if db.IsNotFoundError(err) { + return nil + } + log.Ctx(ctx).Error().Err(err).Str("stakingTxHashHex", stakingTxHashHex). + Msg("error while incrementing staker stats") + return types.NewInternalServiceError(err) + } + } + // Add to the overall stats + // The overall stats should be the last to be updated as it has dependency + // on staker stats. + if !statsLockDocument.OverallStats { + err = s.DbClients.V2DBClient.IncrementOverallStats( + ctx, stakingTxHashHex, stakerPkHex, amount, + ) + if err != nil { + if db.IsNotFoundError(err) { + // This is a duplicate call, ignore it + return nil } + log.Ctx(ctx).Error().Err(err).Str("stakingTxHashHex", stakingTxHashHex). + Msg("error while incrementing overall stats") + return types.NewInternalServiceError(err) } - case types.Unbonded: - // TODO: Add finality provider stats calculation - - if !statsLockDocument.StakerStats { - err = s.DbClients.V2DBClient.SubtractStakerStats( - ctx, stakingTxHashHex, stakerPkHex, amount, - ) - if err != nil { - if db.IsNotFoundError(err) { - return nil - } - log.Ctx(ctx).Error().Err(err).Str("stakingTxHashHex", stakingTxHashHex). - Msg("error while subtracting staker stats") - return types.NewInternalServiceError(err) + } + + return nil +} + +// ProcessUnbondingDelegationStats calculates the unbonding delegation stats +func (s *V2Service) ProcessUnbondingDelegationStats( + ctx context.Context, + stakingTxHashHex string, + stakerPkHex string, + fpBtcPkHexes []string, + amount uint64, +) *types.Error { + statsLockDocument, err := s.DbClients.V2DBClient.GetOrCreateStatsLock( + ctx, + stakingTxHashHex, + types.Unbonded.ToString(), // use same state for both slashed and unbonding + ) + if err != nil { + log.Ctx(ctx).Error(). + Err(err). + Str("staking_tx_hash", stakingTxHashHex). + Msg("Failed to fetch stats lock document") + return types.NewInternalServiceError(err) + } + + // Subtract from the finality stats + if !statsLockDocument.FinalityProviderStats { + err = s.DbClients.V2DBClient.SubtractFinalityProviderStats( + ctx, stakingTxHashHex, fpBtcPkHexes, amount, + ) + if err != nil { + if db.IsNotFoundError(err) { + return nil } + log.Ctx(ctx).Error().Err(err).Str("stakingTxHashHex", stakingTxHashHex). + Msg("error while subtracting finality stats") + return types.NewInternalServiceError(err) } - // Subtract from the overall stats. - // The overall stats should be the last to be updated as it has dependency - // on staker stats. - if !statsLockDocument.OverallStats { - err = s.DbClients.V2DBClient.SubtractOverallStats( - ctx, stakingTxHashHex, stakerPkHex, amount, - ) - if err != nil { - if db.IsNotFoundError(err) { - return nil - } - log.Ctx(ctx).Error().Err(err).Str("stakingTxHashHex", stakingTxHashHex). - Msg("error while subtracting overall stats") - return types.NewInternalServiceError(err) + } + if !statsLockDocument.StakerStats { + err = s.DbClients.V2DBClient.SubtractStakerStats( + ctx, stakingTxHashHex, stakerPkHex, amount, + ) + if err != nil { + if db.IsNotFoundError(err) { + return nil } + log.Ctx(ctx).Error().Err(err).Str("stakingTxHashHex", stakingTxHashHex). + Msg("error while subtracting staker stats") + return types.NewInternalServiceError(err) } - default: - return types.NewErrorWithMsg( - http.StatusBadRequest, - types.BadRequest, - fmt.Sprintf("invalid delegation state for stats calculation: %s", state), + } + // Subtract from the overall stats. + // The overall stats should be the last to be updated as it has dependency + // on staker stats. + if !statsLockDocument.OverallStats { + err = s.DbClients.V2DBClient.SubtractOverallStats( + ctx, stakingTxHashHex, stakerPkHex, amount, ) + if err != nil { + if db.IsNotFoundError(err) { + return nil + } + log.Ctx(ctx).Error().Err(err).Str("stakingTxHashHex", stakingTxHashHex). + Msg("error while subtracting overall stats") + return types.NewInternalServiceError(err) + } } + return nil } diff --git a/tests/config/config-test.yml b/tests/config/config-test.yml deleted file mode 100644 index 185dede9..00000000 --- a/tests/config/config-test.yml +++ /dev/null @@ -1,43 +0,0 @@ -server: - host: 0.0.0.0 - port: 8090 - write-timeout: 60s - read-timeout: 60s - idle-timeout: 60s - allowed-origins: ["*"] - log-level: error - btc-net: "signet" - max-content-length: 40960 - health-check-interval: 2 -staking-db: - username: root - password: example - address: "mongodb://localhost:27017" - db-name: staking-api-service - max-pagination-limit: 10 - db-batch-size-limit: 100 - logical-shard-count: 2 -indexer-db: - username: root - password: example - address: "mongodb://localhost:27019" - db-name: indexer-db - max-pagination-limit: 10 - db-batch-size-limit: 100 -queue: - queue_user: user - queue_password: password - url: "localhost:5672" - processing_timeout: 300 - msg_max_retry_attempts: 2 - requeue_delay_time: 5 - queue_type: quorum -metrics: - host: 0.0.0.0 - port: 2112 -assets: - max_utxos: 100 - ordinals: - host: "http://ord-poc.devnet.babylonchain.io" - port: 8888 - timeout: 100 \ No newline at end of file diff --git a/tests/config/finality-providers-test.json b/tests/config/finality-providers-test.json deleted file mode 100644 index 1da03ba4..00000000 --- a/tests/config/finality-providers-test.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "finality_providers": [ - { - "description": { - "moniker": "Babylon Foundation 0", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "commission": "0.050000000000000000", - "btc_pk": "03d5a0bb72d71993e435d6c5a70e2aa4db500a62cfaae33c56050deefee64ec0" - }, - { - "description": { - "moniker": "Babylon Foundation 1", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "commission": "0.060000000000000000", - "btc_pk": "063deb187a4bf11c114cf825a4726e4c2c35fea5c4c44a20ff08a30a752ec7e0" - }, - { - "description": { - "moniker": "Babylon Foundation 2", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "commission": "0.080000000000000000", - "eots_pk": "094f5861be4128861d69ea4b66a5f974943f100f55400bf26f5cce124b4c9af7" - }, - { - "description": { - "moniker": "Babylon Foundation 3", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "commission": "0.090000000000000000", - "btc_pk": "0d2f9728abc45c0cdeefdd73f52a0e0102470e35fb689fc5bc681959a61b021f" - } - ] -} \ No newline at end of file diff --git a/tests/config/global-params-test.json b/tests/config/global-params-test.json deleted file mode 100644 index 2429e530..00000000 --- a/tests/config/global-params-test.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "versions": [ - { - "version": 0, - "activation_height": 100, - "staking_cap": 5000000, - "tag": "01020304", - "covenant_pks": [ - "03ffeaec52a9b407b355ef6967a7ffc15fd6c3fe07de2844d61550475e7a5233e5", - "03a5c60c2188e833d39d0fa798ab3f69aa12ed3dd2f3bad659effa252782de3c31", - "0359d3532148a597a2d05c0395bf5f7176044b1cd312f37701a9b4d0aad70bc5a4", - "0357349e985e742d5131e1e2b227b5170f6350ac2e2feb72254fcc25b3cee21a18", - "03c8ccb03c379e452f10c81232b41a1ca8b63d0baf8387e57d302c987e5abb8527" - ], - "covenant_quorum": 3, - "unbonding_time": 1000, - "unbonding_fee": 10000, - "max_staking_amount": 300000, - "min_staking_amount": 30000, - "max_staking_time": 10000, - "min_staking_time": 100, - "confirmation_depth": 10 - }, - { - "version": 1, - "activation_height": 200, - "staking_cap": 50000000, - "tag": "01020304", - "covenant_pks": [ - "03ffeaec52a9b407b355ef6967a7ffc15fd6c3fe07de2844d61550475e7a5233e5", - "03a5c60c2188e833d39d0fa798ab3f69aa12ed3dd2f3bad659effa252782de3c31", - "0359d3532148a597a2d05c0395bf5f7176044b1cd312f37701a9b4d0aad70bc5a4", - "0357349e985e742d5131e1e2b227b5170f6350ac2e2feb72254fcc25b3cee21a18" - ], - "covenant_quorum": 2, - "unbonding_time": 2000, - "unbonding_fee": 20000, - "max_staking_amount": 200000, - "min_staking_amount": 30000, - "max_staking_time": 20000, - "min_staking_time": 200, - "confirmation_depth": 10 - }, - { - "version": 2, - "activation_height": 300, - "cap_height": 500, - "tag": "01020304", - "covenant_pks": [ - "03ffeaec52a9b407b355ef6967a7ffc15fd6c3fe07de2844d61550475e7a5233e5", - "03a5c60c2188e833d39d0fa798ab3f69aa12ed3dd2f3bad659effa252782de3c31", - "0359d3532148a597a2d05c0395bf5f7176044b1cd312f37701a9b4d0aad70bc5a4", - "0357349e985e742d5131e1e2b227b5170f6350ac2e2feb72254fcc25b3cee21a18" - ], - "covenant_quorum": 2, - "unbonding_time": 2000, - "unbonding_fee": 20000, - "max_staking_amount": 200000, - "min_staking_amount": 30000, - "max_staking_time": 20000, - "min_staking_time": 200, - "confirmation_depth": 10 - }, - { - "version": 3, - "activation_height": 400, - "cap_height": 1000, - "tag": "01020304", - "covenant_pks": [ - "03ffeaec52a9b407b355ef6967a7ffc15fd6c3fe07de2844d61550475e7a5233e5", - "03a5c60c2188e833d39d0fa798ab3f69aa12ed3dd2f3bad659effa252782de3c31", - "0359d3532148a597a2d05c0395bf5f7176044b1cd312f37701a9b4d0aad70bc5a4", - "0357349e985e742d5131e1e2b227b5170f6350ac2e2feb72254fcc25b3cee21a18" - ], - "covenant_quorum": 2, - "unbonding_time": 2000, - "unbonding_fee": 20000, - "max_staking_amount": 200000, - "min_staking_amount": 30000, - "max_staking_time": 20000, - "min_staking_time": 200, - "confirmation_depth": 10 - } - ] -} diff --git a/tests/integration_test/active_staking_test.go b/tests/integration_test/active_staking_test.go deleted file mode 100644 index 596a1d76..00000000 --- a/tests/integration_test/active_staking_test.go +++ /dev/null @@ -1,134 +0,0 @@ -package tests - -import ( - "bytes" - "encoding/json" - "io" - "net/http" - "testing" - "time" - - "github.com/babylonlabs-io/staking-queue-client/client" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - handler "github.com/babylonlabs-io/staking-api-service/internal/shared/api/handlers/handler" - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - v1service "github.com/babylonlabs-io/staking-api-service/internal/v1/service" -) - -const ( - stakerDelegations = "/v1/staker/delegations" -) - -func TestUnbondActiveStaking(t *testing.T) { - activeStakingEvent := buildActiveStakingEvent(t, 1) - expiredStakingEvent := client.NewExpiredStakingEvent(activeStakingEvent[0].StakingTxHashHex, types.ActiveTxType.ToString()) - testServer := setupTestServer(t, nil) - defer testServer.Close() - sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, activeStakingEvent) - time.Sleep(2 * time.Second) - sendTestMessage(testServer.Queues.V1QueueClient.ExpiredStakingQueueClient, []client.ExpiredStakingEvent{expiredStakingEvent}) - time.Sleep(2 * time.Second) - - // Test the API - url := testServer.Server.URL + stakerDelegations + "?staker_btc_pk=" + activeStakingEvent[0].StakerPkHex - resp, err := http.Get(url) - assert.NoError(t, err, "making GET request to delegations by staker pk should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var response handler.PublicResponse[[]v1service.DelegationPublic] - err = json.Unmarshal(bodyBytes, &response) - assert.NoError(t, err, "unmarshalling response body should not fail") - - // Check that the response body is as expected - assert.Equal(t, 1, len(response.Data), "expected contain 1 item in response") - assert.Equal(t, "unbonded", response.Data[0].State) -} - -func TestUnbondActiveStakingShouldTolerateOutOfOrder(t *testing.T) { - activeStakingEvent := buildActiveStakingEvent(t, 1) - expiredStakingEvent := client.NewExpiredStakingEvent(activeStakingEvent[0].StakingTxHashHex, types.ActiveTxType.ToString()) - testServer := setupTestServer(t, nil) - defer testServer.Close() - sendTestMessage(testServer.Queues.V1QueueClient.ExpiredStakingQueueClient, []client.ExpiredStakingEvent{expiredStakingEvent}) - time.Sleep(2 * time.Second) - sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, activeStakingEvent) - time.Sleep(10 * time.Second) - - // Test the API - url := testServer.Server.URL + stakerDelegations + "?staker_btc_pk=" + activeStakingEvent[0].StakerPkHex - resp, err := http.Get(url) - assert.NoError(t, err, "making GET request to delegations by staker pk should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var response handler.PublicResponse[[]v1service.DelegationPublic] - err = json.Unmarshal(bodyBytes, &response) - assert.NoError(t, err, "unmarshalling response body should not fail") - - // Check that the response body is as expected - assert.Equal(t, 1, len(response.Data), "expected contain 1 item in response") - assert.Equal(t, "unbonded", response.Data[0].State) -} - -func TestShouldNotUnbondIfNotActiveState(t *testing.T) { - activeStakingEvent := getTestActiveStakingEvent() - expiredStakingEvent := client.NewExpiredStakingEvent(activeStakingEvent.StakingTxHashHex, types.ActiveTxType.ToString()) - testServer := setupTestServer(t, nil) - defer testServer.Close() - err := sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, []client.ActiveStakingEvent{*activeStakingEvent}) - require.NoError(t, err) - time.Sleep(2 * time.Second) - - // Let's make a POST request to the unbonding endpoint to change the state to unbonding_requested - unbondingUrl := testServer.Server.URL + unbondingPath - requestBody := getTestUnbondDelegationRequestPayload(activeStakingEvent.StakingTxHashHex) - requestBodyBytes, err := json.Marshal(requestBody) - assert.NoError(t, err, "marshalling request body should not fail") - - resp, err := http.Post(unbondingUrl, "application/json", bytes.NewReader(requestBodyBytes)) - assert.NoError(t, err, "making POST request to unbonding endpoint should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 202 - assert.Equal(t, http.StatusAccepted, resp.StatusCode, "expected HTTP 202 Accepted status") - - sendTestMessage(testServer.Queues.V1QueueClient.ExpiredStakingQueueClient, []client.ExpiredStakingEvent{expiredStakingEvent}) - time.Sleep(2 * time.Second) - - // Test the API - url := testServer.Server.URL + stakerDelegations + "?staker_btc_pk=" + activeStakingEvent.StakerPkHex - resp, err = http.Get(url) - assert.NoError(t, err, "making GET request to delegations by staker pk should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var response handler.PublicResponse[[]v1service.DelegationPublic] - err = json.Unmarshal(bodyBytes, &response) - assert.NoError(t, err, "unmarshalling response body should not fail") - - // Check that the response body is as expected - assert.Equal(t, 1, len(response.Data), "expected contain 1 item in response") - // The state should not be updated to unbonded - assert.Equal(t, "unbonding_requested", response.Data[0].State) -} diff --git a/tests/integration_test/address_lookup_test.go b/tests/integration_test/address_lookup_test.go deleted file mode 100644 index aaff8412..00000000 --- a/tests/integration_test/address_lookup_test.go +++ /dev/null @@ -1,231 +0,0 @@ -package tests - -import ( - "encoding/json" - "io" - "math/rand" - "net/http" - "testing" - "time" - - "github.com/babylonlabs-io/staking-api-service/internal/shared/api/handlers/handler" - dbmodel "github.com/babylonlabs-io/staking-api-service/internal/shared/db/model" - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - "github.com/babylonlabs-io/staking-api-service/internal/shared/utils" - v1dbmodel "github.com/babylonlabs-io/staking-api-service/internal/v1/db/model" - "github.com/babylonlabs-io/staking-api-service/tests/testutils" - "github.com/stretchr/testify/assert" -) - -const ( - stakerPkLookupPath = "/v1/staker/pubkey-lookup" -) - -func FuzzTestPkAddressesMapping(f *testing.F) { - attachRandomSeedsToFuzzer(f, 3) - f.Fuzz(func(t *testing.T, seed int64) { - r := rand.New(rand.NewSource(seed)) - opts := &testutils.TestActiveEventGeneratorOpts{ - NumOfEvents: testutils.RandomPositiveInt(r, 5), - Stakers: testutils.GeneratePks(5), - } - activeStakingEvents := testutils.GenerateRandomActiveStakingEvents(r, opts) - var stakerPks []string - for _, event := range activeStakingEvents { - stakerPks = append(stakerPks, event.StakerPkHex) - } - testServer := setupTestServer(t, nil) - defer testServer.Close() - sendTestMessage( - testServer.Queues.V1QueueClient.ActiveStakingQueueClient, activeStakingEvents, - ) - time.Sleep(5 * time.Second) - - // Test the API - pks := []string{} - for _, event := range activeStakingEvents { - pks = append(pks, event.StakerPkHex) - } - pks = uniqueStrings(pks) - // randomly convert that into addresses with different types - addresses := []string{} - for _, pk := range pks { - addr, err := utils.DeriveAddressesFromNoCoordPk( - pk, testServer.Config.Server.BTCNetParam, - ) - assert.NoError(t, err, "deriving addresses from public key should not fail") - // Pick a random address type - addresses = append(addresses, pickRandomAddress(r, addr)) - } - result := performLookupRequest(t, testServer, addresses) - assert.Equal(t, len(pks), len(result), "expected the same number of results") - for _, addr := range addresses { - resultPk, ok := result[addr] - assert.True(t, ok, "expected the result to contain the address") - assert.Contains(t, pks, resultPk, "expected the result to contain the public key") - } - - // fetch with non-existent addresses - nonExistPks := testutils.GeneratePks(5) - nonExistentAddresses := []string{} - for _, pk := range nonExistPks { - addr, err := utils.DeriveAddressesFromNoCoordPk( - pk, testServer.Config.Server.BTCNetParam, - ) - assert.NoError(t, err, "deriving addresses from public key should not fail") - // Pick a random address type - nonExistentAddresses = append(nonExistentAddresses, pickRandomAddress(r, addr)) - } - nonExistentResult := performLookupRequest(t, testServer, nonExistentAddresses) - assert.Equal(t, 0, len(nonExistentResult)) - - // fetch with a mix of existent and non-existent addresses - mixedAddresses := append(addresses, nonExistentAddresses...) - mixedResult := performLookupRequest(t, testServer, mixedAddresses) - assert.Equal(t, len(addresses), len(mixedResult)) - }) -} - -func TestErrorForNoneTaprootOrNativeSegwitAddressLookup(t *testing.T) { - testServer := setupTestServer(t, nil) - defer testServer.Close() - // Test the API with a non-taproot or native segwit address - legacyAddress := "16o1TKSUWXy51oDpL5wbPxnezSGWC9rMPv" - url := testServer.Server.URL + stakerPkLookupPath + "?" + "address=" + legacyAddress - resp, err := http.Get(url) - assert.NoError(t, err) - defer resp.Body.Close() - assert.Equal(t, http.StatusBadRequest, resp.StatusCode) - - NestedSegWitAddress := "3A2yqzgfxwwqxgse5rDTCQ2qmxZhMnfd5b" - url = testServer.Server.URL + stakerPkLookupPath + "?" + "address=" + NestedSegWitAddress - resp, err = http.Get(url) - assert.NoError(t, err) - defer resp.Body.Close() - assert.Equal(t, http.StatusBadRequest, resp.StatusCode) -} - -// Manually build an older version of the stats event which does not have the -// IsOverflow field and has a schema version less than 1 -type event struct { - EventType int `json:"event_type"` - StakingTxHashHex string `json:"staking_tx_hash_hex"` - StakerPKHex string `json:"staker_pk_hex"` - FinalityProviderPKHex string `json:"finality_provider_pk_hex"` - StakingValue int64 `json:"staking_value"` - State string `json:"state"` -} - -func TestPkAddressMappingWorksForOlderStatsEventVersion(t *testing.T) { - r := rand.New(rand.NewSource(time.Now().UnixNano())) - testServer := setupTestServer(t, nil) - defer testServer.Close() - tx, txHash, err := testutils.GenerateRandomTx(r, nil) - assert.NoError(t, err, "failed to generate random tx") - stakerPk, err := testutils.RandomPk() - assert.NoError(t, err, "failed to generate random public key") - fpPk, err := testutils.RandomPk() - assert.NoError(t, err, "failed to generate random public key") - del := &v1dbmodel.DelegationDocument{ - StakingTxHashHex: txHash, - StakerPkHex: stakerPk, - FinalityProviderPkHex: fpPk, - StakingValue: uint64(testutils.RandomAmount(r)), - State: types.Active, - StakingTx: &v1dbmodel.TimelockTransaction{ - TxHex: tx.TxHash().String(), - OutputIndex: uint64(tx.TxOut[0].Value), - StartTimestamp: time.Now().Unix(), - StartHeight: 1, - TimeLock: 100, - }, - IsOverflow: false, - } - oldStatsMsg := &event{ - EventType: 5, - StakingTxHashHex: del.StakingTxHashHex, - StakerPKHex: del.StakerPkHex, - FinalityProviderPKHex: del.FinalityProviderPkHex, - StakingValue: int64(del.StakingValue), - State: string(del.State), - } - testutils.InjectDbDocument( - testServer.Config, dbmodel.V1DelegationCollection, del, - ) - sendTestMessage( - testServer.Queues.V1QueueClient.StatsQueueClient, []event{*oldStatsMsg}, - ) - time.Sleep(5 * time.Second) - - // inspect the items in the database - pkAddresses, err := testutils.InspectDbDocuments[dbmodel.PkAddressMapping]( - testServer.Config, dbmodel.PkAddressMappingsCollection, - ) - assert.NoError(t, err, "failed to inspect the items in the database") - assert.Equal(t, 1, len(pkAddresses), "expected only one item in the database") - assert.Equal(t, del.StakerPkHex, pkAddresses[0].PkHex) - // Check the address is correct - addresses, err := utils.DeriveAddressesFromNoCoordPk( - del.StakerPkHex, testServer.Config.Server.BTCNetParam, - ) - assert.NoError(t, err, "failed to derive addresses from the public key") - assert.Equal(t, addresses.Taproot, pkAddresses[0].Taproot) - assert.Equal(t, addresses.NativeSegwitOdd, pkAddresses[0].NativeSegwitOdd) - assert.Equal(t, addresses.NativeSegwitEven, pkAddresses[0].NativeSegwitEven) -} - -func pickRandomAddress(r *rand.Rand, addresses *utils.SupportedAddress) string { - choices := []string{ - addresses.Taproot, addresses.NativeSegwitEven, addresses.NativeSegwitOdd, - } - return choices[r.Intn(len(choices))] -} - -func performLookupRequest( - t *testing.T, testServer *TestServer, addresses []string, -) map[string]string { - // form the addresses query as a string with format of `address=xyz&address=abc` - query := "" - for index, addr := range addresses { - if index == len(addresses)-1 { - query += "address=" + addr - } else { - query += "address=" + addr + "&" - } - } - - url := testServer.Server.URL + stakerPkLookupPath + "?" + query - resp, err := http.Get(url) - assert.NoError(t, err) - defer resp.Body.Close() - - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode) - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err) - - var response handler.PublicResponse[map[string]string] - err = json.Unmarshal(bodyBytes, &response) - assert.NoError(t, err) - return response.Data -} - -func uniqueStrings(input []string) []string { - // Create a map to track unique strings - uniqueMap := make(map[string]struct{}) - - // Iterate over the input slice and add each string to the map - for _, str := range input { - uniqueMap[str] = struct{}{} - } - - // Create a slice to hold the unique strings - var uniqueSlice []string - for str := range uniqueMap { - uniqueSlice = append(uniqueSlice, str) - } - - return uniqueSlice -} diff --git a/tests/integration_test/assets_checking_test.go b/tests/integration_test/assets_checking_test.go deleted file mode 100644 index 1a4fdf46..00000000 --- a/tests/integration_test/assets_checking_test.go +++ /dev/null @@ -1,269 +0,0 @@ -package tests - -import ( - "bytes" - "encoding/json" - "math/rand" - "net/http" - "testing" - - "github.com/babylonlabs-io/staking-api-service/internal/shared/api" - "github.com/babylonlabs-io/staking-api-service/internal/shared/api/handlers/handler" - "github.com/babylonlabs-io/staking-api-service/internal/shared/config" - "github.com/babylonlabs-io/staking-api-service/internal/shared/http/clients" - "github.com/babylonlabs-io/staking-api-service/internal/shared/http/clients/ordinals" - "github.com/babylonlabs-io/staking-api-service/internal/shared/services/service" - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - "github.com/babylonlabs-io/staking-api-service/internal/shared/utils" - "github.com/babylonlabs-io/staking-api-service/tests/mocks" - "github.com/babylonlabs-io/staking-api-service/tests/testutils" - "github.com/btcsuite/btcd/chaincfg" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -const verifyUTXOsPath = "/v1/ordinals/verify-utxos" - -func TestVerifyUtxosEndpointNotAvailableIfAssetsConfigNotSet(t *testing.T) { - cfg, err := config.New("../config/config-test.yml") - if err != nil { - t.Fatalf("Failed to load test config: %v", err) - } - cfg.Assets = nil - - testServer := setupTestServer(t, &TestServerDependency{ConfigOverrides: cfg}) - defer testServer.Close() - - url := testServer.Server.URL + verifyUTXOsPath - resp, err := http.Post(url, "application/json", bytes.NewReader([]byte{})) - if err != nil { - t.Fatalf("Failed to make POST request to %s: %v", url, err) - } - defer resp.Body.Close() - - assert.Equal(t, http.StatusNotFound, resp.StatusCode) -} - -func FuzzSuccessfullyVerifyUTXOsAssetsViaOrdinalService(f *testing.F) { - attachRandomSeedsToFuzzer(f, 10) - f.Fuzz(func(t *testing.T, seed int64) { - r := rand.New(rand.NewSource(seed)) - numOfUTXOs := testutils.RandomPositiveInt(r, 100) - payload := createPayload(t, r, &chaincfg.MainNetParams, numOfUTXOs) - jsonPayload, err := json.Marshal(payload) - assert.NoError(t, err, "failed to marshal payload") - - // create some ordinal responses that contains inscriptions - numOfUTXOsWithAsset := r.Intn(numOfUTXOs) - - var txidsWithAsset []string - for i := 0; i < numOfUTXOsWithAsset; i++ { - txidsWithAsset = append(txidsWithAsset, payload.UTXOs[i].Txid) - } - - mockedOrdinalResponse := createOrdinalServiceResponse(t, r, payload.UTXOs, txidsWithAsset) - - mockOrdinal := new(mocks.OrdinalsClient) - mockOrdinal.On("FetchUTXOInfos", mock.Anything, mock.Anything).Return(mockedOrdinalResponse, nil) - mockedClients := &clients.Clients{ - Ordinals: mockOrdinal, - } - testServer := setupTestServer(t, &TestServerDependency{MockedClients: mockedClients}) - defer testServer.Close() - - url := testServer.Server.URL + verifyUTXOsPath - resp, err := http.Post(url, "application/json", bytes.NewReader(jsonPayload)) - if err != nil { - t.Fatalf("Failed to make POST request to %s: %v", url, err) - } - defer resp.Body.Close() - - assert.Equal(t, http.StatusOK, resp.StatusCode) - // decode the response body - var response handler.PublicResponse[[]service.SafeUTXOPublic] - err = json.NewDecoder(resp.Body).Decode(&response) - if err != nil { - t.Fatalf("Failed to decode response body: %v", err) - } - - // check the response - assert.Equal(t, len(payload.UTXOs), len(response.Data)) - // check if the inscriptions are correctly returned and order is preserved - for i, u := range response.Data { - // Make sure the UTXO identifiers are correct - assert.Equal(t, payload.UTXOs[i].Txid, u.TxId) - assert.Equal(t, payload.UTXOs[i].Vout, u.Vout) - var isWithAsset bool - for _, txid := range txidsWithAsset { - if txid == u.TxId { - assert.True(t, u.Inscription) - isWithAsset = true - break - } - } - if !isWithAsset { - assert.False(t, u.Inscription) - } - } - - mockOrdinal.AssertNumberOfCalls( - t, "FetchUTXOInfos", - 1, - ) - }) -} - -func FuzzErrorWhenExceedMaxAllowedLength(f *testing.F) { - attachRandomSeedsToFuzzer(f, 10) - f.Fuzz(func(t *testing.T, seed int64) { - r := rand.New(rand.NewSource(seed)) - cfg, err := config.New("../config/config-test.yml") - if err != nil { - t.Fatalf("Failed to load test config: %v", err) - } - numOfUTXOs := testutils.RandomPositiveInt(r, 100) + int(cfg.Assets.MaxUTXOs) - payload := createPayload(t, r, &chaincfg.MainNetParams, numOfUTXOs) - jsonPayload, err := json.Marshal(payload) - assert.NoError(t, err) - - testServer := setupTestServer(t, nil) - defer testServer.Close() - - url := testServer.Server.URL + verifyUTXOsPath - resp, err := http.Post(url, "application/json", bytes.NewReader(jsonPayload)) - if err != nil { - t.Fatalf("Failed to make POST request to %s: %v", url, err) - } - defer resp.Body.Close() - - assert.Equal(t, http.StatusBadRequest, resp.StatusCode) - - // decode the response body - var response api.ErrorResponse - err = json.NewDecoder(resp.Body).Decode(&response) - if err != nil { - t.Fatalf("Failed to decode response body: %v", err) - } - - assert.Equal(t, types.BadRequest.String(), response.ErrorCode, "expected error code to be BAD_REQUEST") - assert.Equal(t, "too many UTXOs in the request", response.Message, "expected error message to be 'too many UTXOs in the request'") - }) -} - -func FuzzErrorWithInvalidTxid(f *testing.F) { - attachRandomSeedsToFuzzer(f, 10) - f.Fuzz(func(t *testing.T, seed int64) { - r := rand.New(rand.NewSource(seed)) - cfg, err := config.New("../config/config-test.yml") - if err != nil { - t.Fatalf("Failed to load test config: %v", err) - } - numOfUTXOs := testutils.RandomPositiveInt(r, int(cfg.Assets.MaxUTXOs)) - - payload := createPayload(t, r, &chaincfg.MainNetParams, numOfUTXOs) - // Create an invalid UTXO txid - payload.UTXOs[r.Intn(numOfUTXOs)].Txid = testutils.RandomString(r, 64) - jsonPayload, err := json.Marshal(payload) - assert.NoError(t, err) - - testServer := setupTestServer(t, nil) - defer testServer.Close() - - url := testServer.Server.URL + verifyUTXOsPath - resp, err := http.Post(url, "application/json", bytes.NewReader(jsonPayload)) - if err != nil { - t.Fatalf("Failed to make POST request to %s: %v", url, err) - } - defer resp.Body.Close() - - assert.Equal(t, http.StatusBadRequest, resp.StatusCode) - - var response api.ErrorResponse - err = json.NewDecoder(resp.Body).Decode(&response) - if err != nil { - t.Fatalf("Failed to decode response body: %v", err) - } - - assert.Equal(t, types.BadRequest.String(), response.ErrorCode, "expected error code to be BAD_REQUEST") - assert.Contains(t, response.Message, "invalid UTXO txid", "expected error message to contain 'invalid UTXO txid'") - }) -} - -func createOrdinalServiceResponse(t *testing.T, r *rand.Rand, utxos []types.UTXOIdentifier, txidsWithAsset []string) []ordinals.OrdinalsOutputResponse { - var responses []ordinals.OrdinalsOutputResponse - - for _, utxo := range utxos { - withAsset := false - for _, txid := range txidsWithAsset { - if txid == utxo.Txid { - withAsset = true - break - } - } - if withAsset { - // randomly inject runes or inscriptions - if r.Intn(2) == 0 { - responses = append(responses, ordinals.OrdinalsOutputResponse{ - Transaction: utxo.Txid, - Inscriptions: []string{testutils.RandomString(r, r.Intn(100))}, - Runes: json.RawMessage(`{}`), - }) - } else { - responses = append(responses, ordinals.OrdinalsOutputResponse{ - Transaction: utxo.Txid, - Inscriptions: []string{}, - Runes: json.RawMessage(`{"rune1": "rune1"}`), - }) - } - } else { - responses = append(responses, ordinals.OrdinalsOutputResponse{ - Transaction: utxo.Txid, - Inscriptions: []string{}, - Runes: json.RawMessage(`{}`), - }) - } - } - return responses -} - -func createPayload(t *testing.T, r *rand.Rand, netParam *chaincfg.Params, size int) handler.VerifyUTXOsRequestPayload { - var utxos []types.UTXOIdentifier - - for i := 0; i < size; i++ { - tx, _, err := testutils.GenerateRandomTx(r, nil) - if err != nil { - t.Fatalf("Failed to generate random tx: %v", err) - } - txid := tx.TxHash().String() - utxos = append(utxos, types.UTXOIdentifier{ - Txid: txid, - Vout: uint32(r.Intn(10)), - }) - } - pk, err := testutils.RandomPk() - if err != nil { - t.Fatalf("Failed to generate random pk: %v", err) - } - addresses, err := utils.DeriveAddressesFromNoCoordPk(pk, netParam) - if err != nil { - t.Fatalf("Failed to generate taproot address from pk: %v", err) - } - return handler.VerifyUTXOsRequestPayload{ - UTXOs: utxos, - Address: addresses.Taproot, - } -} - -// Chunk function to split a slice into chunks of specified size -func Chunk[T any](slice []T, size int) [][]T { - if size <= 0 { - return nil // Return nil if the size is invalid - } - - var chunks [][]T - for size < len(slice) { - slice, chunks = slice[size:], append(chunks, slice[0:size:size]) - } - chunks = append(chunks, slice) - return chunks -} diff --git a/tests/integration_test/delegation_test.go b/tests/integration_test/delegation_test.go deleted file mode 100644 index 75aa9201..00000000 --- a/tests/integration_test/delegation_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package tests - -import ( - "encoding/json" - "io" - "math/rand" - "net/http" - "testing" - "time" - - "github.com/babylonlabs-io/staking-queue-client/client" - "github.com/stretchr/testify/assert" - - handler "github.com/babylonlabs-io/staking-api-service/internal/shared/api/handlers/handler" - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - v1service "github.com/babylonlabs-io/staking-api-service/internal/v1/service" - "github.com/babylonlabs-io/staking-api-service/tests/testutils" -) - -const ( - delegationRouter = "/v1/delegation" -) - -func TestGetDelegationByTxHashHex(t *testing.T) { - r := rand.New(rand.NewSource(time.Now().UnixNano())) - activeStakingEvent := testutils.GenerateRandomActiveStakingEvents( - r, - &testutils.TestActiveEventGeneratorOpts{ - NumOfEvents: 1, - FinalityProviders: testutils.GeneratePks(1), - Stakers: testutils.GeneratePks(1), - }, - ) - - expiredStakingEvent := client.NewExpiredStakingEvent(activeStakingEvent[0].StakingTxHashHex, types.ActiveTxType.ToString()) - testServer := setupTestServer(t, nil) - defer testServer.Close() - sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, activeStakingEvent) - time.Sleep(2 * time.Second) - sendTestMessage(testServer.Queues.V1QueueClient.ExpiredStakingQueueClient, []client.ExpiredStakingEvent{expiredStakingEvent}) - time.Sleep(2 * time.Second) - - // Test the API - url := testServer.Server.URL + delegationRouter + "?staking_tx_hash_hex=" + activeStakingEvent[0].StakingTxHashHex - resp, err := http.Get(url) - assert.NoError(t, err, "making GET request to delegation by tx hash should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var response handler.PublicResponse[v1service.DelegationPublic] - err = json.Unmarshal(bodyBytes, &response) - assert.NoError(t, err, "unmarshalling response body should not fail") - - // Check that the response body is as expected - assert.Equal(t, "unbonded", response.Data.State) - assert.Equal(t, activeStakingEvent[0].StakingTxHashHex, response.Data.StakingTxHashHex) -} diff --git a/tests/integration_test/finality_provider_test.go b/tests/integration_test/finality_provider_test.go deleted file mode 100644 index 32bffbc0..00000000 --- a/tests/integration_test/finality_provider_test.go +++ /dev/null @@ -1,472 +0,0 @@ -package tests - -import ( - "encoding/json" - "errors" - "io" - "math/rand" - "net/http" - "testing" - "time" - - handler "github.com/babylonlabs-io/staking-api-service/internal/shared/api/handlers/handler" - "github.com/babylonlabs-io/staking-api-service/internal/shared/config" - "github.com/babylonlabs-io/staking-api-service/internal/shared/db" - dbclients "github.com/babylonlabs-io/staking-api-service/internal/shared/db/clients" - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - v1dbmodel "github.com/babylonlabs-io/staking-api-service/internal/v1/db/model" - v1service "github.com/babylonlabs-io/staking-api-service/internal/v1/service" - testmock "github.com/babylonlabs-io/staking-api-service/tests/mocks" - "github.com/babylonlabs-io/staking-api-service/tests/testutils" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "go.mongodb.org/mongo-driver/mongo" -) - -const ( - finalityProvidersPath = "/v1/finality-providers" -) - -func shouldGetFinalityProvidersSuccessfully(t *testing.T, testServer *TestServer) { - url := testServer.Server.URL + finalityProvidersPath - defer testServer.Close() - - responseBody := fetchSuccessfulResponse[[]v1service.FpDetailsPublic](t, url) - result := responseBody.Data - assert.Equal(t, "Babylon Foundation 2", result[2].Description.Moniker) - assert.Equal(t, "0.060000000000000000", result[1].Commission) - assert.Equal(t, "0d2f9728abc45c0cdeefdd73f52a0e0102470e35fb689fc5bc681959a61b021f", result[3].BtcPk) - assert.Equal(t, "094f5861be4128861d69ea4b66a5f974943f100f55400bf26f5cce124b4c9af7", result[2].BtcPk) - - assert.Equal(t, 4, len(result)) - - assert.Equal(t, int64(0), result[0].ActiveTvl) - assert.Equal(t, int64(0), result[0].TotalTvl) - assert.Equal(t, int64(0), result[0].ActiveDelegations) - assert.Equal(t, int64(0), result[0].TotalDelegations) -} - -func TestGetFinalityProvidersSuccessfully(t *testing.T) { - testServer := setupTestServer(t, nil) - shouldGetFinalityProvidersSuccessfully(t, testServer) -} - -func TestGetFinalityProviderShouldNotFailInCaseOfDbFailure(t *testing.T) { - mockV1DBClient := new(testmock.V1DBClient) - mockV1DBClient.On("FindFinalityProviderStats", mock.Anything, mock.Anything).Return(nil, errors.New("just an error")) - mockMongoClient := &mongo.Client{} - testServer := setupTestServer(t, &TestServerDependency{MockDbClients: dbclients.DbClients{ - StakingMongoClient: mockMongoClient, - V1DBClient: mockV1DBClient, - }}) - shouldGetFinalityProvidersSuccessfully(t, testServer) -} - -func TestGetFinalityProviderShouldReturnFallbackToGlobalParams(t *testing.T) { - mockedResultMap := &db.DbResultMap[*v1dbmodel.FinalityProviderStatsDocument]{ - Data: []*v1dbmodel.FinalityProviderStatsDocument{}, - PaginationToken: "", - } - mockV1DBClient := new(testmock.V1DBClient) - mockV1DBClient.On("FindFinalityProviderStats", mock.Anything, mock.Anything).Return(mockedResultMap, nil) - mockMongoClient := &mongo.Client{} - - testServer := setupTestServer(t, &TestServerDependency{MockDbClients: dbclients.DbClients{ - StakingMongoClient: mockMongoClient, - V1DBClient: mockV1DBClient, - }}) - shouldGetFinalityProvidersSuccessfully(t, testServer) -} - -func TestGetFinalityProviderReturn4xxErrorIfPageTokenInvalid(t *testing.T) { - mockV1DBClient := new(testmock.V1DBClient) - mockV1DBClient.On("FindFinalityProviderStats", mock.Anything, mock.Anything).Return(nil, &db.InvalidPaginationTokenError{}) - mockMongoClient := &mongo.Client{} - - testServer := setupTestServer(t, &TestServerDependency{MockDbClients: dbclients.DbClients{ - StakingMongoClient: mockMongoClient, - V1DBClient: mockV1DBClient, - }}) - url := testServer.Server.URL + finalityProvidersPath - defer testServer.Close() - // Make a GET request to the finality providers endpoint - resp, err := http.Get(url) - assert.NoError(t, err, "making GET request to finality providers endpoint should not fail") - defer resp.Body.Close() - - assert.Equal(t, http.StatusBadRequest, resp.StatusCode) -} - -func TestGetFinalityProviderReturn4xxErrorIfPkInvalid(t *testing.T) { - testServer := setupTestServer(t, nil) - url := testServer.Server.URL + finalityProvidersPath + "?fp_btc_pk=invalid" - defer testServer.Close() - // Make a GET request to the finality providers endpoint - resp, err := http.Get(url) - assert.NoError(t, err) - defer resp.Body.Close() - - assert.Equal(t, http.StatusBadRequest, resp.StatusCode) -} - -func FuzzGetFinalityProviderShouldReturnAllRegisteredFps(f *testing.F) { - attachRandomSeedsToFuzzer(f, 100) - f.Fuzz(func(t *testing.T, seed int64) { - r := rand.New(rand.NewSource(seed)) - fpParams, registeredFpsStats, notRegisteredFpsStats := setUpFinalityProvidersStatsDataSet(t, r, nil) - - mockV1DBClient := new(testmock.V1DBClient) - mockV1DBClient.On("FindFinalityProviderStatsByFinalityProviderPkHex", - mock.Anything, mock.Anything, - ).Return(registeredFpsStats, nil) - - mockedFinalityProviderStats := &db.DbResultMap[*v1dbmodel.FinalityProviderStatsDocument]{ - Data: append(registeredFpsStats, notRegisteredFpsStats...), - PaginationToken: "", - } - mockV1DBClient.On("FindFinalityProviderStats", mock.Anything, mock.Anything).Return(mockedFinalityProviderStats, nil) - - mockMongoClient := &mongo.Client{} - - testServer := setupTestServer(t, &TestServerDependency{MockDbClients: dbclients.DbClients{ - StakingMongoClient: mockMongoClient, - V1DBClient: mockV1DBClient, - }, MockedFinalityProviders: fpParams}) - - url := testServer.Server.URL + finalityProvidersPath - defer testServer.Close() - // Make a GET request to the finality providers endpoint - resp, err := http.Get(url) - assert.NoError(t, err, "making GET request to finality providers endpoint should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var responseBody handler.PublicResponse[[]v1service.FpDetailsPublic] - err = json.Unmarshal(bodyBytes, &responseBody) - assert.NoError(t, err, "unmarshalling response body should not fail") - - result := responseBody.Data - // Check that the response body is as expected - - assert.NotEmptyf(t, result, "expected response body to be non-empty") - // We expect all registered finality providers to be returned, plus the one that is not registered - var fpParamsWithStakingMap = make(map[string]bool) - for _, fp := range fpParams { - found := false - for _, fpStat := range registeredFpsStats { - if fp.BtcPk == fpStat.FinalityProviderPkHex { - found = true - break - } - } - fpParamsWithStakingMap[fp.BtcPk] = found - } - assert.Equal(t, len(fpParams)+len(notRegisteredFpsStats), len(result)) - - resultMap := make(map[string]v1service.FpDetailsPublic) - for _, fp := range result { - resultMap[fp.BtcPk] = fp - } - - // Check all the registered finality providers should apprear in the response - for _, f := range fpParams { - assert.Equal(t, f.Description.Moniker, resultMap[f.BtcPk].Description.Moniker) - assert.Equal(t, f.Commission, resultMap[f.BtcPk].Commission) - // Check that the stats are correct for the registered finality providers without any delegations - if fpParamsWithStakingMap[f.BtcPk] == false { - assert.Equal(t, int64(0), resultMap[f.BtcPk].ActiveTvl) - assert.Equal(t, int64(0), resultMap[f.BtcPk].TotalTvl) - assert.Equal(t, int64(0), resultMap[f.BtcPk].ActiveDelegations) - assert.Equal(t, int64(0), resultMap[f.BtcPk].TotalDelegations) - } else { - assert.NotZero(t, resultMap[f.BtcPk].ActiveTvl) - assert.NotZero(t, resultMap[f.BtcPk].TotalTvl) - assert.NotZero(t, resultMap[f.BtcPk].ActiveDelegations) - assert.NotZero(t, resultMap[f.BtcPk].TotalDelegations) - } - } - for _, f := range notRegisteredFpsStats { - assert.Equal(t, "", resultMap[f.FinalityProviderPkHex].Description.Moniker) - } - }) -} - -func FuzzTestGetFinalityProviderWithPaginationResponse(f *testing.F) { - attachRandomSeedsToFuzzer(f, 3) - f.Fuzz(func(t *testing.T, seed int64) { - r := rand.New(rand.NewSource(seed)) - opts := &testutils.TestActiveEventGeneratorOpts{ - NumOfEvents: 20, - FinalityProviders: testutils.GeneratePks(20), - Stakers: testutils.GeneratePks(20), - } - - activeStakingEvents := testutils.GenerateRandomActiveStakingEvents(r, opts) - cfg, err := config.New("../config/config-test.yml") - if err != nil { - t.Fatalf("Failed to load test config: %v", err) - } - cfg.StakingDb.MaxPaginationLimit = 2 - - testServer := setupTestServer(t, &TestServerDependency{ConfigOverrides: cfg}) - defer testServer.Close() - sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, activeStakingEvents) - time.Sleep(10 * time.Second) - - var paginationKey string - var allDataCollected []v1service.FpDetailsPublic - var atLeastOnePage bool - // Test the API - for { - url := testServer.Server.URL + finalityProvidersPath + "?pagination_key=" + paginationKey - resp, err := http.Get(url) - assert.NoError(t, err, "making GET request to finality providers endpoint should not fail") - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - var response handler.PublicResponse[[]v1service.FpDetailsPublic] - err = json.Unmarshal(bodyBytes, &response) - assert.NoError(t, err, "unmarshalling response body should not fail") - - // Check that the response body is as expected - assert.NotEmptyf(t, response.Data, "expected response body to have data") - allDataCollected = append(allDataCollected, response.Data...) - if response.Pagination.NextKey != "" { - atLeastOnePage = true - paginationKey = response.Pagination.NextKey - } else { - break - } - } - - assert.True(t, atLeastOnePage, "expected at least one page") - for i := 0; i < len(allDataCollected)-1; i++ { - assert.True(t, allDataCollected[i].ActiveTvl >= allDataCollected[i+1].ActiveTvl) - } - }) -} - -func FuzzGetFinalityProviderShouldNotReturnRegisteredFpWithoutStakingForPaginatedDbResponse(f *testing.F) { - attachRandomSeedsToFuzzer(f, 100) - f.Fuzz(func(t *testing.T, seed int64) { - r := rand.New(rand.NewSource(seed)) - fpParams, registeredFpsStats, notRegisteredFpsStats := setUpFinalityProvidersStatsDataSet(t, r, nil) - - mockV1DBClient := new(testmock.V1DBClient) - mockV1DBClient.On("FindFinalityProviderStatsByFinalityProviderPkHex", - mock.Anything, mock.Anything, - ).Return(registeredFpsStats, nil) - - registeredWithoutStakeFpsStats := registeredFpsStats[:len(registeredFpsStats)-testutils.RandomPositiveInt(r, len(registeredFpsStats))] - - mockedFinalityProviderStats := &db.DbResultMap[*v1dbmodel.FinalityProviderStatsDocument]{ - Data: append(registeredWithoutStakeFpsStats, notRegisteredFpsStats...), - PaginationToken: "abcd", - } - mockV1DBClient.On("FindFinalityProviderStats", mock.Anything, mock.Anything).Return(mockedFinalityProviderStats, nil) - mockMongoClient := &mongo.Client{} - - testServer := setupTestServer(t, &TestServerDependency{MockDbClients: dbclients.DbClients{ - StakingMongoClient: mockMongoClient, - V1DBClient: mockV1DBClient, - }, MockedFinalityProviders: fpParams}) - - url := testServer.Server.URL + finalityProvidersPath - defer testServer.Close() - // Make a GET request to the finality providers endpoint - resp, err := http.Get(url) - assert.NoError(t, err, "making GET request to finality providers endpoint should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var responseBody handler.PublicResponse[[]v1service.FpDetailsPublic] - err = json.Unmarshal(bodyBytes, &responseBody) - assert.NoError(t, err, "unmarshalling response body should not fail") - result := responseBody.Data - - var registeredFpsWithoutStaking []string - for _, fp := range fpParams { - for _, fpStat := range registeredWithoutStakeFpsStats { - if fp.BtcPk == fpStat.FinalityProviderPkHex { - registeredFpsWithoutStaking = append(registeredFpsWithoutStaking, fp.BtcPk) - break - } - } - } - - assert.Equal(t, len(registeredWithoutStakeFpsStats)+len(notRegisteredFpsStats), len(result)) - assert.Less(t, len(registeredFpsWithoutStaking), len(fpParams)) - }) -} - -func FuzzShouldNotReturnDefaultFpFromParamsWhenPageTokenIsPresent(f *testing.F) { - attachRandomSeedsToFuzzer(f, 100) - f.Fuzz(func(t *testing.T, seed int64) { - r := rand.New(rand.NewSource(seed)) - opts := &SetupFpStatsDataSetOpts{ - NumOfRegisterFps: testutils.RandomPositiveInt(r, 10), - NumOfNotRegisteredFps: testutils.RandomPositiveInt(r, 10), - } - fpParams, registeredFpsStats, _ := setUpFinalityProvidersStatsDataSet(t, r, opts) - - mockV1DBClient := new(testmock.V1DBClient) - // Mock the response for the registered finality providers - numOfFpNotHaveStats := testutils.RandomPositiveInt(r, int(opts.NumOfRegisterFps)) - mockV1DBClient.On("FindFinalityProviderStatsByFinalityProviderPkHex", - mock.Anything, mock.Anything, - ).Return(registeredFpsStats[:len(registeredFpsStats)-numOfFpNotHaveStats], nil) - - // We are mocking the last page of the response where there is no more data to fetch - mockedFinalityProviderStats := &db.DbResultMap[*v1dbmodel.FinalityProviderStatsDocument]{ - Data: []*v1dbmodel.FinalityProviderStatsDocument{}, - PaginationToken: "", - } - mockV1DBClient.On("FindFinalityProviderStats", mock.Anything, mock.Anything).Return(mockedFinalityProviderStats, nil) - - mockMongoClient := &mongo.Client{} - testServer := setupTestServer(t, &TestServerDependency{MockDbClients: dbclients.DbClients{ - StakingMongoClient: mockMongoClient, - V1DBClient: mockV1DBClient, - }, MockedFinalityProviders: fpParams}) - - url := testServer.Server.URL + finalityProvidersPath + "?pagination_key=abcd" - defer testServer.Close() - // Make a GET request to the finality providers endpoint - resp, err := http.Get(url) - assert.NoError(t, err, "making GET request to finality providers endpoint should not fail") - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - var response handler.PublicResponse[[]v1service.FpDetailsPublic] - err = json.Unmarshal(bodyBytes, &response) - assert.NoError(t, err, "unmarshalling response body should not fail") - assert.Equal(t, numOfFpNotHaveStats, len(response.Data)) - }) -} - -func FuzzGetFinalityProvider(f *testing.F) { - attachRandomSeedsToFuzzer(f, 3) - f.Fuzz(func(t *testing.T, seed int64) { - r := rand.New(rand.NewSource(seed)) - fpParams, registeredFpsStats, notRegisteredFpsStats := setUpFinalityProvidersStatsDataSet(t, r, nil) - // Manually force a single value for the finality provider to be used in db mocking - fpStats := []*v1dbmodel.FinalityProviderStatsDocument{registeredFpsStats[0]} - - mockV1DBClient := new(testmock.V1DBClient) - mockV1DBClient.On("FindFinalityProviderStatsByFinalityProviderPkHex", - mock.Anything, mock.Anything, - ).Return(fpStats, nil) - mockMongoClient := &mongo.Client{} - - testServer := setupTestServer(t, &TestServerDependency{MockDbClients: dbclients.DbClients{ - StakingMongoClient: mockMongoClient, - V1DBClient: mockV1DBClient, - }, MockedFinalityProviders: fpParams}) - url := testServer.Server.URL + finalityProvidersPath + "?fp_btc_pk=" + fpParams[0].BtcPk - // Make a GET request to the finality providers endpoint - respBody := fetchSuccessfulResponse[[]v1service.FpDetailsPublic](t, url) - result := respBody.Data - assert.Equal(t, 1, len(result)) - assert.Equal(t, fpParams[0].Description.Moniker, result[0].Description.Moniker) - assert.Equal(t, fpParams[0].Commission, result[0].Commission) - assert.Equal(t, fpParams[0].BtcPk, result[0].BtcPk) - assert.Equal(t, registeredFpsStats[0].ActiveTvl, result[0].ActiveTvl) - assert.Equal(t, registeredFpsStats[0].TotalTvl, result[0].TotalTvl) - assert.Equal(t, registeredFpsStats[0].ActiveDelegations, result[0].ActiveDelegations) - assert.Equal(t, registeredFpsStats[0].TotalDelegations, result[0].TotalDelegations) - testServer.Close() - - // Test the API with a non-existent finality provider from notRegisteredFpsStats - fpStats = []*v1dbmodel.FinalityProviderStatsDocument{notRegisteredFpsStats[0]} - mockV1DBClient = new(testmock.V1DBClient) - mockV1DBClient.On("FindFinalityProviderStatsByFinalityProviderPkHex", - mock.Anything, mock.Anything, - ).Return(fpStats, nil) - testServer = setupTestServer(t, &TestServerDependency{ - MockDbClients: dbclients.DbClients{ - StakingMongoClient: mockMongoClient, - V1DBClient: mockV1DBClient, - }, - MockedFinalityProviders: fpParams, - }) - notRegisteredFp := notRegisteredFpsStats[0] - url = testServer.Server.URL + - finalityProvidersPath + - "?fp_btc_pk=" + notRegisteredFp.FinalityProviderPkHex - respBody = fetchSuccessfulResponse[[]v1service.FpDetailsPublic](t, url) - result = respBody.Data - assert.Equal(t, 1, len(result)) - assert.Equal(t, "", result[0].Description.Moniker) - assert.Equal(t, "", result[0].Commission) - assert.Equal(t, notRegisteredFp.FinalityProviderPkHex, result[0].BtcPk) - assert.Equal(t, notRegisteredFp.ActiveTvl, result[0].ActiveTvl) - testServer.Close() - - // Test the API with a non-existent finality provider PK - randomPk, err := testutils.RandomPk() - testServer = setupTestServer(t, &TestServerDependency{ - MockedFinalityProviders: fpParams, - }) - defer testServer.Close() - assert.NoError(t, err, "generating random public key should not fail") - url = testServer.Server.URL + finalityProvidersPath + "?fp_btc_pk=" + randomPk - respBody = fetchSuccessfulResponse[[]v1service.FpDetailsPublic](t, url) - result = respBody.Data - assert.Equal(t, 0, len(result)) - }) -} - -func generateFinalityProviderStatsDocument(r *rand.Rand, pk string) *v1dbmodel.FinalityProviderStatsDocument { - return &v1dbmodel.FinalityProviderStatsDocument{ - FinalityProviderPkHex: pk, - ActiveTvl: testutils.RandomAmount(r), - TotalTvl: testutils.RandomAmount(r), - ActiveDelegations: r.Int63n(100) + 1, - TotalDelegations: r.Int63n(1000) + 1, - } -} - -type SetupFpStatsDataSetOpts struct { - NumOfRegisterFps int - NumOfNotRegisteredFps int -} - -func setUpFinalityProvidersStatsDataSet(t *testing.T, r *rand.Rand, opts *SetupFpStatsDataSetOpts) ([]types.FinalityProviderDetails, []*v1dbmodel.FinalityProviderStatsDocument, []*v1dbmodel.FinalityProviderStatsDocument) { - numOfRegisterFps := testutils.RandomPositiveInt(r, 10) - numOfNotRegisteredFps := testutils.RandomPositiveInt(r, 10) - if opts != nil { - numOfRegisterFps = opts.NumOfRegisterFps - numOfNotRegisteredFps = opts.NumOfNotRegisteredFps - } - fpParams := testutils.GenerateRandomFinalityProviderDetail(r, uint64(numOfRegisterFps)) - - // Generate a set of registered finality providers - var registeredFpsStats []*v1dbmodel.FinalityProviderStatsDocument - for i := 0; i < numOfRegisterFps; i++ { - fpStats := generateFinalityProviderStatsDocument(r, fpParams[i].BtcPk) - registeredFpsStats = append(registeredFpsStats, fpStats) - } - - var notRegisteredFpsStats []*v1dbmodel.FinalityProviderStatsDocument - for i := 0; i < numOfNotRegisteredFps; i++ { - fpNotRegisteredPk, err := testutils.RandomPk() - assert.NoError(t, err, "generating random public key should not fail") - - stats := generateFinalityProviderStatsDocument(r, fpNotRegisteredPk) - notRegisteredFpsStats = append(notRegisteredFpsStats, stats) - } - assert.LessOrEqual(t, len(registeredFpsStats), len(fpParams)) - - return fpParams, registeredFpsStats, notRegisteredFpsStats -} diff --git a/tests/integration_test/global_params_test.go b/tests/integration_test/global_params_test.go deleted file mode 100644 index 1a7ab4fa..00000000 --- a/tests/integration_test/global_params_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package tests - -import ( - "encoding/json" - "io" - "net/http" - "testing" - - handler "github.com/babylonlabs-io/staking-api-service/internal/shared/api/handlers/handler" - v1service "github.com/babylonlabs-io/staking-api-service/internal/v1/service" - "github.com/stretchr/testify/assert" -) - -const ( - globalParamsPath = "/v1/global-params" -) - -func TestGlobalParams(t *testing.T) { - testServer := setupTestServer(t, nil) - defer testServer.Close() - - url := testServer.Server.URL + globalParamsPath - - // Make a GET request to the global params endpoint - resp, err := http.Get(url) - assert.NoError(t, err, "making GET request to global params endpoint should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var responseBody handler.PublicResponse[v1service.GlobalParamsPublic] - err = json.Unmarshal(bodyBytes, &responseBody) - assert.NoError(t, err, "unmarshalling response body should not fail") - - result := responseBody.Data.Versions - // Check that the response body is as expected - assert.NotEmptyf(t, result, "expected response body to be non-empty") - assert.Equal(t, 4, len(result)) - versionedGlobalParam := result[0] - assert.Equal(t, uint64(0), versionedGlobalParam.Version) - assert.Equal(t, uint64(100), versionedGlobalParam.ActivationHeight) - assert.Equal(t, uint64(5000000), versionedGlobalParam.StakingCap) - assert.Equal(t, "01020304", versionedGlobalParam.Tag) - assert.Equal(t, 5, len(versionedGlobalParam.CovenantPks)) - assert.Equal(t, uint64(3), versionedGlobalParam.CovenantQuorum) - assert.Equal(t, uint64(1000), versionedGlobalParam.UnbondingTime) - assert.Equal(t, uint64(10000), versionedGlobalParam.UnbondingFee) - assert.Equal(t, uint64(300000), versionedGlobalParam.MaxStakingAmount) - assert.Equal(t, uint64(30000), versionedGlobalParam.MinStakingAmount) - assert.Equal(t, uint64(10000), versionedGlobalParam.MaxStakingTime) - assert.Equal(t, uint64(100), versionedGlobalParam.MinStakingTime) - assert.Equal(t, uint64(10), versionedGlobalParam.ConfirmationDepth) - - versionedGlobalParam2 := result[1] - assert.Equal(t, uint64(1), versionedGlobalParam2.Version) - assert.Equal(t, uint64(200), versionedGlobalParam2.ActivationHeight) - assert.Equal(t, uint64(50000000), versionedGlobalParam2.StakingCap) - assert.Equal(t, "01020304", versionedGlobalParam2.Tag) - assert.Equal(t, 4, len(versionedGlobalParam2.CovenantPks)) - assert.Equal(t, uint64(2), versionedGlobalParam2.CovenantQuorum) - assert.Equal(t, uint64(2000), versionedGlobalParam2.UnbondingTime) - assert.Equal(t, uint64(20000), versionedGlobalParam2.UnbondingFee) - assert.Equal(t, uint64(200000), versionedGlobalParam2.MaxStakingAmount) - assert.Equal(t, uint64(30000), versionedGlobalParam2.MinStakingAmount) - assert.Equal(t, uint64(20000), versionedGlobalParam2.MaxStakingTime) - assert.Equal(t, uint64(200), versionedGlobalParam2.MinStakingTime) - assert.Equal(t, uint64(10), versionedGlobalParam2.ConfirmationDepth) - - versionedGlobalParam3 := result[2] - assert.Equal(t, uint64(2), versionedGlobalParam3.Version) - assert.Equal(t, uint64(300), versionedGlobalParam3.ActivationHeight) - assert.Equal(t, uint64(500), versionedGlobalParam3.CapHeight) - assert.Equal(t, uint64(0), versionedGlobalParam3.StakingCap) - - versionedGlobalParam4 := result[3] - assert.Equal(t, uint64(3), versionedGlobalParam4.Version) - assert.Equal(t, uint64(400), versionedGlobalParam4.ActivationHeight) - assert.Equal(t, uint64(1000), versionedGlobalParam4.CapHeight) - assert.Equal(t, uint64(0), versionedGlobalParam4.StakingCap) -} diff --git a/tests/integration_test/healthcheck_test.go b/tests/integration_test/healthcheck_test.go deleted file mode 100644 index ad23019e..00000000 --- a/tests/integration_test/healthcheck_test.go +++ /dev/null @@ -1,135 +0,0 @@ -package tests - -import ( - "encoding/json" - "io" - "net/http" - "testing" - - dbclients "github.com/babylonlabs-io/staking-api-service/internal/shared/db/clients" - testmock "github.com/babylonlabs-io/staking-api-service/tests/mocks" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "go.mongodb.org/mongo-driver/mongo" -) - -const ( - healthCheckPath = "/healthcheck" -) - -func TestHealthCheck(t *testing.T) { - testServer := setupTestServer(t, nil) - defer testServer.Close() - - url := testServer.Server.URL + healthCheckPath - - // Make a GET request to the health check endpoint - resp, err := http.Get(url) - assert.NoError(t, err, "making GET request to health check endpoint should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var responseBody map[string]string - err = json.Unmarshal(bodyBytes, &responseBody) - assert.NoError(t, err, "unmarshalling response body should not fail") - - // Check that the response body is as expected - assert.Equal(t, "Server is up and running", responseBody["data"], "expected response body to match") -} - -// Test the db connection error case -func TestHealthCheckDBError(t *testing.T) { - mockDbClients := new(testmock.DBClient) - mockDbClients.On("Ping", mock.Anything).Return(io.EOF) // Expect db error - mockMongoClient := &mongo.Client{} - mockIndexerDbClient := &mongo.Client{} - - testServer := setupTestServer(t, &TestServerDependency{MockDbClients: dbclients.DbClients{ - StakingMongoClient: mockMongoClient, - IndexerMongoClient: mockIndexerDbClient, - SharedDBClient: mockDbClients, - }}) - - defer testServer.Close() - - url := testServer.Server.URL + healthCheckPath - - // Make a GET request to the health check endpoint - resp, err := http.Get(url) - assert.NoError(t, err, "making GET request to health check endpoint should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 500 Internal Server Error - assert.Equal(t, http.StatusInternalServerError, resp.StatusCode, "expected HTTP 500 Internal Server Error status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - // Convert the response body to a string - responseBody := string(bodyBytes) - - assert.Equal(t, "{\"errorCode\":\"INTERNAL_SERVICE_ERROR\",\"message\":\"Internal service error\"}", responseBody, "expected response body to match") -} - -func TestOptionsRequest(t *testing.T) { - testServer := setupTestServer(t, nil) - defer testServer.Close() - - url := testServer.Server.URL + healthCheckPath - - // Make a OPTION request to the health check endpoint - client := &http.Client{} - req, err := http.NewRequest("OPTIONS", url, nil) - assert.NoError(t, err, "making OPTION request to health check endpoint should not fail") - req.Header.Add("Origin", "https://dashboard.testnet3.babylonlabs-io.io") - req.Header.Add("Access-Control-Request-Headers", "Content-Type") - req.Header.Add("Access-Control-Request-Method", "GET") - - // Send the request - resp, err := client.Do(req) - assert.NoError(t, err, "making OPTION request to polygon address check endpoint should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 204 - assert.Equal(t, http.StatusNoContent, resp.StatusCode, "expected HTTP 204 OK status") - assert.Equal(t, "*", resp.Header.Get("Access-Control-Allow-Origin"), "expected Access-Control-Allow-Origin to be *") - assert.Equal(t, "GET", resp.Header.Get("Access-Control-Allow-Methods"), "expected Access-Control-Allow-Methods to be GET") -} - -func TestSecurityHeaders(t *testing.T) { - // Create a test server with the SecurityHeadersMiddleware - testServer := setupTestServer(t, nil) - defer testServer.Close() - - // Test the default CSP by making a request to a non-swagger endpoint - url := testServer.Server.URL + healthCheckPath - - resp, err := http.Get(url) - assert.NoError(t, err, "making GET request to /somepath should not fail") - defer resp.Body.Close() - - assert.Equal(t, "nosniff", resp.Header.Get("X-Content-Type-Options"), "expected X-Content-Type-Options to be nosniff") - assert.Equal(t, "1; mode=block", resp.Header.Get("X-Xss-Protection"), "expected X-Xss-Protection to be 1; mode=block") - assert.Equal(t, "DENY", resp.Header.Get("X-Frame-Options"), "expected X-Frame-Options to be DENY") - assert.Equal(t, "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self'; object-src 'none'; frame-ancestors 'self'; form-action 'self'; block-all-mixed-content; base-uri 'self';", resp.Header.Get("Content-Security-Policy"), "expected default Content-Security-Policy") - assert.Equal(t, "strict-origin-when-cross-origin", resp.Header.Get("Referrer-Policy"), "expected Referrer-Policy to be strict-origin-when-cross-origin") - - // Test the Swagger CSP by making a request to the /swagger/* endpoint - swaggerURL := testServer.Server.URL + "/swagger/index.html" - resp, err = http.Get(swaggerURL) - assert.NoError(t, err, "making GET request to /swagger/index.html should not fail") - defer resp.Body.Close() - - assert.Equal(t, "nosniff", resp.Header.Get("X-Content-Type-Options"), "expected X-Content-Type-Options to be nosniff") - assert.Equal(t, "1; mode=block", resp.Header.Get("X-Xss-Protection"), "expected X-Xss-Protection to be 1; mode=block") - assert.Equal(t, "DENY", resp.Header.Get("X-Frame-Options"), "expected X-Frame-Options to be DENY") - assert.Equal(t, "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com https://stackpath.bootstrap.com; style-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com https://stackpath.bootstrap.com; img-src 'self' data: https://cdnjs.cloudflare.com https://stackpath.bootstrap.com; font-src 'self' https://cdnjs.cloudflare.com https://stackpath.bootstrap.com; object-src 'none'; frame-ancestors 'self'; form-action 'self'; block-all-mixed-content; base-uri 'self';", resp.Header.Get("Content-Security-Policy"), "expected Swagger Content-Security-Policy") - assert.Equal(t, "strict-origin-when-cross-origin", resp.Header.Get("Referrer-Policy"), "expected Referrer-Policy to be strict-origin-when-cross-origin") -} diff --git a/tests/integration_test/replay_unprocessed_messages_test.go b/tests/integration_test/replay_unprocessed_messages_test.go deleted file mode 100644 index b7acc801..00000000 --- a/tests/integration_test/replay_unprocessed_messages_test.go +++ /dev/null @@ -1,97 +0,0 @@ -package tests - -import ( - "context" - "encoding/json" - "io" - "net/http" - "testing" - "time" - - "github.com/babylonlabs-io/staking-api-service/cmd/staking-api-service/scripts" - "github.com/babylonlabs-io/staking-api-service/internal/shared/api/handlers/handler" - dbclient "github.com/babylonlabs-io/staking-api-service/internal/shared/db/client" - dbmodel "github.com/babylonlabs-io/staking-api-service/internal/shared/db/model" - "github.com/babylonlabs-io/staking-api-service/tests/testutils" - "github.com/babylonlabs-io/staking-queue-client/client" - "github.com/stretchr/testify/assert" -) - -func TestReplayUnprocessableMessages(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - - testServer := setupTestServer(t, nil) - defer testServer.Close() - - activeStakingEvents := buildActiveStakingEvent(t, 1) - activeStakingEvent := activeStakingEvents[0] - - data, err := json.Marshal(activeStakingEvent) - assert.NoError(t, err, "marshal events should not return an error") - - doc := string(data) - - testutils.InjectDbDocument( - testServer.Config, dbmodel.V1UnprocessableMsgCollection, - dbmodel.NewUnprocessableMessageDocument(doc, "receipt"), - ) - dbClients, _ := testutils.DirectDbConnection(testServer.Config) - defer dbClients.StakingMongoClient.Disconnect(ctx) - dbclient, err := dbclient.New(ctx, dbClients.StakingMongoClient, testServer.Config.StakingDb) - assert.NoError(t, err, "creating db client should not return an error") - - scripts.ReplayUnprocessableMessages(ctx, testServer.Config, testServer.Queues, dbclient) - - time.Sleep(3 * time.Second) - - url := testServer.Server.URL + stakerDelegations + "?staker_btc_pk=" + activeStakingEvent.StakerPkHex - resp, err := http.Get(url) - assert.NoError(t, err, "making GET request to delegations by staker pk should not fail") - defer resp.Body.Close() - - assert.Equal(t, http.StatusOK, resp.StatusCode, "HTTP response status should be OK") - - body, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var responseJSON handler.PublicResponse[[]client.ActiveStakingEvent] - err = json.Unmarshal(body, &responseJSON) - assert.NoError(t, err, "unmarshal response JSON should not return an error") - - // Verify the response contains expected fields - expectedFields := []string{ - "StakingTxHashHex", - "IsOverflow", - "StakingTxHex", - "StakingTimeLock", - "StakingOutputIndex", - "StakingStartTimestamp", - "StakingStartHeight", - "StakingValue", - "FinalityProviderPkHex", - "StakerPkHex", - } - - assert.Greater(t, len(responseJSON.Data), 0, "'data' array should not be empty") - - for _, item := range responseJSON.Data { - itemMap := map[string]interface{}{ - "StakingTxHashHex": item.StakingTxHashHex, - "IsOverflow": item.IsOverflow, - "StakingTxHex": item.StakingTxHex, - "StakingTimeLock": item.StakingTimeLock, - "StakingOutputIndex": item.StakingOutputIndex, - "StakingStartTimestamp": item.StakingStartTimestamp, - "StakingStartHeight": item.StakingStartHeight, - "StakingValue": item.StakingValue, - "FinalityProviderPkHex": item.FinalityProviderPkHex, - "StakerPkHex": item.StakerPkHex, - } - - for _, field := range expectedFields { - _, exists := itemMap[field] - assert.True(t, exists, "response should contain field %s", field) - } - } -} diff --git a/tests/integration_test/setup.go b/tests/integration_test/setup.go deleted file mode 100644 index f0cf0096..00000000 --- a/tests/integration_test/setup.go +++ /dev/null @@ -1,292 +0,0 @@ -package tests - -import ( - "context" - "encoding/json" - "fmt" - "io" - "log" - "math/rand" - "net/http" - "net/http/httptest" - "strings" - "testing" - "time" - - bbndatagen "github.com/babylonlabs-io/babylon/testutil/datagen" - "github.com/babylonlabs-io/staking-queue-client/client" - "github.com/go-chi/chi" - "github.com/rabbitmq/amqp091-go" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "go.mongodb.org/mongo-driver/mongo" - - queueConfig "github.com/babylonlabs-io/staking-queue-client/config" - - "github.com/babylonlabs-io/staking-api-service/internal/shared/api" - "github.com/babylonlabs-io/staking-api-service/internal/shared/api/handlers/handler" - "github.com/babylonlabs-io/staking-api-service/internal/shared/api/middlewares" - "github.com/babylonlabs-io/staking-api-service/internal/shared/config" - dbclients "github.com/babylonlabs-io/staking-api-service/internal/shared/db/clients" - "github.com/babylonlabs-io/staking-api-service/internal/shared/http/clients" - "github.com/babylonlabs-io/staking-api-service/internal/shared/observability/metrics" - queueclients "github.com/babylonlabs-io/staking-api-service/internal/shared/queue/clients" - "github.com/babylonlabs-io/staking-api-service/internal/shared/services" - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - "github.com/babylonlabs-io/staking-api-service/tests/testutils" -) - -var setUpDbIndex = false - -type TestServerDependency struct { - ConfigOverrides *config.Config - MockDbClients dbclients.DbClients - PreInjectEventsHandler func(queueClient client.QueueClient) error - MockedFinalityProviders []types.FinalityProviderDetails - MockedGlobalParams *types.GlobalParams - MockedClients *clients.Clients -} - -type TestServer struct { - Server *httptest.Server - Queues *queueclients.QueueClients - Conn *amqp091.Connection - channel *amqp091.Channel - Config *config.Config - Db *mongo.Client -} - -func (ts *TestServer) Close() { - ts.Server.Close() - ts.Queues.V1QueueClient.StopReceivingMessages() - if err := ts.Conn.Close(); err != nil { - log.Fatalf("failed to close connection in test: %v", err) - } - if err := ts.channel.Close(); err != nil { - log.Fatalf("failed to close channel in test: %v", err) - } - if err := ts.Db.Disconnect(context.Background()); err != nil { - log.Fatalf("failed to close db connection in test: %v", err) - } -} - -func loadTestConfig(t *testing.T) *config.Config { - cfg, err := config.New("../config/config-test.yml") - if err != nil { - t.Fatalf("Failed to load test config: %v", err) - } - return cfg -} - -func setupTestServer(t *testing.T, dep *TestServerDependency) *TestServer { - var err error - var cfg *config.Config - if dep != nil && dep.ConfigOverrides != nil { - cfg = dep.ConfigOverrides - } else { - cfg = testutils.LoadTestConfig() - } - metricsPort := cfg.Metrics.GetMetricsPort() - metrics.Init(metricsPort) - - var params *types.GlobalParams - if dep != nil && dep.MockedGlobalParams != nil { - params = dep.MockedGlobalParams - } else { - params, err = types.NewGlobalParams("../config/global-params-test.json") - if err != nil { - t.Fatalf("Failed to load global params: %v", err) - } - } - - var fps []types.FinalityProviderDetails - if dep != nil && dep.MockedFinalityProviders != nil { - fps = dep.MockedFinalityProviders - } else { - fps, err = types.NewFinalityProviders("../config/finality-providers-test.json") - if err != nil { - t.Fatalf("Failed to load finality providers: %v", err) - } - } - - var c *clients.Clients - if dep != nil && dep.MockedClients != nil { - c = dep.MockedClients - } else { - c = clients.New(cfg) - } - - // setup test db - dbClients := testutils.SetupTestDB(*cfg) - - if dep != nil && (dep.MockDbClients.V1DBClient != nil || dep.MockDbClients.V2DBClient != nil || dep.MockDbClients.StakingMongoClient != nil) { - dbClients = &dep.MockDbClients - } - - services, err := services.New(context.Background(), cfg, params, fps, c, dbClients) - if err != nil { - t.Fatalf("Failed to initialize services: %v", err) - } - - apiServer, err := api.New(context.Background(), cfg, services) - if err != nil { - t.Fatalf("Failed to initialize API server: %v", err) - } - - // Setup routes - r := chi.NewRouter() - - r.Use(middlewares.CorsMiddleware(cfg)) - r.Use(middlewares.SecurityHeadersMiddleware()) - r.Use(middlewares.ContentLengthMiddleware(cfg)) - apiServer.SetupRoutes(r) - - queues, conn, ch, err := setUpTestQueue(cfg.Queue, services) - if err != nil { - t.Fatalf("Failed to setup test queue: %v", err) - } - - // Create an httptest server - server := httptest.NewServer(r) - - return &TestServer{ - Server: server, - Queues: queues, - Conn: conn, - channel: ch, - Config: cfg, - Db: dbClients.StakingMongoClient, - } -} - -func setUpTestQueue(cfg *queueConfig.QueueConfig, services *services.Services) (*queueclients.QueueClients, *amqp091.Connection, *amqp091.Channel, error) { - amqpURI := fmt.Sprintf("amqp://%s:%s@%s", cfg.QueueUser, cfg.QueuePassword, cfg.Url) - conn, err := amqp091.Dial(amqpURI) - if err != nil { - log.Fatal("failed to connect to RabbitMQ in test: ", err) - return nil, nil, nil, err - } - - ch, err := conn.Channel() - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to open a channel in test: %w", err) - } - purgeError := purgeQueues(ch, []string{ - client.ActiveStakingQueueName, - client.UnbondingStakingQueueName, - client.WithdrawStakingQueueName, - client.ExpiredStakingQueueName, - client.StakingStatsQueueName, - // purge delay queues as well - client.ActiveStakingQueueName + "_delay", - client.UnbondingStakingQueueName + "_delay", - client.WithdrawStakingQueueName + "_delay", - client.ExpiredStakingQueueName + "_delay", - client.StakingStatsQueueName + "_delay", - }) - if purgeError != nil { - log.Fatal("failed to purge queues in test: ", purgeError) - return nil, nil, nil, purgeError - } - - // Start the actual queue processing in our codebase - queueClients := queueclients.New(context.Background(), cfg, services) - queueClients.StartReceivingMessages() - - return queueClients, conn, ch, nil -} - -// inspectQueueMessageCount inspects the number of messages in the given queue. -func inspectQueueMessageCount(t *testing.T, conn *amqp091.Connection, queueName string) (int, error) { - ch, err := conn.Channel() - if err != nil { - t.Fatalf("failed to open a channel in test: %v", err) - } - q, err := ch.QueueInspect(queueName) - if err != nil { - if strings.Contains(err.Error(), "NOT_FOUND") || strings.Contains(err.Error(), "channel/connection is not open") { - return 0, nil - } - return 0, fmt.Errorf("failed to inspect queue in test %s: %w", queueName, err) - } - return q.Messages, nil -} - -// purgeQueues purges all messages from the given list of queues. -func purgeQueues(ch *amqp091.Channel, queues []string) error { - for _, queue := range queues { - _, err := ch.QueuePurge(queue, false) - if err != nil { - if strings.Contains(err.Error(), "NOT_FOUND") || strings.Contains(err.Error(), "channel/connection is not open") { - continue - } - return fmt.Errorf("failed to purge queue in test %s: %w", queue, err) - } - } - - return nil -} - -func sendTestMessage[T any](client client.QueueClient, data []T) error { - for _, d := range data { - jsonBytes, err := json.Marshal(d) - if err != nil { - return err - } - messageBody := string(jsonBytes) - err = client.SendMessage(context.TODO(), messageBody) - if err != nil { - return fmt.Errorf("failed to publish a message to queue %s: %w", client.GetQueueName(), err) - } - } - return nil -} - -// TODO: To be removed and use the method from testutils -func buildActiveStakingEvent(t *testing.T, numOfEvenet int) []*client.ActiveStakingEvent { - var activeStakingEvents []*client.ActiveStakingEvent - stakerPk, err := testutils.RandomPk() - require.NoError(t, err) - rand.New(rand.NewSource(time.Now().Unix())) - - for i := 0; i < numOfEvenet; i++ { - activeStakingEvent := &client.ActiveStakingEvent{ - EventType: client.ActiveStakingEventType, - StakingTxHashHex: "0x1234567890abcdef" + fmt.Sprint(i), - StakerPkHex: stakerPk, - FinalityProviderPkHex: "0xabcdef1234567890" + fmt.Sprint(i), - StakingValue: uint64(rand.Intn(1000)), - StakingStartHeight: uint64(rand.Intn(200)), - StakingStartTimestamp: time.Now().Unix(), - StakingTimeLock: uint64(rand.Intn(100)), - StakingOutputIndex: uint64(rand.Intn(100)), - StakingTxHex: "0xabcdef1234567890" + fmt.Sprint(i), - IsOverflow: false, - } - activeStakingEvents = append(activeStakingEvents, activeStakingEvent) - } - return activeStakingEvents -} - -func attachRandomSeedsToFuzzer(f *testing.F, numOfSeeds int) { - bbndatagen.AddRandomSeedsToFuzzer(f, uint(numOfSeeds)) -} - -func fetchSuccessfulResponse[T any](t *testing.T, url string) handler.PublicResponse[T] { - // Make a GET request to the finality providers endpoint - resp, err := http.Get(url) - assert.NoError(t, err) - defer resp.Body.Close() - - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var responseBody handler.PublicResponse[T] - err = json.Unmarshal(bodyBytes, &responseBody) - assert.NoError(t, err, "unmarshalling response body should not fail") - return responseBody -} diff --git a/tests/integration_test/staker_test.go b/tests/integration_test/staker_test.go deleted file mode 100644 index 5f6d1812..00000000 --- a/tests/integration_test/staker_test.go +++ /dev/null @@ -1,463 +0,0 @@ -package tests - -import ( - "encoding/json" - "fmt" - "io" - "math/rand" - "net/http" - "testing" - "time" - - "github.com/babylonlabs-io/staking-api-service/internal/shared/api" - handler "github.com/babylonlabs-io/staking-api-service/internal/shared/api/handlers/handler" - dbmodel "github.com/babylonlabs-io/staking-api-service/internal/shared/db/model" - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - "github.com/babylonlabs-io/staking-api-service/internal/shared/utils" - v1handlers "github.com/babylonlabs-io/staking-api-service/internal/v1/api/handlers" - v1service "github.com/babylonlabs-io/staking-api-service/internal/v1/service" - "github.com/babylonlabs-io/staking-api-service/tests/testutils" - "github.com/babylonlabs-io/staking-queue-client/client" - "github.com/stretchr/testify/assert" - "go.mongodb.org/mongo-driver/bson" -) - -const ( - checkStakerDelegationUrl = "/v1/staker/delegation/check" -) - -func FuzzTestStakerDelegationsWithPaginationResponse(f *testing.F) { - attachRandomSeedsToFuzzer(f, 3) - f.Fuzz(func(t *testing.T, seed int64) { - r := rand.New(rand.NewSource(seed)) - testServer := setupTestServer(t, nil) - defer testServer.Close() - numOfStaker1Events := int(testServer.Config.StakingDb.MaxPaginationLimit) + r.Intn(100) - activeStakingEventsByStaker1 := testutils.GenerateRandomActiveStakingEvents( - r, - &testutils.TestActiveEventGeneratorOpts{ - NumOfEvents: numOfStaker1Events, - Stakers: testutils.GeneratePks(1), - }, - ) - activeStakingEventsByStaker2 := testutils.GenerateRandomActiveStakingEvents( - r, - &testutils.TestActiveEventGeneratorOpts{ - NumOfEvents: int(testServer.Config.StakingDb.MaxPaginationLimit) + 1, - Stakers: testutils.GeneratePks(1), - }, - ) - - // Modify the height to simulate all events are processed at the same btc height - btcHeight := uint64(testutils.RandomPositiveInt(r, 100000)) - for i := range activeStakingEventsByStaker1 { - activeStakingEventsByStaker1[i].StakingStartHeight = btcHeight - } - - sendTestMessage( - testServer.Queues.V1QueueClient.ActiveStakingQueueClient, - append(activeStakingEventsByStaker1, activeStakingEventsByStaker2...), - ) - time.Sleep(5 * time.Second) - - // Test the API - stakerPk := activeStakingEventsByStaker1[0].StakerPkHex - staker1Delegations := fetchStakerDelegations( - t, testServer, stakerPk, "", - ) - assert.Equal(t, numOfStaker1Events, len(staker1Delegations)) - for _, events := range activeStakingEventsByStaker1 { - found := false - for _, d := range staker1Delegations { - if d.StakingTxHashHex == events.StakingTxHashHex { - found = true - break - } - } - assert.True(t, found) - } - for i := 0; i < len(staker1Delegations)-1; i++ { - assert.True(t, staker1Delegations[i].StakingTx.StartHeight >= - staker1Delegations[i+1].StakingTx.StartHeight) - } - - stakerPk2 := activeStakingEventsByStaker2[0].StakerPkHex - staker2Delegations := fetchStakerDelegations( - t, testServer, stakerPk2, "", - ) - assert.Equal(t, len(activeStakingEventsByStaker2), len(staker2Delegations)) - for _, events := range activeStakingEventsByStaker2 { - found := false - for _, d := range staker2Delegations { - if d.StakingTxHashHex == events.StakingTxHashHex { - found = true - break - } - } - assert.True(t, found) - } - for i := 0; i < len(staker2Delegations)-1; i++ { - assert.True(t, staker2Delegations[i].StakingTx.StartHeight >= - staker2Delegations[i+1].StakingTx.StartHeight) - } - }) -} - -func TestActiveStakingFetchedByStakerPkWithInvalidPaginationKey(t *testing.T) { - r := rand.New(rand.NewSource(time.Now().Unix())) - activeStakingEvent := testutils.GenerateRandomActiveStakingEvents(r, &testutils.TestActiveEventGeneratorOpts{ - NumOfEvents: 11, - FinalityProviders: testutils.GeneratePks(11), - Stakers: testutils.GeneratePks(1), - }) - testServer := setupTestServer(t, nil) - defer testServer.Close() - sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, activeStakingEvent) - // Wait for 2 seconds to make sure the message is processed - time.Sleep(2 * time.Second) - - // Test the API with an invalid pagination key - url := fmt.Sprintf("%s%s?staker_btc_pk=%s&pagination_key=%s", testServer.Server.URL, stakerDelegations, activeStakingEvent[0].StakerPkHex, "btc_to_one_milly") - - resp, err := http.Get(url) - assert.NoError(t, err, "making GET request to delegations by staker pk should not fail") - defer resp.Body.Close() - - // Check that the status code is 400 Bad Request - assert.Equal(t, http.StatusBadRequest, resp.StatusCode, "expected HTTP 400 Bad Request status") - - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var response api.ErrorResponse - err = json.Unmarshal(bodyBytes, &response) - assert.NoError(t, err, "unmarshalling response body should not fail") - - assert.Equal(t, "invalid pagination key format", response.Message) -} - -func TestCheckStakerDelegationAllowOptionRequestForGalxe(t *testing.T) { - testServer := setupTestServer(t, nil) - defer testServer.Close() - - url := testServer.Server.URL + checkStakerDelegationUrl - client := &http.Client{} - req, err := http.NewRequest("OPTIONS", url, nil) - assert.NoError(t, err) - req.Header.Add("Access-Control-Request-Method", "GET") - req.Header.Add("Origin", "https://dashboard.galxe.com") - req.Header.Add("Access-Control-Request-Headers", "Content-Type") - - // Send the request - resp, err := client.Do(req) - assert.NoError(t, err) - defer resp.Body.Close() - - // Check that the status code is HTTP 204 - assert.Equal(t, http.StatusNoContent, resp.StatusCode, "expected HTTP 204") - assert.Equal(t, "https://dashboard.galxe.com", resp.Header.Get("Access-Control-Allow-Origin"), "expected Access-Control-Allow-Origin to be https://dashboard.galxe.com") - assert.Equal(t, "GET, OPTIONS, POST", resp.Header.Get("Access-Control-Allow-Methods"), "expected Access-Control-Allow-Methods to be GET and OPTIONS") - - // Try with a different origin - req.Header.Add("Origin", "https://dashboard.galxe.com") - resp, err = client.Do(req) - assert.NoError(t, err) - defer resp.Body.Close() - assert.Equal(t, http.StatusNoContent, resp.StatusCode, "expected HTTP 204") -} - -func FuzzCheckStakerActiveDelegations(f *testing.F) { - attachRandomSeedsToFuzzer(f, 3) - f.Fuzz(func(t *testing.T, seed int64) { - r := rand.New(rand.NewSource(seed)) - opts := &testutils.TestActiveEventGeneratorOpts{ - NumOfEvents: testutils.RandomPositiveInt(r, 10), - Stakers: testutils.GeneratePks(1), - EnforceNotOverflow: true, - } - activeStakingEvents := testutils.GenerateRandomActiveStakingEvents( - r, opts, - ) - testServer := setupTestServer(t, nil) - defer testServer.Close() - sendTestMessage( - testServer.Queues.V1QueueClient.ActiveStakingQueueClient, activeStakingEvents, - ) - time.Sleep(5 * time.Second) - - // Test the API - stakerPk := activeStakingEvents[0].StakerPkHex - addresses, err := utils.DeriveAddressesFromNoCoordPk( - stakerPk, testServer.Config.Server.BTCNetParam, - ) - assert.NoError(t, err, "failed to get taproot address from staker pk") - isExist := fetchCheckStakerActiveDelegations(t, testServer, addresses.Taproot, "") - - assert.True(t, isExist, "expected staker to have active delegation") - - // Test the API with a staker PK that never had any active delegation - stakerPkWithoutDelegation, err := testutils.RandomPk() - if err != nil { - t.Fatalf("failed to generate random public key for staker: %v", err) - } - addressWithNoDelegation, err := utils.DeriveAddressesFromNoCoordPk( - stakerPkWithoutDelegation, testServer.Config.Server.BTCNetParam, - ) - assert.NoError(t, err, "failed to get taproot address from staker pk") - isExist = fetchCheckStakerActiveDelegations( - t, testServer, addressWithNoDelegation.Taproot, "", - ) - assert.False(t, isExist, "expected staker to not have active delegation") - - // Update the staker to have its delegations in a different state - var unbondingEvents []client.UnbondingStakingEvent - for _, activeStakingEvent := range activeStakingEvents { - unbondingEvent := client.NewUnbondingStakingEvent( - activeStakingEvent.StakingTxHashHex, - activeStakingEvent.StakingStartHeight+100, - time.Now().Unix(), - 10, - 1, - activeStakingEvent.StakingTxHex, // mocked data, it doesn't matter in stats calculation - activeStakingEvent.StakingTxHashHex, // mocked data, it doesn't matter in stats calculation - ) - unbondingEvents = append(unbondingEvents, unbondingEvent) - } - sendTestMessage(testServer.Queues.V1QueueClient.UnbondingStakingQueueClient, unbondingEvents) - time.Sleep(5 * time.Second) - - isExist = fetchCheckStakerActiveDelegations(t, testServer, addresses.Taproot, "") - assert.False(t, isExist, "expected staker to not have active delegation") - }) -} - -func FuzzCheckStakerActiveDelegationsForToday(f *testing.F) { - attachRandomSeedsToFuzzer(f, 3) - f.Fuzz(func(t *testing.T, seed int64) { - r := rand.New(rand.NewSource(seed)) - stakerPk := testutils.GeneratePks(1) - opts := &testutils.TestActiveEventGeneratorOpts{ - NumOfEvents: testutils.RandomPositiveInt(r, 3), - Stakers: stakerPk, - EnforceNotOverflow: true, - BeforeTimestamp: utils.GetTodayStartTimestampInSeconds() - 1, // To make it yesterday - } - activeStakingEvents := testutils.GenerateRandomActiveStakingEvents(r, opts) - testServer := setupTestServer(t, nil) - defer testServer.Close() - sendTestMessage( - testServer.Queues.V1QueueClient.ActiveStakingQueueClient, activeStakingEvents, - ) - time.Sleep(3 * time.Second) - - // Test the API - addresses, err := utils.DeriveAddressesFromNoCoordPk( - stakerPk[0], testServer.Config.Server.BTCNetParam, - ) - assert.NoError(t, err, "failed to get taproot address from staker pk") - isExist := fetchCheckStakerActiveDelegations(t, testServer, addresses.Taproot, "") - - assert.True(t, isExist, "expected staker to have active delegation") - - // Test with the is_active_today query parameter - isExist = fetchCheckStakerActiveDelegations(t, testServer, addresses.Taproot, "today") - assert.False(t, isExist, "expected staker to not have active delegation") - - opts = &testutils.TestActiveEventGeneratorOpts{ - NumOfEvents: testutils.RandomPositiveInt(r, 3), - Stakers: stakerPk, - EnforceNotOverflow: true, - AfterTimestamp: utils.GetTodayStartTimestampInSeconds(), // To make it today - } - activeStakingEvents = testutils.GenerateRandomActiveStakingEvents(r, opts) - sendTestMessage( - testServer.Queues.V1QueueClient.ActiveStakingQueueClient, activeStakingEvents, - ) - time.Sleep(3 * time.Second) - - isExist = fetchCheckStakerActiveDelegations(t, testServer, addresses.Taproot, "today") - assert.True(t, isExist, "expected staker to have active delegation") - }) -} - -func TestGetDelegationReturnEmptySliceWhenNoDelegation(t *testing.T) { - testServer := setupTestServer(t, nil) - defer testServer.Close() - - stakerPk, err := testutils.RandomPk() - assert.NoError(t, err) - url := testServer.Server.URL + stakerDelegations + "?staker_btc_pk=" + stakerPk - resp, err := http.Get(url) - assert.NoError(t, err) - - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var response handler.PublicResponse[[]v1service.DelegationPublic] - err = json.Unmarshal(bodyBytes, &response) - assert.NoError(t, err, "unmarshalling response body should not fail") - - assert.NotNil(t, response.Data, "expected response body to have data") - assert.Equal(t, 0, len(response.Data), "expected response body to have no data") -} - -func FuzzStakerDelegationsFilterByState(f *testing.F) { - attachRandomSeedsToFuzzer(f, 3) - f.Fuzz(func(t *testing.T, seed int64) { - r := rand.New(rand.NewSource(seed)) - testServer := setupTestServer(t, nil) - defer testServer.Close() - numOfDelegations := int(testServer.Config.StakingDb.MaxPaginationLimit) + - testutils.RandomPositiveInt(r, 10) - activeStakingEventsByStaker := testutils.GenerateRandomActiveStakingEvents( - r, - &testutils.TestActiveEventGeneratorOpts{ - NumOfEvents: numOfDelegations, - Stakers: testutils.GeneratePks(1), - }, - ) - - sendTestMessage( - testServer.Queues.V1QueueClient.ActiveStakingQueueClient, - activeStakingEventsByStaker, - ) - time.Sleep(5 * time.Second) - // Randomly modify the state of the delegations - var stateTxIdMap = make(map[types.DelegationState][]string) - for i := 0; i < len(activeStakingEventsByStaker); i++ { - state := getRandomDelegationState(r) - updateDelegationState( - t, testServer, activeStakingEventsByStaker[i].StakingTxHashHex, state, - ) - stateTxIdMap[state] = append( - stateTxIdMap[state], activeStakingEventsByStaker[i].StakingTxHashHex, - ) - } - - // Test the API - stakerPk := activeStakingEventsByStaker[0].StakerPkHex - delegations := fetchStakerDelegations(t, testServer, stakerPk, "") - assert.Equal(t, numOfDelegations, len(delegations)) - - // Test the API with state filter - for state, txIds := range stateTxIdMap { - delegations := fetchStakerDelegations(t, testServer, stakerPk, state) - assert.Equal(t, len(txIds), len(delegations)) - for _, d := range delegations { - assert.Contains(t, txIds, d.StakingTxHashHex) - } - } - }) -} - -func TestReturnErrorWhenInvalidStatePassed(t *testing.T) { - testServer := setupTestServer(t, nil) - defer testServer.Close() - - stakerPk, err := testutils.RandomPk() - assert.NoError(t, err) - url := testServer.Server.URL + stakerDelegations + "?staker_btc_pk=" + stakerPk + "&state=invalid_state" - resp, err := http.Get(url) - assert.NoError(t, err) - - // Check that the status code is HTTP 400 Bad Request - assert.Equal(t, http.StatusBadRequest, resp.StatusCode, "expected HTTP 400 Bad Request status") - - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var response api.ErrorResponse - err = json.Unmarshal(bodyBytes, &response) - assert.NoError(t, err, "unmarshalling response body should not fail") - - assert.Equal(t, "invalid delegation state: invalid_state", response.Message) -} - -func fetchCheckStakerActiveDelegations( - t *testing.T, testServer *TestServer, btcAddress string, timeframe string, -) bool { - url := testServer.Server.URL + checkStakerDelegationUrl + "?address=" + btcAddress - if timeframe != "" { - url += "&timeframe=" + timeframe - } - resp, err := http.Get(url) - assert.NoError(t, err) - - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var response v1handlers.DelegationCheckPublicResponse - err = json.Unmarshal(bodyBytes, &response) - assert.NoError(t, err, "unmarshalling response body should not fail") - - assert.Equal(t, response.Code, 0, "expected response code to be 0") - - return response.Data -} - -func fetchStakerDelegations( - t *testing.T, testServer *TestServer, stakerPk string, stateFilter types.DelegationState, -) []v1service.DelegationPublic { - url := testServer.Server.URL + stakerDelegations + "?staker_btc_pk=" + stakerPk - if stateFilter != "" { - url += "&state=" + stateFilter.ToString() - } - var paginationKey string - var allDataCollected []v1service.DelegationPublic - for { - resp, err := http.Get(url + "&pagination_key=" + paginationKey) - assert.NoError(t, err, "making GET request to delegations by staker pk should not fail") - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - var response handler.PublicResponse[[]v1service.DelegationPublic] - err = json.Unmarshal(bodyBytes, &response) - assert.NoError(t, err, "unmarshalling response body should not fail") - - if len(response.Data) == 0 { - break - } - for _, d := range response.Data { - assert.Equal(t, stakerPk, d.StakerPkHex, "expected response body to match") - } - allDataCollected = append(allDataCollected, response.Data...) - if response.Pagination.NextKey != "" { - paginationKey = response.Pagination.NextKey - } else { - break - } - } - return allDataCollected -} - -func updateDelegationState( - t *testing.T, testServer *TestServer, txId string, state types.DelegationState, -) { - filter := bson.M{"_id": txId} - update := bson.M{"state": state.ToString()} - err := testutils.UpdateDbDocument( - testServer.Db, testServer.Config, dbmodel.V1DelegationCollection, - filter, update, - ) - assert.NoError(t, err) -} - -// getRandomDelegationState returns a randomly selected DelegationState. -func getRandomDelegationState(r *rand.Rand) types.DelegationState { - states := []types.DelegationState{ - types.Active, - types.UnbondingRequested, - types.Unbonding, - types.Unbonded, - types.Withdrawn, - } - randomIndex := r.Intn(len(states)) - // Return the randomly selected state - return states[randomIndex] -} diff --git a/tests/integration_test/stats_test.go b/tests/integration_test/stats_test.go deleted file mode 100644 index 3e02e134..00000000 --- a/tests/integration_test/stats_test.go +++ /dev/null @@ -1,534 +0,0 @@ -package tests - -import ( - "bytes" - "encoding/json" - "io" - "math" - "math/rand" - "net/http" - "testing" - "time" - - handler "github.com/babylonlabs-io/staking-api-service/internal/shared/api/handlers/handler" - "github.com/babylonlabs-io/staking-api-service/internal/shared/config" - dbmodel "github.com/babylonlabs-io/staking-api-service/internal/shared/db/model" - v1dbmodel "github.com/babylonlabs-io/staking-api-service/internal/v1/db/model" - v1service "github.com/babylonlabs-io/staking-api-service/internal/v1/service" - "github.com/babylonlabs-io/staking-api-service/tests/testutils" - "github.com/babylonlabs-io/staking-queue-client/client" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -const ( - overallStatsEndpoint = "/v1/stats" - topStakerStatsPath = "/v1/stats/staker" -) - -func TestStatsShouldBeShardedInDb(t *testing.T) { - activeStakingEvent := buildActiveStakingEvent(t, 10) - // build the unbonding event based on the active staking event - var unbondingEvents []client.UnbondingStakingEvent - for _, event := range activeStakingEvent { - unbondingEvents = append(unbondingEvents, client.NewUnbondingStakingEvent( - event.StakingTxHashHex, - event.StakingStartHeight+100, - time.Now().Unix(), - 10, - 1, - event.StakingTxHex, // mocked data, it doesn't matter in stats calculation - event.StakingTxHashHex, // mocked data, it doesn't matter in stats calculation - )) - } - testServer := setupTestServer(t, nil) - defer testServer.Close() - sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, activeStakingEvent) - time.Sleep(2 * time.Second) - sendTestMessage(testServer.Queues.V1QueueClient.UnbondingStakingQueueClient, unbondingEvents) - time.Sleep(2 * time.Second) - - // directly read from the db to check that we have more than 2 records in the overall stats collection - results, err := testutils.InspectDbDocuments[v1dbmodel.OverallStatsDocument]( - testServer.Config, dbmodel.V1OverallStatsCollection, - ) - if err != nil { - t.Fatalf("Failed to inspect DB documents: %v", err) - } - assert.Equal(t, 2, len(results), "expected 2 logical shards in the overall stats collection") - - // Sum it up, we shall get 0 active tvl and 0 active delegations. the total should remain positive number - var totalActiveTvl int64 - var totalActiveDelegations int64 - var totalTvl int64 - var totalDelegations int64 - for _, r := range results { - totalActiveTvl += r.ActiveTvl - totalActiveDelegations += r.ActiveDelegations - totalTvl += r.TotalTvl - totalDelegations += r.TotalDelegations - } - assert.Equal(t, int64(0), totalActiveTvl, "total acvtive tvl shall be 0 as all staking tx are now unbonded") - assert.Equal(t, int64(0), totalActiveDelegations) - assert.NotZero(t, totalTvl) - assert.Equal(t, int64(10), totalDelegations) -} - -func TestShouldSkipStatsCalculationForOverflowedStakingEvent(t *testing.T) { - activeStakingEvent := getTestActiveStakingEvent() - // Set the overflow flag to true - activeStakingEvent.IsOverflow = true - testServer := setupTestServer(t, nil) - defer testServer.Close() - - err := sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, []client.ActiveStakingEvent{*activeStakingEvent}) - require.NoError(t, err) - - time.Sleep(2 * time.Second) - - // Let's make a POST request to the unbonding endpoint - unbondingUrl := testServer.Server.URL + unbondingPath - requestBody := getTestUnbondDelegationRequestPayload(activeStakingEvent.StakingTxHashHex) - requestBodyBytes, err := json.Marshal(requestBody) - assert.NoError(t, err, "marshalling request body should not fail") - - resp, err := http.Post(unbondingUrl, "application/json", bytes.NewReader(requestBodyBytes)) - assert.NoError(t, err, "making POST request to unbonding endpoint should not fail") - defer resp.Body.Close() - - // Let's inspect what's stored in the database - results, err := testutils.InspectDbDocuments[v1dbmodel.UnbondingDocument]( - testServer.Config, dbmodel.V1UnbondingCollection, - ) - assert.NoError(t, err, "failed to inspect DB documents") - - assert.Equal(t, 1, len(results), "expected 1 document in the DB") - assert.Equal(t, "INSERTED", results[0].State) - assert.Equal(t, activeStakingEvent.StakingTxHex, results[0].StakingTxHex) - - // Let's send an unbonding event - unbondingEvent := client.UnbondingStakingEvent{ - EventType: client.UnbondingStakingEventType, - StakingTxHashHex: requestBody.StakingTxHashHex, - UnbondingTxHashHex: requestBody.UnbondingTxHashHex, - UnbondingTxHex: requestBody.UnbondingTxHex, - UnbondingTimeLock: 10, - UnbondingStartTimestamp: time.Now().Unix(), - UnbondingStartHeight: activeStakingEvent.StakingStartHeight + 100, - UnbondingOutputIndex: 1, - } - - sendTestMessage(testServer.Queues.V1QueueClient.UnbondingStakingQueueClient, []client.UnbondingStakingEvent{unbondingEvent}) - time.Sleep(2 * time.Second) - - // directly read from the db to check that we only have 1 shard in the overall stats collection - stats, err := testutils.InspectDbDocuments[v1dbmodel.OverallStatsDocument]( - testServer.Config, dbmodel.V1OverallStatsCollection, - ) - if err != nil { - t.Fatalf("Failed to inspect DB documents: %v", err) - } - assert.Equal(t, 0, len(stats)) -} - -func TestShouldNotPerformStatsCalculationForUnbondingTxWhenDelegationIsOverflowed(t *testing.T) { - activeStakingEvent := buildActiveStakingEvent(t, 10) - // Let's pick a random staking event and set the overflow flag to true - event := activeStakingEvent[6] - event.IsOverflow = true - // build the unbonding event based on the active staking event - var unbondingEvents []client.UnbondingStakingEvent - unbondingEvents = append(unbondingEvents, client.NewUnbondingStakingEvent( - event.StakingTxHashHex, - event.StakingStartHeight+100, - time.Now().Unix(), - 10, - 1, - event.StakingTxHex, // mocked data, it doesn't matter in stats calculation - event.StakingTxHashHex, // mocked data, it doesn't matter in stats calculation - )) - testServer := setupTestServer(t, nil) - defer testServer.Close() - sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, activeStakingEvent) - time.Sleep(2 * time.Second) - sendTestMessage(testServer.Queues.V1QueueClient.UnbondingStakingQueueClient, unbondingEvents) - time.Sleep(2 * time.Second) - - // directly read from the db to check that we have more than 2 records in the - // overall stats collection - results, err := testutils.InspectDbDocuments[v1dbmodel.OverallStatsDocument]( - testServer.Config, dbmodel.V1OverallStatsCollection, - ) - if err != nil { - t.Fatalf("Failed to inspect DB documents: %v", err) - } - assert.Equal(t, 2, len(results), "expected 2 logical shards in the overall stats collection") - - // Sum it up, we shall get 0 active tvl and 0 active delegations. the total should remain positive number - var totalActiveTvl int64 - var totalActiveDelegations int64 - var totalTvl int64 - var totalDelegations int64 - for _, r := range results { - totalActiveTvl += r.ActiveTvl - totalActiveDelegations += r.ActiveDelegations - totalTvl += r.TotalTvl - totalDelegations += r.TotalDelegations - } - - // calculate the total expect tvl from the active staking events - var expectedTotalTvl int64 - for _, e := range activeStakingEvent { - if !e.IsOverflow { - expectedTotalTvl += int64(e.StakingValue) - } - } - assert.Equal(t, expectedTotalTvl, totalActiveTvl) - assert.Equal(t, int64(9), totalActiveDelegations) - assert.Equal(t, expectedTotalTvl, totalTvl) - assert.Equal(t, int64(9), totalDelegations) -} - -func TestStatsEndpoints(t *testing.T) { - activeStakingEvent := getTestActiveStakingEvent() - testServer := setupTestServer(t, nil) - defer testServer.Close() - sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, []client.ActiveStakingEvent{*activeStakingEvent}) - time.Sleep(2 * time.Second) - - // Test the finality endpoint first - result := fetchFinalityEndpoint(t, testServer) - assert.Equal(t, 4, len(result)) - for _, r := range result { - if r.BtcPk == activeStakingEvent.FinalityProviderPkHex { - assert.Equal(t, int64(activeStakingEvent.StakingValue), r.ActiveTvl) - assert.Equal(t, int64(activeStakingEvent.StakingValue), r.TotalTvl) - assert.Equal(t, int64(1), r.ActiveDelegations) - assert.Equal(t, int64(1), r.TotalDelegations) - } else { - assert.Equal(t, int64(0), r.ActiveTvl) - assert.Equal(t, int64(0), r.TotalTvl) - assert.Equal(t, int64(0), r.ActiveDelegations) - assert.Equal(t, int64(0), r.TotalDelegations) - } - } - - // Test the overall stats endpoint - overallStats := fetchOverallStatsEndpoint(t, testServer) - assert.Equal(t, int64(activeStakingEvent.StakingValue), overallStats.TotalTvl) - assert.Equal(t, int64(1), overallStats.ActiveDelegations) - assert.Equal(t, int64(1), overallStats.TotalDelegations) - assert.Equal(t, uint64(1), overallStats.TotalStakers) - // We have not yet sent any ConfirmedInfoEvent and UnconfirmedInfoEvent, hence no recrod in db - assert.Equal(t, int64(0), overallStats.ActiveTvl) - assert.Equal(t, uint64(0), overallStats.UnconfirmedTvl) - assert.Equal(t, uint64(0), overallStats.PendingTvl) - - // Test the top staker stats endpoint - stakerStats := fetchStakerStatsEndpoint(t, testServer, "") - assert.Equal(t, 1, len(stakerStats)) - assert.Equal(t, activeStakingEvent.StakerPkHex, stakerStats[0].StakerPkHex) - assert.Equal(t, int64(activeStakingEvent.StakingValue), stakerStats[0].ActiveTvl) - assert.Equal(t, int64(activeStakingEvent.StakingValue), stakerStats[0].TotalTvl) - assert.Equal(t, int64(1), stakerStats[0].ActiveDelegations) - assert.Equal(t, int64(1), stakerStats[0].TotalDelegations) - - // Now let's send an unbonding event - unbondingEvent := client.NewUnbondingStakingEvent( - activeStakingEvent.StakingTxHashHex, - activeStakingEvent.StakingStartHeight+100, - time.Now().Unix(), - 10, - 1, - activeStakingEvent.StakingTxHex, // mocked data, it doesn't matter in stats calculation - activeStakingEvent.StakingTxHashHex, // mocked data, it doesn't matter in stats calculation - ) - sendTestMessage(testServer.Queues.V1QueueClient.UnbondingStakingQueueClient, []client.UnbondingStakingEvent{unbondingEvent}) - time.Sleep(2 * time.Second) - - // Make a GET request to the finality providers endpoint - result = fetchFinalityEndpoint(t, testServer) - assert.Equal(t, 4, len(result)) - for _, r := range result { - if r.BtcPk == activeStakingEvent.FinalityProviderPkHex { - assert.Equal(t, int64(0), r.ActiveTvl) - assert.Equal(t, int64(activeStakingEvent.StakingValue), r.TotalTvl) - assert.Equal(t, int64(0), r.ActiveDelegations) - assert.Equal(t, int64(1), r.TotalDelegations) - } else { - assert.Equal(t, int64(0), r.ActiveTvl) - assert.Equal(t, int64(0), r.TotalTvl) - assert.Equal(t, int64(0), r.ActiveDelegations) - assert.Equal(t, int64(0), r.TotalDelegations) - } - } - - overallStats = fetchOverallStatsEndpoint(t, testServer) - assert.Equal(t, int64(0), overallStats.ActiveTvl) - assert.Equal(t, int64(activeStakingEvent.StakingValue), overallStats.TotalTvl) - assert.Equal(t, int64(0), overallStats.ActiveDelegations) - assert.Equal(t, int64(1), overallStats.TotalDelegations) - assert.Equal(t, uint64(1), overallStats.TotalStakers) - - stakerStats = fetchStakerStatsEndpoint(t, testServer, "") - assert.Equal(t, 1, len(stakerStats)) - assert.Equal(t, activeStakingEvent.StakerPkHex, stakerStats[0].StakerPkHex) - assert.Equal(t, int64(0), stakerStats[0].ActiveTvl) - assert.Equal(t, int64(activeStakingEvent.StakingValue), stakerStats[0].TotalTvl) - assert.Equal(t, int64(0), stakerStats[0].ActiveDelegations) - assert.Equal(t, int64(1), stakerStats[0].TotalDelegations) - - // Send two new active events, it will increment the stats - activeEvents := buildActiveStakingEvent(t, 2) - sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, activeEvents) - time.Sleep(2 * time.Second) - - // Make a GET request to the finality providers endpoint - finalityProviderStats := fetchFinalityEndpoint(t, testServer) - assert.Equal(t, 6, len(finalityProviderStats)) - // Make sure sorted by active TVL - for i := 0; i < len(finalityProviderStats)-1; i++ { - assert.True(t, finalityProviderStats[i].ActiveTvl >= finalityProviderStats[i+1].ActiveTvl, "expected response body to be sorted") - } - - overallStats = fetchOverallStatsEndpoint(t, testServer) - - expectedTvl := int64(activeEvents[0].StakingValue + activeEvents[1].StakingValue) - expectedTotalTvl := int64(expectedTvl) + int64(activeStakingEvent.StakingValue) - assert.Equal(t, expectedTotalTvl, overallStats.TotalTvl) - assert.Equal(t, int64(2), overallStats.ActiveDelegations) - assert.Equal(t, int64(3), overallStats.TotalDelegations) - assert.Equal(t, uint64(2), overallStats.TotalStakers, "expected 2 stakers as the last 2 belong to same staker") - - stakerStats = fetchStakerStatsEndpoint(t, testServer, "") - assert.Equal(t, 2, len(stakerStats)) - - // Also make sure the returned data is sorted by active TVL - for i := 0; i < len(stakerStats)-1; i++ { - assert.True(t, stakerStats[i].ActiveTvl >= stakerStats[i+1].ActiveTvl, "expected response body to be sorted") - } - - // send an BtcInfoEvent which shall update the unconfirmed active TVL - btcInfoEvent := &client.BtcInfoEvent{ - EventType: client.BtcInfoEventType, - Height: 100, - ConfirmedTvl: 90, - UnconfirmedTvl: 100, - } - sendTestMessage(testServer.Queues.V1QueueClient.BtcInfoQueueClient, []*client.BtcInfoEvent{btcInfoEvent}) - - time.Sleep(2 * time.Second) - - overallStats = fetchOverallStatsEndpoint(t, testServer) - assert.Equal(t, uint64(100), overallStats.UnconfirmedTvl) - assert.Equal(t, int64(90), overallStats.ActiveTvl) -} - -func TestReturnEmptyArrayWhenNoStakerStatsFound(t *testing.T) { - testServer := setupTestServer(t, nil) - defer testServer.Close() - stakerPk, err := testutils.RandomPk() - require.NoError(t, err) - stakerStats := fetchStakerStatsEndpoint(t, testServer, stakerPk) - assert.Equal(t, 0, len(stakerStats)) -} - -func FuzzReturnStakerStatsByStakerPk(f *testing.F) { - attachRandomSeedsToFuzzer(f, 3) - f.Fuzz(func(t *testing.T, seed int64) { - testServer := setupTestServer(t, nil) - defer testServer.Close() - r := rand.New(rand.NewSource(seed)) - events := testutils.GenerateRandomActiveStakingEvents(r, &testutils.TestActiveEventGeneratorOpts{ - NumOfEvents: testutils.RandomPositiveInt(r, 10), - Stakers: testutils.GeneratePks(10), - EnforceNotOverflow: true, - }) - sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, events) - time.Sleep(10 * time.Second) - - // Find the unique staker pks - var stakerPks []string - for _, e := range events { - // append into stakerPks if it's not already there - if !testutils.Contains(stakerPks, e.StakerPkHex) { - stakerPks = append(stakerPks, e.StakerPkHex) - } - } - - // Fetch the staker stats for each staker - for _, stakerPk := range stakerPks { - stakerStats := fetchStakerStatsEndpoint(t, testServer, stakerPk) - assert.Equal(t, 1, len(stakerStats)) - } - }) -} - -func FuzzStatsEndpointReturnHighestUnconfirmedTvlFromEvents(f *testing.F) { - attachRandomSeedsToFuzzer(f, 5) - f.Fuzz(func(t *testing.T, seed int64) { - r := rand.New(rand.NewSource(seed)) - testServer := setupTestServer(t, nil) - defer testServer.Close() - - overallStats := fetchOverallStatsEndpoint(t, testServer) - assert.Equal(t, uint64(0), overallStats.UnconfirmedTvl) - - highestHeightEvent := &client.BtcInfoEvent{ - EventType: client.BtcInfoEventType, - Height: 0, - ConfirmedTvl: 0, - UnconfirmedTvl: 0, - } - var messages []*client.BtcInfoEvent - for i := 0; i < 10; i++ { - confirmedTvl := uint64(testutils.RandomAmount(r)) - btcInfoEvent := &client.BtcInfoEvent{ - EventType: client.BtcInfoEventType, - Height: uint64(testutils.RandomPositiveInt(r, 1000000)), - ConfirmedTvl: confirmedTvl, - UnconfirmedTvl: confirmedTvl + uint64(testutils.RandomAmount(r)), - } - messages = append(messages, btcInfoEvent) - if btcInfoEvent.Height > highestHeightEvent.Height { - highestHeightEvent = btcInfoEvent - } - } - sendTestMessage(testServer.Queues.V1QueueClient.BtcInfoQueueClient, messages) - time.Sleep(5 * time.Second) - - overallStats = fetchOverallStatsEndpoint(t, testServer) - assert.Equal(t, &highestHeightEvent.UnconfirmedTvl, &overallStats.UnconfirmedTvl) - pendingTvl := highestHeightEvent.UnconfirmedTvl - highestHeightEvent.ConfirmedTvl - assert.Equal(t, pendingTvl, overallStats.PendingTvl) - }) -} - -func FuzzTestTopStakersWithPaginationResponse(f *testing.F) { - attachRandomSeedsToFuzzer(f, 3) - f.Fuzz(func(t *testing.T, seed int64) { - r := rand.New(rand.NewSource(seed)) - numOfStakers := testutils.RandomPositiveInt(r, 10) - // Pagination size shall alway be greater than 2 - paginationSize := testutils.RandomPositiveInt(r, 10) + 1 - var events []*client.ActiveStakingEvent - for i := 0; i < numOfStakers; i++ { - opts := &testutils.TestActiveEventGeneratorOpts{ - NumOfEvents: testutils.RandomPositiveInt(r, 1), - Stakers: testutils.GeneratePks(1), - EnforceNotOverflow: true, - } - activeStakingEventsByStaker := - testutils.GenerateRandomActiveStakingEvents(r, opts) - events = append(events, activeStakingEventsByStaker...) - } - cfg, err := config.New("../config/config-test.yml") - if err != nil { - t.Fatalf("Failed to load test config: %v", err) - } - cfg.StakingDb.MaxPaginationLimit = int64(paginationSize) - - testServer := setupTestServer(t, &TestServerDependency{ConfigOverrides: cfg}) - defer testServer.Close() - sendTestMessage( - testServer.Queues.V1QueueClient.ActiveStakingQueueClient, - events, - ) - time.Sleep(5 * time.Second) - // Test the API - url := testServer.Server.URL + topStakerStatsPath - var paginationKey string - var allDataCollected []v1service.StakerStatsPublic - var numOfRequestsToFetchAllResults int - for { - numOfRequestsToFetchAllResults++ - resp, err := http.Get(url + "?pagination_key=" + paginationKey) - assert.NoError(t, err, "making GET request to staker stats endpoint should not fail") - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - var response handler.PublicResponse[[]v1service.StakerStatsPublic] - err = json.Unmarshal(bodyBytes, &response) - assert.NoError(t, err, "unmarshalling response body should not fail") - // Check that the response body is as expected - allDataCollected = append(allDataCollected, response.Data...) - if response.Pagination.NextKey != "" { - assert.NotEmptyf(t, response.Data, "expected response body to have data") - assert.Equal(t, paginationSize, len(response.Data)) - paginationKey = response.Pagination.NextKey - } else { - break - } - } - - assert.Equal(t, math.Ceil(float64(numOfStakers)/float64(paginationSize)), float64(numOfRequestsToFetchAllResults)) - assert.Equal(t, numOfStakers, len(allDataCollected)) - for i := 0; i < len(allDataCollected)-1; i++ { - assert.True(t, allDataCollected[i].ActiveTvl >= allDataCollected[i+1].ActiveTvl, "expected collected data to be sorted by start height") - } - }) -} - -func fetchFinalityEndpoint(t *testing.T, testServer *TestServer) []v1service.FpDetailsPublic { - url := testServer.Server.URL + finalityProvidersPath - // Make a GET request to the finality providers endpoint - resp, err := http.Get(url) - assert.NoError(t, err, "making GET request to finality providers endpoint should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var responseBody handler.PublicResponse[[]v1service.FpDetailsPublic] - err = json.Unmarshal(bodyBytes, &responseBody) - assert.NoError(t, err, "unmarshalling response body should not fail") - - return responseBody.Data -} - -func fetchOverallStatsEndpoint(t *testing.T, testServer *TestServer) v1service.OverallStatsPublic { - url := testServer.Server.URL + overallStatsEndpoint - // Make a GET request to the stats endpoint - resp, err := http.Get(url) - assert.NoError(t, err, "making GET request to stats endpoint should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var responseBody handler.PublicResponse[v1service.OverallStatsPublic] - err = json.Unmarshal(bodyBytes, &responseBody) - assert.NoError(t, err, "unmarshalling response body should not fail") - - return responseBody.Data -} - -func fetchStakerStatsEndpoint(t *testing.T, testServer *TestServer, stakerPk string) []v1service.StakerStatsPublic { - url := testServer.Server.URL + topStakerStatsPath - if stakerPk != "" { - url += "?staker_btc_pk=" + stakerPk - } - resp, err := http.Get(url) - assert.NoError(t, err, "making GET request to staker stats endpoint should not fail") - defer resp.Body.Close() - - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var responseBody handler.PublicResponse[[]v1service.StakerStatsPublic] - err = json.Unmarshal(bodyBytes, &responseBody) - assert.NoError(t, err, "unmarshalling response body should not fail") - - return responseBody.Data -} diff --git a/tests/integration_test/timelock_test.go b/tests/integration_test/timelock_test.go deleted file mode 100644 index 4c605ca0..00000000 --- a/tests/integration_test/timelock_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package tests - -import ( - "testing" - "time" - - dbmodel "github.com/babylonlabs-io/staking-api-service/internal/shared/db/model" - v1model "github.com/babylonlabs-io/staking-api-service/internal/v1/db/model" - "github.com/babylonlabs-io/staking-api-service/tests/testutils" - "github.com/stretchr/testify/assert" -) - -func TestSaveTimelock(t *testing.T) { - // Inject random data - activeStakingEvent := buildActiveStakingEvent(t, 1) - testServer := setupTestServer(t, nil) - defer testServer.Close() - sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, activeStakingEvent) - - // Wait for 2 seconds to make sure the message is processed - time.Sleep(2 * time.Second) - // Check from DB if the data is saved - results, err := testutils.InspectDbDocuments[v1model.TimeLockDocument]( - testServer.Config, dbmodel.V1TimeLockCollection, - ) - if err != nil { - t.Fatalf("Failed to inspect DB documents: %v", err) - } - assert.Equal(t, 1, len(results), "expected 1 document in the DB") - - // Check the data - assert.Equal(t, activeStakingEvent[0].StakingTxHashHex, results[0].StakingTxHashHex, "expected address to be the same") - - expectedExpireHeight := activeStakingEvent[0].StakingStartHeight + activeStakingEvent[0].StakingTimeLock - assert.Equal(t, expectedExpireHeight, results[0].ExpireHeight, "expected address to be the same") -} - -func TestNotSaveExpireCheckIfAlreadyProcessed(t *testing.T) { - // Inject random data - activeStakingEvent := buildActiveStakingEvent(t, 1) - testServer := setupTestServer(t, nil) - defer testServer.Close() - sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, activeStakingEvent) - // Send again - sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, activeStakingEvent) - - // Wait for 2 seconds to make sure the message is processed - time.Sleep(5 * time.Second) - // Check from DB if the data is saved - results, err := testutils.InspectDbDocuments[v1model.TimeLockDocument]( - testServer.Config, dbmodel.V1TimeLockCollection, - ) - if err != nil { - t.Fatalf("Failed to inspect DB documents: %v", err) - } - assert.Equal(t, 1, len(results), "expected 1 document in the DB") - - // Check the data - assert.Equal(t, activeStakingEvent[0].StakingTxHashHex, results[0].StakingTxHashHex, "expected address to be the same") - expectedExpireHeight := activeStakingEvent[0].StakingStartHeight + activeStakingEvent[0].StakingTimeLock - assert.Equal(t, expectedExpireHeight, results[0].ExpireHeight, "expected address to be the same") - - // Now, let's inject the same data but with different expireHeight - eventWithDifferentExpireHeight := buildActiveStakingEvent(t, 1) - - sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, eventWithDifferentExpireHeight) - time.Sleep(2 * time.Second) - - results, err = testutils.InspectDbDocuments[v1model.TimeLockDocument]( - testServer.Config, dbmodel.V1TimeLockCollection, - ) - if err != nil { - t.Fatalf("Failed to inspect DB documents: %v", err) - } - assert.Equal(t, 1, len(results), "expected 1 document in the DB") - - // Check the data, it shall never be updated again - assert.Equal(t, activeStakingEvent[0].StakingTxHashHex, results[0].StakingTxHashHex, "expected address to be the same") - assert.Equal(t, expectedExpireHeight, results[0].ExpireHeight, "expected address to be the same") -} diff --git a/tests/integration_test/unbonding_test.go b/tests/integration_test/unbonding_test.go deleted file mode 100644 index 4c6a411d..00000000 --- a/tests/integration_test/unbonding_test.go +++ /dev/null @@ -1,640 +0,0 @@ -package tests - -import ( - "bytes" - "encoding/json" - "io" - "math/rand" - "net/http" - "testing" - "time" - - "github.com/babylonlabs-io/staking-api-service/internal/shared/api" - handler "github.com/babylonlabs-io/staking-api-service/internal/shared/api/handlers/handler" - "github.com/babylonlabs-io/staking-api-service/internal/shared/config" - dbclients "github.com/babylonlabs-io/staking-api-service/internal/shared/db/clients" - dbmodel "github.com/babylonlabs-io/staking-api-service/internal/shared/db/model" - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - v1handlers "github.com/babylonlabs-io/staking-api-service/internal/v1/api/handlers" - v1dbmodel "github.com/babylonlabs-io/staking-api-service/internal/v1/db/model" - v1service "github.com/babylonlabs-io/staking-api-service/internal/v1/service" - testmock "github.com/babylonlabs-io/staking-api-service/tests/mocks" - "github.com/babylonlabs-io/staking-api-service/tests/testutils" - "github.com/babylonlabs-io/staking-queue-client/client" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "go.mongodb.org/mongo-driver/mongo" -) - -const ( - unbondingEligibilityPath = "/v1/unbonding/eligibility" - unbondingPath = "/v1/unbonding" -) - -func TestUnbondingRequest(t *testing.T) { - activeStakingEvent := getTestActiveStakingEvent() - testServer := setupTestServer(t, nil) - defer testServer.Close() - - err := sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, []client.ActiveStakingEvent{*activeStakingEvent}) - require.NoError(t, err) - - time.Sleep(2 * time.Second) - - eligibilityUrl := testServer.Server.URL + unbondingEligibilityPath + "?staking_tx_hash_hex=" + activeStakingEvent.StakingTxHashHex - - // Make a GET request to the unbonding eligibility check endpoint again - resp, err := http.Get(eligibilityUrl) - assert.NoError(t, err, "making GET request to unbonding eligibility check endpoint should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 200 - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - // Let's make a POST request to the unbonding endpoint - unbondingUrl := testServer.Server.URL + unbondingPath - requestBody := getTestUnbondDelegationRequestPayload(activeStakingEvent.StakingTxHashHex) - requestBodyBytes, err := json.Marshal(requestBody) - assert.NoError(t, err, "marshalling request body should not fail") - - resp, err = http.Post(unbondingUrl, "application/json", bytes.NewReader(requestBodyBytes)) - assert.NoError(t, err, "making POST request to unbonding endpoint should not fail") - defer resp.Body.Close() - - // Make a GET request to the unbonding eligibility check endpoint again - resp, err = http.Get(eligibilityUrl) - assert.NoError(t, err, "making GET request to unbonding eligibility check endpoint should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 403 Forbidden - assert.Equal(t, http.StatusForbidden, resp.StatusCode, "expected HTTP 403 Forbidden status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var response api.ErrorResponse - err = json.Unmarshal(bodyBytes, &response) - assert.NoError(t, err, "unmarshalling response body should not fail") - assert.Equal(t, "FORBIDDEN", response.ErrorCode, "expected error code to be FORBIDDEN") - assert.Equal(t, "delegation state is not active", response.Message, "expected error message to be 'delegation state is not active'") - - // Let's make a POST request to the unbonding endpoint again - resp, err = http.Post(unbondingUrl, "application/json", bytes.NewReader(requestBodyBytes)) - assert.NoError(t, err, "making POST request to unbonding endpoint should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 403 Forbidden - assert.Equal(t, http.StatusForbidden, resp.StatusCode, "expected HTTP 403 Forbidden status") - - // Read the response body - bodyBytes, err = io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - err = json.Unmarshal(bodyBytes, &response) - assert.NoError(t, err, "unmarshalling response body should not fail") - assert.Equal(t, "FORBIDDEN", response.ErrorCode, "expected error code to be FORBIDDEN") - assert.Equal(t, "delegation state is not active", response.Message, "expected error message to be 'no active delegation found for unbonding request'") - - // The state should be updated to UnbondingRequested - getStakerDelegationUrl := testServer.Server.URL + stakerDelegations + "?staker_btc_pk=" + activeStakingEvent.StakerPkHex - resp, err = http.Get(getStakerDelegationUrl) - assert.NoError(t, err, "making GET request to delegations by staker pk should not fail") - defer resp.Body.Close() - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - // Read the response body - bodyBytes, err = io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var getStakerDelegationResponse handler.PublicResponse[[]v1service.DelegationPublic] - err = json.Unmarshal(bodyBytes, &getStakerDelegationResponse) - assert.NoError(t, err, "unmarshalling response body should not fail") - - // Check that the response body is as expected - assert.Equal(t, activeStakingEvent.StakerPkHex, getStakerDelegationResponse.Data[0].StakerPkHex, "expected response body to match") - assert.Equal(t, types.UnbondingRequested.ToString(), getStakerDelegationResponse.Data[0].State, "state should be unbonding requested") - - // Let's inspect what's stored in the database - results, err := testutils.InspectDbDocuments[v1dbmodel.UnbondingDocument]( - testServer.Config, dbmodel.V1UnbondingCollection, - ) - assert.NoError(t, err, "failed to inspect DB documents") - - assert.Equal(t, 1, len(results), "expected 1 document in the DB") - assert.Equal(t, activeStakingEvent.StakerPkHex, results[0].StakerPkHex) - assert.Equal(t, activeStakingEvent.FinalityProviderPkHex, results[0].FinalityPkHex) - assert.Equal(t, requestBody.StakerSignedSignatureHex, results[0].UnbondingTxSigHex) - assert.Equal(t, "INSERTED", results[0].State) - assert.Equal(t, activeStakingEvent.StakingTxHashHex, results[0].StakingTxHashHex) - assert.Equal(t, requestBody.UnbondingTxHashHex, results[0].UnbondingTxHashHex) - assert.Equal(t, requestBody.UnbondingTxHex, results[0].UnbondingTxHex) - assert.Equal(t, activeStakingEvent.StakingTxHex, results[0].StakingTxHex) - assert.Equal(t, activeStakingEvent.StakingOutputIndex, results[0].StakingOutputIndex) - assert.Equal(t, activeStakingEvent.StakingTimeLock, results[0].StakingTimelock) - assert.Equal(t, activeStakingEvent.StakingValue, results[0].StakingAmount) -} - -func TestUnbondingRequestEligibilityWhenNoMatchingDelegation(t *testing.T) { - r := rand.New(rand.NewSource(time.Now().UnixNano())) - activeStakingEvent := testutils.GenerateRandomActiveStakingEvents(r, &testutils.TestActiveEventGeneratorOpts{ - NumOfEvents: 1, - FinalityProviders: testutils.GeneratePks(1), - Stakers: testutils.GeneratePks(1), - }) - testServer := setupTestServer(t, nil) - defer testServer.Close() - - eligibilityUrl := testServer.Server.URL + unbondingEligibilityPath + "?staking_tx_hash_hex=" + activeStakingEvent[0].StakingTxHashHex - - // Make a GET request to the unbonding eligibility check endpoint - resp, err := http.Get(eligibilityUrl) - assert.NoError(t, err, "making GET request to unbonding eligibility check endpoint should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 403 Forbidden - assert.Equal(t, http.StatusForbidden, resp.StatusCode, "expected HTTP 403 Forbidden status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var response api.ErrorResponse - err = json.Unmarshal(bodyBytes, &response) - assert.NoError(t, err, "unmarshalling response body should not fail") - assert.Equal(t, "NOT_FOUND", response.ErrorCode, "expected error code to be NOT_FOUND") -} - -func getTestActiveStakingEvent() *client.ActiveStakingEvent { - return &client.ActiveStakingEvent{ - EventType: client.ActiveStakingEventType, - StakingTxHashHex: "06cb98777a9cc5d3556498f6e5607947759e60f01e1441b6ce375174b8588037", - StakerPkHex: "91fef91f0f00d010d6c918acb9197db6cd33d99ee617090fa8cb61fa2a31405a", - FinalityProviderPkHex: "03d5a0bb72d71993e435d6c5a70e2aa4db500a62cfaae33c56050deefee64ec0", - StakingValue: 100000, - StakingStartTimestamp: 1714035159, - StakingStartHeight: 102, - StakingTimeLock: 100, - StakingOutputIndex: 1, - StakingTxHex: "0100000000010103f23a34f828a8335be0ce0400b0f1b8a5a26fd04b94abcff2ce59443b373fff0000000000ffffffff030000000000000000496a47010203040091fef91f0f00d010d6c918acb9197db6cd33d99ee617090fa8cb61fa2a31405a03d5a0bb72d71993e435d6c5a70e2aa4db500a62cfaae33c56050deefee64ec00064a08601000000000022512072a6ef79c17676fb1b54a157a4921fa57f4295dae778a423523a378171b09f3e756a042a01000000160014257cf22a8f4502076820609a30d7370856c342c40247304402203fd7b14cd32f7640c8575fe7516b2b3233c9eb3b956fe9d26bb67c156287787d0220093a1a2cd9276b53f60435fbbc55e9c007f607987c1d62f259f14ddd14a5cab501210291fef91f0f00d010d6c918acb9197db6cd33d99ee617090fa8cb61fa2a31405a00000000", - IsOverflow: false, - } -} - -func getTestUnbondDelegationRequestPayload(stakingTxHashHex string) v1handlers.UnbondDelegationRequestPayload { - return v1handlers.UnbondDelegationRequestPayload{ - StakingTxHashHex: stakingTxHashHex, - UnbondingTxHashHex: "17aad3b01a9fa134f0e6374b9ad1b049376a9bdbd889afc369dcb8074bbdf1b3", - UnbondingTxHex: "02000000000101378058b8745137ceb641141ef0609e75477960e5f6986455d3c59c7a7798cb060100000000ffffffff01905f010000000000225120ba296d88e83fd2faf5864ddda74ac8d0df6a7d76b39d5ef4c0751117a26cfd3104403c3d32c844ff751de59190ffc57427794450ba97b0d6ead43d53d865b34021abb52a6370382cfc46416f42f28d32704e504f84720d8458b5d51fee69d28cf94940728ab06ac8ab2f14b4c60cacb0e8932760f1559df93dd9053327e72cec53fc9749d5abaa4a96758b7f3588b3ad80e4c157233f1e689a37bea3ccaa9e50ba153ece2091fef91f0f00d010d6c918acb9197db6cd33d99ee617090fa8cb61fa2a31405aad2057349e985e742d5131e1e2b227b5170f6350ac2e2feb72254fcc25b3cee21a18ac2059d3532148a597a2d05c0395bf5f7176044b1cd312f37701a9b4d0aad70bc5a4ba20a5c60c2188e833d39d0fa798ab3f69aa12ed3dd2f3bad659effa252782de3c31ba20c8ccb03c379e452f10c81232b41a1ca8b63d0baf8387e57d302c987e5abb8527ba20ffeaec52a9b407b355ef6967a7ffc15fd6c3fe07de2844d61550475e7a5233e5ba539c61c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0957294d847c7353393803c6a2c03d6b777bb2cbb69aa4c85291d2d9bb981bb59cc2f4c8bba33b96629a6e942aad0c9815a4e5e7322f63e521e762371b71e3c1300000000", - StakerSignedSignatureHex: "728ab06ac8ab2f14b4c60cacb0e8932760f1559df93dd9053327e72cec53fc9749d5abaa4a96758b7f3588b3ad80e4c157233f1e689a37bea3ccaa9e50ba153e", - } -} - -func TestProcessUnbondingStakingEvent(t *testing.T) { - activeStakingEvent := getTestActiveStakingEvent() - testServer := setupTestServer(t, nil) - defer testServer.Close() - - err := sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, []*client.ActiveStakingEvent{activeStakingEvent}) - require.NoError(t, err) - - time.Sleep(2 * time.Second) - - // Let's make a POST request to the unbonding endpoint - unbondingUrl := testServer.Server.URL + unbondingPath - requestBody := getTestUnbondDelegationRequestPayload(activeStakingEvent.StakingTxHashHex) - requestBodyBytes, err := json.Marshal(requestBody) - assert.NoError(t, err, "marshalling request body should not fail") - - resp, err := http.Post(unbondingUrl, "application/json", bytes.NewReader(requestBodyBytes)) - assert.NoError(t, err, "making POST request to unbonding endpoint should not fail") - defer resp.Body.Close() - - // Let's inspect what's stored in the database - results, err := testutils.InspectDbDocuments[v1dbmodel.UnbondingDocument]( - testServer.Config, dbmodel.V1UnbondingCollection, - ) - assert.NoError(t, err, "failed to inspect DB documents") - - assert.Equal(t, 1, len(results), "expected 1 document in the DB") - assert.Equal(t, "INSERTED", results[0].State) - assert.Equal(t, activeStakingEvent.StakingTxHex, results[0].StakingTxHex) - - // Let's send an unbonding event - unbondingEvent := client.UnbondingStakingEvent{ - EventType: client.UnbondingStakingEventType, - StakingTxHashHex: requestBody.StakingTxHashHex, - UnbondingTxHashHex: requestBody.UnbondingTxHashHex, - UnbondingTxHex: requestBody.UnbondingTxHex, - UnbondingTimeLock: 10, - UnbondingStartTimestamp: time.Now().Unix(), - UnbondingStartHeight: activeStakingEvent.StakingStartHeight + 100, - UnbondingOutputIndex: 1, - } - - sendTestMessage(testServer.Queues.V1QueueClient.UnbondingStakingQueueClient, []client.UnbondingStakingEvent{unbondingEvent}) - time.Sleep(2 * time.Second) - - // Let's GET the delegation from API - getStakerDelegationUrl := testServer.Server.URL + stakerDelegations + "?staker_btc_pk=" + activeStakingEvent.StakerPkHex - resp, err = http.Get(getStakerDelegationUrl) - assert.NoError(t, err, "making GET request to delegations by staker pk should not fail") - defer resp.Body.Close() - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var getStakerDelegationResponse handler.PublicResponse[[]v1service.DelegationPublic] - err = json.Unmarshal(bodyBytes, &getStakerDelegationResponse) - assert.NoError(t, err, "unmarshalling response body should not fail") - - // Check that the response body is as expected - assert.Equal(t, 1, len(getStakerDelegationResponse.Data), "expected 1 delegation in the response") - assert.Equal(t, activeStakingEvent.StakerPkHex, getStakerDelegationResponse.Data[0].StakerPkHex, "expected response body to match") - assert.Equal(t, types.Unbonding.ToString(), getStakerDelegationResponse.Data[0].State, "state should be unbonding") - // Make sure the unbonding tx exist in the response body - assert.NotNil(t, getStakerDelegationResponse.Data[0].UnbondingTx, "expected unbonding tx to be present in the response body") - assert.Equal(t, unbondingEvent.UnbondingTxHex, getStakerDelegationResponse.Data[0].UnbondingTx.TxHex, "expected unbonding tx to match") - - _, err = time.Parse(time.RFC3339, getStakerDelegationResponse.Data[0].UnbondingTx.StartTimestamp) - assert.NoError(t, err, "expected timestamp to be in RFC3339 format") - - // Let's also fetch the DB to make sure the expired check is processed - timeLockResults, err := testutils.InspectDbDocuments[v1dbmodel.TimeLockDocument]( - testServer.Config, dbmodel.V1TimeLockCollection, - ) - assert.NoError(t, err, "failed to inspect DB documents") - - assert.Equal(t, 2, len(timeLockResults), "expected 2 document in the DB") - // The first one is from the - assert.Equal(t, activeStakingEvent.StakingTxHashHex, timeLockResults[0].StakingTxHashHex) - assert.Equal(t, types.ActiveTxType.ToString(), timeLockResults[0].TxType) - // Point to the same staking tx hash - assert.Equal(t, activeStakingEvent.StakingTxHashHex, timeLockResults[1].StakingTxHashHex) - assert.Equal(t, requestBody.StakingTxHashHex, timeLockResults[1].StakingTxHashHex) - assert.Equal(t, types.UnbondingTxType.ToString(), timeLockResults[1].TxType) -} - -func TestProcessUnbondingStakingEventDuringBootstrap(t *testing.T) { - activeStakingEvent := getTestActiveStakingEvent() - testServer := setupTestServer(t, nil) - defer testServer.Close() - - err := sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, []*client.ActiveStakingEvent{activeStakingEvent}) - require.NoError(t, err) - - time.Sleep(2 * time.Second) - - // We generate the necessary unbonding request payload, but we not sending it to the unbonding endpoint - // Instead, we send the unbonding event directly to simulate the case where our system is bootstrapping - // which means we have the unbonding data but not the unbonding request - requestBody := getTestUnbondDelegationRequestPayload(activeStakingEvent.StakingTxHashHex) - unbondingEvent := client.UnbondingStakingEvent{ - EventType: client.UnbondingStakingEventType, - StakingTxHashHex: requestBody.StakingTxHashHex, - UnbondingTxHashHex: requestBody.UnbondingTxHashHex, - UnbondingTxHex: requestBody.UnbondingTxHex, - UnbondingTimeLock: 10, - UnbondingStartTimestamp: time.Now().Unix(), - UnbondingStartHeight: activeStakingEvent.StakingStartHeight + 100, - UnbondingOutputIndex: 1, - } - - sendTestMessage(testServer.Queues.V1QueueClient.UnbondingStakingQueueClient, []client.UnbondingStakingEvent{unbondingEvent}) - time.Sleep(2 * time.Second) - - // Let's GET the delegation from API - getStakerDelegationUrl := testServer.Server.URL + stakerDelegations + "?staker_btc_pk=" + activeStakingEvent.StakerPkHex - resp, err := http.Get(getStakerDelegationUrl) - assert.NoError(t, err, "making GET request to delegations by staker pk should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var getStakerDelegationResponse handler.PublicResponse[[]v1service.DelegationPublic] - err = json.Unmarshal(bodyBytes, &getStakerDelegationResponse) - assert.NoError(t, err, "unmarshalling response body should not fail") - - // Check that the response body is as expected - assert.Equal(t, 1, len(getStakerDelegationResponse.Data), "expected 1 delegation in the response") - assert.Equal(t, activeStakingEvent.StakerPkHex, getStakerDelegationResponse.Data[0].StakerPkHex, "expected response body to match") - assert.Equal(t, types.Unbonding.ToString(), getStakerDelegationResponse.Data[0].State, "state should be unbonding") - // Make sure the unbonding tx exist in the response body - assert.NotNil(t, getStakerDelegationResponse.Data[0].UnbondingTx, "expected unbonding tx to be present in the response body") - assert.Equal(t, unbondingEvent.UnbondingTxHex, getStakerDelegationResponse.Data[0].UnbondingTx.TxHex, "expected unbonding tx to match") - - // Let's also fetch the DB to make sure the expired check is processed - timeLockResults, err := testutils.InspectDbDocuments[v1dbmodel.TimeLockDocument]( - testServer.Config, dbmodel.V1TimeLockCollection, - ) - assert.NoError(t, err, "failed to inspect DB documents") - - assert.Equal(t, 2, len(timeLockResults), "expected 2 document in the DB") - // The first one is from the - assert.Equal(t, activeStakingEvent.StakingTxHashHex, timeLockResults[0].StakingTxHashHex) - assert.Equal(t, types.ActiveTxType.ToString(), timeLockResults[0].TxType) - // Point to the same staking tx hash - assert.Equal(t, activeStakingEvent.StakingTxHashHex, timeLockResults[1].StakingTxHashHex) - assert.Equal(t, requestBody.StakingTxHashHex, timeLockResults[1].StakingTxHashHex) - assert.Equal(t, types.UnbondingTxType.ToString(), timeLockResults[1].TxType) -} - -func TestShouldIgnoreOutdatedUnbondingEvent(t *testing.T) { - activeStakingEvent := getTestActiveStakingEvent() - testServer := setupTestServer(t, nil) - defer testServer.Close() - - err := sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, []*client.ActiveStakingEvent{activeStakingEvent}) - require.NoError(t, err) - - time.Sleep(2 * time.Second) - - requestBody := getTestUnbondDelegationRequestPayload(activeStakingEvent.StakingTxHashHex) - unbondingEvent := client.UnbondingStakingEvent{ - EventType: client.UnbondingStakingEventType, - StakingTxHashHex: requestBody.StakingTxHashHex, - UnbondingTxHashHex: requestBody.UnbondingTxHashHex, - UnbondingTxHex: requestBody.UnbondingTxHex, - UnbondingTimeLock: 10, - UnbondingStartTimestamp: time.Now().Unix(), - UnbondingStartHeight: activeStakingEvent.StakingStartHeight + 100, - UnbondingOutputIndex: 1, - } - - sendTestMessage(testServer.Queues.V1QueueClient.UnbondingStakingQueueClient, []client.UnbondingStakingEvent{unbondingEvent}) - time.Sleep(2 * time.Second) - - // Let's GET the delegation from API - getStakerDelegationUrl := testServer.Server.URL + stakerDelegations + "?staker_btc_pk=" + activeStakingEvent.StakerPkHex - resp, err := http.Get(getStakerDelegationUrl) - assert.NoError(t, err, "making GET request to delegations by staker pk should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var getStakerDelegationResponse handler.PublicResponse[[]v1service.DelegationPublic] - err = json.Unmarshal(bodyBytes, &getStakerDelegationResponse) - assert.NoError(t, err, "unmarshalling response body should not fail") - - // Check that the response body is as expected - assert.Equal(t, 1, len(getStakerDelegationResponse.Data), "expected 1 delegation in the response") - assert.Equal(t, activeStakingEvent.StakerPkHex, getStakerDelegationResponse.Data[0].StakerPkHex, "expected response body to match") - assert.Equal(t, types.Unbonding.ToString(), getStakerDelegationResponse.Data[0].State, "state should be unbonding") - // Make sure the unbonding tx exist in the response body - assert.NotNil(t, getStakerDelegationResponse.Data[0].UnbondingTx, "expected unbonding tx to be present in the response body") - assert.Equal(t, unbondingEvent.UnbondingTxHex, getStakerDelegationResponse.Data[0].UnbondingTx.TxHex, "expected unbonding tx to match") - - // Let's also fetch the DB to make sure the expired check is processed - timeLockResults, err := testutils.InspectDbDocuments[v1dbmodel.TimeLockDocument]( - testServer.Config, dbmodel.V1TimeLockCollection, - ) - assert.NoError(t, err, "failed to inspect DB documents") - - assert.Equal(t, 2, len(timeLockResults), "expected 2 document in the DB") - // The first one is from the - assert.Equal(t, activeStakingEvent.StakingTxHashHex, timeLockResults[0].StakingTxHashHex) - assert.Equal(t, types.ActiveTxType.ToString(), timeLockResults[0].TxType) - // Point to the same staking tx hash - assert.Equal(t, activeStakingEvent.StakingTxHashHex, timeLockResults[1].StakingTxHashHex) - assert.Equal(t, requestBody.StakingTxHashHex, timeLockResults[1].StakingTxHashHex) - assert.Equal(t, types.UnbondingTxType.ToString(), timeLockResults[1].TxType) - - // Let's send an outdated unbonding event - sendTestMessage(testServer.Queues.V1QueueClient.UnbondingStakingQueueClient, []client.UnbondingStakingEvent{unbondingEvent}) - time.Sleep(2 * time.Second) - - // Fetch from the expire checker to make sure we only processed the unbonding event once - timeLockResults, err = testutils.InspectDbDocuments[v1dbmodel.TimeLockDocument]( - testServer.Config, dbmodel.V1TimeLockCollection, - ) - assert.NoError(t, err, "failed to inspect DB documents") - - // Should still be 2 - assert.Equal(t, 2, len(timeLockResults), "expected 2 document in the DB") -} - -func TestProcessUnbondingStakingEventShouldTolerateEventMsgOutOfOrder(t *testing.T) { - testServer := setupTestServer(t, nil) - defer testServer.Close() - - // We generate the active event, but not sending it yet. we will send it after sending the unbonding event - activeStakingEvent := getTestActiveStakingEvent() - requestBody := getTestUnbondDelegationRequestPayload(activeStakingEvent.StakingTxHashHex) - unbondingEvent := client.UnbondingStakingEvent{ - EventType: client.UnbondingStakingEventType, - StakingTxHashHex: requestBody.StakingTxHashHex, - UnbondingTxHashHex: requestBody.UnbondingTxHashHex, - UnbondingTxHex: requestBody.UnbondingTxHex, - UnbondingTimeLock: 10, - UnbondingStartTimestamp: time.Now().Unix(), - UnbondingStartHeight: activeStakingEvent.StakingStartHeight + 100, - UnbondingOutputIndex: 1, - } - - sendTestMessage(testServer.Queues.V1QueueClient.UnbondingStakingQueueClient, []client.UnbondingStakingEvent{unbondingEvent}) - time.Sleep(2 * time.Second) - // Check DB, there should be no unbonding document - results, err := testutils.InspectDbDocuments[v1dbmodel.UnbondingDocument]( - testServer.Config, dbmodel.V1UnbondingCollection, - ) - assert.NoError(t, err, "failed to inspect DB documents") - assert.Empty(t, results, "expected no unbonding document in the DB") - - // Send the active event - err = sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, []*client.ActiveStakingEvent{activeStakingEvent}) - require.NoError(t, err) - - time.Sleep(10 * time.Second) - - // Let's GET the delegation from API - getStakerDelegationUrl := testServer.Server.URL + stakerDelegations + "?staker_btc_pk=" + activeStakingEvent.StakerPkHex - resp, err := http.Get(getStakerDelegationUrl) - assert.NoError(t, err, "making GET request to delegations by staker pk should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 200 OK - assert.Equal(t, http.StatusOK, resp.StatusCode, "expected HTTP 200 OK status") - - // Read the response body - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var getStakerDelegationResponse handler.PublicResponse[[]v1service.DelegationPublic] - err = json.Unmarshal(bodyBytes, &getStakerDelegationResponse) - assert.NoError(t, err, "unmarshalling response body should not fail") - - // Check that the response body is as expected - assert.Equal(t, 1, len(getStakerDelegationResponse.Data), "expected 1 delegation in the response") - assert.Equal(t, types.Unbonding.ToString(), getStakerDelegationResponse.Data[0].State, "state should be unbonding") - // Make sure the unbonding tx exist in the response body - assert.NotNil(t, getStakerDelegationResponse.Data[0].UnbondingTx, "expected unbonding tx to be present in the response body") - assert.Equal(t, unbondingEvent.UnbondingTxHex, getStakerDelegationResponse.Data[0].UnbondingTx.TxHex, "expected unbonding tx to match") - - // Let's also fetch the DB to make sure the expired check is processed - timeLockResults, err := testutils.InspectDbDocuments[v1dbmodel.TimeLockDocument]( - testServer.Config, dbmodel.V1TimeLockCollection, - ) - assert.NoError(t, err, "failed to inspect DB documents") - - assert.Equal(t, 2, len(timeLockResults), "expected 2 document in the DB") - // The first one is from the - assert.Equal(t, activeStakingEvent.StakingTxHashHex, timeLockResults[0].StakingTxHashHex) - assert.Equal(t, types.ActiveTxType.ToString(), timeLockResults[0].TxType) - // Point to the same staking tx hash - assert.Equal(t, activeStakingEvent.StakingTxHashHex, timeLockResults[1].StakingTxHashHex) - assert.Equal(t, requestBody.StakingTxHashHex, timeLockResults[1].StakingTxHashHex) - assert.Equal(t, types.UnbondingTxType.ToString(), timeLockResults[1].TxType) -} - -func TestUnbondingRequestValidation(t *testing.T) { - r := rand.New(rand.NewSource(time.Now().UnixNano())) - mockV1DBClient := new(testmock.V1DBClient) - mockV1DBClient.On("FindDelegationByTxHashHex", mock.Anything, mock.Anything).Return( - &v1dbmodel.DelegationDocument{ - State: "active", - StakingTx: &v1dbmodel.TimelockTransaction{ - StartHeight: 300, - }, - }, - nil, - ) - mockMongoClient := &mongo.Client{} - testServer := setupTestServer(t, &TestServerDependency{MockDbClients: dbclients.DbClients{ - StakingMongoClient: mockMongoClient, - V1DBClient: mockV1DBClient, - }}) - defer testServer.Close() - unbondingUrl := testServer.Server.URL + unbondingPath - - // TODO: Convert this to a table driven test, and test for all validations. - // Test case 1: Hash from unbonding request does not match the hash on unbonding tranactions - _, stakingTxHashHex := testutils.RandomBytes(r, 32) - _, unbondingTxHashHex := testutils.RandomBytes(r, 32) - _, unbondingTxHex, _ := testutils.GenerateRandomTx( - r, - &struct{ DisableRbf bool }{DisableRbf: true}, - ) - _, fakeSig := testutils.RandomBytes(r, 64) - - payload := v1handlers.UnbondDelegationRequestPayload{ - StakingTxHashHex: stakingTxHashHex, - // unbondingTxHashHex does not match the hash of unbondingTxHex as it is - // generated randomly - UnbondingTxHashHex: unbondingTxHashHex, - UnbondingTxHex: unbondingTxHex, - StakerSignedSignatureHex: fakeSig, - } - - requestBodyBytes, err := json.Marshal(payload) - assert.NoError(t, err, "marshalling request body should not fail") - - resp, err := http.Post(unbondingUrl, "application/json", bytes.NewReader(requestBodyBytes)) - assert.NoError(t, err, "making POST request to unbonding endpoint should not fail") - defer resp.Body.Close() - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - var unbondingResponse api.ErrorResponse - err = json.Unmarshal(bodyBytes, &unbondingResponse) - assert.NoError(t, err, "unmarshalling response body should not fail") - assert.Equal(t, types.ValidationError.String(), unbondingResponse.ErrorCode) - assert.Equal(t, "unbonding_tx_hash_hex must match the hash calculated from the provided unbonding tx", unbondingResponse.Message) - - // Test case 2: unbonding tx input enables rbf - _, stakingTxHashHex = testutils.RandomBytes(r, 32) - unbondingTx, unbondingTxHex, _ := testutils.GenerateRandomTx(r, nil) - unbondingTxHashHex = unbondingTx.TxHash().String() - _, fakeSig = testutils.RandomBytes(r, 64) - - payload = v1handlers.UnbondDelegationRequestPayload{ - StakingTxHashHex: stakingTxHashHex, - // unbondingTxHashHex does not match the hash of unbondingTxHex as it is - // generated randomly - UnbondingTxHashHex: unbondingTxHashHex, - UnbondingTxHex: unbondingTxHex, - StakerSignedSignatureHex: fakeSig, - } - - requestBodyBytes, err = json.Marshal(payload) - assert.NoError(t, err, "marshalling request body should not fail") - - resp, err = http.Post(unbondingUrl, "application/json", bytes.NewReader(requestBodyBytes)) - assert.NoError(t, err, "making POST request to unbonding endpoint should not fail") - defer resp.Body.Close() - bodyBytes, err = io.ReadAll(resp.Body) - assert.NoError(t, err, "reading response body should not fail") - - err = json.Unmarshal(bodyBytes, &unbondingResponse) - assert.NoError(t, err, "unmarshalling response body should not fail") - assert.Equal(t, types.ValidationError.String(), unbondingResponse.ErrorCode) - assert.Equal(t, "invalid unbonding tx hex: the unbonding tx is not a valid pre-signed unbonding tx: pre-signed tx must not be replaceable", unbondingResponse.Message) -} - -func TestContentLength(t *testing.T) { - // Setup test server with ContentLengthMiddleware - testServer := setupTestServer(t, nil) - defer testServer.Close() - - unbondingUrl := testServer.Server.URL + unbondingPath - - cfg, err := config.New("../config/config-test.yml") - if err != nil { - t.Fatal(err) - } - - maxContentLength := cfg.Server.MaxContentLength - - // Create a payload that exceeds the max content length - exceedingPayloadLen := maxContentLength + 1 - exceedingPayload := make([]byte, exceedingPayloadLen) - for i := range exceedingPayload { - exceedingPayload[i] = 'a' - } - - // Make a POST request with the exceeding payload - resp, err := http.Post(unbondingUrl, "application/json", bytes.NewReader(exceedingPayload)) - assert.NoError(t, err, "making POST request with exceeding payload should not fail") - defer resp.Body.Close() - - // Check that the status code is HTTP 413 Request Entity Too Large - assert.Equal(t, http.StatusRequestEntityTooLarge, resp.StatusCode, "expected HTTP 413 Request Entity Too Large status") - - // Test payload exactly at the limit - exactPayload := make([]byte, maxContentLength) - for i := range exactPayload { - exactPayload[i] = 'a' - } - - resp, err = http.Post(unbondingUrl, "application/json", bytes.NewReader(exactPayload)) - assert.NoError(t, err, "making POST request with exact payload should not fail") - defer resp.Body.Close() - - assert.NotEqual(t, http.StatusRequestEntityTooLarge, resp.StatusCode, "expected status other than HTTP 413 Request Entity Too Large") - - // Create a normal payload that's below the max content length - activeStakingEvent := getTestActiveStakingEvent() - normalPayload := getTestUnbondDelegationRequestPayload(activeStakingEvent.StakingTxHashHex) - requestBodyBytes, err := json.Marshal(normalPayload) - assert.NoError(t, err, "marshalling request body should not fail") - - resp, err = http.Post(unbondingUrl, "application/json", bytes.NewReader(requestBodyBytes)) - assert.NoError(t, err, "making POST request with normal payload should not fail") - defer resp.Body.Close() - - assert.NotEqual(t, http.StatusRequestEntityTooLarge, resp.StatusCode, "expected status other than HTTP 413 Request Entity Too Large") -} diff --git a/tests/integration_test/unprocessable_message_test.go b/tests/integration_test/unprocessable_message_test.go deleted file mode 100644 index 5693df42..00000000 --- a/tests/integration_test/unprocessable_message_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package tests - -import ( - "testing" - "time" - - dbmodel "github.com/babylonlabs-io/staking-api-service/internal/shared/db/model" - "github.com/babylonlabs-io/staking-api-service/tests/testutils" - "github.com/babylonlabs-io/staking-queue-client/client" - "github.com/stretchr/testify/assert" -) - -func TestUnprocessableMessageShouldBeStoredInDB(t *testing.T) { - testServer := setupTestServer(t, nil) - defer testServer.Close() - sendTestMessage[string](testServer.Queues.V1QueueClient.ActiveStakingQueueClient, []string{"a rubbish message"}) - // In test, we retry 3 times. (config is 2, but counting start from 0) - time.Sleep(20 * time.Second) - - // Fetch from DB and check - docs, err := testutils.InspectDbDocuments[dbmodel.UnprocessableMessageDocument]( - testServer.Config, dbmodel.V1UnprocessableMsgCollection, - ) - if err != nil { - t.Fatalf("Failed to inspect DB documents: %v", err) - } - - if len(docs) != 1 { - t.Fatalf("Expected 1 unprocessable message, got %d", len(docs)) - } - - assert.Equal(t, "\"a rubbish message\"", docs[0].MessageBody) - - // Also make sure the message is not in the queue anymore - count, err := inspectQueueMessageCount(t, testServer.Conn, client.ActiveStakingQueueName) - if err != nil { - t.Fatalf("Failed to inspect queue: %v", err) - } - assert.Equal(t, 0, count, "expected no message in the queue") -} diff --git a/tests/integration_test/withdraw_staking_test.go b/tests/integration_test/withdraw_staking_test.go deleted file mode 100644 index f81b5831..00000000 --- a/tests/integration_test/withdraw_staking_test.go +++ /dev/null @@ -1,304 +0,0 @@ -package tests - -import ( - "bytes" - "encoding/json" - "net/http" - "testing" - "time" - - dbmodel "github.com/babylonlabs-io/staking-api-service/internal/shared/db/model" - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - v1model "github.com/babylonlabs-io/staking-api-service/internal/v1/db/model" - "github.com/babylonlabs-io/staking-api-service/tests/testutils" - "github.com/babylonlabs-io/staking-queue-client/client" - "github.com/stretchr/testify/assert" -) - -func TestWithdrawFromActiveStaking(t *testing.T) { - activeStakingEvent := getTestActiveStakingEvent() - testServer := setupTestServer(t, nil) - defer testServer.Close() - sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, []client.ActiveStakingEvent{*activeStakingEvent}) - - // Wait for 2 seconds to make sure the message is processed - time.Sleep(2 * time.Second) - - // Check from DB that this delegatin exist and has the state of active - results, err := testutils.InspectDbDocuments[v1model.DelegationDocument]( - testServer.Config, dbmodel.V1DelegationCollection, - ) - if err != nil { - t.Fatalf("Failed to inspect DB documents: %v", err) - } - assert.Equal(t, 1, len(results), "expected 1 document in the DB") - - // Check the data - assert.Equal(t, activeStakingEvent.StakingTxHashHex, results[0].StakingTxHashHex, "expected address to be the same") - assert.Equal(t, types.Active, results[0].State, "expected state to be active") - - // Send the timelock expire event so that the state change to "unbonded" - expiredEvent := client.ExpiredStakingEvent{ - EventType: client.ExpiredStakingEventType, - StakingTxHashHex: activeStakingEvent.StakingTxHashHex, - TxType: types.ActiveTxType.ToString(), - } - - sendTestMessage(testServer.Queues.V1QueueClient.ExpiredStakingQueueClient, []client.ExpiredStakingEvent{expiredEvent}) - time.Sleep(2 * time.Second) - - // Check from DB that this delegatin is in "unbonded" state - results, err = testutils.InspectDbDocuments[v1model.DelegationDocument]( - testServer.Config, dbmodel.V1DelegationCollection, - ) - if err != nil { - t.Fatalf("Failed to inspect DB documents: %v", err) - } - assert.Equal(t, 1, len(results), "expected 1 document in the DB") - - // Check the data - assert.Equal(t, activeStakingEvent.StakingTxHashHex, results[0].StakingTxHashHex, "expected address to be the same") - assert.Equal(t, types.Unbonded, results[0].State, "expected state to be unbonded") - - // Ready for withdraw - withdrawEvent := client.WithdrawStakingEvent{ - EventType: client.WithdrawStakingEventType, - StakingTxHashHex: activeStakingEvent.StakingTxHashHex, - } - - sendTestMessage(testServer.Queues.V1QueueClient.WithdrawStakingQueueClient, []client.WithdrawStakingEvent{withdrawEvent}) - time.Sleep(2 * time.Second) - - // Check the DB, now it shall be "withdrawn" state - results, err = testutils.InspectDbDocuments[v1model.DelegationDocument]( - testServer.Config, dbmodel.V1DelegationCollection, - ) - if err != nil { - t.Fatalf("Failed to inspect DB documents: %v", err) - } - assert.Equal(t, 1, len(results), "expected 1 document in the DB") - - // Check the data - assert.Equal(t, activeStakingEvent.StakingTxHashHex, results[0].StakingTxHashHex, "expected address to be the same") - assert.Equal(t, types.Withdrawn, results[0].State, "expected state to be unbonded") -} - -func TestWithdrawFromStakingHasUnbondingRequested(t *testing.T) { - activeStakingEvent := getTestActiveStakingEvent() - testServer := setupTestServer(t, nil) - defer testServer.Close() - sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, []client.ActiveStakingEvent{*activeStakingEvent}) - - // Wait for 2 seconds to make sure the message is processed - time.Sleep(2 * time.Second) - - // Check from DB that this delegatin exist and has the state of active - results, err := testutils.InspectDbDocuments[v1model.DelegationDocument]( - testServer.Config, dbmodel.V1DelegationCollection, - ) - if err != nil { - t.Fatalf("Failed to inspect DB documents: %v", err) - } - assert.Equal(t, 1, len(results), "expected 1 document in the DB") - - // Check the data - assert.Equal(t, activeStakingEvent.StakingTxHashHex, results[0].StakingTxHashHex, "expected address to be the same") - assert.Equal(t, types.Active, results[0].State, "expected state to be active") - - // Let's make a POST request to the unbonding endpoint - unbondingUrl := testServer.Server.URL + unbondingPath - requestBody := getTestUnbondDelegationRequestPayload(activeStakingEvent.StakingTxHashHex) - requestBodyBytes, err := json.Marshal(requestBody) - assert.NoError(t, err, "marshalling request body should not fail") - - resp, err := http.Post(unbondingUrl, "application/json", bytes.NewReader(requestBodyBytes)) - assert.NoError(t, err, "making POST request to unbonding endpoint should not fail") - defer resp.Body.Close() - - // Let's send an unbonding event - unbondingEvent := client.UnbondingStakingEvent{ - EventType: client.UnbondingStakingEventType, - StakingTxHashHex: requestBody.StakingTxHashHex, - UnbondingTxHashHex: requestBody.UnbondingTxHashHex, - UnbondingTxHex: requestBody.UnbondingTxHex, - UnbondingTimeLock: 10, - UnbondingStartTimestamp: time.Now().Unix(), - UnbondingStartHeight: activeStakingEvent.StakingStartHeight + 100, - UnbondingOutputIndex: 1, - } - - sendTestMessage(testServer.Queues.V1QueueClient.UnbondingStakingQueueClient, []client.UnbondingStakingEvent{unbondingEvent}) - time.Sleep(2 * time.Second) - - // Send the timelock expire event so that the state change to "unbonded" - expiredEvent := client.ExpiredStakingEvent{ - EventType: client.ExpiredStakingEventType, - StakingTxHashHex: activeStakingEvent.StakingTxHashHex, - TxType: types.UnbondingTxType.ToString(), - } - - sendTestMessage(testServer.Queues.V1QueueClient.ExpiredStakingQueueClient, []client.ExpiredStakingEvent{expiredEvent}) - time.Sleep(2 * time.Second) - - // Check from DB that this delegatin is in "unbonded" state - results, err = testutils.InspectDbDocuments[v1model.DelegationDocument]( - testServer.Config, dbmodel.V1DelegationCollection, - ) - if err != nil { - t.Fatalf("Failed to inspect DB documents: %v", err) - } - assert.Equal(t, 1, len(results), "expected 1 document in the DB") - - // Check the data - assert.Equal(t, activeStakingEvent.StakingTxHashHex, results[0].StakingTxHashHex, "expected address to be the same") - assert.Equal(t, types.Unbonded, results[0].State, "expected state to be unbonded") - - // Ready for withdraw - withdrawEvent := client.WithdrawStakingEvent{ - EventType: client.WithdrawStakingEventType, - StakingTxHashHex: activeStakingEvent.StakingTxHashHex, - } - - sendTestMessage(testServer.Queues.V1QueueClient.WithdrawStakingQueueClient, []client.WithdrawStakingEvent{withdrawEvent}) - time.Sleep(2 * time.Second) - - // Check the DB, now it shall be "withdrawn" state - results, err = testutils.InspectDbDocuments[v1model.DelegationDocument]( - testServer.Config, dbmodel.V1DelegationCollection, - ) - if err != nil { - t.Fatalf("Failed to inspect DB documents: %v", err) - } - assert.Equal(t, 1, len(results), "expected 1 document in the DB") - - // Check the data - assert.Equal(t, activeStakingEvent.StakingTxHashHex, results[0].StakingTxHashHex, "expected address to be the same") - assert.Equal(t, types.Withdrawn, results[0].State, "expected state to be unbonded") -} - -func TestProcessWithdrawStakingEventShouldTolerateEventMsgOutOfOrder(t *testing.T) { - activeStakingEvent := getTestActiveStakingEvent() - testServer := setupTestServer(t, nil) - defer testServer.Close() - sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, []client.ActiveStakingEvent{*activeStakingEvent}) - - // Wait for 2 seconds to make sure the message is processed - time.Sleep(2 * time.Second) - - // Check from DB that this delegatin exist and has the state of active - results, err := testutils.InspectDbDocuments[v1model.DelegationDocument]( - testServer.Config, dbmodel.V1DelegationCollection, - ) - if err != nil { - t.Fatalf("Failed to inspect DB documents: %v", err) - } - assert.Equal(t, 1, len(results), "expected 1 document in the DB") - - // Check the data - assert.Equal(t, activeStakingEvent.StakingTxHashHex, results[0].StakingTxHashHex, "expected address to be the same") - assert.Equal(t, types.Active, results[0].State, "expected state to be active") - - // Send the withdraw event before timelock expire event which would change the state to unbonded - withdrawEvent := client.WithdrawStakingEvent{ - EventType: client.WithdrawStakingEventType, - StakingTxHashHex: activeStakingEvent.StakingTxHashHex, - } - - sendTestMessage(testServer.Queues.V1QueueClient.WithdrawStakingQueueClient, []client.WithdrawStakingEvent{withdrawEvent}) - time.Sleep(2 * time.Second) - - // Check the DB, it should still be "active" state as the withdraw event will be requeued - results, err = testutils.InspectDbDocuments[v1model.DelegationDocument]( - testServer.Config, dbmodel.V1DelegationCollection, - ) - if err != nil { - t.Fatalf("Failed to inspect DB documents: %v", err) - } - assert.Equal(t, activeStakingEvent.StakingTxHashHex, results[0].StakingTxHashHex, "expected address to be the same") - assert.Equal(t, types.Active, results[0].State, "expected state to be active") - - // Now, send the timelock expire event so that the state change to "unbonded" - expiredEvent := client.ExpiredStakingEvent{ - EventType: client.ExpiredStakingEventType, - StakingTxHashHex: activeStakingEvent.StakingTxHashHex, - TxType: types.ActiveTxType.ToString(), - } - - sendTestMessage(testServer.Queues.V1QueueClient.ExpiredStakingQueueClient, []client.ExpiredStakingEvent{expiredEvent}) - time.Sleep(10 * time.Second) - - // Check the DB after a while, now it shall be "withdrawn" state - results, err = testutils.InspectDbDocuments[v1model.DelegationDocument]( - testServer.Config, dbmodel.V1DelegationCollection, - ) - if err != nil { - t.Fatalf("Failed to inspect DB documents: %v", err) - } - assert.Equal(t, 1, len(results), "expected 1 document in the DB") - - // Check the data - assert.Equal(t, activeStakingEvent.StakingTxHashHex, results[0].StakingTxHashHex, "expected address to be the same") - assert.Equal(t, types.Withdrawn, results[0].State, "expected state to be unbonded") -} - -func TestShouldIgnoreWithdrawnEventIfAlreadyWithdrawn(t *testing.T) { - activeStakingEvent := getTestActiveStakingEvent() - testServer := setupTestServer(t, nil) - defer testServer.Close() - sendTestMessage(testServer.Queues.V1QueueClient.ActiveStakingQueueClient, []client.ActiveStakingEvent{*activeStakingEvent}) - // Wait for 2 seconds to make sure the message is processed - time.Sleep(2 * time.Second) - - // Now, send the timelock expire event so that the state change to "unbonded" - expiredEvent := client.ExpiredStakingEvent{ - EventType: client.ExpiredStakingEventType, - StakingTxHashHex: activeStakingEvent.StakingTxHashHex, - TxType: types.ActiveTxType.ToString(), - } - - sendTestMessage(testServer.Queues.V1QueueClient.ExpiredStakingQueueClient, []client.ExpiredStakingEvent{expiredEvent}) - time.Sleep(10 * time.Second) - - // Send the withdraw event before timelock expire event which would change the state to unbonded - withdrawEvent := client.WithdrawStakingEvent{ - EventType: client.WithdrawStakingEventType, - StakingTxHashHex: activeStakingEvent.StakingTxHashHex, - } - - sendTestMessage(testServer.Queues.V1QueueClient.WithdrawStakingQueueClient, []client.WithdrawStakingEvent{withdrawEvent}) - time.Sleep(2 * time.Second) - - // Check the DB after a while, now it shall be "withdrawn" state - results, err := testutils.InspectDbDocuments[v1model.DelegationDocument]( - testServer.Config, dbmodel.V1DelegationCollection, - ) - if err != nil { - t.Fatalf("Failed to inspect DB documents: %v", err) - } - assert.Equal(t, 1, len(results), "expected 1 document in the DB") - - // Check the data - assert.Equal(t, activeStakingEvent.StakingTxHashHex, results[0].StakingTxHashHex, "expected address to be the same") - assert.Equal(t, types.Withdrawn, results[0].State, "expected state to be unbonded") - - // Send again the withdraw event, it should be ignored - sendTestMessage(testServer.Queues.V1QueueClient.WithdrawStakingQueueClient, []client.WithdrawStakingEvent{withdrawEvent}) - time.Sleep(2 * time.Second) - - // Check the DB, nothing should be changed. - results, err = testutils.InspectDbDocuments[v1model.DelegationDocument]( - testServer.Config, dbmodel.V1DelegationCollection, - ) - if err != nil { - t.Fatalf("Failed to inspect DB documents: %v", err) - } - assert.Equal(t, 1, len(results), "expected 1 document in the DB") - assert.Equal(t, activeStakingEvent.StakingTxHashHex, results[0].StakingTxHashHex, "expected address to be the same") - assert.Equal(t, types.Withdrawn, results[0].State, "expected state to be unbonded") - // also checking the queue. Nothing should exist in the queue - count, err := inspectQueueMessageCount(t, testServer.Conn, client.WithdrawStakingQueueName) - if err != nil { - t.Fatalf("Failed to inspect queue: %v", err) - } - assert.Equal(t, 0, count, "expected no message in the queue") -} diff --git a/tests/mocks/mock_db_client.go b/tests/mocks/mock_db_client.go deleted file mode 100644 index b247612e..00000000 --- a/tests/mocks/mock_db_client.go +++ /dev/null @@ -1,192 +0,0 @@ -// Code generated by mockery v2.41.0. DO NOT EDIT. - -package mocks - -import ( - context "context" - - dbmodel "github.com/babylonlabs-io/staking-api-service/internal/shared/db/model" - - mock "github.com/stretchr/testify/mock" -) - -// DBClient is an autogenerated mock type for the DBClient type -type DBClient struct { - mock.Mock -} - -// DeleteUnprocessableMessage provides a mock function with given fields: ctx, Receipt -func (_m *DBClient) DeleteUnprocessableMessage(ctx context.Context, Receipt interface{}) error { - ret := _m.Called(ctx, Receipt) - - if len(ret) == 0 { - panic("no return value specified for DeleteUnprocessableMessage") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, interface{}) error); ok { - r0 = rf(ctx, Receipt) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// FindPkMappingsByNativeSegwitAddress provides a mock function with given fields: ctx, nativeSegwitAddresses -func (_m *DBClient) FindPkMappingsByNativeSegwitAddress(ctx context.Context, nativeSegwitAddresses []string) ([]*dbmodel.PkAddressMapping, error) { - ret := _m.Called(ctx, nativeSegwitAddresses) - - if len(ret) == 0 { - panic("no return value specified for FindPkMappingsByNativeSegwitAddress") - } - - var r0 []*dbmodel.PkAddressMapping - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []string) ([]*dbmodel.PkAddressMapping, error)); ok { - return rf(ctx, nativeSegwitAddresses) - } - if rf, ok := ret.Get(0).(func(context.Context, []string) []*dbmodel.PkAddressMapping); ok { - r0 = rf(ctx, nativeSegwitAddresses) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*dbmodel.PkAddressMapping) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, []string) error); ok { - r1 = rf(ctx, nativeSegwitAddresses) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FindPkMappingsByTaprootAddress provides a mock function with given fields: ctx, taprootAddresses -func (_m *DBClient) FindPkMappingsByTaprootAddress(ctx context.Context, taprootAddresses []string) ([]*dbmodel.PkAddressMapping, error) { - ret := _m.Called(ctx, taprootAddresses) - - if len(ret) == 0 { - panic("no return value specified for FindPkMappingsByTaprootAddress") - } - - var r0 []*dbmodel.PkAddressMapping - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []string) ([]*dbmodel.PkAddressMapping, error)); ok { - return rf(ctx, taprootAddresses) - } - if rf, ok := ret.Get(0).(func(context.Context, []string) []*dbmodel.PkAddressMapping); ok { - r0 = rf(ctx, taprootAddresses) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*dbmodel.PkAddressMapping) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, []string) error); ok { - r1 = rf(ctx, taprootAddresses) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FindUnprocessableMessages provides a mock function with given fields: ctx -func (_m *DBClient) FindUnprocessableMessages(ctx context.Context) ([]dbmodel.UnprocessableMessageDocument, error) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for FindUnprocessableMessages") - } - - var r0 []dbmodel.UnprocessableMessageDocument - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) ([]dbmodel.UnprocessableMessageDocument, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) []dbmodel.UnprocessableMessageDocument); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]dbmodel.UnprocessableMessageDocument) - } - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// InsertPkAddressMappings provides a mock function with given fields: ctx, stakerPkHex, taproot, nativeSigwitOdd, nativeSigwitEven -func (_m *DBClient) InsertPkAddressMappings(ctx context.Context, stakerPkHex string, taproot string, nativeSigwitOdd string, nativeSigwitEven string) error { - ret := _m.Called(ctx, stakerPkHex, taproot, nativeSigwitOdd, nativeSigwitEven) - - if len(ret) == 0 { - panic("no return value specified for InsertPkAddressMappings") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) error); ok { - r0 = rf(ctx, stakerPkHex, taproot, nativeSigwitOdd, nativeSigwitEven) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Ping provides a mock function with given fields: ctx -func (_m *DBClient) Ping(ctx context.Context) error { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for Ping") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// SaveUnprocessableMessage provides a mock function with given fields: ctx, messageBody, receipt -func (_m *DBClient) SaveUnprocessableMessage(ctx context.Context, messageBody string, receipt string) error { - ret := _m.Called(ctx, messageBody, receipt) - - if len(ret) == 0 { - panic("no return value specified for SaveUnprocessableMessage") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { - r0 = rf(ctx, messageBody, receipt) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// NewDBClient creates a new instance of DBClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewDBClient(t interface { - mock.TestingT - Cleanup(func()) -}) *DBClient { - mock := &DBClient{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/tests/mocks/mock_ordinal_client.go b/tests/mocks/mock_ordinal_client.go deleted file mode 100644 index 95dff743..00000000 --- a/tests/mocks/mock_ordinal_client.go +++ /dev/null @@ -1,121 +0,0 @@ -// Code generated by mockery v2.41.0. DO NOT EDIT. - -package mocks - -import ( - context "context" - http "net/http" - - mock "github.com/stretchr/testify/mock" - - ordinals "github.com/babylonlabs-io/staking-api-service/internal/shared/http/clients/ordinals" - - types "github.com/babylonlabs-io/staking-api-service/internal/shared/types" -) - -// OrdinalsClient is an autogenerated mock type for the OrdinalsClient type -type OrdinalsClient struct { - mock.Mock -} - -// FetchUTXOInfos provides a mock function with given fields: ctx, utxos -func (_m *OrdinalsClient) FetchUTXOInfos(ctx context.Context, utxos []types.UTXOIdentifier) ([]ordinals.OrdinalsOutputResponse, *types.Error) { - ret := _m.Called(ctx, utxos) - - if len(ret) == 0 { - panic("no return value specified for FetchUTXOInfos") - } - - var r0 []ordinals.OrdinalsOutputResponse - var r1 *types.Error - if rf, ok := ret.Get(0).(func(context.Context, []types.UTXOIdentifier) ([]ordinals.OrdinalsOutputResponse, *types.Error)); ok { - return rf(ctx, utxos) - } - if rf, ok := ret.Get(0).(func(context.Context, []types.UTXOIdentifier) []ordinals.OrdinalsOutputResponse); ok { - r0 = rf(ctx, utxos) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]ordinals.OrdinalsOutputResponse) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, []types.UTXOIdentifier) *types.Error); ok { - r1 = rf(ctx, utxos) - } else { - if ret.Get(1) != nil { - r1 = ret.Get(1).(*types.Error) - } - } - - return r0, r1 -} - -// GetBaseURL provides a mock function with given fields: -func (_m *OrdinalsClient) GetBaseURL() string { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetBaseURL") - } - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// GetDefaultRequestTimeout provides a mock function with given fields: -func (_m *OrdinalsClient) GetDefaultRequestTimeout() int { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetDefaultRequestTimeout") - } - - var r0 int - if rf, ok := ret.Get(0).(func() int); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(int) - } - - return r0 -} - -// GetHttpClient provides a mock function with given fields: -func (_m *OrdinalsClient) GetHttpClient() *http.Client { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetHttpClient") - } - - var r0 *http.Client - if rf, ok := ret.Get(0).(func() *http.Client); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*http.Client) - } - } - - return r0 -} - -// NewOrdinalsClient creates a new instance of OrdinalsClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewOrdinalsClient(t interface { - mock.TestingT - Cleanup(func()) -}) *OrdinalsClient { - mock := &OrdinalsClient{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/tests/mocks/mock_v1_db_client.go b/tests/mocks/mock_v1_db_client.go deleted file mode 100644 index 6cd0a26c..00000000 --- a/tests/mocks/mock_v1_db_client.go +++ /dev/null @@ -1,779 +0,0 @@ -// Code generated by mockery v2.41.0. DO NOT EDIT. - -package mocks - -import ( - context "context" - - db "github.com/babylonlabs-io/staking-api-service/internal/shared/db" - dbmodel "github.com/babylonlabs-io/staking-api-service/internal/shared/db/model" - - mock "github.com/stretchr/testify/mock" - - types "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - - v1dbclient "github.com/babylonlabs-io/staking-api-service/internal/v1/db/client" - - v1dbmodel "github.com/babylonlabs-io/staking-api-service/internal/v1/db/model" -) - -// V1DBClient is an autogenerated mock type for the V1DBClient type -type V1DBClient struct { - mock.Mock -} - -// CheckDelegationExistByStakerPk provides a mock function with given fields: ctx, address, extraFilter -func (_m *V1DBClient) CheckDelegationExistByStakerPk(ctx context.Context, address string, extraFilter *v1dbclient.DelegationFilter) (bool, error) { - ret := _m.Called(ctx, address, extraFilter) - - if len(ret) == 0 { - panic("no return value specified for CheckDelegationExistByStakerPk") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, *v1dbclient.DelegationFilter) (bool, error)); ok { - return rf(ctx, address, extraFilter) - } - if rf, ok := ret.Get(0).(func(context.Context, string, *v1dbclient.DelegationFilter) bool); ok { - r0 = rf(ctx, address, extraFilter) - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func(context.Context, string, *v1dbclient.DelegationFilter) error); ok { - r1 = rf(ctx, address, extraFilter) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DeleteUnprocessableMessage provides a mock function with given fields: ctx, Receipt -func (_m *V1DBClient) DeleteUnprocessableMessage(ctx context.Context, Receipt interface{}) error { - ret := _m.Called(ctx, Receipt) - - if len(ret) == 0 { - panic("no return value specified for DeleteUnprocessableMessage") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, interface{}) error); ok { - r0 = rf(ctx, Receipt) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// FindDelegationByTxHashHex provides a mock function with given fields: ctx, txHashHex -func (_m *V1DBClient) FindDelegationByTxHashHex(ctx context.Context, txHashHex string) (*v1dbmodel.DelegationDocument, error) { - ret := _m.Called(ctx, txHashHex) - - if len(ret) == 0 { - panic("no return value specified for FindDelegationByTxHashHex") - } - - var r0 *v1dbmodel.DelegationDocument - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (*v1dbmodel.DelegationDocument, error)); ok { - return rf(ctx, txHashHex) - } - if rf, ok := ret.Get(0).(func(context.Context, string) *v1dbmodel.DelegationDocument); ok { - r0 = rf(ctx, txHashHex) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*v1dbmodel.DelegationDocument) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, txHashHex) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FindDelegationsByStakerPk provides a mock function with given fields: ctx, stakerPk, extraFilter, paginationToken -func (_m *V1DBClient) FindDelegationsByStakerPk(ctx context.Context, stakerPk string, extraFilter *v1dbclient.DelegationFilter, paginationToken string) (*db.DbResultMap[v1dbmodel.DelegationDocument], error) { - ret := _m.Called(ctx, stakerPk, extraFilter, paginationToken) - - if len(ret) == 0 { - panic("no return value specified for FindDelegationsByStakerPk") - } - - var r0 *db.DbResultMap[v1dbmodel.DelegationDocument] - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, *v1dbclient.DelegationFilter, string) (*db.DbResultMap[v1dbmodel.DelegationDocument], error)); ok { - return rf(ctx, stakerPk, extraFilter, paginationToken) - } - if rf, ok := ret.Get(0).(func(context.Context, string, *v1dbclient.DelegationFilter, string) *db.DbResultMap[v1dbmodel.DelegationDocument]); ok { - r0 = rf(ctx, stakerPk, extraFilter, paginationToken) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*db.DbResultMap[v1dbmodel.DelegationDocument]) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string, *v1dbclient.DelegationFilter, string) error); ok { - r1 = rf(ctx, stakerPk, extraFilter, paginationToken) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FindFinalityProviderStats provides a mock function with given fields: ctx, paginationToken -func (_m *V1DBClient) FindFinalityProviderStats(ctx context.Context, paginationToken string) (*db.DbResultMap[*v1dbmodel.FinalityProviderStatsDocument], error) { - ret := _m.Called(ctx, paginationToken) - - if len(ret) == 0 { - panic("no return value specified for FindFinalityProviderStats") - } - - var r0 *db.DbResultMap[*v1dbmodel.FinalityProviderStatsDocument] - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (*db.DbResultMap[*v1dbmodel.FinalityProviderStatsDocument], error)); ok { - return rf(ctx, paginationToken) - } - if rf, ok := ret.Get(0).(func(context.Context, string) *db.DbResultMap[*v1dbmodel.FinalityProviderStatsDocument]); ok { - r0 = rf(ctx, paginationToken) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*db.DbResultMap[*v1dbmodel.FinalityProviderStatsDocument]) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, paginationToken) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FindFinalityProviderStatsByFinalityProviderPkHex provides a mock function with given fields: ctx, finalityProviderPkHex -func (_m *V1DBClient) FindFinalityProviderStatsByFinalityProviderPkHex(ctx context.Context, finalityProviderPkHex []string) ([]*v1dbmodel.FinalityProviderStatsDocument, error) { - ret := _m.Called(ctx, finalityProviderPkHex) - - if len(ret) == 0 { - panic("no return value specified for FindFinalityProviderStatsByFinalityProviderPkHex") - } - - var r0 []*v1dbmodel.FinalityProviderStatsDocument - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []string) ([]*v1dbmodel.FinalityProviderStatsDocument, error)); ok { - return rf(ctx, finalityProviderPkHex) - } - if rf, ok := ret.Get(0).(func(context.Context, []string) []*v1dbmodel.FinalityProviderStatsDocument); ok { - r0 = rf(ctx, finalityProviderPkHex) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*v1dbmodel.FinalityProviderStatsDocument) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, []string) error); ok { - r1 = rf(ctx, finalityProviderPkHex) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FindPkMappingsByNativeSegwitAddress provides a mock function with given fields: ctx, nativeSegwitAddresses -func (_m *V1DBClient) FindPkMappingsByNativeSegwitAddress(ctx context.Context, nativeSegwitAddresses []string) ([]*dbmodel.PkAddressMapping, error) { - ret := _m.Called(ctx, nativeSegwitAddresses) - - if len(ret) == 0 { - panic("no return value specified for FindPkMappingsByNativeSegwitAddress") - } - - var r0 []*dbmodel.PkAddressMapping - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []string) ([]*dbmodel.PkAddressMapping, error)); ok { - return rf(ctx, nativeSegwitAddresses) - } - if rf, ok := ret.Get(0).(func(context.Context, []string) []*dbmodel.PkAddressMapping); ok { - r0 = rf(ctx, nativeSegwitAddresses) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*dbmodel.PkAddressMapping) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, []string) error); ok { - r1 = rf(ctx, nativeSegwitAddresses) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FindPkMappingsByTaprootAddress provides a mock function with given fields: ctx, taprootAddresses -func (_m *V1DBClient) FindPkMappingsByTaprootAddress(ctx context.Context, taprootAddresses []string) ([]*dbmodel.PkAddressMapping, error) { - ret := _m.Called(ctx, taprootAddresses) - - if len(ret) == 0 { - panic("no return value specified for FindPkMappingsByTaprootAddress") - } - - var r0 []*dbmodel.PkAddressMapping - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []string) ([]*dbmodel.PkAddressMapping, error)); ok { - return rf(ctx, taprootAddresses) - } - if rf, ok := ret.Get(0).(func(context.Context, []string) []*dbmodel.PkAddressMapping); ok { - r0 = rf(ctx, taprootAddresses) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*dbmodel.PkAddressMapping) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, []string) error); ok { - r1 = rf(ctx, taprootAddresses) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FindTopStakersByTvl provides a mock function with given fields: ctx, paginationToken -func (_m *V1DBClient) FindTopStakersByTvl(ctx context.Context, paginationToken string) (*db.DbResultMap[*v1dbmodel.StakerStatsDocument], error) { - ret := _m.Called(ctx, paginationToken) - - if len(ret) == 0 { - panic("no return value specified for FindTopStakersByTvl") - } - - var r0 *db.DbResultMap[*v1dbmodel.StakerStatsDocument] - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (*db.DbResultMap[*v1dbmodel.StakerStatsDocument], error)); ok { - return rf(ctx, paginationToken) - } - if rf, ok := ret.Get(0).(func(context.Context, string) *db.DbResultMap[*v1dbmodel.StakerStatsDocument]); ok { - r0 = rf(ctx, paginationToken) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*db.DbResultMap[*v1dbmodel.StakerStatsDocument]) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, paginationToken) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FindUnprocessableMessages provides a mock function with given fields: ctx -func (_m *V1DBClient) FindUnprocessableMessages(ctx context.Context) ([]dbmodel.UnprocessableMessageDocument, error) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for FindUnprocessableMessages") - } - - var r0 []dbmodel.UnprocessableMessageDocument - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) ([]dbmodel.UnprocessableMessageDocument, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) []dbmodel.UnprocessableMessageDocument); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]dbmodel.UnprocessableMessageDocument) - } - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetLatestBtcInfo provides a mock function with given fields: ctx -func (_m *V1DBClient) GetLatestBtcInfo(ctx context.Context) (*v1dbmodel.BtcInfo, error) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for GetLatestBtcInfo") - } - - var r0 *v1dbmodel.BtcInfo - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (*v1dbmodel.BtcInfo, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) *v1dbmodel.BtcInfo); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*v1dbmodel.BtcInfo) - } - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetOrCreateStatsLock provides a mock function with given fields: ctx, stakingTxHashHex, state -func (_m *V1DBClient) GetOrCreateStatsLock(ctx context.Context, stakingTxHashHex string, state string) (*v1dbmodel.StatsLockDocument, error) { - ret := _m.Called(ctx, stakingTxHashHex, state) - - if len(ret) == 0 { - panic("no return value specified for GetOrCreateStatsLock") - } - - var r0 *v1dbmodel.StatsLockDocument - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) (*v1dbmodel.StatsLockDocument, error)); ok { - return rf(ctx, stakingTxHashHex, state) - } - if rf, ok := ret.Get(0).(func(context.Context, string, string) *v1dbmodel.StatsLockDocument); ok { - r0 = rf(ctx, stakingTxHashHex, state) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*v1dbmodel.StatsLockDocument) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { - r1 = rf(ctx, stakingTxHashHex, state) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetOverallStats provides a mock function with given fields: ctx -func (_m *V1DBClient) GetOverallStats(ctx context.Context) (*v1dbmodel.OverallStatsDocument, error) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for GetOverallStats") - } - - var r0 *v1dbmodel.OverallStatsDocument - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (*v1dbmodel.OverallStatsDocument, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) *v1dbmodel.OverallStatsDocument); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*v1dbmodel.OverallStatsDocument) - } - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetStakerStats provides a mock function with given fields: ctx, stakerPkHex -func (_m *V1DBClient) GetStakerStats(ctx context.Context, stakerPkHex string) (*v1dbmodel.StakerStatsDocument, error) { - ret := _m.Called(ctx, stakerPkHex) - - if len(ret) == 0 { - panic("no return value specified for GetStakerStats") - } - - var r0 *v1dbmodel.StakerStatsDocument - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (*v1dbmodel.StakerStatsDocument, error)); ok { - return rf(ctx, stakerPkHex) - } - if rf, ok := ret.Get(0).(func(context.Context, string) *v1dbmodel.StakerStatsDocument); ok { - r0 = rf(ctx, stakerPkHex) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*v1dbmodel.StakerStatsDocument) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, stakerPkHex) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// IncrementFinalityProviderStats provides a mock function with given fields: ctx, stakingTxHashHex, fpPkHex, amount -func (_m *V1DBClient) IncrementFinalityProviderStats(ctx context.Context, stakingTxHashHex string, fpPkHex string, amount uint64) error { - ret := _m.Called(ctx, stakingTxHashHex, fpPkHex, amount) - - if len(ret) == 0 { - panic("no return value specified for IncrementFinalityProviderStats") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, uint64) error); ok { - r0 = rf(ctx, stakingTxHashHex, fpPkHex, amount) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// IncrementOverallStats provides a mock function with given fields: ctx, stakingTxHashHex, stakerPkHex, amount -func (_m *V1DBClient) IncrementOverallStats(ctx context.Context, stakingTxHashHex string, stakerPkHex string, amount uint64) error { - ret := _m.Called(ctx, stakingTxHashHex, stakerPkHex, amount) - - if len(ret) == 0 { - panic("no return value specified for IncrementOverallStats") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, uint64) error); ok { - r0 = rf(ctx, stakingTxHashHex, stakerPkHex, amount) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// IncrementStakerStats provides a mock function with given fields: ctx, stakingTxHashHex, stakerPkHex, amount -func (_m *V1DBClient) IncrementStakerStats(ctx context.Context, stakingTxHashHex string, stakerPkHex string, amount uint64) error { - ret := _m.Called(ctx, stakingTxHashHex, stakerPkHex, amount) - - if len(ret) == 0 { - panic("no return value specified for IncrementStakerStats") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, uint64) error); ok { - r0 = rf(ctx, stakingTxHashHex, stakerPkHex, amount) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// InsertPkAddressMappings provides a mock function with given fields: ctx, stakerPkHex, taproot, nativeSigwitOdd, nativeSigwitEven -func (_m *V1DBClient) InsertPkAddressMappings(ctx context.Context, stakerPkHex string, taproot string, nativeSigwitOdd string, nativeSigwitEven string) error { - ret := _m.Called(ctx, stakerPkHex, taproot, nativeSigwitOdd, nativeSigwitEven) - - if len(ret) == 0 { - panic("no return value specified for InsertPkAddressMappings") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) error); ok { - r0 = rf(ctx, stakerPkHex, taproot, nativeSigwitOdd, nativeSigwitEven) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Ping provides a mock function with given fields: ctx -func (_m *V1DBClient) Ping(ctx context.Context) error { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for Ping") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// SaveActiveStakingDelegation provides a mock function with given fields: ctx, stakingTxHashHex, stakerPkHex, fpPkHex, stakingTxHex, amount, startHeight, timelock, outputIndex, startTimestamp, isOverflow -func (_m *V1DBClient) SaveActiveStakingDelegation(ctx context.Context, stakingTxHashHex string, stakerPkHex string, fpPkHex string, stakingTxHex string, amount uint64, startHeight uint64, timelock uint64, outputIndex uint64, startTimestamp int64, isOverflow bool) error { - ret := _m.Called(ctx, stakingTxHashHex, stakerPkHex, fpPkHex, stakingTxHex, amount, startHeight, timelock, outputIndex, startTimestamp, isOverflow) - - if len(ret) == 0 { - panic("no return value specified for SaveActiveStakingDelegation") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, uint64, uint64, uint64, uint64, int64, bool) error); ok { - r0 = rf(ctx, stakingTxHashHex, stakerPkHex, fpPkHex, stakingTxHex, amount, startHeight, timelock, outputIndex, startTimestamp, isOverflow) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// SaveTimeLockExpireCheck provides a mock function with given fields: ctx, stakingTxHashHex, expireHeight, txType -func (_m *V1DBClient) SaveTimeLockExpireCheck(ctx context.Context, stakingTxHashHex string, expireHeight uint64, txType string) error { - ret := _m.Called(ctx, stakingTxHashHex, expireHeight, txType) - - if len(ret) == 0 { - panic("no return value specified for SaveTimeLockExpireCheck") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, uint64, string) error); ok { - r0 = rf(ctx, stakingTxHashHex, expireHeight, txType) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// SaveUnbondingTx provides a mock function with given fields: ctx, stakingTxHashHex, unbondingTxHashHex, txHex, signatureHex -func (_m *V1DBClient) SaveUnbondingTx(ctx context.Context, stakingTxHashHex string, unbondingTxHashHex string, txHex string, signatureHex string) error { - ret := _m.Called(ctx, stakingTxHashHex, unbondingTxHashHex, txHex, signatureHex) - - if len(ret) == 0 { - panic("no return value specified for SaveUnbondingTx") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) error); ok { - r0 = rf(ctx, stakingTxHashHex, unbondingTxHashHex, txHex, signatureHex) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// SaveUnprocessableMessage provides a mock function with given fields: ctx, messageBody, receipt -func (_m *V1DBClient) SaveUnprocessableMessage(ctx context.Context, messageBody string, receipt string) error { - ret := _m.Called(ctx, messageBody, receipt) - - if len(ret) == 0 { - panic("no return value specified for SaveUnprocessableMessage") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { - r0 = rf(ctx, messageBody, receipt) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// ScanDelegationsPaginated provides a mock function with given fields: ctx, paginationToken -func (_m *V1DBClient) ScanDelegationsPaginated(ctx context.Context, paginationToken string) (*db.DbResultMap[v1dbmodel.DelegationDocument], error) { - ret := _m.Called(ctx, paginationToken) - - if len(ret) == 0 { - panic("no return value specified for ScanDelegationsPaginated") - } - - var r0 *db.DbResultMap[v1dbmodel.DelegationDocument] - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (*db.DbResultMap[v1dbmodel.DelegationDocument], error)); ok { - return rf(ctx, paginationToken) - } - if rf, ok := ret.Get(0).(func(context.Context, string) *db.DbResultMap[v1dbmodel.DelegationDocument]); ok { - r0 = rf(ctx, paginationToken) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*db.DbResultMap[v1dbmodel.DelegationDocument]) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, paginationToken) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SubtractFinalityProviderStats provides a mock function with given fields: ctx, stakingTxHashHex, fpPkHex, amount -func (_m *V1DBClient) SubtractFinalityProviderStats(ctx context.Context, stakingTxHashHex string, fpPkHex string, amount uint64) error { - ret := _m.Called(ctx, stakingTxHashHex, fpPkHex, amount) - - if len(ret) == 0 { - panic("no return value specified for SubtractFinalityProviderStats") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, uint64) error); ok { - r0 = rf(ctx, stakingTxHashHex, fpPkHex, amount) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// SubtractOverallStats provides a mock function with given fields: ctx, stakingTxHashHex, stakerPkHex, amount -func (_m *V1DBClient) SubtractOverallStats(ctx context.Context, stakingTxHashHex string, stakerPkHex string, amount uint64) error { - ret := _m.Called(ctx, stakingTxHashHex, stakerPkHex, amount) - - if len(ret) == 0 { - panic("no return value specified for SubtractOverallStats") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, uint64) error); ok { - r0 = rf(ctx, stakingTxHashHex, stakerPkHex, amount) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// SubtractStakerStats provides a mock function with given fields: ctx, stakingTxHashHex, stakerPkHex, amount -func (_m *V1DBClient) SubtractStakerStats(ctx context.Context, stakingTxHashHex string, stakerPkHex string, amount uint64) error { - ret := _m.Called(ctx, stakingTxHashHex, stakerPkHex, amount) - - if len(ret) == 0 { - panic("no return value specified for SubtractStakerStats") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, uint64) error); ok { - r0 = rf(ctx, stakingTxHashHex, stakerPkHex, amount) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// TransitionToTransitionedState provides a mock function with given fields: ctx, stakingTxHashHex -func (_m *V1DBClient) TransitionToTransitionedState(ctx context.Context, stakingTxHashHex string) error { - ret := _m.Called(ctx, stakingTxHashHex) - - if len(ret) == 0 { - panic("no return value specified for TransitionToTransitionedState") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { - r0 = rf(ctx, stakingTxHashHex) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// TransitionToUnbondedState provides a mock function with given fields: ctx, stakingTxHashHex, eligiblePreviousState -func (_m *V1DBClient) TransitionToUnbondedState(ctx context.Context, stakingTxHashHex string, eligiblePreviousState []types.DelegationState) error { - ret := _m.Called(ctx, stakingTxHashHex, eligiblePreviousState) - - if len(ret) == 0 { - panic("no return value specified for TransitionToUnbondedState") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, []types.DelegationState) error); ok { - r0 = rf(ctx, stakingTxHashHex, eligiblePreviousState) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// TransitionToUnbondingState provides a mock function with given fields: ctx, txHashHex, startHeight, timelock, outputIndex, txHex, startTimestamp -func (_m *V1DBClient) TransitionToUnbondingState(ctx context.Context, txHashHex string, startHeight uint64, timelock uint64, outputIndex uint64, txHex string, startTimestamp int64) error { - ret := _m.Called(ctx, txHashHex, startHeight, timelock, outputIndex, txHex, startTimestamp) - - if len(ret) == 0 { - panic("no return value specified for TransitionToUnbondingState") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, uint64, uint64, uint64, string, int64) error); ok { - r0 = rf(ctx, txHashHex, startHeight, timelock, outputIndex, txHex, startTimestamp) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// TransitionToWithdrawnState provides a mock function with given fields: ctx, txHashHex -func (_m *V1DBClient) TransitionToWithdrawnState(ctx context.Context, txHashHex string) error { - ret := _m.Called(ctx, txHashHex) - - if len(ret) == 0 { - panic("no return value specified for TransitionToWithdrawnState") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { - r0 = rf(ctx, txHashHex) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// UpsertLatestBtcInfo provides a mock function with given fields: ctx, height, confirmedTvl, unconfirmedTvl -func (_m *V1DBClient) UpsertLatestBtcInfo(ctx context.Context, height uint64, confirmedTvl uint64, unconfirmedTvl uint64) error { - ret := _m.Called(ctx, height, confirmedTvl, unconfirmedTvl) - - if len(ret) == 0 { - panic("no return value specified for UpsertLatestBtcInfo") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64, uint64) error); ok { - r0 = rf(ctx, height, confirmedTvl, unconfirmedTvl) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// NewV1DBClient creates a new instance of V1DBClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewV1DBClient(t interface { - mock.TestingT - Cleanup(func()) -}) *V1DBClient { - mock := &V1DBClient{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/tests/mocks/mock_v2_db_client.go b/tests/mocks/mock_v2_db_client.go deleted file mode 100644 index 27929f3f..00000000 --- a/tests/mocks/mock_v2_db_client.go +++ /dev/null @@ -1,355 +0,0 @@ -// Code generated by mockery v2.41.0. DO NOT EDIT. - -package mocks - -import ( - context "context" - - dbmodel "github.com/babylonlabs-io/staking-api-service/internal/shared/db/model" - mock "github.com/stretchr/testify/mock" - - v2dbmodel "github.com/babylonlabs-io/staking-api-service/internal/v2/db/model" -) - -// V2DBClient is an autogenerated mock type for the V2DBClient type -type V2DBClient struct { - mock.Mock -} - -// DeleteUnprocessableMessage provides a mock function with given fields: ctx, Receipt -func (_m *V2DBClient) DeleteUnprocessableMessage(ctx context.Context, Receipt interface{}) error { - ret := _m.Called(ctx, Receipt) - - if len(ret) == 0 { - panic("no return value specified for DeleteUnprocessableMessage") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, interface{}) error); ok { - r0 = rf(ctx, Receipt) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// FindPkMappingsByNativeSegwitAddress provides a mock function with given fields: ctx, nativeSegwitAddresses -func (_m *V2DBClient) FindPkMappingsByNativeSegwitAddress(ctx context.Context, nativeSegwitAddresses []string) ([]*dbmodel.PkAddressMapping, error) { - ret := _m.Called(ctx, nativeSegwitAddresses) - - if len(ret) == 0 { - panic("no return value specified for FindPkMappingsByNativeSegwitAddress") - } - - var r0 []*dbmodel.PkAddressMapping - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []string) ([]*dbmodel.PkAddressMapping, error)); ok { - return rf(ctx, nativeSegwitAddresses) - } - if rf, ok := ret.Get(0).(func(context.Context, []string) []*dbmodel.PkAddressMapping); ok { - r0 = rf(ctx, nativeSegwitAddresses) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*dbmodel.PkAddressMapping) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, []string) error); ok { - r1 = rf(ctx, nativeSegwitAddresses) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FindPkMappingsByTaprootAddress provides a mock function with given fields: ctx, taprootAddresses -func (_m *V2DBClient) FindPkMappingsByTaprootAddress(ctx context.Context, taprootAddresses []string) ([]*dbmodel.PkAddressMapping, error) { - ret := _m.Called(ctx, taprootAddresses) - - if len(ret) == 0 { - panic("no return value specified for FindPkMappingsByTaprootAddress") - } - - var r0 []*dbmodel.PkAddressMapping - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []string) ([]*dbmodel.PkAddressMapping, error)); ok { - return rf(ctx, taprootAddresses) - } - if rf, ok := ret.Get(0).(func(context.Context, []string) []*dbmodel.PkAddressMapping); ok { - r0 = rf(ctx, taprootAddresses) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*dbmodel.PkAddressMapping) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, []string) error); ok { - r1 = rf(ctx, taprootAddresses) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FindUnprocessableMessages provides a mock function with given fields: ctx -func (_m *V2DBClient) FindUnprocessableMessages(ctx context.Context) ([]dbmodel.UnprocessableMessageDocument, error) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for FindUnprocessableMessages") - } - - var r0 []dbmodel.UnprocessableMessageDocument - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) ([]dbmodel.UnprocessableMessageDocument, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) []dbmodel.UnprocessableMessageDocument); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]dbmodel.UnprocessableMessageDocument) - } - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetOrCreateStatsLock provides a mock function with given fields: ctx, stakingTxHashHex, state -func (_m *V2DBClient) GetOrCreateStatsLock(ctx context.Context, stakingTxHashHex string, state string) (*v2dbmodel.V2StatsLockDocument, error) { - ret := _m.Called(ctx, stakingTxHashHex, state) - - if len(ret) == 0 { - panic("no return value specified for GetOrCreateStatsLock") - } - - var r0 *v2dbmodel.V2StatsLockDocument - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) (*v2dbmodel.V2StatsLockDocument, error)); ok { - return rf(ctx, stakingTxHashHex, state) - } - if rf, ok := ret.Get(0).(func(context.Context, string, string) *v2dbmodel.V2StatsLockDocument); ok { - r0 = rf(ctx, stakingTxHashHex, state) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*v2dbmodel.V2StatsLockDocument) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { - r1 = rf(ctx, stakingTxHashHex, state) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetOverallStats provides a mock function with given fields: ctx -func (_m *V2DBClient) GetOverallStats(ctx context.Context) (*v2dbmodel.V2OverallStatsDocument, error) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for GetOverallStats") - } - - var r0 *v2dbmodel.V2OverallStatsDocument - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (*v2dbmodel.V2OverallStatsDocument, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) *v2dbmodel.V2OverallStatsDocument); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*v2dbmodel.V2OverallStatsDocument) - } - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetStakerStats provides a mock function with given fields: ctx, stakerPKHex -func (_m *V2DBClient) GetStakerStats(ctx context.Context, stakerPKHex string) (*v2dbmodel.V2StakerStatsDocument, error) { - ret := _m.Called(ctx, stakerPKHex) - - if len(ret) == 0 { - panic("no return value specified for GetStakerStats") - } - - var r0 *v2dbmodel.V2StakerStatsDocument - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (*v2dbmodel.V2StakerStatsDocument, error)); ok { - return rf(ctx, stakerPKHex) - } - if rf, ok := ret.Get(0).(func(context.Context, string) *v2dbmodel.V2StakerStatsDocument); ok { - r0 = rf(ctx, stakerPKHex) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*v2dbmodel.V2StakerStatsDocument) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, stakerPKHex) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// IncrementOverallStats provides a mock function with given fields: ctx, stakingTxHashHex, stakerPkHex, amount -func (_m *V2DBClient) IncrementOverallStats(ctx context.Context, stakingTxHashHex string, stakerPkHex string, amount uint64) error { - ret := _m.Called(ctx, stakingTxHashHex, stakerPkHex, amount) - - if len(ret) == 0 { - panic("no return value specified for IncrementOverallStats") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, uint64) error); ok { - r0 = rf(ctx, stakingTxHashHex, stakerPkHex, amount) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// IncrementStakerStats provides a mock function with given fields: ctx, stakingTxHashHex, stakerPkHex, amount -func (_m *V2DBClient) IncrementStakerStats(ctx context.Context, stakingTxHashHex string, stakerPkHex string, amount uint64) error { - ret := _m.Called(ctx, stakingTxHashHex, stakerPkHex, amount) - - if len(ret) == 0 { - panic("no return value specified for IncrementStakerStats") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, uint64) error); ok { - r0 = rf(ctx, stakingTxHashHex, stakerPkHex, amount) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// InsertPkAddressMappings provides a mock function with given fields: ctx, stakerPkHex, taproot, nativeSigwitOdd, nativeSigwitEven -func (_m *V2DBClient) InsertPkAddressMappings(ctx context.Context, stakerPkHex string, taproot string, nativeSigwitOdd string, nativeSigwitEven string) error { - ret := _m.Called(ctx, stakerPkHex, taproot, nativeSigwitOdd, nativeSigwitEven) - - if len(ret) == 0 { - panic("no return value specified for InsertPkAddressMappings") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) error); ok { - r0 = rf(ctx, stakerPkHex, taproot, nativeSigwitOdd, nativeSigwitEven) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Ping provides a mock function with given fields: ctx -func (_m *V2DBClient) Ping(ctx context.Context) error { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for Ping") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// SaveUnprocessableMessage provides a mock function with given fields: ctx, messageBody, receipt -func (_m *V2DBClient) SaveUnprocessableMessage(ctx context.Context, messageBody string, receipt string) error { - ret := _m.Called(ctx, messageBody, receipt) - - if len(ret) == 0 { - panic("no return value specified for SaveUnprocessableMessage") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { - r0 = rf(ctx, messageBody, receipt) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// SubtractOverallStats provides a mock function with given fields: ctx, stakingTxHashHex, stakerPkHex, amount -func (_m *V2DBClient) SubtractOverallStats(ctx context.Context, stakingTxHashHex string, stakerPkHex string, amount uint64) error { - ret := _m.Called(ctx, stakingTxHashHex, stakerPkHex, amount) - - if len(ret) == 0 { - panic("no return value specified for SubtractOverallStats") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, uint64) error); ok { - r0 = rf(ctx, stakingTxHashHex, stakerPkHex, amount) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// SubtractStakerStats provides a mock function with given fields: ctx, stakingTxHashHex, stakerPkHex, amount -func (_m *V2DBClient) SubtractStakerStats(ctx context.Context, stakingTxHashHex string, stakerPkHex string, amount uint64) error { - ret := _m.Called(ctx, stakingTxHashHex, stakerPkHex, amount) - - if len(ret) == 0 { - panic("no return value specified for SubtractStakerStats") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, uint64) error); ok { - r0 = rf(ctx, stakingTxHashHex, stakerPkHex, amount) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// NewV2DBClient creates a new instance of V2DBClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewV2DBClient(t interface { - mock.TestingT - Cleanup(func()) -}) *V2DBClient { - mock := &V2DBClient{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/tests/scripts_test/pubkey_address_backfil_test.go b/tests/scripts_test/pubkey_address_backfil_test.go deleted file mode 100644 index 112ba20a..00000000 --- a/tests/scripts_test/pubkey_address_backfil_test.go +++ /dev/null @@ -1,100 +0,0 @@ -package scripts_test - -import ( - "context" - "math/rand" - "testing" - "time" - - "github.com/babylonlabs-io/staking-api-service/cmd/staking-api-service/scripts" - "github.com/babylonlabs-io/staking-api-service/internal/shared/config" - dbmodel "github.com/babylonlabs-io/staking-api-service/internal/shared/db/model" - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - "github.com/babylonlabs-io/staking-api-service/internal/shared/utils" - v1model "github.com/babylonlabs-io/staking-api-service/internal/v1/db/model" - "github.com/babylonlabs-io/staking-api-service/tests/testutils" - "github.com/stretchr/testify/assert" -) - -func createNewDelegationDocuments(cfg *config.Config, numOfDocs int) []*v1model.DelegationDocument { - r := rand.New(rand.NewSource(time.Now().UnixNano())) - var delegationDocuments []*v1model.DelegationDocument - opts := &testutils.TestActiveEventGeneratorOpts{ - NumOfEvents: 1, // a single event to make sure it's always unique - } - for i := 0; i < numOfDocs; i++ { - activeStakingEvenets := testutils.GenerateRandomActiveStakingEvents(r, opts) - for _, event := range activeStakingEvenets { - doc := &v1model.DelegationDocument{ - StakingTxHashHex: event.StakingTxHashHex, - StakerPkHex: event.StakerPkHex, - FinalityProviderPkHex: event.FinalityProviderPkHex, - StakingValue: event.StakingValue, - State: types.Active, - StakingTx: &v1model.TimelockTransaction{ - TxHex: event.StakingTxHex, - OutputIndex: event.StakingOutputIndex, - StartTimestamp: event.StakingStartTimestamp, - StartHeight: event.StakingStartHeight, - TimeLock: event.StakingStartHeight, - }, - IsOverflow: event.IsOverflow, - } - delegationDocuments = append(delegationDocuments, doc) - } - } - return delegationDocuments -} - -func TestBackfillAddressesBasedOnPubKeys(t *testing.T) { - cfg := testutils.LoadTestConfig() - ctx := context.Background() - // Clean the database - testutils.SetupTestDB(*cfg) - // inject some data - docs := createNewDelegationDocuments(cfg, int(cfg.StakingDb.MaxPaginationLimit)+1) - for _, doc := range docs { - testutils.InjectDbDocument( - cfg, dbmodel.V1DelegationCollection, doc, - ) - } - - // sleep for a while to let the data be inserted - time.Sleep(5 * time.Second) - err := scripts.BackfillPubkeyAddressesMappings(ctx, cfg) - assert.Nil(t, err) - // check if the data is inserted - results, err := testutils.InspectDbDocuments[dbmodel.PkAddressMapping]( - cfg, dbmodel.PkAddressMappingsCollection, - ) - assert.Nil(t, err) - // find the num of unique staker pks from the docs - stakerPks := make(map[string]struct{}) - for _, doc := range docs { - stakerPks[doc.StakerPkHex] = struct{}{} - } - // check if the number of unique staker pks is equal to the number of results - assert.Equal(t, len(stakerPks), len(results)) - // check if the data is inserted correctly - for _, result := range results { - _, ok := stakerPks[result.PkHex] - assert.True(t, ok) - addresses, err := utils.DeriveAddressesFromNoCoordPk( - result.PkHex, cfg.Server.BTCNetParam, - ) - assert.Nil(t, err) - assert.Equal(t, result.Taproot, addresses.Taproot) - assert.Equal(t, result.NativeSegwitOdd, addresses.NativeSegwitOdd) - assert.Equal(t, result.NativeSegwitEven, addresses.NativeSegwitEven) - } - - // Run the script again, the result should be the same as it does not - // change the existing data - err = scripts.BackfillPubkeyAddressesMappings(ctx, cfg) - assert.Nil(t, err) - results2, err := testutils.InspectDbDocuments[dbmodel.PkAddressMapping]( - cfg, dbmodel.PkAddressMappingsCollection, - ) - assert.Nil(t, err) - assert.Equal(t, len(results), len(results2)) -} diff --git a/tests/testutils/database.go b/tests/testutils/database.go deleted file mode 100644 index 010572cf..00000000 --- a/tests/testutils/database.go +++ /dev/null @@ -1,162 +0,0 @@ -package testutils - -import ( - "context" - "log" - - indexerdbclient "github.com/babylonlabs-io/staking-api-service/internal/indexer/db/client" - "github.com/babylonlabs-io/staking-api-service/internal/shared/config" - dbclient "github.com/babylonlabs-io/staking-api-service/internal/shared/db/client" - dbclients "github.com/babylonlabs-io/staking-api-service/internal/shared/db/clients" - dbmodel "github.com/babylonlabs-io/staking-api-service/internal/shared/db/model" - v1dbclient "github.com/babylonlabs-io/staking-api-service/internal/v1/db/client" - v2dbclient "github.com/babylonlabs-io/staking-api-service/internal/v2/db/client" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" -) - -var setUpDbIndex = false - -func DirectDbConnection(cfg *config.Config) (*dbclients.DbClients, string) { - stakingMongoClient, err := mongo.Connect( - context.TODO(), options.Client().ApplyURI(cfg.StakingDb.Address), - ) - if err != nil { - log.Fatal(err) - } - dbClient, err := dbclient.New(context.TODO(), stakingMongoClient, cfg.StakingDb) - if err != nil { - log.Fatal(err) - } - v1dbClient, err := v1dbclient.New(context.TODO(), stakingMongoClient, cfg.StakingDb) - if err != nil { - log.Fatal(err) - } - v2dbClient, err := v2dbclient.New(context.TODO(), stakingMongoClient, cfg.StakingDb) - if err != nil { - log.Fatal(err) - } - - // IndexerDBClient - indexerMongoClient, err := mongo.Connect( - context.TODO(), options.Client().ApplyURI(cfg.IndexerDb.Address), - ) - if err != nil { - log.Fatal(err) - } - - indexerdbClient, err := indexerdbclient.New(context.TODO(), indexerMongoClient, cfg.IndexerDb) - if err != nil { - log.Fatal(err) - } - return &dbclients.DbClients{ - StakingMongoClient: stakingMongoClient, - IndexerMongoClient: indexerMongoClient, - SharedDBClient: dbClient, - V1DBClient: v1dbClient, - V2DBClient: v2dbClient, - IndexerDBClient: indexerdbClient, - }, cfg.StakingDb.DbName -} - -// SetupTestDB connects to MongoDB and purges all collections. -func SetupTestDB(cfg config.Config) *dbclients.DbClients { - // Connect to MongoDB - dbClients, dbName := DirectDbConnection(&cfg) - // Purge all collections in the test database - // Setup the db index only once for all tests - if !setUpDbIndex { - err := dbmodel.Setup(context.Background(), &cfg) - if err != nil { - log.Fatal("Failed to setup database:", err) - } - setUpDbIndex = true - } - if err := PurgeAllCollections(context.TODO(), dbClients.StakingMongoClient, dbName); err != nil { - log.Fatal("Failed to purge database:", err) - } - - return dbClients -} - -// InjectDbDocument inserts a single document into the specified collection. -func InjectDbDocument[T any]( - cfg *config.Config, collectionName string, doc T, -) { - connection, dbName := DirectDbConnection(cfg) - defer connection.StakingMongoClient.Disconnect(context.Background()) - collection := connection.StakingMongoClient.Database(dbName). - Collection(collectionName) - - _, err := collection.InsertOne(context.Background(), doc) - if err != nil { - log.Fatalf("Failed to insert document: %v", err) - } -} - -// Inspect the items in the real database -func InspectDbDocuments[T any]( - cfg *config.Config, collectionName string, -) ([]T, error) { - connection, dbName := DirectDbConnection(cfg) - collection := connection.StakingMongoClient.Database(dbName). - Collection(collectionName) - - cursor, err := collection.Find(context.Background(), bson.D{}) - if err != nil { - return nil, err - } - defer cursor.Close(context.Background()) - defer connection.StakingMongoClient.Disconnect(context.Background()) - - var results []T - for cursor.Next(context.Background()) { - var result T - err := cursor.Decode(&result) - if err != nil { - return nil, err - } - results = append(results, result) - } - - return results, nil -} - -// UpdateDbDocument updates a document in the specified collection based on the -// provided filter and update data. -func UpdateDbDocument( - connection *mongo.Client, cfg *config.Config, collectionName string, - filter bson.M, update bson.M, -) error { - collection := connection.Database(cfg.StakingDb.DbName). - Collection(collectionName) - - // Perform the update operation - _, err := collection.UpdateOne( - context.Background(), filter, bson.M{"$set": update}, - ) - if err != nil { - return err - } - - return nil -} - -// PurgeAllCollections drops all collections in the specified database. -func PurgeAllCollections(ctx context.Context, client *mongo.Client, databaseName string) error { - database := client.Database(databaseName) - collections, err := database.ListCollectionNames(ctx, bson.D{{}}) - if err != nil { - return err - } - - for _, collection := range collections { - // Use DeleteMany with an empty filter to delete all documents - _, err := database.Collection(collection).DeleteMany(ctx, bson.D{{}}) - if err != nil { - return err - } - } - return nil -} diff --git a/tests/testutils/datagen.go b/tests/testutils/datagen.go deleted file mode 100644 index cf9d20fb..00000000 --- a/tests/testutils/datagen.go +++ /dev/null @@ -1,291 +0,0 @@ -package testutils - -import ( - "bytes" - "encoding/hex" - "fmt" - "log" - "math/rand" - "time" - - bbndatagen "github.com/babylonlabs-io/babylon/testutil/datagen" - indexertypes "github.com/babylonlabs-io/staking-api-service/internal/indexer/types" - "github.com/babylonlabs-io/staking-api-service/internal/shared/config" - "github.com/babylonlabs-io/staking-api-service/internal/shared/types" - "github.com/babylonlabs-io/staking-queue-client/client" - "github.com/btcsuite/btcd/btcec/v2" - "github.com/btcsuite/btcd/btcec/v2/schnorr" - "github.com/btcsuite/btcd/chaincfg/chainhash" - "github.com/btcsuite/btcd/wire" -) - -const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - -type TestActiveEventGeneratorOpts struct { - NumOfEvents int - FinalityProviders []string - Stakers []string - EnforceNotOverflow bool - BeforeTimestamp int64 - AfterTimestamp int64 -} - -func LoadTestConfig() *config.Config { - cfg, err := config.New("../config/config-test.yml") - if err != nil { - log.Fatalf("Failed to load test config: %v", err) - } - return cfg -} - -func RandomPk() (string, error) { - fpPirvKey, err := btcec.NewPrivateKey() - if err != nil { - return "", err - } - fpPk := fpPirvKey.PubKey() - return hex.EncodeToString(schnorr.SerializePubKey(fpPk)), nil -} - -func GeneratePks(numOfKeys int) []string { - var pks []string - for i := 0; i < numOfKeys; i++ { - k, err := RandomPk() - if err != nil { - log.Fatalf("Failed to generate random pk: %v", err) - } - pks = append(pks, k) - } - return pks -} - -// RandomPostiveFloat64 generates a random float64 value greater than 0. -func RandomPostiveFloat64(r *rand.Rand) float64 { - for { - f := r.Float64() // Generate a random float64 - if f > 0 { - return f - } - // If f is 0 (extremely rare), regenerate - } -} - -// RandomPositiveInt generates a random positive integer from 1 to max. -func RandomPositiveInt(r *rand.Rand, max int) int { - // Generate a random number from 1 to max (inclusive) - return r.Intn(max) + 1 -} - -// RandomString generates a random alphanumeric string of length n. -func RandomString(r *rand.Rand, n int) string { - result := make([]byte, n) - letterLen := len(letters) - for i := range result { - num := r.Int() % letterLen - result[i] = letters[num] - } - return string(result) -} - -// RandomAmount generates a random BTC amount from 0.1 to 10000 -// the returned value is in satoshis -func RandomAmount(r *rand.Rand) int64 { - // Generate a random value range from 0.1 to 10000 BTC - randomBTC := r.Float64()*(9999.9-0.1) + 0.1 - // convert to satoshi - return int64(randomBTC*1e8) + 1 -} - -// GenerateRandomTx generates a random transaction with random values for each field. -func GenerateRandomTx( - r *rand.Rand, - options *struct{ DisableRbf bool }, -) (*wire.MsgTx, string, error) { - sequence := r.Uint32() - if options != nil && options.DisableRbf { - sequence = wire.MaxTxInSequenceNum - } - tx := &wire.MsgTx{ - Version: 1, - TxIn: []*wire.TxIn{ - { - PreviousOutPoint: wire.OutPoint{ - Hash: chainhash.HashH(bbndatagen.GenRandomByteArray(r, 10)), - Index: r.Uint32(), - }, - SignatureScript: []byte{}, - Sequence: sequence, - }, - }, - TxOut: []*wire.TxOut{ - { - Value: int64(r.Int31()), - PkScript: bbndatagen.GenRandomByteArray(r, 80), - }, - }, - LockTime: 0, - } - var buf bytes.Buffer - if err := tx.Serialize(&buf); err != nil { - return nil, "", err - } - txHex := hex.EncodeToString(buf.Bytes()) - - return tx, txHex, nil -} - -// GenerateRandomTxWithOutput generates a random transaction with random values -// for each field. -func RandomBytes(r *rand.Rand, n uint64) ([]byte, string) { - randomBytes := bbndatagen.GenRandomByteArray(r, n) - return randomBytes, hex.EncodeToString(randomBytes) -} - -// GenerateRandomTimestamp generates a random timestamp before the specified timestamp. -// If beforeTimestamp is 0, then the current time is used. -func GenerateRandomTimestamp(afterTimestamp, beforeTimestamp int64) int64 { - timeNow := time.Now().Unix() - if beforeTimestamp == 0 && afterTimestamp == 0 { - return timeNow - } - if beforeTimestamp == 0 { - return afterTimestamp + rand.Int63n(timeNow-afterTimestamp) - } else if afterTimestamp == 0 { - // Generate a reasonable timestamp between 1 second to 6 months in the past - sixMonthsInSeconds := int64(6 * 30 * 24 * 60 * 60) - return beforeTimestamp - rand.Int63n(sixMonthsInSeconds) - } - return afterTimestamp + rand.Int63n(beforeTimestamp-afterTimestamp) -} - -// GenerateRandomFinalityProviderDetail generates a random number of finality providers -func GenerateRandomFinalityProviderDetail(r *rand.Rand, numOfFps uint64) []types.FinalityProviderDetails { - var finalityProviders []types.FinalityProviderDetails - - for i := uint64(0); i < numOfFps; i++ { - fpPkInHex, err := RandomPk() - if err != nil { - log.Fatalf("failed to generate random public key: %v", err) - } - - randomStr := RandomString(r, 10) - finalityProviders = append(finalityProviders, types.FinalityProviderDetails{ - Description: types.FinalityProviderDescription{ - Moniker: "Moniker" + randomStr, - Identity: "Identity" + randomStr, - Website: "Website" + randomStr, - SecurityContact: "SecurityContact" + randomStr, - Details: "Details" + randomStr, - }, - Commission: fmt.Sprintf("%f", RandomPostiveFloat64(r)), - BtcPk: fpPkInHex, - }) - } - return finalityProviders -} - -func RandomFinalityProviderState(r *rand.Rand) types.FinalityProviderQueryingState { - states := []types.FinalityProviderQueryingState{types.FinalityProviderStateActive, types.FinalityProviderStateStandby} - return states[r.Intn(len(states))] -} - -// GenerateRandomActiveStakingEvents generates a random number of active staking events -// with random values for each field. -// default to max 11 events, 11 finality providers, and 11 stakers -func GenerateRandomActiveStakingEvents( - r *rand.Rand, opts *TestActiveEventGeneratorOpts, -) []*client.ActiveStakingEvent { - var activeStakingEvents []*client.ActiveStakingEvent - genOpts := &TestActiveEventGeneratorOpts{ - NumOfEvents: 11, - FinalityProviders: GeneratePks(11), - Stakers: GeneratePks(11), - } - - if opts != nil { - if opts.NumOfEvents > 0 { - genOpts.NumOfEvents = opts.NumOfEvents - } - if len(opts.FinalityProviders) > 0 { - genOpts.FinalityProviders = opts.FinalityProviders - } - if len(opts.Stakers) > 0 { - genOpts.Stakers = opts.Stakers - } - } - - fpPks := genOpts.FinalityProviders - stakerPks := genOpts.Stakers - - for i := 0; i < genOpts.NumOfEvents; i++ { - randomFpPk := fpPks[rand.Intn(len(fpPks))] - randomStakerPk := stakerPks[rand.Intn(len(stakerPks))] - tx, hex, err := GenerateRandomTx(r, nil) - if err != nil { - log.Fatalf("failed to generate random tx: %v", err) - } - var isOverflow bool - if opts.EnforceNotOverflow { - isOverflow = false - } else { - isOverflow = rand.Int()%2 == 0 - } - activeStakingEvent := &client.ActiveStakingEvent{ - EventType: client.ActiveStakingEventType, - StakingTxHashHex: tx.TxHash().String(), - StakerPkHex: randomStakerPk, - FinalityProviderPkHex: randomFpPk, - StakingValue: uint64(RandomAmount(r)), - StakingStartHeight: uint64(RandomPositiveInt(r, 100000)), - StakingStartTimestamp: GenerateRandomTimestamp( - opts.AfterTimestamp, opts.BeforeTimestamp, - ), - StakingTimeLock: uint64(rand.Intn(100)), - StakingOutputIndex: uint64(rand.Intn(100)), - StakingTxHex: hex, - IsOverflow: isOverflow, - } - activeStakingEvents = append(activeStakingEvents, activeStakingEvent) - } - return activeStakingEvents -} - -func GenerateRandomBabylonParams(r *rand.Rand) indexertypes.BbnStakingParams { - return indexertypes.BbnStakingParams{ - Version: uint32(r.Intn(10)), - CovenantPks: GeneratePks(r.Intn(10)), - CovenantQuorum: uint32(r.Intn(10)), - MinStakingValueSat: int64(r.Intn(1000000000000000000)), - MaxStakingValueSat: int64(r.Intn(1000000000000000000)), - MinStakingTimeBlocks: uint32(r.Intn(1000000000000000000)), - MaxStakingTimeBlocks: uint32(r.Intn(1000000000000000000)), - SlashingPkScript: RandomString(r, 10), - MinSlashingTxFeeSat: int64(r.Intn(1000000000000000000)), - SlashingRate: fmt.Sprintf("%f", RandomPostiveFloat64(r)), - MinUnbondingTimeBlocks: uint32(r.Intn(1000000000000000000)), - UnbondingFeeSat: int64(r.Intn(1000000000000000000)), - MinCommissionRate: fmt.Sprintf("%f", RandomPostiveFloat64(r)), - MaxActiveFinalityProviders: uint32(r.Intn(10)), - DelegationCreationBaseGasFee: uint64(r.Intn(1000000000000000000)), - } -} - -func GenerateRandomBTCParams(r *rand.Rand) indexertypes.BtcCheckpointParams { - return indexertypes.BtcCheckpointParams{ - Version: uint32(r.Intn(10)), - BtcConfirmationDepth: uint64(r.Intn(10)), - } -} - -func RandomDelegationState(r *rand.Rand) types.DelegationState { - states := []types.DelegationState{types.Active, types.UnbondingRequested, types.Unbonding, types.Unbonded, types.Withdrawn} - return states[r.Intn(len(states))] -} - -func RandomTransactionInfo(r *rand.Rand) types.TransactionInfo { - _, txHex, _ := GenerateRandomTx(r, nil) - return types.TransactionInfo{ - TxHex: txHex, - OutputIndex: r.Intn(100), - } -} diff --git a/tests/testutils/utils.go b/tests/testutils/utils.go deleted file mode 100644 index a7661eff..00000000 --- a/tests/testutils/utils.go +++ /dev/null @@ -1,11 +0,0 @@ -package testutils - -// Contains checks if a slice of strings contains a specific string. -func Contains(slice []string, item string) bool { - for _, s := range slice { - if s == item { - return true - } - } - return false -} diff --git a/tests/unit_test/utils/btc_test.go b/tests/unit_test/utils/btc_test.go deleted file mode 100644 index f66f1e64..00000000 --- a/tests/unit_test/utils/btc_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package utilstest - -import ( - "testing" - - "github.com/babylonlabs-io/staking-api-service/internal/shared/utils" - "github.com/btcsuite/btcd/chaincfg" - "github.com/stretchr/testify/assert" -) - -func TestDeriveAddressesFromNoCoordPk(t *testing.T) { - // Given a known BTC public key hex string (32 bytes X coordinate) - pkHex := "30bb400d3ef60a5bb66a3f5d9e0e870ccbf8ae1a4ab2263a9fabf90adf94c70a" - expectedTaprootAddress := "bc1p89k3uz7fdt58gl3vtxqvfxcsgh0t923qfxyuw8l5qdz70fsxzzqq35fjjt" - expectedEvenAddress := "bc1qem92n3xk2rm72mua7jq66m700m3r2ama60mc35" - expectedOddAddress := "bc1q032et33x53y97ersj3k32dytfuh2lef3ewy4z2" - - addresses, err := utils.DeriveAddressesFromNoCoordPk(pkHex, &chaincfg.MainNetParams) - - // Then assert that there is no error - assert.NoError(t, err) - - // And assert that the derived addresses match the expected values - assert.Equal(t, expectedTaprootAddress, addresses.Taproot) - assert.Equal(t, expectedEvenAddress, addresses.NativeSegwitEven) - assert.Equal(t, expectedOddAddress, addresses.NativeSegwitOdd) -}