From 295cc865ecbcd3039e3cfc87de9c4cc4aaeb168b Mon Sep 17 00:00:00 2001 From: sampocs Date: Tue, 23 Jul 2024 16:32:02 -0500 Subject: [PATCH] added ibc-rate-limiting module for sdk 47 (#201) * added rate limiting module for sdk 47 * added gh actions for labeling, linting, and tests * pulled core module code back a directory * renamed module path to ibc-apps version * regenerated protos * renamed protocgen -> generate * fixed unit test makefile command * nit pulled validChannelId/denom to top as constants * lint * license --- .github/labeler.yml | 5 +- .github/workflows/rate-limiting.yml | 44 + README.md | 3 +- modules/rate-limiting/.gitignore | 42 + modules/rate-limiting/LICENSE | 201 ++ modules/rate-limiting/Makefile | 130 + modules/rate-limiting/README.md | 383 +++ modules/rate-limiting/client/cli/query.go | 149 + modules/rate-limiting/go.mod | 194 ++ modules/rate-limiting/go.sum | 1670 +++++++++++ modules/rate-limiting/ibc_middleware.go | 184 ++ modules/rate-limiting/keeper/abci.go | 22 + modules/rate-limiting/keeper/abci_test.go | 78 + modules/rate-limiting/keeper/blacklist.go | 48 + .../rate-limiting/keeper/blacklist_test.go | 55 + modules/rate-limiting/keeper/epoch.go | 48 + modules/rate-limiting/keeper/epoch_test.go | 97 + modules/rate-limiting/keeper/events.go | 27 + modules/rate-limiting/keeper/flow.go | 91 + modules/rate-limiting/keeper/flow_test.go | 433 +++ modules/rate-limiting/keeper/genesis.go | 61 + modules/rate-limiting/keeper/genesis_test.go | 100 + modules/rate-limiting/keeper/grpc_query.go | 88 + .../rate-limiting/keeper/grpc_query_test.go | 120 + modules/rate-limiting/keeper/keeper.go | 56 + modules/rate-limiting/keeper/keeper_test.go | 23 + modules/rate-limiting/keeper/msg_server.go | 81 + .../rate-limiting/keeper/msg_server_test.go | 203 ++ modules/rate-limiting/keeper/packet.go | 305 ++ modules/rate-limiting/keeper/packet_test.go | 447 +++ modules/rate-limiting/keeper/params.go | 17 + modules/rate-limiting/keeper/pending_send.go | 72 + .../rate-limiting/keeper/pending_send_test.go | 40 + modules/rate-limiting/keeper/rate_limit.go | 162 ++ .../rate-limiting/keeper/rate_limit_test.go | 95 + modules/rate-limiting/keeper/whitelist.go | 52 + .../rate-limiting/keeper/whitelist_test.go | 52 + modules/rate-limiting/module.go | 160 ++ modules/rate-limiting/proto/buf.gen.gogo.yaml | 8 + modules/rate-limiting/proto/buf.lock | 23 + modules/rate-limiting/proto/buf.yaml | 24 + .../proto/ratelimit/v1/genesis.proto | 34 + .../proto/ratelimit/v1/params.proto | 7 + .../proto/ratelimit/v1/query.proto | 90 + .../proto/ratelimit/v1/ratelimit.proto | 93 + .../rate-limiting/proto/ratelimit/v1/tx.proto | 111 + modules/rate-limiting/scripts/generate.sh | 28 + modules/rate-limiting/testing/app.go | 1 + .../testing/simapp/ante_handler.go | 50 + modules/rate-limiting/testing/simapp/app.go | 896 ++++++ .../testing/simapp/apptesting/test_helpers.go | 74 + .../rate-limiting/testing/simapp/encoding.go | 16 + .../rate-limiting/testing/simapp/export.go | 203 ++ .../rate-limiting/testing/simapp/genesis.go | 20 + .../testing/simapp/params/encoding.go | 32 + .../rate-limiting/testing/simapp/simd/main.go | 20 + .../rate-limiting/testing/simapp/simd/root.go | 264 ++ .../testing/simapp/test_setup.go | 165 ++ modules/rate-limiting/types/codec.go | 43 + modules/rate-limiting/types/errors.go | 24 + modules/rate-limiting/types/events.go | 16 + .../rate-limiting/types/expected_keepers.go | 38 + modules/rate-limiting/types/flow.go | 47 + modules/rate-limiting/types/flow_test.go | 228 ++ modules/rate-limiting/types/genesis.go | 80 + modules/rate-limiting/types/genesis.pb.go | 623 +++++ modules/rate-limiting/types/genesis_test.go | 103 + modules/rate-limiting/types/keys.go | 54 + modules/rate-limiting/types/msgs.go | 292 ++ modules/rate-limiting/types/msgs_test.go | 467 ++++ modules/rate-limiting/types/params.go | 32 + modules/rate-limiting/types/params.pb.go | 264 ++ modules/rate-limiting/types/query.pb.go | 2463 +++++++++++++++++ modules/rate-limiting/types/query.pb.gw.go | 604 ++++ modules/rate-limiting/types/quota.go | 22 + modules/rate-limiting/types/quota_test.go | 79 + modules/rate-limiting/types/ratelimit.pb.go | 1772 ++++++++++++ modules/rate-limiting/types/tx.pb.go | 2231 +++++++++++++++ 78 files changed, 17677 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/rate-limiting.yml create mode 100644 modules/rate-limiting/.gitignore create mode 100644 modules/rate-limiting/LICENSE create mode 100644 modules/rate-limiting/Makefile create mode 100644 modules/rate-limiting/README.md create mode 100644 modules/rate-limiting/client/cli/query.go create mode 100644 modules/rate-limiting/go.mod create mode 100644 modules/rate-limiting/go.sum create mode 100644 modules/rate-limiting/ibc_middleware.go create mode 100644 modules/rate-limiting/keeper/abci.go create mode 100644 modules/rate-limiting/keeper/abci_test.go create mode 100644 modules/rate-limiting/keeper/blacklist.go create mode 100644 modules/rate-limiting/keeper/blacklist_test.go create mode 100644 modules/rate-limiting/keeper/epoch.go create mode 100644 modules/rate-limiting/keeper/epoch_test.go create mode 100644 modules/rate-limiting/keeper/events.go create mode 100644 modules/rate-limiting/keeper/flow.go create mode 100644 modules/rate-limiting/keeper/flow_test.go create mode 100644 modules/rate-limiting/keeper/genesis.go create mode 100644 modules/rate-limiting/keeper/genesis_test.go create mode 100644 modules/rate-limiting/keeper/grpc_query.go create mode 100644 modules/rate-limiting/keeper/grpc_query_test.go create mode 100644 modules/rate-limiting/keeper/keeper.go create mode 100644 modules/rate-limiting/keeper/keeper_test.go create mode 100644 modules/rate-limiting/keeper/msg_server.go create mode 100644 modules/rate-limiting/keeper/msg_server_test.go create mode 100644 modules/rate-limiting/keeper/packet.go create mode 100644 modules/rate-limiting/keeper/packet_test.go create mode 100644 modules/rate-limiting/keeper/params.go create mode 100644 modules/rate-limiting/keeper/pending_send.go create mode 100644 modules/rate-limiting/keeper/pending_send_test.go create mode 100644 modules/rate-limiting/keeper/rate_limit.go create mode 100644 modules/rate-limiting/keeper/rate_limit_test.go create mode 100644 modules/rate-limiting/keeper/whitelist.go create mode 100644 modules/rate-limiting/keeper/whitelist_test.go create mode 100644 modules/rate-limiting/module.go create mode 100644 modules/rate-limiting/proto/buf.gen.gogo.yaml create mode 100644 modules/rate-limiting/proto/buf.lock create mode 100644 modules/rate-limiting/proto/buf.yaml create mode 100644 modules/rate-limiting/proto/ratelimit/v1/genesis.proto create mode 100644 modules/rate-limiting/proto/ratelimit/v1/params.proto create mode 100644 modules/rate-limiting/proto/ratelimit/v1/query.proto create mode 100644 modules/rate-limiting/proto/ratelimit/v1/ratelimit.proto create mode 100644 modules/rate-limiting/proto/ratelimit/v1/tx.proto create mode 100644 modules/rate-limiting/scripts/generate.sh create mode 100644 modules/rate-limiting/testing/app.go create mode 100644 modules/rate-limiting/testing/simapp/ante_handler.go create mode 100644 modules/rate-limiting/testing/simapp/app.go create mode 100644 modules/rate-limiting/testing/simapp/apptesting/test_helpers.go create mode 100644 modules/rate-limiting/testing/simapp/encoding.go create mode 100644 modules/rate-limiting/testing/simapp/export.go create mode 100644 modules/rate-limiting/testing/simapp/genesis.go create mode 100644 modules/rate-limiting/testing/simapp/params/encoding.go create mode 100644 modules/rate-limiting/testing/simapp/simd/main.go create mode 100644 modules/rate-limiting/testing/simapp/simd/root.go create mode 100644 modules/rate-limiting/testing/simapp/test_setup.go create mode 100644 modules/rate-limiting/types/codec.go create mode 100644 modules/rate-limiting/types/errors.go create mode 100644 modules/rate-limiting/types/events.go create mode 100644 modules/rate-limiting/types/expected_keepers.go create mode 100644 modules/rate-limiting/types/flow.go create mode 100644 modules/rate-limiting/types/flow_test.go create mode 100644 modules/rate-limiting/types/genesis.go create mode 100644 modules/rate-limiting/types/genesis.pb.go create mode 100644 modules/rate-limiting/types/genesis_test.go create mode 100644 modules/rate-limiting/types/keys.go create mode 100644 modules/rate-limiting/types/msgs.go create mode 100644 modules/rate-limiting/types/msgs_test.go create mode 100644 modules/rate-limiting/types/params.go create mode 100644 modules/rate-limiting/types/params.pb.go create mode 100644 modules/rate-limiting/types/query.pb.go create mode 100644 modules/rate-limiting/types/query.pb.gw.go create mode 100644 modules/rate-limiting/types/quota.go create mode 100644 modules/rate-limiting/types/quota_test.go create mode 100644 modules/rate-limiting/types/ratelimit.pb.go create mode 100644 modules/rate-limiting/types/tx.pb.go diff --git a/.github/labeler.yml b/.github/labeler.yml index b83ed73c..a2f0f656 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -5,4 +5,7 @@ ibc-hooks: - modules/ibc-hooks/** packet-forward-middleware: - - middleware/packet-forward-middleware/** \ No newline at end of file + - middleware/packet-forward-middleware/** + +rate-limit: + - modules/rate-limit/** \ No newline at end of file diff --git a/.github/workflows/rate-limiting.yml b/.github/workflows/rate-limiting.yml new file mode 100644 index 00000000..caf2c91e --- /dev/null +++ b/.github/workflows/rate-limiting.yml @@ -0,0 +1,44 @@ +name: rate-limiting +on: + pull_request: + paths: + - "modules/rate-limiting/**" + - ".github/workflows/rate-limiting.yml" + +env: + LINT_VERSION: v1.57.1 + GO_VERSION: 1.22.1 + WORKING_DIRECTORY: modules/rate-limiting + + DOCKER_TAG: rate-limiting:local + TAR_PATH: /tmp/rate-limiting-image.tar + IMAGE_NAME: rate-limiting-image + +jobs: + golangci: + name: Linter + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: golangci-lint + uses: golangci/golangci-lint-action@v2 + with: + version: ${{ env.LINT_VERSION }} + working-directory: ${{ env.WORKING_DIRECTORY }} + args: --timeout=5m + + test: + runs-on: ubuntu-latest + name: test + steps: + - name: Install Go + uses: actions/setup-go@v4 + with: + go-version: ${{ env.GO_VERSION }} + + - uses: actions/checkout@v4 + + - name: Test + run: make test-unit + working-directory: ${{ env.WORKING_DIRECTORY }} \ No newline at end of file diff --git a/README.md b/README.md index a41f9d71..35193fb6 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ An [example IBC app](./examples/hello-world/) | [Async Interchain Query](./modules/async-icq/) | Module | Link | [Strangelove](https://github.com/strangelove-ventures/) | Interchain Queries enable blockchains to query the state of an account on another chain without the need for ICA auth. | | [IBC Hooks](./modules/ibc-hooks/) | Module | [Link](./modules/ibc-hooks/simapp/app.go) | [Osmosis](https://github.com/osmosis-labs) | The IBC hooks module is an IBC middleware that enables ICS-20 token transfers to initiate contract calls. | | [Packet Forward Middleware](./middleware/packet-forward-middleware) | Middleware | Link | [Strangelove](https://github.com/strangelove-ventures/) | Middleware for forwarding IBC packets. | +| [Rate Limit](./modules/rate-limiting/) | Module | Link | [Stride](https://github.com/Stride-Labs/) | Module for rate limiting ingress/egress of packets. | ## Ecosystem Apps @@ -83,6 +84,6 @@ Modules and middleware developed by other awesome teams in the ecosystem: | [NFT Transfer (ICS 721)](https://github.com/bianjieai/nft-transfer) | Module | [Bianjieai](https://github.com/bianjieai) | An application that enables cross chain NFT transfer. | | [CosmWasm NFT Transfer (ICS 721)](https://github.com/public-awesome/cw-ics721) | WASM Contract | [Public Awesome (Stargaze)](https://github.com/public-awesome), [Ark Protocol](https://twitter.com/ArkProtocol) | An application that enables cross chain NFT transfer. CosmWasm implementation of the above, written in Rust. | | [recovery](https://github.com/evmos/evmos/tree/main/x/recovery) | Middleware | [Evmos](https://github.com/evmos) | Middleware enabling the recovery of tokens sent to unsupported addresses. | -| [ibc-rate-limit](https://github.com/osmosis-labs/osmosis/tree/main/x/ibc-rate-limit) | Middleware | [Osmosis Labs](https://github.com/osmosis-labs) | Middleware that limits the in or out flow of an asset in a certain time period to minimise the risks of cross chain token transfers. This is implemented as a middleware wrapping ICS20 with the rate limiting logic implemented by cosmwasm contracts. | +| [cw-ibc-rate-limit](https://github.com/osmosis-labs/osmosis/tree/main/x/ibc-rate-limit) | Middleware | [Osmosis Labs](https://github.com/osmosis-labs) | Middleware that limits the in or out flow of an asset in a certain time period to minimise the risks of cross chain token transfers. This is implemented as a middleware wrapping ICS20 with the rate limiting logic implemented by cosmwasm contracts. | | [Interchain Atomic Swap](https://github.com/sideprotocol/ibcswap-wasm/tree/main/contracts/ics100) | WASM Contract | [Side Labs](https://github.com/sideprotocol) | An application that facilitates inter-blockchain peer-to-peer asset swaps. | | [Interchain Liquidity](https://github.com/sideprotocol/ibcswap-wasm/tree/main/contracts/ics101) | WASM Contract | [Side Labs](https://github.com/sideprotocol) | An application that splits the state of a weighted liquidity pool between two chains, enabling inter-blockchain automated asset swaps. | diff --git a/modules/rate-limiting/.gitignore b/modules/rate-limiting/.gitignore new file mode 100644 index 00000000..8153ce13 --- /dev/null +++ b/modules/rate-limiting/.gitignore @@ -0,0 +1,42 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +**state.json +**test.py +**test.sh +**test.py +# build +launch.sh +build/* +state/* +scripts/state +scripts/logs +dockernet/state +dockernet/logs +dockernet/upgrades/binaries +dockernet/upgrades/cosmovisor +dockernet/temp.sh +scripts/temp.sh +vue/* +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + + +.DS_Store +.terraform +*.pem + +.vscode +!.vscode/settings.json + +.ipynb_checkpoints/* diff --git a/modules/rate-limiting/LICENSE b/modules/rate-limiting/LICENSE new file mode 100644 index 00000000..dcdfc3f8 --- /dev/null +++ b/modules/rate-limiting/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright for rate limiting public infrastructure attributed to Stride + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/modules/rate-limiting/Makefile b/modules/rate-limiting/Makefile new file mode 100644 index 00000000..7191cccc --- /dev/null +++ b/modules/rate-limiting/Makefile @@ -0,0 +1,130 @@ +#!/usr/bin/make -f +VERSION := $(shell echo $(shell git describe --tags)) +BUILDDIR ?= $(CURDIR)/build +build=s +cache=false +COMMIT := $(shell git log -1 --format='%H') +DOCKER := $(shell which docker) +DOCKER_BUF := $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace bufbuild/buf:1.7.0 +STRIDE_HOME=./ +DOCKERNET_HOME=./dockernet +DOCKERNET_COMPOSE_FILE=$(DOCKERNET_HOME)/docker-compose.yml +LOCALSTRIDE_HOME=./testutil/localstride +LOCALNET_COMPOSE_FILE=$(LOCALSTRIDE_HOME)/localnet/docker-compose.yml +STATE_EXPORT_COMPOSE_FILE=$(LOCALSTRIDE_HOME)/state-export/docker-compose.yml +LOCAL_TO_MAIN_COMPOSE_FILE=./scripts/local-to-mainnet/docker-compose.yml + +# process build tags +LEDGER_ENABLED ?= true +build_tags = netgo +ifeq ($(LEDGER_ENABLED),true) + ifeq ($(OS),Windows_NT) + GCCEXE = $(shell where gcc.exe 2> NUL) + ifeq ($(GCCEXE),) + $(error gcc.exe not installed for ledger support, please install or set LEDGER_ENABLED=false) + else + build_tags += ledger + endif + else + UNAME_S = $(shell uname -s) + ifeq ($(UNAME_S),OpenBSD) + $(warning OpenBSD detected, disabling ledger support (https://github.com/cosmos/cosmos-sdk/issues/1988)) + else + GCC = $(shell command -v gcc 2> /dev/null) + ifeq ($(GCC),) + $(error gcc not installed for ledger support, please install or set LEDGER_ENABLED=false) + else + build_tags += ledger + endif + endif + endif +endif + +build_tags += $(BUILD_TAGS) +build_tags := $(strip $(build_tags)) + +whitespace := +whitespace += $(whitespace) +comma := , +build_tags_comma_sep := $(subst $(whitespace),$(comma),$(build_tags)) + +# process linker flags +ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=stride \ + -X github.com/cosmos/cosmos-sdk/version.AppName=strided \ + -X github.com/cosmos/cosmos-sdk/version.Version=$(VERSION) \ + -X github.com/cosmos/cosmos-sdk/version.Commit=$(COMMIT) \ + -X "github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags_comma_sep)" + +ifeq ($(LINK_STATICALLY),true) + ldflags += -linkmode=external -extldflags "-Wl,-z,muldefs -static" +endif +ldflags += $(LDFLAGS) +ldflags := $(strip $(ldflags)) + +BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags)' + +.PHONY: build + +############################################################################### +### Build & Clean ### +############################################################################### + +build: + which go + mkdir -p $(BUILDDIR)/ + go build -mod=readonly $(BUILD_FLAGS) -trimpath -o $(BUILDDIR) ./...; + +build-linux: + GOOS=linux GOARCH=amd64 $(MAKE) build + +install: go.sum + go install $(BUILD_FLAGS) ./cmd/strided + +clean: + rm -rf $(BUILDDIR)/* + +############################################################################### +### CI ### +############################################################################### + +gosec: + gosec -exclude-dir=deps -severity=high ./... + +lint: + golangci-lint run + +############################################################################### +### Tests ### +############################################################################### + +test-unit: + @go test -mod=readonly ./... + + +############################################################################### +### Protobuf ### +############################################################################### + +containerProtoVer=0.14.0 +containerProtoImage=ghcr.io/cosmos/proto-builder:$(containerProtoVer) + +proto-all: proto-format proto-gen + +proto-gen: + @echo "Generating Protobuf files" + @$(DOCKER) run --user $(id -u):$(id -g) --rm -v $(CURDIR):/workspace --workdir /workspace $(containerProtoImage) \ + sh ./scripts/generate.sh; + +proto-format: + @echo "Formatting Protobuf files" + @$(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace tendermintdev/docker-build-proto \ + find ./proto -name "*.proto" -exec clang-format -i {} \; + +proto-swagger-gen: + @echo "Generating Protobuf Swagger" + @$(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace $(containerProtoImage) \ + sh ./scripts/protoc-swagger-gen.sh; + +proto-check-breaking: + @$(DOCKER_BUF) breaking --against $(HTTPS_GIT)#branch=main + diff --git a/modules/rate-limiting/README.md b/modules/rate-limiting/README.md new file mode 100644 index 00000000..2a0fd6b2 --- /dev/null +++ b/modules/rate-limiting/README.md @@ -0,0 +1,383 @@ +# IBC Rate Limiting + +## Overview + +This `ratelimit` module is a native golang implementation, inspired by Osmosis's CosmWasm [`ibc-rate-limit`](https://github.com/osmosis-labs/osmosis/tree/main/x/ibc-rate-limit) module. The module is meant as a safety control in the event of a bug, attack, or economic failure of an external zone. It prevents massive inflows or outflows of IBC tokens in a short time frame. See [here](https://github.com/osmosis-labs/osmosis/tree/main/x/ibc-rate-limit#motivation) for an excellent summary by the Osmosis team on the motivation for rate limiting. + +Each rate limit is applied at a ChannelID + Denom granularity and is evaluated in evenly spaced fixed windows. For instance, a rate limit might be specified on `uosmo` (denominated as `ibc/D24B4564BCD51D3D02D9987D92571EAC5915676A9BD6D9B0C1D0254CB8A5EA34` on Stride), on the Stride <-> Osmosis transfer channel (`channel-5`), with a 24 hour window. + +Each rate limit will also have a configurable threshold that dictates the max inflow/outflow along the channel. The threshold is represented as a percentage of the total value along the channel. The channel value is calculated by querying the total supply of the denom at the start of the time window, and it remains constant until the window expires. For instance, the rate limit described above might have a threshold of 10% for both inflow and outflow. If the total supply of `ibc/D24B4564BCD51D3D02D9987D92571EAC5915676A9BD6D9B0C1D0254CB8A5EA34` was 100, then any transfer that would cause a net inflow or outflow greater than 10 (i.e. greater than 10% the channel value) would be rejected. Once the time window expires, the net inflow and outflow are reset to 0 and the channel value is re-calculated. + +The _net_ inflow and outflow is used (rather than the total inflow/outflow) to prevent DOS attacks where someone repeatedly sends the same token back and forth across the same channel, causing the rate limit to be reached. + +The module is implemented as IBC Middleware around the transfer module. An "hour epoch" abstraction is leveraged to determine when each rate limit window has expired (each window is denominated in hours). This means all rate limit windows with the same window duration will start and end at the same time. In the case of a 24 hour rate limit window, the rate limit will reset at the end of the day in UTC (i.e. 00:00 UTC). + +## Integration +To add the rate limit module, wire it up in `app.go` in line with the following example. The module must be included in a middleware stack alongside the transfer module. + +```go +// app.go + +// Import the rate limit module +import ( + "github.com/Stride-Labs/ibc-rate-limiting/v1/ratelimit" + ratelimitkeeper "github.com/Stride-Labs/ibc-rate-limiting/v1/ratelimit/keeper" + ratelimittypes "github.com/Stride-Labs/ibc-rate-limiting/v1/ratelimit/types" +) + +... + +// Register the AppModule +ModuleBasics = module.NewBasicManager( + ... + ratelimit.AppModuleBasic{}, + ... +) + +... + +// Add the RatelimitKeeper to the App +type App struct { + ... + RatelimitKeeper ratelimitkeeper.Keeper + ... +} + +// Add the store key +keys := sdk.NewKVStoreKeys( + ... + ratelimittypes.StoreKey, + ... +) + +// Create the rate limit keeper +app.RatelimitKeeper = *ratelimitkeeper.NewKeeper( + appCodec, + keys[ratelimittypes.StoreKey], + app.GetSubspace(ratelimittypes.ModuleName), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + app.BankKeeper, + app.IBCKeeper.ChannelKeeper, + app.IBCKeeper.ChannelKeeper, // ICS4Wrapper +) + +// Add the rate limit module to a middleware stack with the transfer module +// +// Note: If the integrating chain already has middleware wired, you'll just +// have to add the rate limit module to the existing stack +// +// The following will create the following stack +// - Core IBC +// - ratelimit +// - transfer +// - base app +var transferStack ibcporttypes.IBCModule = transfer.NewIBCModule(app.TransferKeeper) +transferStack = ratelimit.NewIBCMiddleware(app.RatelimitKeeper, transferStack) + +// Add IBC Router +ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) + +// Add the rate limit module to the module manager +app.mm = module.NewManager( + ... + ratelimit.NewAppModule(appCodec, app.RatelimitKeeper), +) + +// Add the rate limit module to begin and end blockers, and init genesis +app.mm.SetOrderBeginBlockers( + ... + ratelimittypes.ModuleName, +) + +app.mm.SetOrderEndBlockers( + ... + ratelimittypes.ModuleName, +) + +genesisModuleOrder := []string{ + ... + ratelimittypes.ModuleName, +} + +// Add the rate limit module to the params keeper +func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey) paramskeeper.Keeper { + ... + paramsKeeper.Subspace(ratelimittypes.ModuleName) + ... +} +``` + +## Implementation + +Each rate limit is defined by the following three components: + +1. **Path**: Defines the `ChannelId` and `Denom` +2. **Quota**: Defines the rate limit time window (`DurationHours`) and the max threshold for inflows/outflows (`MaxPercentRecv` and `MaxPercentSend` respectively) +3. **Flow**: Stores the current `Inflow`, `Outflow` and `ChannelValue`. Each time a quota expires, the inflow and outflow get reset to 0 and the channel value gets recalculated. Throughout the window, the inflow and outflow each increase monotonically. The net flow is used when determining if a transfer would exceed the quota. + - For `Send` packets: + $$\text{Exceeds Quota if:} \left(\frac{\text{Outflow} - \text{Inflow} + \text{Packet Amount}}{\text{ChannelValue}}\right) > \text{MaxPercentSend}$$ + - For `Receive` packets: + $$\text{Exceeds Quota if:} \left(\frac{\text{Inflow} - \text{Outflow} + \text{Packet Amount}}{\text{ChannelValue}}\right) > \text{MaxPercentRecv}$$ + +## Example Walk-Through + +Using the example above, let's say we created a 24 hour rate limit on `ibc/D24B4564BCD51D3D02D9987D92571EAC5915676A9BD6D9B0C1D0254CB8A5EA34` ("`ibc/uosmo`"), `channel-5`, on Stride, with a 10% send and receive threshold. + +1. At the start of the window, the supply will be queried, to determine the channel value. Let's say the total supply was 100 +2. If someone transferred `8uosmo` from `Osmosis -> Stride`, the `Inflow` would increment by 8 +3. If someone tried to transfer another `8uosmo` from `Osmosis -> Stride`, it would exceed the quota since `(8+8)/100 = 16%` (which is greater than 10%) and thus, the transfer would be rejected. +4. If someone tried to transfer `12ibc/uosmo` from Stride -> Osmosis, the `Outflow` would increment by 12. Notice, even though 12 is greater than 10% the total channel value, the _net_ outflow is only `4uatom` (since it's offset by the `8uatom` `Inflow`). As a result, this transaction would succeed. +5. Now if the person in (3) attempted to retry their transfer of`8uosmo` from `Osmosis -> Stride`, the `Inflow` would increment by 8 and the transaction would succeed (leaving a net inflow of 4). +6. Finally, at the end of the 24 hours, the `Inflow` and `Outflow` would get reset to 0 and the `ChannelValue` would be re-calculated. In this example, the new channel value would be 104 (since more `uosmo` was sent to Stride, and thus more `ibc/uosmo` was minted) + +| Step | Description | Transfer Status | Inflow | Outflow | Net Inflow | Net Outflow | Channel Value | +| :--: | :------------------------------: | :-------------: | :----: | :-----: | :--------: | :---------: | :-----------: | +| 1 | Rate limit created | | 0 | 0 | | | 100 | +| 2 | 8usomo Osmosis → Stride | Successful | 8 | 0 | 8% | | 100 | +| 3 | 8usomo Osmosis → Stride | Rejected | 16 | 0 | 16% (>10%) | | 100 | +| 3 | State reverted after rejected Tx | | 8 | 0 | 8% | | 100 | +| 4 | 12ibc/uosmo Stride → Osmosis | Successful | 8 | 12 | | 4% | 100 | +| 5 | 8usomo Osmosis → Stride | Successful | 16 | 12 | 4% | | 100 | +| 6 | Quota Reset | | 0 | 0 | | | 104 | + +## Denom Blacklist + +The module also contains a blacklist to completely halt all IBC transfers for a given denom. There are keeper functions to add or remove denoms from the blacklist; however, these functions are not exposed externally through transactions or governance, and they should only be leveraged internally from the protocol in extreme scenarios. + +## Address Whitelist + +There is also a whitelist, mainly used to exclude protocol-owned accounts. For instance, Stride periodically bundles liquid staking deposits and transfers in a single transaction at the top of the epoch. Without a whitelist, this transfer would make the rate limit more likely to trigger a false positive. + +## Denoms + +We always want to refer to the channel ID and denom as they appear on the rate limited chain. For instance, in the example above where rate limiting was added to Stride, we would store the rate limit with denom `ibc/D24B4564BCD51D3D02D9987D92571EAC5915676A9BD6D9B0C1D0254CB8A5EA34` and `channel-5` (the ChannelID on Stride), instead of `uosmo` and `channel-326` (the ChannelID on Osmosis). + +However, since the ratelimit module acts as middleware to the transfer module, the respective denoms need to be interpreted using the denom trace associated with each packet. There are a few scenarios at play here... + +### Send Packets + +The denom that the rate limiter will use for a send packet depends on whether it was a native token (i.e. tokens minted on the rate limited chain) or non-native token (e.g. ibc/...)... + +#### Native vs Non-Native + +- We can identify if the token is native or not by parsing the denom trace from the packet + - If the token is **native**, it **will not** have a prefix (e.g. `ustrd`) + - If the token is **non-native**, it **will** have a prefix (e.g. `transfer/channel-X/uosmo`) + +#### Determining the denom in the rate limit + +- For **native** tokens, return as is (e.g. `ustrd`) +- For **non-native** tokens, take the ibc hash (e.g. hash `transfer/channel-X/uosmo` into `ibc/...`) + +### Receive Packets + +The denom that the rate limiter will use for a receive packet depends on whether it was a source or sink. + +#### Source vs Sink + +As a token travels across IBC chains, its path is recorded in the denom trace. + +- **Sink**: If the token moves **forward**, to a chain different than its previous hop, the destination chain acts as a **sink zone**, and the new port and channel are **appended** to the denom trace. + - Ex1: `uatom` is sent from Cosmoshub to Stride + - Stride is the first destination for `uatom`, and acts as a sink zone + - The IBC denom becomes the hash of: `/{stride-port)/{stride-channel}/uatom` + - Ex2: `uatom` is sent from Cosmoshub to Osmosis then to Stride + - Here the receiving chain (Stride) is not the same as the previous hop (Cosmoshub), so Stride, once again, is acting as a sink zone + - The IBC denom becomes the hash of: `/{stride-port)/{stride-channel}/{osmosis-port}/{osmosis-channel}/uatom` +- **Source**: If the token moves **backwards** (i.e. revisits the last chain it was sent from), the destination chain is acting as a **source zone**, and the port and channel are **removed** from the denom trace - undoing the last hop. Should a token reverse its course completely and head back along the same path to its native chain, the denom trace will unwind and reduce back down to the original base denom. + - Ex1: `ustrd` is sent from Stride to Osmosis, and then back to Stride + - Here the trace reduces from `/{osmosis-port}/{osmosis-channel}/ustrd` to simply `ustrd` + - Ex2: `ujuno` is sent to Stride, then to Osmosis, then back to Stride + - Here the trace reduces from `/{osmosis-port}/{osmosis-channel}/{stride-port}/{stride-channel}/ujuno` to just `/{stride-port}/{stride-channel}/ujuno` (the Osmosis hop is removed) + - Stride is the source in the examples above because the token went back and forth from Stride -> Osmosis -> Stride + +For a more detailed explanation, see the[ ICS-20 ADR](https://github.com/cosmos/ibc-go/blob/main/docs/architecture/adr-001-coin-source-tracing.md#example) and [spec](https://github.com/cosmos/ibc/tree/main/spec/app/ics-020-fungible-token-transfer). + +#### Determining the denom in the rate limit + +- If the chain is acting as a **Sink**: Add on the port and channel from the rate limited chain and hash it + + - Ex1: `uosmo` sent from Osmosis to Stride + + - Packet Denom Trace: `uosmo` + - (1) Add Stride Channel as Prefix: `transfer/channel-X/uosmo` + - (2) Hash: `ibc/...` + + - Ex2: `ujuno` sent from Osmosis to Stride + - Packet Denom Trace: `transfer/channel-Y/ujuno` (where channel-Y is the Juno <> Osmosis channel) + - (1) Add Stride Channel as Prefix: `transfer/channel-X/transfer/channel-Y/ujuno` + - (2) Hash: `ibc/...` + +- If the chain is acting as a **Source**: First, remove the prefix. Then if there is still a trace prefix, hash it + - Ex1: `ustrd` sent back to Stride from Osmosis + - Packet Denom: `transfer/channel-X/ustrd` + - (1) Remove Prefix: `ustrd` + - (2) No trace remaining, leave as is: `ustrd` + - Ex2: juno was sent to Stride, then to Osmosis, then back to Stride + - Packet Denom: `transfer/channel-X/transfer/channel-Z/ujuno` + - (1) Remove Prefix: `transfer/channel-Z/ujuno` + - (2) Hash: `ibc/...` + +## Packet Failures and Timeouts +When a transfer is sent, the `Outflow` for the corresponding rate limit is incremented. Consequently, if the transfer fails on the host or times out, the change in `Outflow` must be reverted. However, the decrement is only necessary if the acknowledgement or timeout is returned in the same quota window that the packet was originally sent from. + +To keep track of whether the packet was sent in the same quota, the sequence number of all pending packets are stored. This is implemented by recording the sequence number of a SendPacket as it is sent, and then removing that list of sequence numbers each time the rate limit is reset at the end of the quota. Additionally, the sequence numbers are also removed when after an acknowledgement or timeout (a step that is not entirely necessary, but does reduce the size of the state). + +## State + +```go +RateLimit + Path + Denom string + ChannelId string + Quota + MaxPercentSend sdkmath.Int + MaxPercentRecv sdkmath.Int + DurationHours uint64 + Flow + Inflow sdkmath.Int + Outflow sdkmath.Int + ChannelValue sdkmath.Int +``` + +## Keeper functions +### RateLimit +```go +// Stores a RateLimit object in the store +SetRateLimit(rateLimit types.RateLimit) + +// Removes a RateLimit object from the store +RemoveRateLimit(denom string, channelId string) + +// Reads a RateLimit object from the store +GetRateLimit(denom string, channelId string) (RateLimit, found) + +// Gets a list of all RateLimit objects +GetAllRateLimits() []RateLimit + +// Resets the Inflow and Outflow of a RateLimit and re-calculates the ChannelValue +ResetRateLimit(denom string, channelId string) +``` + +### PendingSendPacket +```go +// Sets the sequence number of a packet that was just sent +SetPendingSendPacket(channelId string, sequence uint64) + +// Remove a pending packet sequence number from the store +// This is used after the ack or timeout for a packet has been received +RemovePendingSendPacket(channelId string, sequence uint64) + +// Checks whether the packet sequence number is in the store - indicating that it was +// sent during the current quota +CheckPacketSentDuringCurrentQuota(channelId string, sequence uint64) bool + +// Removes all pending sequence numbers from the store +// This is executed when the quota resets +RemoveAllChannelPendingSendPackets(channelId string) +``` + +### DenomBlacklist +```go +// Adds a denom to a blacklist to prevent all IBC transfers with this denom +AddDenomToBlacklist(denom string) + +// Removes a denom from a blacklist to re-enable IBC transfers for that denom +RemoveDenomFromBlacklist(denom string) + +// Check if a denom is currently blacklisted +IsDenomBlacklisted(denom string) bool + +// Get all the blacklisted denoms +GetAllBlacklistedDenoms() []string +``` + +### AddressWhitelist +```go +// Adds an pair of sender and receiver addresses to the whitelist to allow all +// IBC transfers between those addresses to skip all flow calculations +SetWhitelistedAddressPair(whitelist types.WhitelistedAddressPair) + +// Removes a whitelisted address pair so that it's transfers are counted in the quota +RemoveWhitelistedAddressPair(sender, receiver string) + +// Check if a sender/receiver address pair is currently whitelisted +IsAddressPairWhitelisted(sender, receiver string) bool + +// Get all the whitelisted addresses +GetAllWhitelistedAddressPairs() []types.WhitelistedAddressPair +``` + + +### Business Logic +```go +// Checks whether a packet will exceed a rate limit quota +// If it does not exceed the quota, it updates the `Inflow` or `Outflow` +// If it exceeds the quota, it returns an error +CheckRateLimitAndUpdateFlow(direction types.PacketDirection, packetInfo RateLimitedPacketInfo) (updated bool) + +// Reverts the change in outflow from a SendPacket if it fails or times out +UndoSendPacket(channelId string, sequence uint64, denom string, amount sdkmath.Int) +``` + +## Middleware Functions + +```go +SendRateLimitedPacket (ICS4Wrapper SendPacket) +ReceiveRateLimitedPacket (IBCModule OnRecvPacket) +``` + +## Transactions (via Governance) + +```go +// Adds a new rate limit +// Errors if: +// - `ChannelValue` is 0 (meaning supply of the denom is 0) +// - Rate limit already exists (as identified by the `channel_id` and `denom`) +// - Channel does not exist +AddRateLimit() +{"denom": string, "channel_id": string, "duration_hours": string, "max_percent_send": string, "max_percent_recv": string} + +// Updates a rate limit quota, and resets the rate limit +// Errors if: +// - Rate limit does not exist (as identified by the `channel_id` and `denom`) +UpdateRateLimit() +{"denom": string, "channel_id": string, "duration_hours": string, "max_percent_send": string, "max_percent_recv": string} + +// Resets the `Inflow` and `Outflow` of a rate limit to 0, and re-calculates the `ChannelValue` +// Errors if: +// - Rate limit does not exist (as identified by the `channel_id` and `denom`) +ResetRateLimit() +{"denom": string, "channel_id": string} + +// Removes the rate limit from the store +// Errors if: +// - Rate limit does not exist (as identified by the `channel_id` and `denom`) +RemoveRateLimit() +{"denom": string, "channel_id": string} +``` + +## Queries + +```go +// Queries all rate limits +// CLI: +// binaryd q ratelimit list-rate-limits +// API: +// /Stride-Labs/ibc-rate-limiting/ratelimit/ratelimits +QueryRateLimits() + +// Queries a specific rate limit given a ChannelID and Denom +// CLI: +// binaryd q ratelimit rate-limit [denom] [channel-id] +// API: +// /Stride-Labs/ibc-rate-limiting/ratelimit/ratelimit/{denom}/{channel_id} +QueryRateLimit(denom string, channelId string) + +// Queries all rate limits associated with a given host chain +// CLI: +// binaryd q ratelimit rate-limits-by-chain [chain-id] +// API: +// /Stride-Labs/ibc-rate-limiting/ratelimit/ratelimits/{chain_id} +QueryRateLimitsByChainId(chainId string) +``` diff --git a/modules/rate-limiting/client/cli/query.go b/modules/rate-limiting/client/cli/query.go new file mode 100644 index 00000000..c348fda2 --- /dev/null +++ b/modules/rate-limiting/client/cli/query.go @@ -0,0 +1,149 @@ +package cli + +import ( + "context" + "fmt" + "strings" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/version" +) + +const ( + FlagDenom = "denom" +) + +// GetQueryCmd returns the cli query commands for this module. +func GetQueryCmd() *cobra.Command { + // Group ratelimit queries under a subcommand + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + GetCmdQueryRateLimit(), + GetCmdQueryAllRateLimits(), + GetCmdQueryRateLimitsByChainId(), + ) + return cmd +} + +// GetCmdQueryRateLimit implements a command to query rate limits by channel-id and denom +func GetCmdQueryRateLimit() *cobra.Command { + cmd := &cobra.Command{ + Use: "rate-limit [channel-id]", + Short: "Query rate limits by channel-id and denom", + Long: strings.TrimSpace( + fmt.Sprintf(`Query rate limits by channel-id and denom. + +Example: + $ %s query %s rate-limit [channel-id] + $ %s query %s rate-limit [channel-id] --denom=[denom] +`, + version.AppName, types.ModuleName, version.AppName, types.ModuleName, + ), + ), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + channelId := args[0] + denom, err := cmd.Flags().GetString(FlagDenom) + if err != nil { + return err + } + + clientCtx := client.GetClientContextFromCmd(cmd) + queryClient := types.NewQueryClient(clientCtx) + + if denom == "" { + req := &types.QueryRateLimitsByChannelIdRequest{ + ChannelId: channelId, + } + res, err := queryClient.RateLimitsByChannelId(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintObjectLegacy(res.RateLimits) + } + + req := &types.QueryRateLimitRequest{ + Denom: denom, + ChannelId: channelId, + } + res, err := queryClient.RateLimit(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res.RateLimit) + }, + } + + cmd.Flags().String(FlagDenom, "", "The denom identifying a specific rate limit") + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// GetCmdQueryAllRateLimits return all available rate limits. +func GetCmdQueryAllRateLimits() *cobra.Command { + cmd := &cobra.Command{ + Use: "list-rate-limits", + Short: "Query all rate limits", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QueryAllRateLimitsRequest{} + res, err := queryClient.AllRateLimits(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// GetCmdQueryRateLimitsByChainId return all rate limits that exist between Stride +// and the specified ChainId +func GetCmdQueryRateLimitsByChainId() *cobra.Command { + cmd := &cobra.Command{ + Use: "rate-limits-by-chain [chain-id]", + Short: "Query all rate limits with the given ChainID", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + chainId := args[0] + + clientCtx := client.GetClientContextFromCmd(cmd) + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QueryRateLimitsByChainIdRequest{ + ChainId: chainId, + } + res, err := queryClient.RateLimitsByChainId(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/modules/rate-limiting/go.mod b/modules/rate-limiting/go.mod new file mode 100644 index 00000000..f77207eb --- /dev/null +++ b/modules/rate-limiting/go.mod @@ -0,0 +1,194 @@ +module github.com/cosmos/ibc-apps/modules/rate-limiting/v7 + +go 1.21 + +require ( + cosmossdk.io/api v0.3.1 + cosmossdk.io/errors v1.0.0 + cosmossdk.io/log v1.2.1 + cosmossdk.io/math v1.1.2 + cosmossdk.io/tools/rosetta v0.2.1 + github.com/cometbft/cometbft v0.37.2 + github.com/cometbft/cometbft-db v0.8.0 + github.com/cosmos/cosmos-proto v1.0.0-beta.2 + github.com/cosmos/cosmos-sdk v0.47.5 + github.com/cosmos/gogoproto v1.4.10 + github.com/cosmos/ibc-go/v7 v7.3.1 + github.com/golang/protobuf v1.5.3 + github.com/gorilla/mux v1.8.0 + github.com/grpc-ecosystem/grpc-gateway v1.16.0 + github.com/rakyll/statik v0.1.7 + github.com/spf13/cast v1.5.1 + github.com/spf13/cobra v1.7.0 + github.com/stretchr/testify v1.8.4 + google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 + google.golang.org/grpc v1.58.2 +) + +require ( + cloud.google.com/go v0.110.4 // indirect + cloud.google.com/go/compute v1.21.0 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/iam v1.1.1 // indirect + cloud.google.com/go/storage v1.30.1 // indirect + cosmossdk.io/core v0.5.1 // indirect + cosmossdk.io/depinject v1.0.0-alpha.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/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/aws/aws-sdk-go v1.44.203 // 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/btcsuite/btcd/btcec/v2 v2.3.2 // indirect + github.com/cenkalti/backoff/v4 v4.1.3 // indirect + github.com/cespare/xxhash v1.1.0 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/chzyer/readline v1.5.1 // indirect + github.com/cockroachdb/apd/v2 v2.0.2 // indirect + github.com/cockroachdb/errors v1.10.0 // indirect + github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect + github.com/cockroachdb/redact v1.1.5 // indirect + github.com/coinbase/rosetta-sdk-go/types v1.0.0 // indirect + github.com/confio/ics23/go v0.9.0 // indirect + github.com/cosmos/btcutil v1.0.5 // indirect + github.com/cosmos/go-bip39 v1.0.0 // indirect + github.com/cosmos/gogogateway v1.2.0 // indirect + github.com/cosmos/iavl v0.20.0 // indirect + github.com/cosmos/ics23/go v0.10.0 // indirect + github.com/cosmos/ledger-cosmos-go v0.12.2 // indirect + github.com/cosmos/rosetta-sdk-go v0.10.0 // indirect + github.com/creachadair/taskgroup v0.4.2 // indirect + github.com/danieljoos/wincred v1.1.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect + github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect + github.com/dgraph-io/badger/v2 v2.2007.4 // indirect + github.com/dgraph-io/ristretto v0.1.1 // indirect + github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/dvsekhvalnov/jose2go v1.5.0 // indirect + github.com/felixge/httpsnoop v1.0.2 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/getsentry/sentry-go v0.23.0 // indirect + github.com/go-kit/kit v0.12.0 // indirect + github.com/go-kit/log v0.2.1 // indirect + github.com/go-logfmt/logfmt v0.6.0 // 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/glog v1.1.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/mock v1.6.0 // indirect + github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect + github.com/google/btree v1.1.2 // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/orderedcode v0.0.1 // indirect + github.com/google/s2a-go v0.1.4 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect + github.com/googleapis/gax-go/v2 v2.11.0 // indirect + github.com/gorilla/handlers v1.5.1 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect + github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect + github.com/gtank/merlin v0.1.1 // indirect + github.com/gtank/ristretto255 v0.1.2 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-getter v1.7.1 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-safetemp v1.0.0 // indirect + github.com/hashicorp/go-uuid v1.0.2 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hdevalence/ed25519consensus v0.1.0 // indirect + github.com/huandu/skiplist v1.2.0 // indirect + github.com/improbable-eng/grpc-web v0.15.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/jmhodges/levigo v1.0.0 // indirect + github.com/klauspost/compress v1.16.3 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/lib/pq v1.10.7 // indirect + github.com/libp2p/go-buffer-pool v0.1.0 // indirect + github.com/linxGnu/grocksdb v1.7.16 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/manifoldco/promptui v0.9.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect + github.com/minio/highwayhash v1.0.2 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mtibben/percent v0.2.1 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.14.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect + github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect + github.com/rs/cors v1.8.3 // indirect + github.com/rs/zerolog v1.30.0 // indirect + github.com/sasha-s/go-deadlock v0.3.1 // indirect + github.com/spf13/afero v1.9.5 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.16.0 // indirect + github.com/subosito/gotenv v1.4.2 // 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.6.0 // indirect + github.com/ulikunitz/xz v0.5.11 // indirect + github.com/zondax/hid v0.9.1 // indirect + github.com/zondax/ledger-go v0.14.1 // indirect + go.etcd.io/bbolt v1.3.7 // indirect + go.opencensus.io v0.24.0 // indirect + golang.org/x/crypto v0.11.0 // indirect + golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/oauth2 v0.10.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/term v0.10.0 // indirect + golang.org/x/text v0.12.0 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + google.golang.org/api v0.126.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/protobuf v1.31.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + nhooyr.io/websocket v1.8.6 // indirect + pgregory.net/rapid v1.1.0 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) + +replace ( + // Use the keyring specified by the cosmos-sdk + github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 + github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.22.2 //indirect + // fork SDK to fix SDKv0.47 Distribution Bug + // TODO - Remove this patch and update Tokens in a subsequent upgrade handler + github.com/cosmos/cosmos-sdk => github.com/Stride-Labs/cosmos-sdk v0.47.5-stride-distribution-fix-0 + + // Add additional verification check to ensure an account is a BaseAccount type before converting + // it to a vesting account: https://github.com/Stride-Labs/vesting/pull/1 + github.com/evmos/vesting => github.com/Stride-Labs/vesting v1.0.0-check-base-account + + // fork cast to add additional error checking + github.com/spf13/cast => github.com/Stride-Labs/cast v0.0.3 + + github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 +) diff --git a/modules/rate-limiting/go.sum b/modules/rate-limiting/go.sum new file mode 100644 index 00000000..6fda1cd3 --- /dev/null +++ b/modules/rate-limiting/go.sum @@ -0,0 +1,1670 @@ +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.44.3/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.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +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.110.4 h1:1JYyxKMN9hd5dR2MYTPWkGUgcoxVVhg0LKNKEo0qvmk= +cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +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.21.0 h1:JNBsyXVoOoNJtTQcnEY5uYpZIbeCTYIeDe0Xh1bySMk= +cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +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.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= +cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +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.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +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.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM= +cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= +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.3.1 h1:NNiOclKRR0AOlO4KIqeaG6PS6kswOMhHD0ir0SscNXE= +cosmossdk.io/api v0.3.1/go.mod h1:DfHfMkiNA2Uhy8fj0JJlOCYOBp4eWUUJ1te5zBGNyIw= +cosmossdk.io/core v0.5.1 h1:vQVtFrIYOQJDV3f7rw4pjjVqc1id4+mE0L9hHP66pyI= +cosmossdk.io/core v0.5.1/go.mod h1:KZtwHCLjcFuo0nmDc24Xy6CRNEL9Vl/MeimQ2aC7NLE= +cosmossdk.io/depinject v1.0.0-alpha.4 h1:PLNp8ZYAMPTUKyG9IK2hsbciDWqna2z1Wsl98okJopc= +cosmossdk.io/depinject v1.0.0-alpha.4/go.mod h1:HeDk7IkR5ckZ3lMGs/o91AVUc7E596vMaOmslGFM3yU= +cosmossdk.io/errors v1.0.0 h1:nxF07lmlBbB8NKQhtJ+sJm6ef5uV1XkvPXG2bUntb04= +cosmossdk.io/errors v1.0.0/go.mod h1:+hJZLuhdDE0pYN8HkOrVNwrIOYvUGnn6+4fjnJs/oV0= +cosmossdk.io/log v1.2.1 h1:Xc1GgTCicniwmMiKwDxUjO4eLhPxoVdI9vtMW8Ti/uk= +cosmossdk.io/log v1.2.1/go.mod h1:GNSCc/6+DhFIj1aLn/j7Id7PaO8DzNylUZoOYBL9+I4= +cosmossdk.io/math v1.1.2 h1:ORZetZCTyWkI5GlZ6CZS28fMHi83ZYf+A2vVnHNzZBM= +cosmossdk.io/math v1.1.2/go.mod h1:l2Gnda87F0su8a/7FEKJfFdJrM0JZRXQaohlgJeyQh0= +cosmossdk.io/tools/rosetta v0.2.1 h1:ddOMatOH+pbxWbrGJKRAawdBkPYLfKXutK9IETnjYxw= +cosmossdk.io/tools/rosetta v0.2.1/go.mod h1:Pqdc1FdvkNV3LcNIkYWt2RQY6IP1ge6YWZk8MhhO9Hw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= +filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= +github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +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 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +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/Stride-Labs/cast v0.0.3 h1:eM3n/t3hSxb+iw9LDo3r/uGBp3w4U7wPv40GKMtJ1dI= +github.com/Stride-Labs/cast v0.0.3/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/Stride-Labs/cosmos-sdk v0.47.5-stride-distribution-fix-0 h1:vFiTvB2FwOWvTmHM8WQ4rS3dV/wniIRYYQ3dkS/ZikA= +github.com/Stride-Labs/cosmos-sdk v0.47.5-stride-distribution-fix-0/go.mod h1:EHwCeN9IXonsjKcjpS12MqeStdZvIdxt3VYXhus3G3c= +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.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I= +github.com/adlio/schema v1.3.3/go.mod h1:1EsRssiv9/Ce2CMzq5DoL7RiMshhuigQxrR4DMV9fHg= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +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.203 h1:pcsP805b9acL3wUqa4JR2vg1k2wnItkDYNvfmcy6F+U= +github.com/aws/aws-sdk-go v1.44.203/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +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= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2gVpmOtVTJZNodLdLQLn/KsJqFvXwnd/s= +github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= +github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcutil v1.1.2 h1:XLMbX8JQEiwMcYft2EGi8zPUkoa0abKIU6/BJSRsjzQ= +github.com/btcsuite/btcd/btcutil v1.1.2/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= +github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= +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.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= +github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/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= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= +github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/errors v1.10.0 h1:lfxS8zZz1+OjtV4MtNWgboi/W5tyLEB6VQZBXN+0VUU= +github.com/cockroachdb/errors v1.10.0/go.mod h1:lknhIsEVQ9Ss/qKDBQS/UqFSvPQjOwNq2qyKAxtHRqE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= +github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= +github.com/cometbft/cometbft v0.37.2 h1:XB0yyHGT0lwmJlFmM4+rsRnczPlHoAKFX6K8Zgc2/Jc= +github.com/cometbft/cometbft v0.37.2/go.mod h1:Y2MMMN//O5K4YKd8ze4r9jmk4Y7h0ajqILXbH5JQFVs= +github.com/cometbft/cometbft-db v0.8.0 h1:vUMDaH3ApkX8m0KZvOFFy9b5DZHBAjsnEuo9AKVZpjo= +github.com/cometbft/cometbft-db v0.8.0/go.mod h1:6ASCP4pfhmrCBpfk01/9E1SI29nD3HfVHrY4PG8x5c0= +github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= +github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= +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/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +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= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= +github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= +github.com/cosmos/cosmos-proto v1.0.0-beta.2 h1:X3OKvWgK9Gsejo0F1qs5l8Qn6xJV/AzgIWR2wZ8Nua8= +github.com/cosmos/cosmos-proto v1.0.0-beta.2/go.mod h1:+XRCLJ14pr5HFEHIUcn51IKXD1Fy3rkEQqt4WqmN4V0= +github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= +github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= +github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= +github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= +github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ4GUkT+tbFI= +github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= +github.com/cosmos/gogoproto v1.4.10 h1:QH/yT8X+c0F4ZDacDv3z+xE3WU1P1Z3wQoLMBRJoKuI= +github.com/cosmos/gogoproto v1.4.10/go.mod h1:3aAZzeRWpAwr+SS/LLkICX2/kDFyaYVzckBDzygIxek= +github.com/cosmos/iavl v0.20.0 h1:fTVznVlepH0KK8NyKq8w+U7c2L6jofa27aFX6YGlm38= +github.com/cosmos/iavl v0.20.0/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A= +github.com/cosmos/ibc-go/v7 v7.3.1 h1:bil1IjnHdyWDASFYKfwdRiNtFP6WK3osW7QFEAgU4I8= +github.com/cosmos/ibc-go/v7 v7.3.1/go.mod h1:wvx4pPBofe5ZdMNV3OFRxSI4auEP5Qfqf8JXLLNV04g= +github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= +github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0= +github.com/cosmos/keyring v1.2.0 h1:8C1lBP9xhImmIabyXW4c3vFjjLiBdGCmfLUfeZlV1Yo= +github.com/cosmos/keyring v1.2.0/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= +github.com/cosmos/ledger-cosmos-go v0.12.2 h1:/XYaBlE2BJxtvpkHiBm97gFGSGmYGKunKyF3nNqAXZA= +github.com/cosmos/ledger-cosmos-go v0.12.2/go.mod h1:ZcqYgnfNJ6lAXe4HPtWgarNEY+B74i+2/8MhZw4ziiI= +github.com/cosmos/rosetta-sdk-go v0.10.0 h1:E5RhTruuoA7KTIXUcMicL76cffyeoyvNybzUGSKFTcM= +github.com/cosmos/rosetta-sdk-go v0.10.0/go.mod h1:SImAZkb96YbwvoRkzSMQB6noNJXFgWl/ENIznEoYQI4= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creachadair/taskgroup v0.4.2 h1:jsBLdAJE42asreGss2xZGZ8fJra7WtwnHWeJFxv2Li8= +github.com/creachadair/taskgroup v0.4.2/go.mod h1:qiXUOSrbwAY3u0JPGTzObbE3yf9hcXHDKBZ2ZjpCbgM= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= +github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= +github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= +github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= +github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= +github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= +github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/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.0/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= +github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= +github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +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/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= +github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/getsentry/sentry-go v0.23.0 h1:dn+QRCeJv4pPt9OjVXiMcGIBIefaTJPw/h0bZWO05nE= +github.com/getsentry/sentry-go v0.23.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= +github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= +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.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= +github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= +github.com/go-kit/log v0.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= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +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-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= +github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.4.1-0.20201022092350-68b0159b7869/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= +github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/groupcache v0.0.0-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= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +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= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.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.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +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= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.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 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +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-20201218002935-b9804c9f04c2/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-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.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= +github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +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 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.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.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +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.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4= +github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +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.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= +github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= +github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= +github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= +github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= +github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-getter v1.7.1 h1:SWiSWN/42qdpR0MdhaOc/bLR48PLuP1ZQtYLRlM69uY= +github.com/hashicorp/go-getter v1.7.1/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= +github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +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/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= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= +github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= +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/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +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= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.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.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= +github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= +github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= +github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/linxGnu/grocksdb v1.7.16 h1:Q2co1xrpdkr5Hx3Fp+f+f7fRGhQFQhvi/+226dtLmA8= +github.com/linxGnu/grocksdb v1.7.16/go.mod h1:JkS7pl5qWpGpuVb3bPqTz8nC12X3YtPZT+Xq7+QfQo4= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +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.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 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/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/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= +github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94= +github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= +github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= +github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= +github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod h1:x5OoJHDHqxHS801UIuhqGl6QdSAEJvtausosHSdazIo= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q= +github.com/onsi/gomega v1.20.0/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= +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.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w= +github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= +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= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +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= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= +github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 h1:hDSdbBuw3Lefr6R18ax0tZ2BJeNB3NehB3trOwYBsdU= +github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= +github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= +github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= +github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= +github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +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.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/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/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= +github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= +github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= +github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= +github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg= +github.com/tidwall/btree v1.6.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 v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +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/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +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.1 h1:gQe66rtmyZ8VeGFcOpbuH3r7erYtNEAezCAYu8LdkJo= +github.com/zondax/hid v0.9.1/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= +github.com/zondax/ledger-go v0.14.1 h1:Pip65OOl4iJ84WTpA4BKChvOufMhhbxED3BaihoZN4c= +github.com/zondax/ledger-go v0.14.1/go.mod h1:fZ3Dqg6qcdXWSOJFKMG8GCTnD7slO/RL2feOQv8K320= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +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/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/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +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= +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-20181203042331-505ab145d0a9/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-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +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-20230711153332-06a737ee72cb h1:xIApU0ow1zwMa2uL1VDNeQlNVFTWMQxZUZCMDy0Q4Us= +golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-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.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-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-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-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-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-20211112202133-69e39bad7dc2/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.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +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.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/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= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +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-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-20210225134936-a50acf3fe073/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-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-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-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.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14/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.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +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.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +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/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-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-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-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.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.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +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.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o= +google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= +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 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +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-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-20210108203827-ffc7fda8c3d7/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-20210226172003-ab064af71705/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-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g= +google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= +google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw= +google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.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.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I= +google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +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= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.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.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/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= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY= +gotest.tools/v3 v3.5.0/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.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/modules/rate-limiting/ibc_middleware.go b/modules/rate-limiting/ibc_middleware.go new file mode 100644 index 00000000..39beb346 --- /dev/null +++ b/modules/rate-limiting/ibc_middleware.go @@ -0,0 +1,184 @@ +package ratelimit + +import ( + "fmt" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/keeper" + + sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + "github.com/cosmos/ibc-go/v7/modules/core/exported" +) + +var _ porttypes.Middleware = &IBCMiddleware{} + +type IBCMiddleware struct { + app porttypes.IBCModule + keeper keeper.Keeper +} + +func NewIBCMiddleware(k keeper.Keeper, app porttypes.IBCModule) IBCMiddleware { + return IBCMiddleware{ + app: app, + keeper: k, + } +} + +// OnChanOpenInit implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanOpenInit(ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID string, + channelID string, + channelCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version string, +) (string, error) { + return im.app.OnChanOpenInit( + ctx, + order, + connectionHops, + portID, + channelID, + channelCap, + counterparty, + version, + ) +} + +// OnChanOpenTry implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + channelCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + counterpartyVersion string, +) (string, error) { + return im.app.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion) +} + +// OnChanOpenAck implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyChannelID string, + counterpartyVersion string, +) error { + return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) +} + +// OnChanOpenConfirm implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return im.app.OnChanOpenConfirm(ctx, portID, channelID) +} + +// OnChanCloseInit implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanCloseInit( + ctx sdk.Context, + portID, + channelID string, +) error { + return im.app.OnChanCloseInit(ctx, portID, channelID) +} + +// OnChanCloseConfirm implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return im.app.OnChanCloseConfirm(ctx, portID, channelID) +} + +// OnRecvPacket implements the IBCMiddleware interface +func (im IBCMiddleware) OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, +) exported.Acknowledgement { + // Check if the packet would cause the rate limit to be exceeded, + // and if so, return an ack error + if err := im.keeper.ReceiveRateLimitedPacket(ctx, packet); err != nil { + im.keeper.Logger(ctx).Error(fmt.Sprintf("ICS20 packet receive was denied: %s", err.Error())) + return channeltypes.NewErrorAcknowledgement(err) + } + + // If the packet was not rate-limited, pass it down to the Transfer OnRecvPacket callback + return im.app.OnRecvPacket(ctx, packet, relayer) +} + +// OnAcknowledgementPacket implements the IBCMiddleware interface +func (im IBCMiddleware) OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, + relayer sdk.AccAddress, +) error { + if err := im.keeper.AcknowledgeRateLimitedPacket(ctx, packet, acknowledgement); err != nil { + im.keeper.Logger(ctx).Error(fmt.Sprintf("ICS20 RateLimited OnAckPacket failed: %s", err.Error())) + return err + } + return im.app.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) +} + +// OnTimeoutPacket implements the IBCMiddleware interface +func (im IBCMiddleware) OnTimeoutPacket( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, +) error { + if err := im.keeper.TimeoutRateLimitedPacket(ctx, packet); err != nil { + im.keeper.Logger(ctx).Error(fmt.Sprintf("ICS20 RateLimited OnTimeoutPacket failed: %s", err.Error())) + return err + } + return im.app.OnTimeoutPacket(ctx, packet, relayer) +} + +// SendPacket implements the ICS4 Wrapper interface +// Rate-limited SendPacket found in RateLimit Keeper +func (im IBCMiddleware) SendPacket( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + sourcePort string, + sourceChannel string, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + data []byte, +) (sequence uint64, err error) { + return im.keeper.SendPacket( + ctx, + chanCap, + sourcePort, + sourceChannel, + timeoutHeight, + timeoutTimestamp, + data, + ) +} + +// WriteAcknowledgement implements the ICS4 Wrapper interface +func (im IBCMiddleware) WriteAcknowledgement( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + packet exported.PacketI, + ack exported.Acknowledgement, +) error { + return im.keeper.WriteAcknowledgement(ctx, chanCap, packet, ack) +} + +// GetAppVersion returns the application version of the underlying application +func (i IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { + return i.keeper.GetAppVersion(ctx, portID, channelID) +} diff --git a/modules/rate-limiting/keeper/abci.go b/modules/rate-limiting/keeper/abci.go new file mode 100644 index 00000000..79a20bb5 --- /dev/null +++ b/modules/rate-limiting/keeper/abci.go @@ -0,0 +1,22 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Before each hour epoch, check if any of the rate limits have expired, +// and reset them if they have +func (k Keeper) BeginBlocker(ctx sdk.Context) { + if epochStarting, epochNumber := k.CheckHourEpochStarting(ctx); epochStarting { + for _, rateLimit := range k.GetAllRateLimits(ctx) { + if rateLimit.Quota.DurationHours != 0 && epochNumber%rateLimit.Quota.DurationHours == 0 { + err := k.ResetRateLimit(ctx, rateLimit.Path.Denom, rateLimit.Path.ChannelId) + if err != nil { + k.Logger(ctx).Error(fmt.Sprintf("Unable to reset quota for Denom: %s, ChannelId: %s", rateLimit.Path.Denom, rateLimit.Path.ChannelId)) + } + } + } + } +} diff --git a/modules/rate-limiting/keeper/abci_test.go b/modules/rate-limiting/keeper/abci_test.go new file mode 100644 index 00000000..9be2b9cb --- /dev/null +++ b/modules/rate-limiting/keeper/abci_test.go @@ -0,0 +1,78 @@ +package keeper_test + +import ( + "fmt" + "time" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + sdkmath "cosmossdk.io/math" +) + +// Store a rate limit with a non-zero flow for each duration +func (s *KeeperTestSuite) resetRateLimits(denom string, durations []uint64, nonZeroFlow int64) { + // Add/reset rate limit with a quota duration hours for each duration in the list + for i, duration := range durations { + channelId := fmt.Sprintf("channel-%d", i) + + s.App.RatelimitKeeper.SetRateLimit(s.Ctx, types.RateLimit{ + Path: &types.Path{ + Denom: denom, + ChannelId: channelId, + }, + Quota: &types.Quota{ + DurationHours: duration, + }, + Flow: &types.Flow{ + Inflow: sdkmath.NewInt(nonZeroFlow), + Outflow: sdkmath.NewInt(nonZeroFlow), + ChannelValue: sdkmath.NewInt(100), + }, + }) + } +} + +func (s *KeeperTestSuite) TestBeginBlocker() { + // We'll create three rate limits with different durations + // And then pass in epoch ids that will cause each to trigger a reset in order + // i.e. epochId 2 will only cause duration 2 to trigger (2 % 2 == 0; and 9 % 2 != 0; 25 % 2 != 0), + // epochId 9, will only cause duration 3 to trigger (9 % 2 != 0; and 9 % 3 == 0; 25 % 3 != 0) + // epochId 25, will only cause duration 5 to trigger (9 % 5 != 0; and 9 % 5 != 0; 25 % 5 == 0) + durations := []uint64{2, 3, 5} + epochIds := []uint64{2, 9, 25} + nonZeroFlow := int64(10) + + blockTime := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC) + s.Ctx = s.Ctx.WithBlockTime(blockTime) + + for i, epochId := range epochIds { + // First reset the rate limits to they have a non-zero flow + s.resetRateLimits(denom, durations, nonZeroFlow) + + duration := durations[i] + channelIdFromResetRateLimit := fmt.Sprintf("channel-%d", i) + + // Setup epochs so that the hook triggers + // (epoch start time + duration must be before block time) + s.App.RatelimitKeeper.SetHourEpoch(s.Ctx, types.HourEpoch{ + EpochNumber: epochId - 1, + Duration: time.Minute, + EpochStartTime: blockTime.Add(-2 * time.Minute), + }) + s.App.RatelimitKeeper.BeginBlocker(s.Ctx) + + // Check rate limits (only one rate limit should reset for each hook trigger) + rateLimits := s.App.RatelimitKeeper.GetAllRateLimits(s.Ctx) + for _, rateLimit := range rateLimits { + context := fmt.Sprintf("duration: %d, epoch: %d", duration, epochId) + + if rateLimit.Path.ChannelId == channelIdFromResetRateLimit { + s.Require().Equal(int64(0), rateLimit.Flow.Inflow.Int64(), "inflow was not reset to 0 - %s", context) + s.Require().Equal(int64(0), rateLimit.Flow.Outflow.Int64(), "outflow was not reset to 0 - %s", context) + } else { + s.Require().Equal(nonZeroFlow, rateLimit.Flow.Inflow.Int64(), "inflow should have been left unchanged - %s", context) + s.Require().Equal(nonZeroFlow, rateLimit.Flow.Outflow.Int64(), "outflow should have been left unchanged - %s", context) + } + } + } +} diff --git a/modules/rate-limiting/keeper/blacklist.go b/modules/rate-limiting/keeper/blacklist.go new file mode 100644 index 00000000..5296ae6c --- /dev/null +++ b/modules/rate-limiting/keeper/blacklist.go @@ -0,0 +1,48 @@ +package keeper + +import ( + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Adds a denom to a blacklist to prevent all IBC transfers with this denom +func (k Keeper) AddDenomToBlacklist(ctx sdk.Context, denom string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomBlacklistKeyPrefix) + key := types.KeyPrefix(denom) + store.Set(key, []byte{1}) +} + +// Removes a denom from a blacklist to re-enable IBC transfers for that denom +func (k Keeper) RemoveDenomFromBlacklist(ctx sdk.Context, denom string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomBlacklistKeyPrefix) + key := types.KeyPrefix(denom) + store.Delete(key) +} + +// Check if a denom is currently blacklisted +func (k Keeper) IsDenomBlacklisted(ctx sdk.Context, denom string) bool { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomBlacklistKeyPrefix) + + key := types.KeyPrefix(denom) + value := store.Get(key) + found := len(value) != 0 + + return found +} + +// Get all the blacklisted denoms +func (k Keeper) GetAllBlacklistedDenoms(ctx sdk.Context) []string { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomBlacklistKeyPrefix) + + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + allBlacklistedDenoms := []string{} + for ; iterator.Valid(); iterator.Next() { + allBlacklistedDenoms = append(allBlacklistedDenoms, string(iterator.Key())) + } + + return allBlacklistedDenoms +} diff --git a/modules/rate-limiting/keeper/blacklist_test.go b/modules/rate-limiting/keeper/blacklist_test.go new file mode 100644 index 00000000..cbbe9952 --- /dev/null +++ b/modules/rate-limiting/keeper/blacklist_test.go @@ -0,0 +1,55 @@ +package keeper_test + +// Helper function to check if an element is in an array +func isInArray(element string, arr []string) bool { + for _, e := range arr { + if e == element { + return true + } + } + return false +} + +func (s *KeeperTestSuite) TestDenomBlacklist() { + allDenoms := []string{"denom1", "denom2", "denom3", "denom4"} + denomsToBlacklist := []string{"denom1", "denom3"} + + // No denoms are currently blacklisted + for _, denom := range allDenoms { + isBlacklisted := s.App.RatelimitKeeper.IsDenomBlacklisted(s.Ctx, denom) + s.Require().False(isBlacklisted, "%s should not be blacklisted yet", denom) + } + + // Blacklist two denoms + for _, denom := range denomsToBlacklist { + s.App.RatelimitKeeper.AddDenomToBlacklist(s.Ctx, denom) + } + + // Confirm half the list was blacklisted and the others were not + for _, denom := range allDenoms { + isBlacklisted := s.App.RatelimitKeeper.IsDenomBlacklisted(s.Ctx, denom) + + if isInArray(denom, denomsToBlacklist) { + s.Require().True(isBlacklisted, "%s should have been blacklisted", denom) + } else { + s.Require().False(isBlacklisted, "%s should not have been blacklisted", denom) + } + } + actualBlacklistedDenoms := s.App.RatelimitKeeper.GetAllBlacklistedDenoms(s.Ctx) + s.Require().Len(actualBlacklistedDenoms, len(denomsToBlacklist), "number of blacklisted denoms") + s.Require().ElementsMatch(denomsToBlacklist, actualBlacklistedDenoms, "list of blacklisted denoms") + + // Finally, remove denoms from blacklist and confirm they were removed + for _, denom := range denomsToBlacklist { + s.App.RatelimitKeeper.RemoveDenomFromBlacklist(s.Ctx, denom) + } + for _, denom := range allDenoms { + isBlacklisted := s.App.RatelimitKeeper.IsDenomBlacklisted(s.Ctx, denom) + + if isInArray(denom, denomsToBlacklist) { + s.Require().False(isBlacklisted, "%s should have been removed from the blacklist", denom) + } else { + s.Require().False(isBlacklisted, "%s should never have been blacklisted", denom) + } + } +} diff --git a/modules/rate-limiting/keeper/epoch.go b/modules/rate-limiting/keeper/epoch.go new file mode 100644 index 00000000..2b61b6cd --- /dev/null +++ b/modules/rate-limiting/keeper/epoch.go @@ -0,0 +1,48 @@ +package keeper + +import ( + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Stores the hour epoch +func (k Keeper) SetHourEpoch(ctx sdk.Context, epoch types.HourEpoch) { + store := ctx.KVStore(k.storeKey) + epochBz := k.cdc.MustMarshal(&epoch) + store.Set(types.HourEpochKey, epochBz) +} + +// Reads the hour epoch from the store +func (k Keeper) GetHourEpoch(ctx sdk.Context) (epoch types.HourEpoch) { + store := ctx.KVStore(k.storeKey) + + epochBz := store.Get(types.HourEpochKey) + if len(epochBz) == 0 { + panic("Hour epoch not found") + } + + k.cdc.MustUnmarshal(epochBz, &epoch) + return epoch +} + +// Checks if it's time to start the new hour epoch +func (k Keeper) CheckHourEpochStarting(ctx sdk.Context) (epochStarting bool, epochNumber uint64) { + hourEpoch := k.GetHourEpoch(ctx) + + // If the block time is later than the current epoch start time + epoch duration, + // move onto the next epoch by incrementing the epoch number, height, and start time + currentEpochEndTime := hourEpoch.EpochStartTime.Add(hourEpoch.Duration) + shouldNextEpochStart := ctx.BlockTime().After(currentEpochEndTime) + if shouldNextEpochStart { + hourEpoch.EpochNumber++ + hourEpoch.EpochStartTime = currentEpochEndTime + hourEpoch.EpochStartHeight = ctx.BlockHeight() + + k.SetHourEpoch(ctx, hourEpoch) + return true, hourEpoch.EpochNumber + } + + // Otherwise, indicate that a new epoch is not starting + return false, 0 +} diff --git a/modules/rate-limiting/keeper/epoch_test.go b/modules/rate-limiting/keeper/epoch_test.go new file mode 100644 index 00000000..c6f3179f --- /dev/null +++ b/modules/rate-limiting/keeper/epoch_test.go @@ -0,0 +1,97 @@ +package keeper_test + +import ( + "time" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" +) + +// Tests Get/Set Hour epoch +func (s *KeeperTestSuite) TestHourEpoch() { + expectedHourEpoch := types.HourEpoch{ + Duration: time.Hour, + EpochNumber: 1, + EpochStartTime: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), + EpochStartHeight: 10, + } + s.App.RatelimitKeeper.SetHourEpoch(s.Ctx, expectedHourEpoch) + + actualHourEpoch := s.App.RatelimitKeeper.GetHourEpoch(s.Ctx) + s.Require().Equal(expectedHourEpoch, actualHourEpoch, "hour epoch") +} + +func (s *KeeperTestSuite) TestCheckHourEpochStarting() { + epochStartTime := time.Date(2024, 1, 1, 0, 0, 1, 0, time.UTC) + blockHeight := int64(10) + duration := time.Minute + + initialEpoch := types.HourEpoch{ + EpochNumber: 10, + EpochStartTime: epochStartTime, + Duration: duration, + } + nextEpoch := types.HourEpoch{ + EpochNumber: initialEpoch.EpochNumber + 1, // epoch number increments + EpochStartTime: epochStartTime.Add(duration), // start time increments by duration + EpochStartHeight: blockHeight, // height gets current block height + Duration: duration, + } + + testCases := []struct { + name string + blockTime time.Time + expectedEpochStarting bool + }{ + { + name: "in middle of epoch", + blockTime: epochStartTime.Add(duration / 2), // halfway through epoch + expectedEpochStarting: false, + }, + { + name: "right before epoch boundary", + blockTime: epochStartTime.Add(duration).Add(-1 * time.Second), // 1 second before epoch + expectedEpochStarting: false, + }, + { + name: "at epoch boundary", + blockTime: epochStartTime.Add(duration), // at epoch boundary + expectedEpochStarting: false, + }, + { + name: "right after epoch boundary", + blockTime: epochStartTime.Add(duration).Add(time.Second), // one second after epoch boundary + expectedEpochStarting: true, + }, + { + name: "in middle of next epoch", + blockTime: epochStartTime.Add(duration).Add(duration / 2), // halfway through next epoch + expectedEpochStarting: true, + }, + { + name: "next epoch skipped", + blockTime: epochStartTime.Add(duration * 10), // way after next epoch (still increments only once) + expectedEpochStarting: true, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + s.Ctx = s.Ctx.WithBlockTime(tc.blockTime) + s.Ctx = s.Ctx.WithBlockHeight(blockHeight) + + s.App.RatelimitKeeper.SetHourEpoch(s.Ctx, initialEpoch) + + actualStarting, actualEpochNumber := s.App.RatelimitKeeper.CheckHourEpochStarting(s.Ctx) + s.Require().Equal(tc.expectedEpochStarting, actualStarting, "epoch starting") + + expectedEpoch := initialEpoch + if tc.expectedEpochStarting { + expectedEpoch = nextEpoch + s.Require().Equal(expectedEpoch.EpochNumber, actualEpochNumber, "epoch number") + } + + actualHourEpoch := s.App.RatelimitKeeper.GetHourEpoch(s.Ctx) + s.Require().Equal(expectedEpoch, actualHourEpoch, "hour epoch") + }) + } +} diff --git a/modules/rate-limiting/keeper/events.go b/modules/rate-limiting/keeper/events.go new file mode 100644 index 00000000..4024aeeb --- /dev/null +++ b/modules/rate-limiting/keeper/events.go @@ -0,0 +1,27 @@ +package keeper + +import ( + "strings" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// If the rate limit is exceeded or the denom is blacklisted, we emit an event +func EmitTransferDeniedEvent(ctx sdk.Context, reason, denom, channelId string, direction types.PacketDirection, amount sdkmath.Int, err error) { + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTransferDenied, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(types.AttributeKeyReason, reason), + sdk.NewAttribute(types.AttributeKeyAction, strings.ToLower(direction.String())), // packet_send or packet_recv + sdk.NewAttribute(types.AttributeKeyDenom, denom), + sdk.NewAttribute(types.AttributeKeyChannel, channelId), + sdk.NewAttribute(types.AttributeKeyAmount, amount.String()), + sdk.NewAttribute(types.AttributeKeyError, err.Error()), + ), + ) +} diff --git a/modules/rate-limiting/keeper/flow.go b/modules/rate-limiting/keeper/flow.go new file mode 100644 index 00000000..8d9b2f77 --- /dev/null +++ b/modules/rate-limiting/keeper/flow.go @@ -0,0 +1,91 @@ +package keeper + +import ( + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// The total value on a given path (aka, the denominator in the percentage calculation) +// is the total supply of the given denom +func (k Keeper) GetChannelValue(ctx sdk.Context, denom string) sdkmath.Int { + return k.bankKeeper.GetSupply(ctx, denom).Amount +} + +// Adds an amount to the flow in either the SEND or RECV direction +func (k Keeper) UpdateFlow(rateLimit types.RateLimit, direction types.PacketDirection, amount sdkmath.Int) error { + switch direction { + case types.PACKET_SEND: + return rateLimit.Flow.AddOutflow(amount, *rateLimit.Quota) + case types.PACKET_RECV: + return rateLimit.Flow.AddInflow(amount, *rateLimit.Quota) + default: + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "invalid packet direction (%s)", direction.String()) + } +} + +// Checks whether the given packet will exceed the rate limit +// Called by OnRecvPacket and OnSendPacket +func (k Keeper) CheckRateLimitAndUpdateFlow( + ctx sdk.Context, + direction types.PacketDirection, + packetInfo RateLimitedPacketInfo, +) (updatedFlow bool, err error) { + denom := packetInfo.Denom + channelId := packetInfo.ChannelID + amount := packetInfo.Amount + + // First check if the denom is blacklisted + if k.IsDenomBlacklisted(ctx, denom) { + err := errorsmod.Wrapf(types.ErrDenomIsBlacklisted, "denom %s is blacklisted", denom) + EmitTransferDeniedEvent(ctx, types.EventBlacklistedDenom, denom, channelId, direction, amount, err) + return false, err + } + + // If there's no rate limit yet for this denom, no action is necessary + rateLimit, found := k.GetRateLimit(ctx, denom, channelId) + if !found { + return false, nil + } + + // Check if the sender/receiver pair is whitelisted + // If so, return a success without modifying the quota + if k.IsAddressPairWhitelisted(ctx, packetInfo.Sender, packetInfo.Receiver) { + return false, nil + } + + // Update the flow object with the change in amount + if err := k.UpdateFlow(rateLimit, direction, amount); err != nil { + // If the rate limit was exceeded, emit an event + EmitTransferDeniedEvent(ctx, types.EventRateLimitExceeded, denom, channelId, direction, amount, err) + return false, err + } + + // If there's no quota error, update the rate limit object in the store with the new flow + k.SetRateLimit(ctx, rateLimit) + + return true, nil +} + +// If a SendPacket fails or times out, undo the outflow increment that happened during the send +func (k Keeper) UndoSendPacket(ctx sdk.Context, channelId string, sequence uint64, denom string, amount sdkmath.Int) error { + rateLimit, found := k.GetRateLimit(ctx, denom, channelId) + if !found { + return nil + } + + // If the packet was sent during this quota, decrement the outflow + // Otherwise, it can be ignored + if k.CheckPacketSentDuringCurrentQuota(ctx, channelId, sequence) { + rateLimit.Flow.Outflow = rateLimit.Flow.Outflow.Sub(amount) + k.SetRateLimit(ctx, rateLimit) + + k.RemovePendingSendPacket(ctx, channelId, sequence) + } + + return nil +} diff --git a/modules/rate-limiting/keeper/flow_test.go b/modules/rate-limiting/keeper/flow_test.go new file mode 100644 index 00000000..6bf515b4 --- /dev/null +++ b/modules/rate-limiting/keeper/flow_test.go @@ -0,0 +1,433 @@ +package keeper_test + +import ( + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/keeper" + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" +) + +func (s *KeeperTestSuite) TestGetChannelValue() { + supply := sdkmath.NewInt(100) + + // Mint coins to increase the supply, which will increase the channel value + err := s.App.BankKeeper.MintCoins(s.Ctx, minttypes.ModuleName, sdk.NewCoins(sdk.NewCoin(denom, supply))) + s.Require().NoError(err) + + expected := supply + actual := s.App.RatelimitKeeper.GetChannelValue(s.Ctx, denom) + s.Require().Equal(expected, actual) +} + +// Adds a rate limit object to the store in preparation for the check rate limit tests +func (s *KeeperTestSuite) SetupCheckRateLimitAndUpdateFlowTest() { + channelValue := sdkmath.NewInt(100) + maxPercentSend := sdkmath.NewInt(10) + maxPercentRecv := sdkmath.NewInt(10) + + s.App.RatelimitKeeper.SetRateLimit(s.Ctx, types.RateLimit{ + Path: &types.Path{ + Denom: denom, + ChannelId: channelId, + }, + Quota: &types.Quota{ + MaxPercentSend: maxPercentSend, + MaxPercentRecv: maxPercentRecv, + DurationHours: 1, + }, + Flow: &types.Flow{ + Inflow: sdkmath.ZeroInt(), + Outflow: sdkmath.ZeroInt(), + ChannelValue: channelValue, + }, + }) + + s.App.RatelimitKeeper.RemoveDenomFromBlacklist(s.Ctx, denom) + s.App.RatelimitKeeper.RemoveWhitelistedAddressPair(s.Ctx, sender, receiver) +} + +// Helper function to check the rate limit across a series of transfers +func (s *KeeperTestSuite) processCheckRateLimitAndUpdateFlowTestCase(tc checkRateLimitTestCase) { + s.SetupCheckRateLimitAndUpdateFlowTest() + + expectedInflow := sdkmath.NewInt(0) + expectedOutflow := sdkmath.NewInt(0) + for i, action := range tc.actions { + if action.addToBlacklist { + s.App.RatelimitKeeper.AddDenomToBlacklist(s.Ctx, denom) + continue + } else if action.removeFromBlacklist { + s.App.RatelimitKeeper.RemoveDenomFromBlacklist(s.Ctx, denom) + continue + } + + if action.addToWhitelist { + s.App.RatelimitKeeper.SetWhitelistedAddressPair(s.Ctx, types.WhitelistedAddressPair{ + Sender: sender, + Receiver: receiver, + }) + continue + } else if action.removeFromWhitelist { + s.App.RatelimitKeeper.RemoveWhitelistedAddressPair(s.Ctx, sender, receiver) + continue + } + + amount := sdkmath.NewInt(action.amount) + packetInfo := keeper.RateLimitedPacketInfo{ + ChannelID: channelId, + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + } + updatedFlow, err := s.App.RatelimitKeeper.CheckRateLimitAndUpdateFlow(s.Ctx, action.direction, packetInfo) + + // Each action optionally errors or skips a flow update + if action.expectedError != "" { + s.Require().ErrorContains(err, action.expectedError, tc.name+" - action: #%d - error", i) + } else { + s.Require().NoError(err, tc.name+" - action: #%d - no error", i) + + expectedUpdateFlow := !action.skipFlowUpdate + s.Require().Equal(expectedUpdateFlow, updatedFlow, tc.name+" - action: #%d - updated flow", i) + + if expectedUpdateFlow { + if action.direction == types.PACKET_RECV { + expectedInflow = expectedInflow.Add(amount) + } else { + expectedOutflow = expectedOutflow.Add(amount) + } + } + } + + // Confirm flow is updated properly (or left as is if the theshold was exceeded) + rateLimit, found := s.App.RatelimitKeeper.GetRateLimit(s.Ctx, denom, channelId) + s.Require().True(found) + s.Require().Equal(expectedInflow.Int64(), rateLimit.Flow.Inflow.Int64(), tc.name+" - action: #%d - inflow", i) + s.Require().Equal(expectedOutflow.Int64(), rateLimit.Flow.Outflow.Int64(), tc.name+" - action: #%d - outflow", i) + } +} + +func (s *KeeperTestSuite) TestCheckRateLimitAndUpdateFlow_UnidirectionalFlow() { + testCases := []checkRateLimitTestCase{ + { + name: "send_under_threshold", + actions: []action{ + {direction: types.PACKET_SEND, amount: 5}, + {direction: types.PACKET_SEND, amount: 5}, + }, + }, + { + name: "send_over_threshold", + actions: []action{ + {direction: types.PACKET_SEND, amount: 5}, + { + direction: types.PACKET_SEND, amount: 6, + expectedError: "Outflow exceeds quota", + }, + }, + }, + { + name: "recv_under_threshold", + actions: []action{ + {direction: types.PACKET_RECV, amount: 5}, + {direction: types.PACKET_RECV, amount: 5}, + }, + }, + { + name: "recv_over_threshold", + actions: []action{ + {direction: types.PACKET_RECV, amount: 5}, + { + direction: types.PACKET_RECV, amount: 6, + expectedError: "Inflow exceeds quota", + }, + }, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + s.processCheckRateLimitAndUpdateFlowTestCase(tc) + }) + } +} + +func (s *KeeperTestSuite) TestCheckRateLimitAndUpdatedFlow_BidirectionalFlow() { + testCases := []checkRateLimitTestCase{ + { + name: "send_then_recv_under_threshold", + actions: []action{ + {direction: types.PACKET_SEND, amount: 6}, + {direction: types.PACKET_RECV, amount: 6}, + {direction: types.PACKET_SEND, amount: 6}, + {direction: types.PACKET_RECV, amount: 6}, + }, + }, + { + name: "recv_then_send_under_threshold", + actions: []action{ + {direction: types.PACKET_RECV, amount: 6}, + {direction: types.PACKET_SEND, amount: 6}, + {direction: types.PACKET_RECV, amount: 6}, + {direction: types.PACKET_SEND, amount: 6}, + }, + }, + { + name: "send_then_recv_over_inflow", + actions: []action{ + {direction: types.PACKET_SEND, amount: 2}, // -2, Net: -2 + {direction: types.PACKET_RECV, amount: 6}, // +6, Net: +4 + {direction: types.PACKET_SEND, amount: 2}, // -2, Net: +2 + {direction: types.PACKET_RECV, amount: 6}, // +6, Net: +8 + {direction: types.PACKET_SEND, amount: 2}, // -2, Net: +6 + {direction: types.PACKET_RECV, amount: 6, // +6, Net: +12 (exceeds threshold) + expectedError: "Inflow exceeds quota"}, + }, + }, + { + name: "send_then_recv_over_outflow", + actions: []action{ + {direction: types.PACKET_SEND, amount: 6}, // -6, Net: -6 + {direction: types.PACKET_RECV, amount: 2}, // +2, Net: -4 + {direction: types.PACKET_SEND, amount: 6}, // -6, Net: -10 + {direction: types.PACKET_RECV, amount: 2}, // +2, Net: -8 + {direction: types.PACKET_SEND, amount: 6, // -6, Net: -14 (exceeds threshold) + expectedError: "Outflow exceeds quota"}, + }, + }, + { + name: "recv_then_send_over_inflow", + actions: []action{ + {direction: types.PACKET_RECV, amount: 6}, // +6, Net: +6 + {direction: types.PACKET_SEND, amount: 2}, // -2, Net: +4 + {direction: types.PACKET_RECV, amount: 6}, // +6, Net: +10 + {direction: types.PACKET_SEND, amount: 2}, // -2, Net: +8 + {direction: types.PACKET_RECV, amount: 6, // +6, Net: +14 (exceeds threshold) + expectedError: "Inflow exceeds quota"}, + }, + }, + { + name: "recv_then_send_over_outflow", + actions: []action{ + {direction: types.PACKET_RECV, amount: 2}, // +2, Net: +2 + {direction: types.PACKET_SEND, amount: 6}, // -6, Net: -4 + {direction: types.PACKET_RECV, amount: 2}, // +2, Net: -2 + {direction: types.PACKET_SEND, amount: 6}, // -6, Net: -8 + {direction: types.PACKET_RECV, amount: 2}, // +2, Net: -6 + {direction: types.PACKET_SEND, amount: 10, // +6, Net: -12 (exceeds threshold) + expectedError: "Outflow exceeds quota"}, + }, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + s.processCheckRateLimitAndUpdateFlowTestCase(tc) + }) + } +} + +func (s *KeeperTestSuite) TestCheckRateLimitAndUpdatedFlow_DenomBlacklist() { + testCases := []checkRateLimitTestCase{ + { + name: "add_then_remove_from_blacklist", // should succeed + actions: []action{ + {direction: types.PACKET_RECV, amount: 6}, + {direction: types.PACKET_SEND, amount: 6}, + {addToBlacklist: true}, + {removeFromBlacklist: true}, + {direction: types.PACKET_RECV, amount: 6}, + {direction: types.PACKET_SEND, amount: 6}, + }, + }, + { + name: "send_recv_blacklist_send", + actions: []action{ + {direction: types.PACKET_SEND, amount: 6}, + {direction: types.PACKET_RECV, amount: 6}, + {addToBlacklist: true}, + { + direction: types.PACKET_SEND, amount: 6, + expectedError: types.ErrDenomIsBlacklisted.Error(), + }, + }, + }, + { + name: "send_recv_blacklist_recv", + actions: []action{ + {direction: types.PACKET_SEND, amount: 6}, + {direction: types.PACKET_RECV, amount: 6}, + {addToBlacklist: true}, + { + direction: types.PACKET_RECV, amount: 6, + expectedError: types.ErrDenomIsBlacklisted.Error(), + }, + }, + }, + { + name: "recv_send_blacklist_send", + actions: []action{ + {direction: types.PACKET_RECV, amount: 6}, + {direction: types.PACKET_SEND, amount: 6}, + {addToBlacklist: true}, + { + direction: types.PACKET_SEND, amount: 6, + expectedError: types.ErrDenomIsBlacklisted.Error(), + }, + }, + }, + { + name: "recv_send_blacklist_recv", + actions: []action{ + {direction: types.PACKET_RECV, amount: 6}, + {direction: types.PACKET_SEND, amount: 6}, + {addToBlacklist: true}, + { + direction: types.PACKET_RECV, amount: 6, + expectedError: types.ErrDenomIsBlacklisted.Error(), + }, + }, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + s.processCheckRateLimitAndUpdateFlowTestCase(tc) + }) + } +} + +func (s *KeeperTestSuite) TestCheckRateLimitAndUpdatedFlow_AddressWhitelist() { + testCases := []checkRateLimitTestCase{ + { + name: "send_whitelist_send", // should succeed + actions: []action{ + {direction: types.PACKET_SEND, amount: 6}, + {addToWhitelist: true}, + {direction: types.PACKET_SEND, amount: 6, skipFlowUpdate: true}, + }, + }, + { + name: "recv_whitelist_recv", // should succeed + actions: []action{ + {direction: types.PACKET_RECV, amount: 6}, + {addToWhitelist: true}, + {direction: types.PACKET_RECV, amount: 6, skipFlowUpdate: true}, + }, + }, + { + name: "send_send_whitelist_send", // should succeed + actions: []action{ + {direction: types.PACKET_SEND, amount: 6}, + {direction: types.PACKET_SEND, amount: 6, expectedError: "Outflow exceeds quota"}, // fails + {addToWhitelist: true}, + {direction: types.PACKET_SEND, amount: 6, skipFlowUpdate: true}, // succeeds + }, + }, + { + name: "recv_recv_whitelist_recv", // should succeed + actions: []action{ + {direction: types.PACKET_RECV, amount: 6}, + {direction: types.PACKET_RECV, amount: 6, expectedError: "Inflow exceeds quota"}, // fails + {addToWhitelist: true}, + {direction: types.PACKET_RECV, amount: 6, skipFlowUpdate: true}, // succeeds + }, + }, + { + name: "send_recv_send_whitelist_send", // should succeed + actions: []action{ + {direction: types.PACKET_SEND, amount: 6}, + {direction: types.PACKET_RECV, amount: 6}, + {direction: types.PACKET_SEND, amount: 6}, + {addToWhitelist: true}, + {direction: types.PACKET_SEND, amount: 6, skipFlowUpdate: true}, + }, + }, + { + name: "recv_send_recv_whitelist_recv", // should succeed + actions: []action{ + {direction: types.PACKET_RECV, amount: 6}, + {direction: types.PACKET_SEND, amount: 6}, + {direction: types.PACKET_RECV, amount: 6}, + {addToWhitelist: true}, + {direction: types.PACKET_RECV, amount: 6, skipFlowUpdate: true}, + }, + }, + { + name: "add_then_remove_whitelist_recv", + actions: []action{ + {direction: types.PACKET_RECV, amount: 6}, + {addToWhitelist: true}, + {removeFromWhitelist: true}, + {direction: types.PACKET_RECV, amount: 6, expectedError: "Inflow exceeds quota"}, + }, + }, + { + name: "add_then_remove_whitelist_send", + actions: []action{ + {direction: types.PACKET_SEND, amount: 6}, + {addToWhitelist: true}, + {removeFromWhitelist: true}, + {direction: types.PACKET_SEND, amount: 6, expectedError: "Outflow exceeds quota"}, + }, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + s.processCheckRateLimitAndUpdateFlowTestCase(tc) + }) + } +} + +func (s *KeeperTestSuite) TestUndoSendPacket() { + // Helper function to check the rate limit outflow amount + checkOutflow := func(channelId, denom string, expectedAmount sdkmath.Int) { + rateLimit, found := s.App.RatelimitKeeper.GetRateLimit(s.Ctx, denom, channelId) + s.Require().True(found, "rate limit should have been found") + s.Require().Equal(expectedAmount.Int64(), rateLimit.Flow.Outflow.Int64(), + "outflow - channel: %s, denom: %s", channelId, denom) + } + + // Create two rate limits + initialOutflow := sdkmath.NewInt(100) + packetSendAmount := sdkmath.NewInt(10) + rateLimit1 := types.RateLimit{ + Path: &types.Path{Denom: denom, ChannelId: channelId}, + Flow: &types.Flow{Outflow: initialOutflow}, + } + rateLimit2 := types.RateLimit{ + Path: &types.Path{Denom: "different-denom", ChannelId: "different-channel"}, + Flow: &types.Flow{Outflow: initialOutflow}, + } + s.App.RatelimitKeeper.SetRateLimit(s.Ctx, rateLimit1) + s.App.RatelimitKeeper.SetRateLimit(s.Ctx, rateLimit2) + + // Store a pending packet sequence number of 2 for the first rate limit + s.App.RatelimitKeeper.SetPendingSendPacket(s.Ctx, channelId, 2) + + // Undo a send of 10 from the first rate limit, with sequence 1 + // If should NOT modify the outflow since sequence 1 was not sent in the current quota + err := s.App.RatelimitKeeper.UndoSendPacket(s.Ctx, channelId, 1, denom, packetSendAmount) + s.Require().NoError(err, "no error expected when undoing send packet sequence 1") + + checkOutflow(channelId, denom, initialOutflow) + + // Now undo a send from the same rate limit with sequence 2 + // If should decrement the outflow since 2 is in the current quota + err = s.App.RatelimitKeeper.UndoSendPacket(s.Ctx, channelId, 2, denom, packetSendAmount) + s.Require().NoError(err, "no error expected when undoing send packet sequence 2") + + checkOutflow(channelId, denom, initialOutflow.Sub(packetSendAmount)) + + // Confirm the outflow of the second rate limit has not been touched + checkOutflow("different-channel", "different-denom", initialOutflow) + + // Confirm sequence number was removed + found := s.App.RatelimitKeeper.CheckPacketSentDuringCurrentQuota(s.Ctx, channelId, 2) + s.Require().False(found, "packet sequence number should have been removed") +} diff --git a/modules/rate-limiting/keeper/genesis.go b/modules/rate-limiting/keeper/genesis.go new file mode 100644 index 00000000..bc121ba0 --- /dev/null +++ b/modules/rate-limiting/keeper/genesis.go @@ -0,0 +1,61 @@ +package keeper + +import ( + "time" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// InitGenesis initializes the capability module's state from a provided genesis +// state. +func (k Keeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) { + k.SetParams(ctx, genState.Params) + + // Set rate limits, blacklists, and whitelists + for _, rateLimit := range genState.RateLimits { + k.SetRateLimit(ctx, rateLimit) + } + for _, denom := range genState.BlacklistedDenoms { + k.AddDenomToBlacklist(ctx, denom) + } + for _, addressPair := range genState.WhitelistedAddressPairs { + k.SetWhitelistedAddressPair(ctx, addressPair) + } + + // Set pending sequence numbers - validating that they're in right format of {channelId}/{sequenceNumber} + for _, pendingPacketId := range genState.PendingSendPacketSequenceNumbers { + channelId, sequence, err := types.ParsePendingPacketId(pendingPacketId) + if err != nil { + panic(err.Error()) + } + k.SetPendingSendPacket(ctx, channelId, sequence) + } + + // If the hour epoch has been initialized already (epoch number != 0), validate and then use it + if genState.HourEpoch.EpochNumber > 0 { + k.SetHourEpoch(ctx, genState.HourEpoch) + } else { + // If the hour epoch has not been initialized yet, set it so that the epoch number matches + // the current hour and the start time is precisely on the hour + genState.HourEpoch.EpochNumber = uint64(ctx.BlockTime().Hour()) + genState.HourEpoch.EpochStartTime = ctx.BlockTime().Truncate(time.Hour) + genState.HourEpoch.EpochStartHeight = ctx.BlockHeight() + k.SetHourEpoch(ctx, genState.HourEpoch) + } +} + +// ExportGenesis returns the capability module's exported genesis. +func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { + genesis := types.DefaultGenesis() + + genesis.Params = k.GetParams(ctx) + genesis.RateLimits = k.GetAllRateLimits(ctx) + genesis.BlacklistedDenoms = k.GetAllBlacklistedDenoms(ctx) + genesis.WhitelistedAddressPairs = k.GetAllWhitelistedAddressPairs(ctx) + genesis.PendingSendPacketSequenceNumbers = k.GetAllPendingSendPackets(ctx) + genesis.HourEpoch = k.GetHourEpoch(ctx) + + return genesis +} diff --git a/modules/rate-limiting/keeper/genesis_test.go b/modules/rate-limiting/keeper/genesis_test.go new file mode 100644 index 00000000..c6037b09 --- /dev/null +++ b/modules/rate-limiting/keeper/genesis_test.go @@ -0,0 +1,100 @@ +package keeper_test + +import ( + "strconv" + "time" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + sdkmath "cosmossdk.io/math" +) + +func createRateLimits() []types.RateLimit { + rateLimits := []types.RateLimit{} + for i := int64(1); i <= 3; i++ { + suffix := strconv.Itoa(int(i)) + rateLimit := types.RateLimit{ + Path: &types.Path{Denom: "denom-" + suffix, ChannelId: "channel-" + suffix}, + Quota: &types.Quota{MaxPercentSend: sdkmath.NewInt(i), MaxPercentRecv: sdkmath.NewInt(i), DurationHours: uint64(i)}, + Flow: &types.Flow{Inflow: sdkmath.NewInt(i), Outflow: sdkmath.NewInt(i), ChannelValue: sdkmath.NewInt(i)}, + } + + rateLimits = append(rateLimits, rateLimit) + } + return rateLimits +} + +func (s *KeeperTestSuite) TestGenesis() { + currentHour := 13 + blockTime := time.Date(2024, 1, 1, currentHour, 55, 8, 0, time.UTC) // 13:55:08 + defaultEpochStartTime := time.Date(2024, 1, 1, currentHour, 0, 0, 0, time.UTC) // 13:00:00 (truncated to hour) + blockHeight := int64(10) + + testCases := []struct { + name string + genesisState types.GenesisState + firstEpoch bool + expectedError string + }{ + { + name: "valid default state", + genesisState: *types.DefaultGenesis(), + firstEpoch: true, + }, + { + name: "valid custom state", + genesisState: types.GenesisState{ + RateLimits: createRateLimits(), + WhitelistedAddressPairs: []types.WhitelistedAddressPair{ + {Sender: "senderA", Receiver: "receiverA"}, + {Sender: "senderB", Receiver: "receiverB"}, + }, + BlacklistedDenoms: []string{"denomA", "denomB"}, + PendingSendPacketSequenceNumbers: []string{"channel-0/1", "channel-2/3"}, + HourEpoch: types.HourEpoch{ + EpochNumber: 1, + EpochStartTime: blockTime, + Duration: time.Minute, + EpochStartHeight: 1, + }, + }, + firstEpoch: false, + }, + { + name: "invalid packet sequence - wrong delimiter", + genesisState: types.GenesisState{ + RateLimits: createRateLimits(), + PendingSendPacketSequenceNumbers: []string{"channel-0/1", "channel-2|3"}, + }, + expectedError: "invalid pending send packet (channel-2|3), must be of form: {channelId}/{sequenceNumber}", + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + s.Ctx = s.Ctx.WithBlockTime(blockTime) + s.Ctx = s.Ctx.WithBlockHeight(blockHeight) + + // Call initGenesis with a panic wrapper for the error cases + defer func() { + if recoveryError := recover(); recoveryError != nil { + s.Require().Equal(tc.expectedError, recoveryError, "expected error from panic") + } + }() + s.App.RatelimitKeeper.InitGenesis(s.Ctx, tc.genesisState) + + // If the hour epoch was not uninitialized in the raw genState, + // it will be initialized during InitGenesis + expectedGenesis := tc.genesisState + if tc.firstEpoch { + expectedGenesis.HourEpoch.EpochNumber = uint64(currentHour) + expectedGenesis.HourEpoch.EpochStartTime = defaultEpochStartTime + expectedGenesis.HourEpoch.EpochStartHeight = blockHeight + } + + // Check that the exported state matches the imported state + exportedState := s.App.RatelimitKeeper.ExportGenesis(s.Ctx) + s.Require().Equal(expectedGenesis, *exportedState, "exported genesis state") + }) + } +} diff --git a/modules/rate-limiting/keeper/grpc_query.go b/modules/rate-limiting/keeper/grpc_query.go new file mode 100644 index 00000000..f9a232cb --- /dev/null +++ b/modules/rate-limiting/keeper/grpc_query.go @@ -0,0 +1,88 @@ +package keeper + +import ( + "context" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" +) + +var _ types.QueryServer = Keeper{} + +// Query all rate limits +func (k Keeper) AllRateLimits(c context.Context, req *types.QueryAllRateLimitsRequest) (*types.QueryAllRateLimitsResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + rateLimits := k.GetAllRateLimits(ctx) + return &types.QueryAllRateLimitsResponse{RateLimits: rateLimits}, nil +} + +// Query a rate limit by denom and channelId +func (k Keeper) RateLimit(c context.Context, req *types.QueryRateLimitRequest) (*types.QueryRateLimitResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + rateLimit, found := k.GetRateLimit(ctx, req.Denom, req.ChannelId) + if !found { + return &types.QueryRateLimitResponse{}, nil + } + return &types.QueryRateLimitResponse{RateLimit: &rateLimit}, nil +} + +// Query all rate limits for a given chain +func (k Keeper) RateLimitsByChainId(c context.Context, req *types.QueryRateLimitsByChainIdRequest) (*types.QueryRateLimitsByChainIdResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + + rateLimits := []types.RateLimit{} + for _, rateLimit := range k.GetAllRateLimits(ctx) { + + // Determine the client state from the channel Id + _, clientState, err := k.channelKeeper.GetChannelClientState(ctx, transfertypes.PortID, rateLimit.Path.ChannelId) + if err != nil { + return &types.QueryRateLimitsByChainIdResponse{}, errorsmod.Wrapf(types.ErrInvalidClientState, "Unable to fetch client state from channelId") + } + client, ok := clientState.(*ibctmtypes.ClientState) + if !ok { + return &types.QueryRateLimitsByChainIdResponse{}, errorsmod.Wrapf(types.ErrInvalidClientState, "Client state is not tendermint") + } + + // If the chain ID matches, add the rate limit to the returned list + if client.ChainId == req.ChainId { + rateLimits = append(rateLimits, rateLimit) + } + } + + return &types.QueryRateLimitsByChainIdResponse{RateLimits: rateLimits}, nil +} + +// Query all rate limits for a given channel +func (k Keeper) RateLimitsByChannelId(c context.Context, req *types.QueryRateLimitsByChannelIdRequest) (*types.QueryRateLimitsByChannelIdResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + + rateLimits := []types.RateLimit{} + for _, rateLimit := range k.GetAllRateLimits(ctx) { + // If the channel ID matches, add the rate limit to the returned list + if rateLimit.Path.ChannelId == req.ChannelId { + rateLimits = append(rateLimits, rateLimit) + } + } + + return &types.QueryRateLimitsByChannelIdResponse{RateLimits: rateLimits}, nil +} + +// Query all blacklisted denoms +func (k Keeper) AllBlacklistedDenoms(c context.Context, req *types.QueryAllBlacklistedDenomsRequest) (*types.QueryAllBlacklistedDenomsResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + blacklistedDenoms := k.GetAllBlacklistedDenoms(ctx) + return &types.QueryAllBlacklistedDenomsResponse{Denoms: blacklistedDenoms}, nil +} + +// Query all whitelisted addresses +func (k Keeper) AllWhitelistedAddresses(c context.Context, req *types.QueryAllWhitelistedAddressesRequest) (*types.QueryAllWhitelistedAddressesResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + whitelistedAddresses := k.GetAllWhitelistedAddressPairs(ctx) + return &types.QueryAllWhitelistedAddressesResponse{AddressPairs: whitelistedAddresses}, nil +} diff --git a/modules/rate-limiting/keeper/grpc_query_test.go b/modules/rate-limiting/keeper/grpc_query_test.go new file mode 100644 index 00000000..414249f8 --- /dev/null +++ b/modules/rate-limiting/keeper/grpc_query_test.go @@ -0,0 +1,120 @@ +package keeper_test + +import ( + "context" + "fmt" + "time" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" +) + +// Add three rate limits on different channels +// Each should have a different chainId +func (s *KeeperTestSuite) setupQueryRateLimitTests() []types.RateLimit { + rateLimits := []types.RateLimit{} + for i := int64(0); i <= 2; i++ { + clientId := fmt.Sprintf("07-tendermint-%d", i) + chainId := fmt.Sprintf("chain-%d", i) + connectionId := fmt.Sprintf("connection-%d", i) + channelId := fmt.Sprintf("channel-%d", i) + + // First register the client, connection, and channel (so we can map back to chainId) + // Nothing in the client state matters besides the chainId + clientState := ibctmtypes.NewClientState( + chainId, ibctmtypes.Fraction{}, time.Duration(0), time.Duration(0), time.Duration(0), clienttypes.Height{}, nil, nil, + ) + connection := connectiontypes.ConnectionEnd{ClientId: clientId} + channel := channeltypes.Channel{ConnectionHops: []string{connectionId}} + + s.App.IBCKeeper.ClientKeeper.SetClientState(s.Ctx, clientId, clientState) + s.App.IBCKeeper.ConnectionKeeper.SetConnection(s.Ctx, connectionId, connection) + s.App.IBCKeeper.ChannelKeeper.SetChannel(s.Ctx, transfertypes.PortID, channelId, channel) + + // Then add the rate limit + rateLimit := types.RateLimit{ + Path: &types.Path{Denom: "denom", ChannelId: channelId}, + } + s.App.RatelimitKeeper.SetRateLimit(s.Ctx, rateLimit) + rateLimits = append(rateLimits, rateLimit) + } + return rateLimits +} + +func (s *KeeperTestSuite) TestQueryAllRateLimits() { + expectedRateLimits := s.setupQueryRateLimitTests() + queryResponse, err := s.QueryClient.AllRateLimits(context.Background(), &types.QueryAllRateLimitsRequest{}) + s.Require().NoError(err) + s.Require().ElementsMatch(expectedRateLimits, queryResponse.RateLimits) +} + +func (s *KeeperTestSuite) TestQueryRateLimit() { + allRateLimits := s.setupQueryRateLimitTests() + for _, expectedRateLimit := range allRateLimits { + queryResponse, err := s.QueryClient.RateLimit(context.Background(), &types.QueryRateLimitRequest{ + Denom: expectedRateLimit.Path.Denom, + ChannelId: expectedRateLimit.Path.ChannelId, + }) + s.Require().NoError(err, "no error expected when querying rate limit on channel: %s", expectedRateLimit.Path.ChannelId) + s.Require().Equal(expectedRateLimit, *queryResponse.RateLimit) + } +} + +func (s *KeeperTestSuite) TestQueryRateLimitsByChainId() { + allRateLimits := s.setupQueryRateLimitTests() + for i, expectedRateLimit := range allRateLimits { + chainId := fmt.Sprintf("chain-%d", i) + queryResponse, err := s.QueryClient.RateLimitsByChainId(context.Background(), &types.QueryRateLimitsByChainIdRequest{ + ChainId: chainId, + }) + s.Require().NoError(err, "no error expected when querying rate limit on chain: %s", chainId) + s.Require().Len(queryResponse.RateLimits, 1) + s.Require().Equal(expectedRateLimit, queryResponse.RateLimits[0]) + } +} + +func (s *KeeperTestSuite) TestQueryRateLimitsByChannelId() { + allRateLimits := s.setupQueryRateLimitTests() + for i, expectedRateLimit := range allRateLimits { + channelId := fmt.Sprintf("channel-%d", i) + queryResponse, err := s.QueryClient.RateLimitsByChannelId(context.Background(), &types.QueryRateLimitsByChannelIdRequest{ + ChannelId: channelId, + }) + s.Require().NoError(err, "no error expected when querying rate limit on channel: %s", channelId) + s.Require().Len(queryResponse.RateLimits, 1) + s.Require().Equal(expectedRateLimit, queryResponse.RateLimits[0]) + } +} + +func (s *KeeperTestSuite) TestQueryAllBlacklistedDenoms() { + s.App.RatelimitKeeper.AddDenomToBlacklist(s.Ctx, "denom-A") + s.App.RatelimitKeeper.AddDenomToBlacklist(s.Ctx, "denom-B") + + queryResponse, err := s.QueryClient.AllBlacklistedDenoms(context.Background(), &types.QueryAllBlacklistedDenomsRequest{}) + s.Require().NoError(err, "no error expected when querying blacklisted denoms") + s.Require().Equal([]string{"denom-A", "denom-B"}, queryResponse.Denoms) +} + +func (s *KeeperTestSuite) TestQueryAllWhitelistedAddresses() { + s.App.RatelimitKeeper.SetWhitelistedAddressPair(s.Ctx, types.WhitelistedAddressPair{ + Sender: "address-A", + Receiver: "address-B", + }) + s.App.RatelimitKeeper.SetWhitelistedAddressPair(s.Ctx, types.WhitelistedAddressPair{ + Sender: "address-C", + Receiver: "address-D", + }) + queryResponse, err := s.QueryClient.AllWhitelistedAddresses(context.Background(), &types.QueryAllWhitelistedAddressesRequest{}) + s.Require().NoError(err, "no error expected when querying whitelisted addresses") + + expectedWhitelist := []types.WhitelistedAddressPair{ + {Sender: "address-A", Receiver: "address-B"}, + {Sender: "address-C", Receiver: "address-D"}, + } + s.Require().Equal(expectedWhitelist, queryResponse.AddressPairs) +} diff --git a/modules/rate-limiting/keeper/keeper.go b/modules/rate-limiting/keeper/keeper.go new file mode 100644 index 00000000..a82d84a4 --- /dev/null +++ b/modules/rate-limiting/keeper/keeper.go @@ -0,0 +1,56 @@ +package keeper + +import ( + "fmt" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + + "github.com/cometbft/cometbft/libs/log" +) + +type ( + Keeper struct { + storeKey storetypes.StoreKey + cdc codec.BinaryCodec + paramstore paramtypes.Subspace + authority string + + bankKeeper types.BankKeeper + channelKeeper types.ChannelKeeper + ics4Wrapper types.ICS4Wrapper + } +) + +func NewKeeper( + cdc codec.BinaryCodec, + key storetypes.StoreKey, + ps paramtypes.Subspace, + authority string, + bankKeeper types.BankKeeper, + channelKeeper types.ChannelKeeper, + ics4Wrapper types.ICS4Wrapper, +) *Keeper { + return &Keeper{ + cdc: cdc, + storeKey: key, + paramstore: ps, + authority: authority, + bankKeeper: bankKeeper, + channelKeeper: channelKeeper, + ics4Wrapper: ics4Wrapper, + } +} + +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} + +// GetAuthority returns the module's authority. +func (k Keeper) GetAuthority() string { + return k.authority +} diff --git a/modules/rate-limiting/keeper/keeper_test.go b/modules/rate-limiting/keeper/keeper_test.go new file mode 100644 index 00000000..402ca698 --- /dev/null +++ b/modules/rate-limiting/keeper/keeper_test.go @@ -0,0 +1,23 @@ +package keeper_test + +import ( + "testing" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/testing/simapp/apptesting" + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + "github.com/stretchr/testify/suite" +) + +type KeeperTestSuite struct { + apptesting.AppTestHelper + QueryClient types.QueryClient +} + +func (s *KeeperTestSuite) SetupTest() { + s.Setup() + s.QueryClient = types.NewQueryClient(s.QueryHelper) +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} diff --git a/modules/rate-limiting/keeper/msg_server.go b/modules/rate-limiting/keeper/msg_server.go new file mode 100644 index 00000000..4587683b --- /dev/null +++ b/modules/rate-limiting/keeper/msg_server.go @@ -0,0 +1,81 @@ +package keeper + +import ( + "context" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" +) + +type msgServer struct { + Keeper +} + +// NewMsgServerImpl returns an implementation of the ratelimit MsgServer interface +func NewMsgServerImpl(keeper Keeper) types.MsgServer { + return &msgServer{Keeper: keeper} +} + +var _ types.MsgServer = msgServer{} + +// Adds a new rate limit. Fails if the rate limit already exists or the channel value is 0 +func (k msgServer) AddRateLimit(goCtx context.Context, msg *types.MsgAddRateLimit) (*types.MsgAddRateLimitResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + if k.authority != msg.Authority { + return nil, errorsmod.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", k.authority, msg.Authority) + } + + if err := k.Keeper.AddRateLimit(ctx, msg); err != nil { + return nil, err + } + + return &types.MsgAddRateLimitResponse{}, nil +} + +// Updates an existing rate limit. Fails if the rate limit doesn't exist +func (k msgServer) UpdateRateLimit(goCtx context.Context, msg *types.MsgUpdateRateLimit) (*types.MsgUpdateRateLimitResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + if k.authority != msg.Authority { + return nil, errorsmod.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", k.authority, msg.Authority) + } + + if err := k.Keeper.UpdateRateLimit(ctx, msg); err != nil { + return nil, err + } + + return &types.MsgUpdateRateLimitResponse{}, nil +} + +// Removes a rate limit. Fails if the rate limit doesn't exist +func (k msgServer) RemoveRateLimit(goCtx context.Context, msg *types.MsgRemoveRateLimit) (*types.MsgRemoveRateLimitResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + if k.authority != msg.Authority { + return nil, errorsmod.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", k.authority, msg.Authority) + } + + _, found := k.Keeper.GetRateLimit(ctx, msg.Denom, msg.ChannelId) + if !found { + return nil, types.ErrRateLimitNotFound + } + + k.Keeper.RemoveRateLimit(ctx, msg.Denom, msg.ChannelId) + return &types.MsgRemoveRateLimitResponse{}, nil +} + +// Resets the flow on a rate limit. Fails if the rate limit doesn't exist +func (k msgServer) ResetRateLimit(goCtx context.Context, msg *types.MsgResetRateLimit) (*types.MsgResetRateLimitResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + if k.authority != msg.Authority { + return nil, errorsmod.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", k.authority, msg.Authority) + } + + if err := k.Keeper.ResetRateLimit(ctx, msg.Denom, msg.ChannelId); err != nil { + return nil, err + } + + return &types.MsgResetRateLimitResponse{}, nil +} diff --git a/modules/rate-limiting/keeper/msg_server_test.go b/modules/rate-limiting/keeper/msg_server_test.go new file mode 100644 index 00000000..3d45f7e6 --- /dev/null +++ b/modules/rate-limiting/keeper/msg_server_test.go @@ -0,0 +1,203 @@ +package keeper_test + +import ( + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/keeper" + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" +) + +var ( + authority = authtypes.NewModuleAddress(govtypes.ModuleName).String() + + addRateLimitMsg = types.MsgAddRateLimit{ + Authority: authority, + Denom: "denom", + ChannelId: "channel-0", + MaxPercentRecv: sdkmath.NewInt(10), + MaxPercentSend: sdkmath.NewInt(20), + DurationHours: 30, + } + + updateRateLimitMsg = types.MsgUpdateRateLimit{ + Authority: authority, + Denom: "denom", + ChannelId: "channel-0", + MaxPercentRecv: sdkmath.NewInt(20), + MaxPercentSend: sdkmath.NewInt(30), + DurationHours: 40, + } + + removeRateLimitMsg = types.MsgRemoveRateLimit{ + Authority: authority, + Denom: "denom", + ChannelId: "channel-0", + } + + resetRateLimitMsg = types.MsgResetRateLimit{ + Authority: authority, + Denom: "denom", + ChannelId: "channel-0", + } +) + +// Helper function to create a channel and prevent a channel not exists error +func (s *KeeperTestSuite) createChannel(channelId string) { + s.App.IBCKeeper.ChannelKeeper.SetChannel(s.Ctx, transfertypes.PortID, channelId, channeltypes.Channel{}) +} + +// Helper function to mint tokens and create channel value to prevent a zero channel value error +func (s *KeeperTestSuite) createChannelValue(denom string, channelValue sdkmath.Int) { + err := s.App.BankKeeper.MintCoins(s.Ctx, minttypes.ModuleName, sdk.NewCoins(sdk.NewCoin(addRateLimitMsg.Denom, channelValue))) + s.Require().NoError(err) +} + +// Helper function to add a rate limit with an optional error expectation +func (s *KeeperTestSuite) addRateLimit(expectedErr *errorsmod.Error) { + msgServer := keeper.NewMsgServerImpl(s.App.RatelimitKeeper) + _, actualErr := msgServer.AddRateLimit(sdk.WrapSDKContext(s.Ctx), &addRateLimitMsg) + + // If it should have been added successfully, confirm no error + // and confirm the rate limit was created + if expectedErr == nil { + s.Require().NoError(actualErr) + + _, found := s.App.RatelimitKeeper.GetRateLimit(s.Ctx, addRateLimitMsg.Denom, addRateLimitMsg.ChannelId) + s.Require().True(found) + } else { + // If it should have failed, check the error + s.Require().Equal(actualErr, expectedErr) + } +} + +// Helper function to add a rate limit successfully +func (s *KeeperTestSuite) addRateLimitSuccessful() { + s.addRateLimit(nil) +} + +// Helper function to add a rate limit with an expected error +func (s *KeeperTestSuite) addRateLimitWithError(expectedErr *errorsmod.Error) { + s.addRateLimit(expectedErr) +} + +func (s *KeeperTestSuite) TestMsgServer_AddRateLimit() { + denom := addRateLimitMsg.Denom + channelId := addRateLimitMsg.ChannelId + channelValue := sdkmath.NewInt(100) + + // First try to add a rate limit when there's no channel value, it will fail + s.addRateLimitWithError(types.ErrZeroChannelValue) + + // Create channel value + s.createChannelValue(denom, channelValue) + + // Then try to add a rate limit before the channel has been created, it will also fail + s.addRateLimitWithError(types.ErrChannelNotFound) + + // Create the channel + s.createChannel(channelId) + + // Now add a rate limit successfully + s.addRateLimitSuccessful() + + // Finally, try to add the same rate limit again - it should fail + s.addRateLimitWithError(types.ErrRateLimitAlreadyExists) +} + +func (s *KeeperTestSuite) TestMsgServer_UpdateRateLimit() { + denom := updateRateLimitMsg.Denom + channelId := updateRateLimitMsg.ChannelId + channelValue := sdkmath.NewInt(100) + + msgServer := keeper.NewMsgServerImpl(s.App.RatelimitKeeper) + + // Create channel and channel value + s.createChannel(channelId) + s.createChannelValue(denom, channelValue) + + // Attempt to update a rate limit that does not exist + _, err := msgServer.UpdateRateLimit(s.Ctx, &updateRateLimitMsg) + s.Require().Equal(err, types.ErrRateLimitNotFound) + + // Add a rate limit successfully + s.addRateLimitSuccessful() + + // Update the rate limit successfully + _, err = msgServer.UpdateRateLimit(s.Ctx, &updateRateLimitMsg) + s.Require().NoError(err) + + // Check ratelimit quota is updated correctly + updatedRateLimit, found := s.App.RatelimitKeeper.GetRateLimit(s.Ctx, denom, channelId) + s.Require().True(found) + s.Require().Equal(updatedRateLimit.Quota, &types.Quota{ + MaxPercentSend: updateRateLimitMsg.MaxPercentSend, + MaxPercentRecv: updateRateLimitMsg.MaxPercentRecv, + DurationHours: updateRateLimitMsg.DurationHours, + }) +} + +func (s *KeeperTestSuite) TestMsgServer_RemoveRateLimit() { + denom := removeRateLimitMsg.Denom + channelId := removeRateLimitMsg.ChannelId + channelValue := sdkmath.NewInt(100) + + msgServer := keeper.NewMsgServerImpl(s.App.RatelimitKeeper) + + s.createChannel(channelId) + s.createChannelValue(denom, channelValue) + + // Attempt to remove a rate limit that does not exist + _, err := msgServer.RemoveRateLimit(s.Ctx, &removeRateLimitMsg) + s.Require().Equal(err, types.ErrRateLimitNotFound) + + // Add a rate limit successfully + s.addRateLimitSuccessful() + + // Remove the rate limit successfully + _, err = msgServer.RemoveRateLimit(s.Ctx, &removeRateLimitMsg) + s.Require().NoError(err) + + // Confirm it was removed + _, found := s.App.RatelimitKeeper.GetRateLimit(s.Ctx, denom, channelId) + s.Require().False(found) +} + +func (s *KeeperTestSuite) TestMsgServer_ResetRateLimit() { + denom := resetRateLimitMsg.Denom + channelId := resetRateLimitMsg.ChannelId + channelValue := sdkmath.NewInt(100) + + msgServer := keeper.NewMsgServerImpl(s.App.RatelimitKeeper) + + s.createChannel(channelId) + s.createChannelValue(denom, channelValue) + + // Attempt to reset a rate limit that does not exist + _, err := msgServer.ResetRateLimit(s.Ctx, &resetRateLimitMsg) + s.Require().Equal(err, types.ErrRateLimitNotFound) + + // Add a rate limit successfully + s.addRateLimitSuccessful() + + // Reset the rate limit successfully + _, err = msgServer.ResetRateLimit(s.Ctx, &resetRateLimitMsg) + s.Require().NoError(err) + + // Check ratelimit quota is flow correctly + resetRateLimit, found := s.App.RatelimitKeeper.GetRateLimit(s.Ctx, denom, channelId) + s.Require().True(found) + s.Require().Equal(resetRateLimit.Flow, &types.Flow{ + Inflow: sdkmath.ZeroInt(), + Outflow: sdkmath.ZeroInt(), + ChannelValue: channelValue, + }) +} diff --git a/modules/rate-limiting/keeper/packet.go b/modules/rate-limiting/keeper/packet.go new file mode 100644 index 00000000..54d7abb8 --- /dev/null +++ b/modules/rate-limiting/keeper/packet.go @@ -0,0 +1,305 @@ +package keeper + +import ( + "encoding/json" + "fmt" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" +) + +type RateLimitedPacketInfo struct { + ChannelID string + Denom string + Amount sdkmath.Int + Sender string + Receiver string +} + +// CheckAcknowledementSucceeded unmarshals IBC Acknowledgements, and determines +// whether the tx was successful +func (k Keeper) CheckAcknowledementSucceeded(ctx sdk.Context, ack []byte) (success bool, err error) { + // Unmarshal the raw ack response + var acknowledgement channeltypes.Acknowledgement + if err := transfertypes.ModuleCdc.UnmarshalJSON(ack, &acknowledgement); err != nil { + return false, errorsmod.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet acknowledgement: %s", err.Error()) + } + + // The ack can come back as either AcknowledgementResult or AcknowledgementError + // If it comes back as AcknowledgementResult, the messages are encoded differently depending on the SDK version + switch response := acknowledgement.Response.(type) { + case *channeltypes.Acknowledgement_Result: + if len(response.Result) == 0 { + return false, errorsmod.Wrapf(channeltypes.ErrInvalidAcknowledgement, "acknowledgement result cannot be empty") + } + return true, nil + + case *channeltypes.Acknowledgement_Error: + k.Logger(ctx).Error(fmt.Sprintf("acknowledgement error: %s", response.Error)) + return false, nil + + default: + return false, errorsmod.Wrapf(channeltypes.ErrInvalidAcknowledgement, "unsupported acknowledgement response field type %T", response) + } +} + +// Parse the denom from the Send Packet that will be used by the rate limit module +// The denom that the rate limiter will use for a SEND packet depends on whether +// it was a NATIVE token (e.g. ustrd, stuatom, etc.) or NON-NATIVE token (e.g. ibc/...)... +// +// We can identify if the token is native or not by parsing the trace denom from the packet +// If the token is NATIVE, it will not have a prefix (e.g. ustrd), +// and if it is NON-NATIVE, it will have a prefix (e.g. transfer/channel-2/uosmo) +// +// For NATIVE denoms, return as is (e.g. ustrd) +// For NON-NATIVE denoms, take the ibc hash (e.g. hash "transfer/channel-2/usoms" into "ibc/...") +func ParseDenomFromSendPacket(packet transfertypes.FungibleTokenPacketData) (denom string) { + // Determine the denom by looking at the denom trace path + denomTrace := transfertypes.ParseDenomTrace(packet.Denom) + + // Native assets will have an empty trace path and can be returned as is + if denomTrace.Path == "" { + denom = packet.Denom + } else { + // Non-native assets should be hashed + denom = denomTrace.IBCDenom() + } + + return denom +} + +// Parse the denom from the Recv Packet that will be used by the rate limit module +// The denom that the rate limiter will use for a RECEIVE packet depends on whether it was a source or sink +// +// Sink: The token moves forward, to a chain different than its previous hop +// The new port and channel are APPENDED to the denom trace. +// (e.g. A -> B, B is a sink) (e.g. A -> B -> C, C is a sink) +// +// Source: The token moves backwards (i.e. revisits the last chain it was sent from) +// The port and channel are REMOVED from the denom trace - undoing the last hop. +// (e.g. A -> B -> A, A is a source) (e.g. A -> B -> C -> B, B is a source) +// +// If the chain is acting as a SINK: We add on the Stride port and channel and hash it +// Ex1: uosmo sent from Osmosis to Stride +// Packet Denom: uosmo +// -> Add Prefix: transfer/channel-X/uosmo +// -> Hash: ibc/... +// +// Ex2: ujuno sent from Osmosis to Stride +// PacketDenom: transfer/channel-Y/ujuno (channel-Y is the Juno <> Osmosis channel) +// -> Add Prefix: transfer/channel-X/transfer/channel-Y/ujuno +// -> Hash: ibc/... +// +// If the chain is acting as a SOURCE: First, remove the prefix. Then if there is still a denom trace, hash it +// Ex1: ustrd sent back to Stride from Osmosis +// Packet Denom: transfer/channel-X/ustrd +// -> Remove Prefix: ustrd +// -> Leave as is: ustrd +// +// Ex2: juno was sent to Stride, then to Osmosis, then back to Stride +// Packet Denom: transfer/channel-X/transfer/channel-Z/ujuno +// -> Remove Prefix: transfer/channel-Z/ujuno +// -> Hash: ibc/... +func ParseDenomFromRecvPacket(packet channeltypes.Packet, packetData transfertypes.FungibleTokenPacketData) (denom string) { + // To determine the denom, first check whether Stride is acting as source + if transfertypes.ReceiverChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), packetData.Denom) { + // Remove the source prefix (e.g. transfer/channel-X/transfer/channel-Z/ujuno -> transfer/channel-Z/ujuno) + sourcePrefix := transfertypes.GetDenomPrefix(packet.GetSourcePort(), packet.GetSourceChannel()) + unprefixedDenom := packetData.Denom[len(sourcePrefix):] + + // Native assets will have an empty trace path and can be returned as is + denomTrace := transfertypes.ParseDenomTrace(unprefixedDenom) + if denomTrace.Path == "" { + denom = unprefixedDenom + } else { + // Non-native assets should be hashed + denom = denomTrace.IBCDenom() + } + } else { + // Prefix the destination channel - this will contain the trailing slash (e.g. transfer/channel-X/) + destinationPrefix := transfertypes.GetDenomPrefix(packet.GetDestPort(), packet.GetDestChannel()) + prefixedDenom := destinationPrefix + packetData.Denom + + // Hash the denom trace + denomTrace := transfertypes.ParseDenomTrace(prefixedDenom) + denom = denomTrace.IBCDenom() + } + + return denom +} + +// Parses the sender and channelId and denom for the corresponding RateLimit object, and +// the sender/receiver/transfer amount +// +// The Stride channelID should always be used as the key for the RateLimit object (not the counterparty channelID) +// For a SEND packet, the Stride channelID is the SOURCE channel +// For a RECEIVE packet, the Stride channelID is the DESTINATION channel +// +// The Source and Desination are defined from the perspective of a packet recipient +// Meaning, when a send packet lands on a the host chain, the "Source" will be the Stride Channel, +// and the "Destination" will be the Host Channel +// And, when a receive packet lands on a Stride, the "Source" will be the host zone's channel, +// and the "Destination" will be the Stride Channel +func ParsePacketInfo(packet channeltypes.Packet, direction types.PacketDirection) (RateLimitedPacketInfo, error) { + var packetData transfertypes.FungibleTokenPacketData + if err := json.Unmarshal(packet.GetData(), &packetData); err != nil { + return RateLimitedPacketInfo{}, err + } + + var channelID, denom string + if direction == types.PACKET_SEND { + channelID = packet.GetSourceChannel() + denom = ParseDenomFromSendPacket(packetData) + } else { + channelID = packet.GetDestChannel() + denom = ParseDenomFromRecvPacket(packet, packetData) + } + + amount, ok := sdk.NewIntFromString(packetData.Amount) + if !ok { + return RateLimitedPacketInfo{}, + errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "Unable to cast packet amount '%s' to sdkmath.Int", packetData.Amount) + } + + packetInfo := RateLimitedPacketInfo{ + ChannelID: channelID, + Denom: denom, + Amount: amount, + Sender: packetData.Sender, + Receiver: packetData.Receiver, + } + + return packetInfo, nil +} + +// Middleware implementation for SendPacket with rate limiting +// Checks whether the rate limit has been exceeded - and if it hasn't, sends the packet +func (k Keeper) SendRateLimitedPacket(ctx sdk.Context, packet channeltypes.Packet) error { + packetInfo, err := ParsePacketInfo(packet, types.PACKET_SEND) + if err != nil { + return err + } + + // Check if the packet would exceed the outflow rate limit + updatedFlow, err := k.CheckRateLimitAndUpdateFlow(ctx, types.PACKET_SEND, packetInfo) + if err != nil { + return err + } + + // Store the sequence number of the packet so that if the transfer fails, + // we can identify if it was sent during this quota and can revert the outflow + if updatedFlow { + k.SetPendingSendPacket(ctx, packetInfo.ChannelID, packet.Sequence) + } + + return nil +} + +// Middleware implementation for RecvPacket with rate limiting +// Checks whether the rate limit has been exceeded - and if it hasn't, allows the packet +func (k Keeper) ReceiveRateLimitedPacket(ctx sdk.Context, packet channeltypes.Packet) error { + packetInfo, err := ParsePacketInfo(packet, types.PACKET_RECV) + if err != nil { + return err + } + + _, err = k.CheckRateLimitAndUpdateFlow(ctx, types.PACKET_RECV, packetInfo) + return err +} + +// Middleware implementation for OnAckPacket with rate limiting +// If the packet failed, we should decrement the Outflow +func (k Keeper) AcknowledgeRateLimitedPacket(ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte) error { + // Check whether the ack was a success or error + ackSuccess, err := k.CheckAcknowledementSucceeded(ctx, acknowledgement) + if err != nil { + return err + } + + // Parse the denom, channelId, and amount from the packet + packetInfo, err := ParsePacketInfo(packet, types.PACKET_SEND) + if err != nil { + return err + } + + // If the ack was successful, remove the pending packet + if ackSuccess { + k.RemovePendingSendPacket(ctx, packetInfo.ChannelID, packet.Sequence) + return nil + } + + // If the ack failed, undo the change to the rate limit Outflow + return k.UndoSendPacket(ctx, packetInfo.ChannelID, packet.Sequence, packetInfo.Denom, packetInfo.Amount) +} + +// Middleware implementation for OnAckPacket with rate limiting +// The Outflow should be decremented from the failed packet +func (k Keeper) TimeoutRateLimitedPacket(ctx sdk.Context, packet channeltypes.Packet) error { + packetInfo, err := ParsePacketInfo(packet, types.PACKET_SEND) + if err != nil { + return err + } + + return k.UndoSendPacket(ctx, packetInfo.ChannelID, packet.Sequence, packetInfo.Denom, packetInfo.Amount) +} + +// SendPacket wraps IBC ChannelKeeper's SendPacket function +// If the packet does not get rate limited, it passes the packet to the IBC Channel keeper +func (k Keeper) SendPacket( + ctx sdk.Context, + channelCap *capabilitytypes.Capability, + sourcePort string, + sourceChannel string, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + data []byte, +) (sequence uint64, err error) { + // The packet must first be sent up the stack to get the sequence number from the channel keeper + sequence, err = k.ics4Wrapper.SendPacket( + ctx, + channelCap, + sourcePort, + sourceChannel, + timeoutHeight, + timeoutTimestamp, + data, + ) + if err != nil { + return sequence, err + } + + err = k.SendRateLimitedPacket(ctx, channeltypes.Packet{ + Sequence: sequence, + SourceChannel: sourceChannel, + SourcePort: sourcePort, + TimeoutHeight: timeoutHeight, + TimeoutTimestamp: timeoutTimestamp, + Data: data, + }) + if err != nil { + k.Logger(ctx).Error(fmt.Sprintf("ICS20 packet send was denied: %s", err.Error())) + return 0, err + } + return sequence, err +} + +// WriteAcknowledgement wraps IBC ChannelKeeper's WriteAcknowledgement function +func (k Keeper) WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, acknowledgement ibcexported.Acknowledgement) error { + return k.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, acknowledgement) +} + +// GetAppVersion wraps IBC ChannelKeeper's GetAppVersion function +func (k Keeper) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { + return k.ics4Wrapper.GetAppVersion(ctx, portID, channelID) +} diff --git a/modules/rate-limiting/keeper/packet_test.go b/modules/rate-limiting/keeper/packet_test.go new file mode 100644 index 00000000..c1b82c6a --- /dev/null +++ b/modules/rate-limiting/keeper/packet_test.go @@ -0,0 +1,447 @@ +package keeper_test + +import ( + "crypto/sha256" + "encoding/json" + "fmt" + "testing" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/keeper" + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + "github.com/stretchr/testify/require" + + sdkmath "cosmossdk.io/math" + + tmbytes "github.com/cometbft/cometbft/libs/bytes" + + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" +) + +const ( + transferPort = "transfer" + uosmo = "uosmo" + ujuno = "ujuno" + ustrd = "ustrd" + stuatom = "stuatom" + channelOnStride = "channel-0" + channelOnHost = "channel-1" +) + +func hashDenomTrace(denomTrace string) string { + trace32byte := sha256.Sum256([]byte(denomTrace)) + var traceTmByte tmbytes.HexBytes = trace32byte[:] + return fmt.Sprintf("ibc/%s", traceTmByte) +} + +func TestParseDenomFromSendPacket(t *testing.T) { + testCases := []struct { + name string + packetDenomTrace string + expectedDenom string + }{ + // Native assets stay as is + { + name: "ustrd", + packetDenomTrace: ustrd, + expectedDenom: ustrd, + }, + { + name: "stuatom", + packetDenomTrace: stuatom, + expectedDenom: stuatom, + }, + // Non-native assets are hashed + { + name: "uosmo_one_hop", + packetDenomTrace: "transfer/channel-0/usomo", + expectedDenom: hashDenomTrace("transfer/channel-0/usomo"), + }, + { + name: "uosmo_two_hops", + packetDenomTrace: "transfer/channel-2/transfer/channel-1/usomo", + expectedDenom: hashDenomTrace("transfer/channel-2/transfer/channel-1/usomo"), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + packet := transfertypes.FungibleTokenPacketData{ + Denom: tc.packetDenomTrace, + } + + parsedDenom := keeper.ParseDenomFromSendPacket(packet) + require.Equal(t, tc.expectedDenom, parsedDenom, tc.name) + }) + } +} + +func TestParseDenomFromRecvPacket(t *testing.T) { + osmoChannelOnStride := "channel-0" + strideChannelOnOsmo := "channel-100" + junoChannelOnOsmo := "channel-200" + junoChannelOnStride := "channel-300" + + testCases := []struct { + name string + packetDenomTrace string + sourceChannel string + destinationChannel string + expectedDenom string + }{ + // Sink asset one hop away: + // uosmo sent from Osmosis to Stride (uosmo) + // -> tack on prefix (transfer/channel-0/uosmo) and hash + { + name: "sink_one_hop", + packetDenomTrace: uosmo, + sourceChannel: strideChannelOnOsmo, + destinationChannel: osmoChannelOnStride, + expectedDenom: hashDenomTrace(fmt.Sprintf("%s/%s/%s", transferPort, osmoChannelOnStride, uosmo)), + }, + // Sink asset two hops away: + // ujuno sent from Juno to Osmosis to Stride (transfer/channel-200/ujuno) + // -> tack on prefix (transfer/channel-0/transfer/channel-200/ujuno) and hash + { + name: "sink_two_hops", + packetDenomTrace: fmt.Sprintf("%s/%s/%s", transferPort, junoChannelOnOsmo, ujuno), + sourceChannel: strideChannelOnOsmo, + destinationChannel: osmoChannelOnStride, + expectedDenom: hashDenomTrace(fmt.Sprintf("%s/%s/%s/%s/%s", transferPort, osmoChannelOnStride, transferPort, junoChannelOnOsmo, ujuno)), + }, + // Native source assets + // ustrd sent from Stride to Osmosis and then back to Stride (transfer/channel-0/ustrd) + // -> remove prefix and leave as is (ustrd) + { + name: "native_source", + packetDenomTrace: fmt.Sprintf("%s/%s/%s", transferPort, strideChannelOnOsmo, ustrd), + sourceChannel: strideChannelOnOsmo, + destinationChannel: osmoChannelOnStride, + expectedDenom: ustrd, + }, + // Non-native source assets + // ujuno was sent from Juno to Stride, then to Osmosis, then back to Stride (transfer/channel-0/transfer/channel-300/ujuno) + // -> remove prefix (transfer/channel-300/ujuno) and hash + { + name: "non_native_source", + packetDenomTrace: fmt.Sprintf("%s/%s/%s/%s/%s", transferPort, strideChannelOnOsmo, transferPort, junoChannelOnStride, ujuno), + sourceChannel: strideChannelOnOsmo, + destinationChannel: osmoChannelOnStride, + expectedDenom: hashDenomTrace(fmt.Sprintf("%s/%s/%s", transferPort, junoChannelOnStride, ujuno)), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + packet := channeltypes.Packet{ + SourcePort: transferPort, + DestinationPort: transferPort, + SourceChannel: tc.sourceChannel, + DestinationChannel: tc.destinationChannel, + } + packetData := transfertypes.FungibleTokenPacketData{ + Denom: tc.packetDenomTrace, + } + + parsedDenom := keeper.ParseDenomFromRecvPacket(packet, packetData) + require.Equal(t, tc.expectedDenom, parsedDenom, tc.name) + }) + } +} + +func (s *KeeperTestSuite) TestParsePacketInfo() { + sourceChannel := "channel-100" + destinationChannel := "channel-200" + denom := "denom" + amountString := "100" + amountInt := sdkmath.NewInt(100) + sender := "sender" + receiver := "receiver" + + packetData, err := json.Marshal(transfertypes.FungibleTokenPacketData{ + Denom: denom, + Amount: amountString, + Sender: sender, + Receiver: receiver, + }) + s.Require().NoError(err) + + packet := channeltypes.Packet{ + SourcePort: transferPort, + SourceChannel: sourceChannel, + DestinationPort: transferPort, + DestinationChannel: destinationChannel, + Data: packetData, + } + + // Send 'denom' from channel-100 (stride) -> channel-200 + // Since the 'denom' is native, it's kept as is for the rate limit object + expectedSendPacketInfo := keeper.RateLimitedPacketInfo{ + ChannelID: sourceChannel, + Denom: denom, + Amount: amountInt, + Sender: sender, + Receiver: receiver, + } + actualSendPacketInfo, err := keeper.ParsePacketInfo(packet, types.PACKET_SEND) + s.Require().NoError(err, "no error expected when parsing send packet") + s.Require().Equal(expectedSendPacketInfo, actualSendPacketInfo, "send packet") + + // Receive 'denom' from channel-100 -> channel-200 (stride) + // The stride channel (channel-200) should be tacked onto the end and the denom should be hashed + expectedRecvPacketInfo := keeper.RateLimitedPacketInfo{ + ChannelID: destinationChannel, + Denom: hashDenomTrace(fmt.Sprintf("transfer/%s/%s", destinationChannel, denom)), + Amount: amountInt, + Sender: sender, + Receiver: receiver, + } + actualRecvPacketInfo, err := keeper.ParsePacketInfo(packet, types.PACKET_RECV) + s.Require().NoError(err, "no error expected when parsing recv packet") + s.Require().Equal(expectedRecvPacketInfo, actualRecvPacketInfo, "recv packet") +} + +func (s *KeeperTestSuite) createRateLimitCloseToQuota(denom string, channelId string, direction types.PacketDirection) { + channelValue := sdkmath.NewInt(100) + threshold := sdkmath.NewInt(10) + + // Set inflow/outflow close to threshold, depending on which direction we're going in + inflow := sdkmath.ZeroInt() + outflow := sdkmath.ZeroInt() + if direction == types.PACKET_RECV { + inflow = sdkmath.NewInt(9) + } else { + outflow = sdkmath.NewInt(9) + } + + // Store rate limit + s.App.RatelimitKeeper.SetRateLimit(s.Ctx, types.RateLimit{ + Path: &types.Path{ + Denom: denom, + ChannelId: channelId, + }, + Quota: &types.Quota{ + MaxPercentSend: threshold, + MaxPercentRecv: threshold, + }, + Flow: &types.Flow{ + Inflow: inflow, + Outflow: outflow, + ChannelValue: channelValue, + }, + }) +} + +func (s *KeeperTestSuite) TestSendRateLimitedPacket() { + // For send packets, the source will be stride and the destination will be the host + denom := ustrd + sourceChannel := channelOnStride + destinationChannel := channelOnHost + amountToExceed := "5" + sequence := uint64(10) + + // Create rate limit (for SEND, use SOURCE channel) + s.createRateLimitCloseToQuota(denom, sourceChannel, types.PACKET_SEND) + + // This packet should cause an Outflow quota exceed error + packetData, err := json.Marshal(transfertypes.FungibleTokenPacketData{Denom: denom, Amount: amountToExceed}) + s.Require().NoError(err) + packet := channeltypes.Packet{ + SourcePort: transferPort, + SourceChannel: sourceChannel, + DestinationPort: transferPort, + DestinationChannel: destinationChannel, + Data: packetData, + Sequence: sequence, + } + + // We check for a quota error because it doesn't appear until the end of the function + // We're avoiding checking for a success here because we can get a false positive if the rate limit doesn't exist + err = s.App.RatelimitKeeper.SendRateLimitedPacket(s.Ctx, packet) + s.Require().ErrorIs(err, types.ErrQuotaExceeded, "error type") + s.Require().ErrorContains(err, "Outflow exceeds quota", "error text") + + // Reset the rate limit and try again + err = s.App.RatelimitKeeper.ResetRateLimit(s.Ctx, denom, channelId) + s.Require().NoError(err, "no error expected when resetting rate limit") + + err = s.App.RatelimitKeeper.SendRateLimitedPacket(s.Ctx, packet) + s.Require().NoError(err, "no error expected when sending packet after reset") + + // Check that the pending packet was stored + found := s.App.RatelimitKeeper.CheckPacketSentDuringCurrentQuota(s.Ctx, sourceChannel, sequence) + s.Require().True(found, "pending send packet") +} + +func (s *KeeperTestSuite) TestReceiveRateLimitedPacket() { + // For receive packets, the source will be the host and the destination will be stride + packetDenom := uosmo + sourceChannel := channelOnHost + destinationChannel := channelOnStride + amountToExceed := "5" + + // When the packet is received, the port and channel prefix will be added and the denom will be hashed + // before the rate limit is found from the store + rateLimitDenom := hashDenomTrace(fmt.Sprintf("%s/%s/%s", transferPort, channelOnStride, packetDenom)) + + // Create rate limit (for RECV, use DESTINATION channel) + s.createRateLimitCloseToQuota(rateLimitDenom, destinationChannel, types.PACKET_RECV) + + // This packet should cause an Outflow quota exceed error + packetData, err := json.Marshal(transfertypes.FungibleTokenPacketData{Denom: packetDenom, Amount: amountToExceed}) + s.Require().NoError(err) + packet := channeltypes.Packet{ + SourcePort: transferPort, + SourceChannel: sourceChannel, + DestinationPort: transferPort, + DestinationChannel: destinationChannel, + Data: packetData, + } + + // We check for a quota error because it doesn't appear until the end of the function + // We're avoiding checking for a success here because we can get a false positive if the rate limit doesn't exist + err = s.App.RatelimitKeeper.ReceiveRateLimitedPacket(s.Ctx, packet) + s.Require().ErrorIs(err, types.ErrQuotaExceeded, "error type") + s.Require().ErrorContains(err, "Inflow exceeds quota", "error text") +} + +func (s *KeeperTestSuite) TestAcknowledgeRateLimitedPacket_AckSuccess() { + // For ack packets, the source will be stride and the destination will be the host + denom := ustrd + sourceChannel := channelOnStride + destinationChannel := channelOnHost + sequence := uint64(10) + + // Create rate limit - the flow and quota does not matter for this test + s.App.RatelimitKeeper.SetRateLimit(s.Ctx, types.RateLimit{ + Path: &types.Path{Denom: denom, ChannelId: channelId}, + }) + + // Store the pending packet for this sequence number + s.App.RatelimitKeeper.SetPendingSendPacket(s.Ctx, sourceChannel, sequence) + + // Build the ack packet + packetData, err := json.Marshal(transfertypes.FungibleTokenPacketData{Denom: denom, Amount: "10"}) + s.Require().NoError(err) + packet := channeltypes.Packet{ + SourcePort: transferPort, + SourceChannel: sourceChannel, + DestinationPort: transferPort, + DestinationChannel: destinationChannel, + Data: packetData, + Sequence: sequence, + } + ackSuccess := transfertypes.ModuleCdc.MustMarshalJSON(&channeltypes.Acknowledgement{ + Response: &channeltypes.Acknowledgement_Result{Result: []byte{1}}, + }) + + // Call AckPacket with the successful ack + err = s.App.RatelimitKeeper.AcknowledgeRateLimitedPacket(s.Ctx, packet, ackSuccess) + s.Require().NoError(err, "no error expected during AckPacket") + + // Confirm the pending packet was removed + found := s.App.RatelimitKeeper.CheckPacketSentDuringCurrentQuota(s.Ctx, sourceChannel, sequence) + s.Require().False(found, "send packet should have been removed") +} + +func (s *KeeperTestSuite) TestAcknowledgeRateLimitedPacket_AckFailure() { + // For ack packets, the source will be stride and the destination will be the host + denom := ustrd + sourceChannel := channelOnStride + destinationChannel := channelOnHost + initialOutflow := sdkmath.NewInt(100) + packetAmount := sdkmath.NewInt(10) + sequence := uint64(10) + + // Create rate limit - only outflow is needed to this tests + s.App.RatelimitKeeper.SetRateLimit(s.Ctx, types.RateLimit{ + Path: &types.Path{Denom: denom, ChannelId: channelId}, + Flow: &types.Flow{Outflow: initialOutflow}, + }) + + // Store the pending packet for this sequence number + s.App.RatelimitKeeper.SetPendingSendPacket(s.Ctx, sourceChannel, sequence) + + // Build the ack packet + packetData, err := json.Marshal(transfertypes.FungibleTokenPacketData{Denom: denom, Amount: packetAmount.String()}) + s.Require().NoError(err) + packet := channeltypes.Packet{ + SourcePort: transferPort, + SourceChannel: sourceChannel, + DestinationPort: transferPort, + DestinationChannel: destinationChannel, + Data: packetData, + Sequence: sequence, + } + ackFailure := transfertypes.ModuleCdc.MustMarshalJSON(&channeltypes.Acknowledgement{ + Response: &channeltypes.Acknowledgement_Error{Error: "error"}, + }) + + // Call OnTimeoutPacket with the failed ack + err = s.App.RatelimitKeeper.AcknowledgeRateLimitedPacket(s.Ctx, packet, ackFailure) + s.Require().NoError(err, "no error expected during AckPacket") + + // Confirm the pending packet was removed + found := s.App.RatelimitKeeper.CheckPacketSentDuringCurrentQuota(s.Ctx, sourceChannel, sequence) + s.Require().False(found, "send packet should have been removed") + + // Confirm the flow was adjusted + rateLimit, found := s.App.RatelimitKeeper.GetRateLimit(s.Ctx, denom, sourceChannel) + s.Require().True(found) + s.Require().Equal(initialOutflow.Sub(packetAmount).Int64(), rateLimit.Flow.Outflow.Int64(), "outflow") +} + +func (s *KeeperTestSuite) TestTimeoutRateLimitedPacket() { + // For timeout packets, the source will be stride and the destination will be the host + denom := ustrd + sourceChannel := channelOnStride + destinationChannel := channelOnHost + initialOutflow := sdkmath.NewInt(100) + packetAmount := sdkmath.NewInt(10) + sequence := uint64(10) + + // Create rate limit - only outflow is needed to this tests + s.App.RatelimitKeeper.SetRateLimit(s.Ctx, types.RateLimit{ + Path: &types.Path{Denom: denom, ChannelId: channelId}, + Flow: &types.Flow{Outflow: initialOutflow}, + }) + + // Store the pending packet for this sequence number + s.App.RatelimitKeeper.SetPendingSendPacket(s.Ctx, sourceChannel, sequence) + + // Build the timeout packet + packetData, err := json.Marshal(transfertypes.FungibleTokenPacketData{Denom: denom, Amount: packetAmount.String()}) + s.Require().NoError(err) + packet := channeltypes.Packet{ + SourcePort: transferPort, + SourceChannel: sourceChannel, + DestinationPort: transferPort, + DestinationChannel: destinationChannel, + Data: packetData, + Sequence: sequence, + } + + // Call OnTimeoutPacket - the outflow should get decremented + err = s.App.RatelimitKeeper.TimeoutRateLimitedPacket(s.Ctx, packet) + s.Require().NoError(err, "no error expected when calling timeout packet") + + expectedOutflow := initialOutflow.Sub(packetAmount) + rateLimit, found := s.App.RatelimitKeeper.GetRateLimit(s.Ctx, denom, channelId) + s.Require().True(found) + s.Require().Equal(expectedOutflow.Int64(), rateLimit.Flow.Outflow.Int64(), "outflow decremented") + + // Check that the pending packet has been removed + found = s.App.RatelimitKeeper.CheckPacketSentDuringCurrentQuota(s.Ctx, channelId, sequence) + s.Require().False(found, "pending packet should have been removed") + + // Call OnTimeoutPacket again with a different sequence number + // (to simulate a timeout that arrived in a different quota window from where the send occurred) + // The outflow should not change + packet.Sequence -= 1 + err = s.App.RatelimitKeeper.TimeoutRateLimitedPacket(s.Ctx, packet) + s.Require().NoError(err, "no error expected when calling timeout packet again") + + rateLimit, found = s.App.RatelimitKeeper.GetRateLimit(s.Ctx, denom, channelId) + s.Require().True(found) + s.Require().Equal(expectedOutflow.Int64(), rateLimit.Flow.Outflow.Int64(), "outflow should not have changed") +} diff --git a/modules/rate-limiting/keeper/params.go b/modules/rate-limiting/keeper/params.go new file mode 100644 index 00000000..389d0623 --- /dev/null +++ b/modules/rate-limiting/keeper/params.go @@ -0,0 +1,17 @@ +package keeper + +import ( + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// GetParams get all parameters as types.Params +func (k Keeper) GetParams(ctx sdk.Context) types.Params { + return types.NewParams() +} + +// SetParams set the params +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramstore.SetParamSet(ctx, ¶ms) +} diff --git a/modules/rate-limiting/keeper/pending_send.go b/modules/rate-limiting/keeper/pending_send.go new file mode 100644 index 00000000..05bcb373 --- /dev/null +++ b/modules/rate-limiting/keeper/pending_send.go @@ -0,0 +1,72 @@ +package keeper + +import ( + "encoding/binary" + "fmt" + "strings" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Sets the sequence number of a packet that was just sent +func (k Keeper) SetPendingSendPacket(ctx sdk.Context, channelId string, sequence uint64) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.PendingSendPacketPrefix) + key := types.GetPendingSendPacketKey(channelId, sequence) + store.Set(key, []byte{1}) +} + +// Remove a pending packet sequence number from the store +// Used after the ack or timeout for a packet has been received +func (k Keeper) RemovePendingSendPacket(ctx sdk.Context, channelId string, sequence uint64) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.PendingSendPacketPrefix) + key := types.GetPendingSendPacketKey(channelId, sequence) + store.Delete(key) +} + +// Checks whether the packet sequence number is in the store - indicating that it was +// sent during the current quota +func (k Keeper) CheckPacketSentDuringCurrentQuota(ctx sdk.Context, channelId string, sequence uint64) bool { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.PendingSendPacketPrefix) + key := types.GetPendingSendPacketKey(channelId, sequence) + valueBz := store.Get(key) + found := len(valueBz) != 0 + return found +} + +// Get all pending packet sequence numbers +func (k Keeper) GetAllPendingSendPackets(ctx sdk.Context) []string { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.PendingSendPacketPrefix) + + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + pendingPackets := []string{} + for ; iterator.Valid(); iterator.Next() { + key := iterator.Key() + + channelId := string(key[:types.PendingSendPacketChannelLength]) + channelId = strings.TrimRight(channelId, "\x00") // removes null bytes from suffix + sequence := binary.BigEndian.Uint64(key[types.PendingSendPacketChannelLength:]) + + packetId := fmt.Sprintf("%s/%d", channelId, sequence) + pendingPackets = append(pendingPackets, packetId) + } + + return pendingPackets +} + +// Remove all pending sequence numbers from the store +// This is executed when the quota resets +func (k Keeper) RemoveAllChannelPendingSendPackets(ctx sdk.Context, channelId string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.PendingSendPacketPrefix) + + iterator := sdk.KVStorePrefixIterator(store, types.KeyPrefix(channelId)) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + store.Delete(iterator.Key()) + } +} diff --git a/modules/rate-limiting/keeper/pending_send_test.go b/modules/rate-limiting/keeper/pending_send_test.go new file mode 100644 index 00000000..8ab6e842 --- /dev/null +++ b/modules/rate-limiting/keeper/pending_send_test.go @@ -0,0 +1,40 @@ +package keeper_test + +import "fmt" + +func (s *KeeperTestSuite) TestPendingSendPacketPrefix() { + // Store 5 packets across two channels + sendPackets := []string{} + for _, channelId := range []string{"channel-0", "channel-1"} { + for sequence := uint64(0); sequence < 5; sequence++ { + s.App.RatelimitKeeper.SetPendingSendPacket(s.Ctx, channelId, sequence) + sendPackets = append(sendPackets, fmt.Sprintf("%s/%d", channelId, sequence)) + } + } + + // Check that they each sequence number is found + for _, channelId := range []string{"channel-0", "channel-1"} { + for sequence := uint64(0); sequence < 5; sequence++ { + found := s.App.RatelimitKeeper.CheckPacketSentDuringCurrentQuota(s.Ctx, channelId, sequence) + s.Require().True(found, "send packet should have been found - channel %s, sequence: %d", channelId, sequence) + } + } + + // Check lookup of all sequence numbers + actualSendPackets := s.App.RatelimitKeeper.GetAllPendingSendPackets(s.Ctx) + s.Require().Equal(sendPackets, actualSendPackets, "all send packets") + + // Remove 0 sequence numbers and all sequence numbers from channel-0 + s.App.RatelimitKeeper.RemovePendingSendPacket(s.Ctx, "channel-0", 0) + s.App.RatelimitKeeper.RemovePendingSendPacket(s.Ctx, "channel-1", 0) + s.App.RatelimitKeeper.RemoveAllChannelPendingSendPackets(s.Ctx, "channel-0") + + // Check that only the remaining sequences are found + for _, channelId := range []string{"channel-0", "channel-1"} { + for sequence := uint64(0); sequence < 5; sequence++ { + expected := (channelId == "channel-1") && (sequence != 0) + actual := s.App.RatelimitKeeper.CheckPacketSentDuringCurrentQuota(s.Ctx, channelId, sequence) + s.Require().Equal(expected, actual, "send packet after removal - channel: %s, sequence: %d", channelId, sequence) + } + } +} diff --git a/modules/rate-limiting/keeper/rate_limit.go b/modules/rate-limiting/keeper/rate_limit.go new file mode 100644 index 00000000..1900ace5 --- /dev/null +++ b/modules/rate-limiting/keeper/rate_limit.go @@ -0,0 +1,162 @@ +package keeper + +import ( + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + sdkmath "cosmossdk.io/math" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" +) + +// Stores/Updates a rate limit object in the store +func (k Keeper) SetRateLimit(ctx sdk.Context, rateLimit types.RateLimit) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.RateLimitKeyPrefix) + + rateLimitKey := types.GetRateLimitItemKey(rateLimit.Path.Denom, rateLimit.Path.ChannelId) + rateLimitValue := k.cdc.MustMarshal(&rateLimit) + + store.Set(rateLimitKey, rateLimitValue) +} + +// Removes a rate limit object from the store using denom and channel-id +func (k Keeper) RemoveRateLimit(ctx sdk.Context, denom string, channelId string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.RateLimitKeyPrefix) + rateLimitKey := types.GetRateLimitItemKey(denom, channelId) + store.Delete(rateLimitKey) +} + +// Grabs and returns a rate limit object from the store using denom and channel-id +func (k Keeper) GetRateLimit(ctx sdk.Context, denom string, channelId string) (rateLimit types.RateLimit, found bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.RateLimitKeyPrefix) + + rateLimitKey := types.GetRateLimitItemKey(denom, channelId) + rateLimitValue := store.Get(rateLimitKey) + + if len(rateLimitValue) == 0 { + return rateLimit, false + } + + k.cdc.MustUnmarshal(rateLimitValue, &rateLimit) + return rateLimit, true +} + +// Returns all rate limits stored +func (k Keeper) GetAllRateLimits(ctx sdk.Context) []types.RateLimit { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.RateLimitKeyPrefix) + + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + allRateLimits := []types.RateLimit{} + for ; iterator.Valid(); iterator.Next() { + + rateLimit := types.RateLimit{} + k.cdc.MustUnmarshal(iterator.Value(), &rateLimit) + allRateLimits = append(allRateLimits, rateLimit) + } + + return allRateLimits +} + +// Adds a new rate limit. Fails if the rate limit already exists or the channel value is 0 +func (k Keeper) AddRateLimit(ctx sdk.Context, msg *types.MsgAddRateLimit) error { + // Confirm the channel value is not zero + channelValue := k.GetChannelValue(ctx, msg.Denom) + if channelValue.IsZero() { + return types.ErrZeroChannelValue + } + + // Confirm the rate limit does not already exist + _, found := k.GetRateLimit(ctx, msg.Denom, msg.ChannelId) + if found { + return types.ErrRateLimitAlreadyExists + } + + // Confirm the channel exists + _, found = k.channelKeeper.GetChannel(ctx, transfertypes.PortID, msg.ChannelId) + if !found { + return types.ErrChannelNotFound + } + + // Create and store the rate limit object + path := types.Path{ + Denom: msg.Denom, + ChannelId: msg.ChannelId, + } + quota := types.Quota{ + MaxPercentSend: msg.MaxPercentSend, + MaxPercentRecv: msg.MaxPercentRecv, + DurationHours: msg.DurationHours, + } + flow := types.Flow{ + Inflow: sdkmath.ZeroInt(), + Outflow: sdkmath.ZeroInt(), + ChannelValue: channelValue, + } + + k.SetRateLimit(ctx, types.RateLimit{ + Path: &path, + Quota: "a, + Flow: &flow, + }) + + return nil +} + +// Updates an existing rate limit. Fails if the rate limit doesn't exist +func (k Keeper) UpdateRateLimit(ctx sdk.Context, msg *types.MsgUpdateRateLimit) error { + // Confirm the rate limit exists + _, found := k.GetRateLimit(ctx, msg.Denom, msg.ChannelId) + if !found { + return types.ErrRateLimitNotFound + } + + // Update the rate limit object with the new quota information + // The flow should also get reset to 0 + path := types.Path{ + Denom: msg.Denom, + ChannelId: msg.ChannelId, + } + quota := types.Quota{ + MaxPercentSend: msg.MaxPercentSend, + MaxPercentRecv: msg.MaxPercentRecv, + DurationHours: msg.DurationHours, + } + flow := types.Flow{ + Inflow: sdkmath.ZeroInt(), + Outflow: sdkmath.ZeroInt(), + ChannelValue: k.GetChannelValue(ctx, msg.Denom), + } + + k.SetRateLimit(ctx, types.RateLimit{ + Path: &path, + Quota: "a, + Flow: &flow, + }) + + return nil +} + +// Reset the rate limit after expiration +// The inflow and outflow should get reset to 0, the channelValue should be updated, +// and all pending send packet sequence numbers should be removed +func (k Keeper) ResetRateLimit(ctx sdk.Context, denom string, channelId string) error { + rateLimit, found := k.GetRateLimit(ctx, denom, channelId) + if !found { + return types.ErrRateLimitNotFound + } + + flow := types.Flow{ + Inflow: sdkmath.ZeroInt(), + Outflow: sdkmath.ZeroInt(), + ChannelValue: k.GetChannelValue(ctx, denom), + } + rateLimit.Flow = &flow + + k.SetRateLimit(ctx, rateLimit) + k.RemoveAllChannelPendingSendPackets(ctx, channelId) + return nil +} diff --git a/modules/rate-limiting/keeper/rate_limit_test.go b/modules/rate-limiting/keeper/rate_limit_test.go new file mode 100644 index 00000000..d3004575 --- /dev/null +++ b/modules/rate-limiting/keeper/rate_limit_test.go @@ -0,0 +1,95 @@ +package keeper_test + +import ( + "strconv" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + sdkmath "cosmossdk.io/math" +) + +const ( + denom = "denom" + channelId = "channel-0" + sender = "sender" + receiver = "receiver" +) + +type action struct { + direction types.PacketDirection + amount int64 + addToBlacklist bool + removeFromBlacklist bool + addToWhitelist bool + removeFromWhitelist bool + skipFlowUpdate bool + expectedError string +} + +type checkRateLimitTestCase struct { + name string + actions []action +} + +// Helper function to create 5 rate limit objects with various attributes +func (s *KeeperTestSuite) createRateLimits() []types.RateLimit { + rateLimits := []types.RateLimit{} + for i := 1; i <= 5; i++ { + suffix := strconv.Itoa(i) + rateLimit := types.RateLimit{ + Path: &types.Path{Denom: "denom-" + suffix, ChannelId: "channel-" + suffix}, + Flow: &types.Flow{Inflow: sdkmath.NewInt(10), Outflow: sdkmath.NewInt(10)}, + } + + rateLimits = append(rateLimits, rateLimit) + s.App.RatelimitKeeper.SetRateLimit(s.Ctx, rateLimit) + } + return rateLimits +} + +func (s *KeeperTestSuite) TestGetRateLimit() { + rateLimits := s.createRateLimits() + + expectedRateLimit := rateLimits[0] + denom := expectedRateLimit.Path.Denom + channelId := expectedRateLimit.Path.ChannelId + + actualRateLimit, found := s.App.RatelimitKeeper.GetRateLimit(s.Ctx, denom, channelId) + s.Require().True(found, "element should have been found, but was not") + s.Require().Equal(expectedRateLimit, actualRateLimit) +} + +func (s *KeeperTestSuite) TestRemoveRateLimit() { + rateLimits := s.createRateLimits() + + rateLimitToRemove := rateLimits[0] + denomToRemove := rateLimitToRemove.Path.Denom + channelIdToRemove := rateLimitToRemove.Path.ChannelId + + s.App.RatelimitKeeper.RemoveRateLimit(s.Ctx, denomToRemove, channelIdToRemove) + _, found := s.App.RatelimitKeeper.GetRateLimit(s.Ctx, denomToRemove, channelIdToRemove) + s.Require().False(found, "the removed element should not have been found, but it was") +} + +func (s *KeeperTestSuite) TestResetRateLimit() { + rateLimits := s.createRateLimits() + + rateLimitToReset := rateLimits[0] + denomToRemove := rateLimitToReset.Path.Denom + channelIdToRemove := rateLimitToReset.Path.ChannelId + + err := s.App.RatelimitKeeper.ResetRateLimit(s.Ctx, denomToRemove, channelIdToRemove) + s.Require().NoError(err) + + rateLimit, found := s.App.RatelimitKeeper.GetRateLimit(s.Ctx, denomToRemove, channelIdToRemove) + s.Require().True(found, "element should have been found, but was not") + s.Require().Zero(rateLimit.Flow.Inflow.Int64(), "Inflow should have been reset to 0") + s.Require().Zero(rateLimit.Flow.Outflow.Int64(), "Outflow should have been reset to 0") +} + +func (s *KeeperTestSuite) TestGetAllRateLimits() { + expectedRateLimits := s.createRateLimits() + actualRateLimits := s.App.RatelimitKeeper.GetAllRateLimits(s.Ctx) + s.Require().Len(actualRateLimits, len(expectedRateLimits)) + s.Require().ElementsMatch(expectedRateLimits, actualRateLimits, "all rate limits") +} diff --git a/modules/rate-limiting/keeper/whitelist.go b/modules/rate-limiting/keeper/whitelist.go new file mode 100644 index 00000000..533e7587 --- /dev/null +++ b/modules/rate-limiting/keeper/whitelist.go @@ -0,0 +1,52 @@ +package keeper + +import ( + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Adds an pair of sender and receiver addresses to the whitelist to allow all +// IBC transfers between those addresses to skip all flow calculations +func (k Keeper) SetWhitelistedAddressPair(ctx sdk.Context, whitelist types.WhitelistedAddressPair) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.AddressWhitelistKeyPrefix) + key := types.GetAddressWhitelistKey(whitelist.Sender, whitelist.Receiver) + value := k.cdc.MustMarshal(&whitelist) + store.Set(key, value) +} + +// Removes a whitelisted address pair so that it's transfers are counted in the quota +func (k Keeper) RemoveWhitelistedAddressPair(ctx sdk.Context, sender, receiver string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.AddressWhitelistKeyPrefix) + key := types.GetAddressWhitelistKey(sender, receiver) + store.Delete(key) +} + +// Check if a sender/receiver address pair is currently whitelisted +func (k Keeper) IsAddressPairWhitelisted(ctx sdk.Context, sender, receiver string) bool { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.AddressWhitelistKeyPrefix) + + key := types.GetAddressWhitelistKey(sender, receiver) + value := store.Get(key) + found := len(value) != 0 + + return found +} + +// Get all the whitelisted addresses +func (k Keeper) GetAllWhitelistedAddressPairs(ctx sdk.Context) []types.WhitelistedAddressPair { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.AddressWhitelistKeyPrefix) + + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + allWhitelistedAddresses := []types.WhitelistedAddressPair{} + for ; iterator.Valid(); iterator.Next() { + whitelist := types.WhitelistedAddressPair{} + k.cdc.MustUnmarshal(iterator.Value(), &whitelist) + allWhitelistedAddresses = append(allWhitelistedAddresses, whitelist) + } + + return allWhitelistedAddresses +} diff --git a/modules/rate-limiting/keeper/whitelist_test.go b/modules/rate-limiting/keeper/whitelist_test.go new file mode 100644 index 00000000..3805a825 --- /dev/null +++ b/modules/rate-limiting/keeper/whitelist_test.go @@ -0,0 +1,52 @@ +package keeper_test + +import "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + +func (s *KeeperTestSuite) TestAddressWhitelist() { + // Store addresses in whitelist + expectedWhitelist := []types.WhitelistedAddressPair{ + {Sender: "sender-1", Receiver: "receiver-1"}, + {Sender: "sender-2", Receiver: "receiver-2"}, + {Sender: "sender-3", Receiver: "receiver-3"}, + } + for _, addressPair := range expectedWhitelist { + s.App.RatelimitKeeper.SetWhitelistedAddressPair(s.Ctx, addressPair) + } + + // Confirm that each was found + for _, addressPair := range expectedWhitelist { + found := s.App.RatelimitKeeper.IsAddressPairWhitelisted(s.Ctx, addressPair.Sender, addressPair.Receiver) + s.Require().True(found, "address pair should have been whitelisted (%s/%s)", + addressPair.Sender, addressPair.Receiver) + } + + // Confirm that looking both the sender and receiver must match for the pair to be whitelisted + for _, addressPair := range expectedWhitelist { + found := s.App.RatelimitKeeper.IsAddressPairWhitelisted(s.Ctx, addressPair.Sender, "fake-receiver") + s.Require().False(found, "address pair should not have been whitelisted (%s/%s)", + addressPair.Sender, "fake-receiver") + + found = s.App.RatelimitKeeper.IsAddressPairWhitelisted(s.Ctx, "fake-sender", addressPair.Receiver) + s.Require().False(found, "address pair should not have been whitelisted (%s/%s)", + "fake-sender", addressPair.Receiver) + } + + // Check GetAll + actualWhitelist := s.App.RatelimitKeeper.GetAllWhitelistedAddressPairs(s.Ctx) + s.Require().Equal(expectedWhitelist, actualWhitelist, "whitelist get all") + + // Finally, remove each from whitelist + for _, addressPair := range expectedWhitelist { + s.App.RatelimitKeeper.RemoveWhitelistedAddressPair(s.Ctx, addressPair.Sender, addressPair.Receiver) + } + + // Confirm there are no longer any whitelisted pairs + actualWhitelist = s.App.RatelimitKeeper.GetAllWhitelistedAddressPairs(s.Ctx) + s.Require().Empty(actualWhitelist, "whitelist should have been cleared") + + for _, addressPair := range expectedWhitelist { + found := s.App.RatelimitKeeper.IsAddressPairWhitelisted(s.Ctx, addressPair.Sender, addressPair.Receiver) + s.Require().False(found, "address pair should no longer be whitelisted (%s/%s)", + addressPair.Sender, addressPair.Receiver) + } +} diff --git a/modules/rate-limiting/module.go b/modules/rate-limiting/module.go new file mode 100644 index 00000000..e8ef61c9 --- /dev/null +++ b/modules/rate-limiting/module.go @@ -0,0 +1,160 @@ +package ratelimit + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/client/cli" + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/keeper" + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + + abci "github.com/cometbft/cometbft/abci/types" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +// ---------------------------------------------------------------------------- +// AppModuleBasic +// ---------------------------------------------------------------------------- + +// AppModuleBasic implements the AppModuleBasic interface for the capability module. +type AppModuleBasic struct { + cdc codec.BinaryCodec +} + +func NewAppModuleBasic(cdc codec.BinaryCodec) AppModuleBasic { + return AppModuleBasic{cdc: cdc} +} + +// Name returns the capability module's name. +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterLegacyAminoCodec(cdc) +} + +// RegisterInterfaces registers the module's interface types +func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(reg) +} + +// DefaultGenesis returns the capability module's default genesis state. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesis()) +} + +// ValidateGenesis performs genesis state validation for the capability module. +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { + var genState types.GenesisState + if err := cdc.UnmarshalJSON(bz, &genState); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + return genState.Validate() +} + +// RegisterRESTRoutes registers the capability module's REST service handlers. +func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) { +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil { + panic(err) + } +} + +// GetTxCmd returns the capability module's root tx command. +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + return nil +} + +// GetQueryCmd returns the capability module's root query command. +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// ---------------------------------------------------------------------------- +// AppModule +// ---------------------------------------------------------------------------- + +// AppModule implements the AppModule interface for the capability module. +type AppModule struct { + AppModuleBasic + + keeper keeper.Keeper +} + +func NewAppModule( + cdc codec.Codec, + keeper keeper.Keeper, +) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(cdc), + keeper: keeper, + } +} + +// Name returns the capability module's name. +func (am AppModule) Name() string { + return am.AppModuleBasic.Name() +} + +// QuerierRoute returns the capability module's query routing key. +func (AppModule) QuerierRoute() string { return types.QuerierRoute } + +// RegisterServices registers a GRPC query service to respond to the +// module-specific GRPC queries. +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterQueryServer(cfg.QueryServer(), am.keeper) + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) +} + +// RegisterInvariants registers the capability module's invariants. +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// InitGenesis performs the capability module's genesis initialization It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { + var genState types.GenesisState + // Initialize global index to index in genesis state + cdc.MustUnmarshalJSON(gs, &genState) + + am.keeper.InitGenesis(ctx, genState) + + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the capability module's exported genesis state as raw JSON bytes. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + genState := am.keeper.ExportGenesis(ctx) + return cdc.MustMarshalJSON(genState) +} + +// ConsensusVersion implements ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return 1 } + +// BeginBlock executes all ABCI BeginBlock logic respective to the capability module. +func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { + am.keeper.BeginBlocker(ctx) +} + +// EndBlock executes all ABCI EndBlock logic respective to the capability module. It +// returns no validator updates. +func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} diff --git a/modules/rate-limiting/proto/buf.gen.gogo.yaml b/modules/rate-limiting/proto/buf.gen.gogo.yaml new file mode 100644 index 00000000..1e35cc88 --- /dev/null +++ b/modules/rate-limiting/proto/buf.gen.gogo.yaml @@ -0,0 +1,8 @@ +version: v1 +plugins: + - name: gocosmos + out: .. + opt: plugins=grpc,Mgoogle/protobuf/duration.proto=github.com/cosmos/gogoproto/types,Mgoogle/protobuf/struct.proto=github.com/cosmos/gogoproto/types,Mgoogle/protobuf/timestamp.proto=github.com/cosmos/gogoproto/types,Mgoogle/protobuf/wrappers.proto=github.com/cosmos/gogoproto/types,Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types,Mcosmos/orm/v1alpha1/orm.proto=github.com/cosmos/cosmos-sdk/api/cosmos/orm/v1alpha1 + - name: grpc-gateway + out: .. + opt: logtostderr=true,allow_colon_final_segments=true diff --git a/modules/rate-limiting/proto/buf.lock b/modules/rate-limiting/proto/buf.lock new file mode 100644 index 00000000..def97047 --- /dev/null +++ b/modules/rate-limiting/proto/buf.lock @@ -0,0 +1,23 @@ +# Generated by buf. DO NOT EDIT. +version: v1 +deps: + - remote: buf.build + owner: cosmos + repository: cosmos-proto + commit: 1935555c206d4afb9e94615dfd0fad31 + digest: shake256:c74d91a3ac7ae07d579e90eee33abf9b29664047ac8816500cf22c081fec0d72d62c89ce0bebafc1f6fec7aa5315be72606717740ca95007248425102c365377 + - remote: buf.build + owner: cosmos + repository: cosmos-sdk + commit: 954f7b05f38440fc8250134b15adec47 + digest: shake256:2ab4404fd04a7d1d52df0e2d0f2d477a3d83ffd88d876957bf3fedfd702c8e52833d65b3ce1d89a3c5adf2aab512616b0e4f51d8463f07eda9a8a3317ee3ac54 + - remote: buf.build + owner: cosmos + repository: gogo-proto + commit: 34d970b699f84aa382f3c29773a60836 + digest: shake256:3d3bee5229ba579e7d19ffe6e140986a228b48a8c7fe74348f308537ab95e9135210e81812489d42cd8941d33ff71f11583174ccc5972e86e6112924b6ce9f04 + - remote: buf.build + owner: googleapis + repository: googleapis + commit: cc916c31859748a68fd229a3c8d7a2e8 + digest: shake256:469b049d0eb04203d5272062636c078decefc96fec69739159c25d85349c50c34c7706918a8b216c5c27f76939df48452148cff8c5c3ae77fa6ba5c25c1b8bf8 diff --git a/modules/rate-limiting/proto/buf.yaml b/modules/rate-limiting/proto/buf.yaml new file mode 100644 index 00000000..a41499ec --- /dev/null +++ b/modules/rate-limiting/proto/buf.yaml @@ -0,0 +1,24 @@ +version: v1 +deps: + - buf.build/cosmos/cosmos-sdk:v0.47.0 + - buf.build/cosmos/cosmos-proto + - buf.build/cosmos/gogo-proto + - buf.build/googleapis/googleapis +breaking: + use: + - FILE +lint: + use: + - DEFAULT + - FILE_LOWER_SNAKE_CASE + - MESSAGE_PASCAL_CASE + - RPC_PASCAL_CASE + - SERVICE_PASCAL_CASE + except: + - UNARY_RPC + - SERVICE_SUFFIX + - PACKAGE_VERSION_SUFFIX + - RPC_REQUEST_STANDARD_NAME + - RPC_RESPONSE_STANDARD_NAME + - ENUM_ZERO_VALUE_SUFFIX + - ENUM_VALUE_PREFIX diff --git a/modules/rate-limiting/proto/ratelimit/v1/genesis.proto b/modules/rate-limiting/proto/ratelimit/v1/genesis.proto new file mode 100644 index 00000000..e11ba8f0 --- /dev/null +++ b/modules/rate-limiting/proto/ratelimit/v1/genesis.proto @@ -0,0 +1,34 @@ +syntax = "proto3"; +package ratelimit.v1; + +import "gogoproto/gogo.proto"; +import "ratelimit/v1/params.proto"; +import "ratelimit/v1/ratelimit.proto"; + +option go_package = "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types"; + +// GenesisState defines the ratelimit module's genesis state. +message GenesisState { + Params params = 1 [ + (gogoproto.moretags) = "yaml:\"params\"", + (gogoproto.nullable) = false + ]; + + repeated RateLimit rate_limits = 2 [ + (gogoproto.moretags) = "yaml:\"rate_limits\"", + (gogoproto.nullable) = false + ]; + + repeated WhitelistedAddressPair whitelisted_address_pairs = 3 [ + (gogoproto.moretags) = "yaml:\"whitelisted_address_pairs\"", + (gogoproto.nullable) = false + ]; + + repeated string blacklisted_denoms = 4; + repeated string pending_send_packet_sequence_numbers = 5; + + HourEpoch hour_epoch = 6 [ + (gogoproto.moretags) = "yaml:\"hour_epoch\"", + (gogoproto.nullable) = false + ]; +} diff --git a/modules/rate-limiting/proto/ratelimit/v1/params.proto b/modules/rate-limiting/proto/ratelimit/v1/params.proto new file mode 100644 index 00000000..532a8508 --- /dev/null +++ b/modules/rate-limiting/proto/ratelimit/v1/params.proto @@ -0,0 +1,7 @@ +syntax = "proto3"; +package ratelimit.v1; + +option go_package = "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types"; + +// Params defines the ratelimit module's parameters. +message Params {} diff --git a/modules/rate-limiting/proto/ratelimit/v1/query.proto b/modules/rate-limiting/proto/ratelimit/v1/query.proto new file mode 100644 index 00000000..68b8758d --- /dev/null +++ b/modules/rate-limiting/proto/ratelimit/v1/query.proto @@ -0,0 +1,90 @@ +syntax = "proto3"; +package ratelimit.v1; + +import "ratelimit/v1/ratelimit.proto"; +import "google/api/annotations.proto"; +import "gogoproto/gogo.proto"; + +option go_package = "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types"; + +// Query defines the gRPC querier service. +service Query { + // Queries all rate limits + rpc AllRateLimits(QueryAllRateLimitsRequest) + returns (QueryAllRateLimitsResponse) { + option (google.api.http).get = + "/Stride-Labs/ibc-rate-limiting/ratelimit/ratelimits"; + } + + // Queries a specific rate limit by channel ID and denom + // Ex: + // - /ratelimit/{channel_id}/by_denom?denom={denom} + rpc RateLimit(QueryRateLimitRequest) returns (QueryRateLimitResponse) { + option (google.api.http).get = "/Stride-Labs/ibc-rate-limiting/ratelimit/" + "ratelimit/{channel_id}/by_denom"; + } + + // Queries all the rate limits for a given chain + rpc RateLimitsByChainId(QueryRateLimitsByChainIdRequest) + returns (QueryRateLimitsByChainIdResponse) { + option (google.api.http).get = + "/Stride-Labs/ibc-rate-limiting/ratelimit/ratelimits/{chain_id}"; + } + + // Queries all the rate limits for a given channel ID + rpc RateLimitsByChannelId(QueryRateLimitsByChannelIdRequest) + returns (QueryRateLimitsByChannelIdResponse) { + option (google.api.http).get = + "/Stride-Labs/ibc-rate-limiting/ratelimit/ratelimits/{channel_id}"; + } + + // Queries all blacklisted denoms + rpc AllBlacklistedDenoms(QueryAllBlacklistedDenomsRequest) + returns (QueryAllBlacklistedDenomsResponse) { + option (google.api.http).get = + "/Stride-Labs/ibc-rate-limiting/ratelimit/blacklisted_denoms"; + } + + // Queries all whitelisted address pairs + rpc AllWhitelistedAddresses(QueryAllWhitelistedAddressesRequest) + returns (QueryAllWhitelistedAddressesResponse) { + option (google.api.http).get = + "/Stride-Labs/ibc-rate-limiting/ratelimit/whitelisted_addresses"; + } +} + +// Queries all rate limits +message QueryAllRateLimitsRequest {} +message QueryAllRateLimitsResponse { + repeated RateLimit rate_limits = 1 [ (gogoproto.nullable) = false ]; +} + +// Queries a specific rate limit by channel ID and denom +message QueryRateLimitRequest { + string denom = 1; + string channel_id = 2; +} +message QueryRateLimitResponse { RateLimit rate_limit = 1; } + +// Queries all the rate limits for a given chain +message QueryRateLimitsByChainIdRequest { string chain_id = 1; } +message QueryRateLimitsByChainIdResponse { + repeated RateLimit rate_limits = 1 [ (gogoproto.nullable) = false ]; +} + +// Queries all the rate limits for a given channel ID +message QueryRateLimitsByChannelIdRequest { string channel_id = 1; } +message QueryRateLimitsByChannelIdResponse { + repeated RateLimit rate_limits = 1 [ (gogoproto.nullable) = false ]; +} + +// Queries all blacklisted denoms +message QueryAllBlacklistedDenomsRequest {} +message QueryAllBlacklistedDenomsResponse { repeated string denoms = 1; } + +// Queries all whitelisted address pairs +message QueryAllWhitelistedAddressesRequest {} +message QueryAllWhitelistedAddressesResponse { + repeated WhitelistedAddressPair address_pairs = 1 + [ (gogoproto.nullable) = false ]; +} \ No newline at end of file diff --git a/modules/rate-limiting/proto/ratelimit/v1/ratelimit.proto b/modules/rate-limiting/proto/ratelimit/v1/ratelimit.proto new file mode 100644 index 00000000..3aee3875 --- /dev/null +++ b/modules/rate-limiting/proto/ratelimit/v1/ratelimit.proto @@ -0,0 +1,93 @@ +syntax = "proto3"; +package ratelimit.v1; + +import "gogoproto/gogo.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; + +option go_package = "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types"; + +// PacketDirection defines whether the transfer packet is being sent from +// this chain or is being received on this chain +enum PacketDirection { + option (gogoproto.goproto_enum_prefix) = false; + + PACKET_SEND = 0; + PACKET_RECV = 1; +} + +// Path holds the denom and channelID that define the rate limited route +message Path { + string denom = 1; + string channel_id = 2; +} + +// Quota defines the rate limit thresholds for transfer packets +message Quota { + // MaxPercentSend defines the threshold for outflows + // The threshold is defined as a percentage (e.g. 10 indicates 10%) + string max_percent_send = 1 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + // MaxPercentSend defines the threshold for inflows + // The threshold is defined as a percentage (e.g. 10 indicates 10%) + string max_percent_recv = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + // DurationHours specifies the number of hours before the rate limit + // is reset (e.g. 24 indicates that the rate limit is reset each day) + uint64 duration_hours = 3; +} + +message Flow { + // Inflow defines the total amount of inbound transfers for the given + // rate limit in the current window + string inflow = 1 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + // Outflow defines the total amount of outbound transfers for the given + // rate limit in the current window + string outflow = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + // ChannelValue stores the total supply of the denom at the start of + // the rate limit. This is used as the denominator when checking + // the rate limit threshold + // The ChannelValue is fixed for the duration of the rate limit window + string channel_value = 3 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; +} + +// RateLimit stores all the context about a given rate limit, including +// the relevant denom and channel, rate limit thresholds, and current +// progress towards the limits +message RateLimit { + Path path = 1; + Quota quota = 2; + Flow flow = 3; +} + +// WhitelistedAddressPair represents a sender-receiver combo that is +// not subject to rate limit restrictions +message WhitelistedAddressPair { + string sender = 1; + string receiver = 2; +} + +message HourEpoch { + uint64 epoch_number = 1; + google.protobuf.Duration duration = 2 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true, + (gogoproto.jsontag) = "duration,omitempty" + ]; + google.protobuf.Timestamp epoch_start_time = 3 + [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; + int64 epoch_start_height = 4; +} \ No newline at end of file diff --git a/modules/rate-limiting/proto/ratelimit/v1/tx.proto b/modules/rate-limiting/proto/ratelimit/v1/tx.proto new file mode 100644 index 00000000..4a55e73f --- /dev/null +++ b/modules/rate-limiting/proto/ratelimit/v1/tx.proto @@ -0,0 +1,111 @@ +syntax = "proto3"; +package ratelimit.v1; + +import "gogoproto/gogo.proto"; +import "amino/amino.proto"; +import "cosmos_proto/cosmos.proto"; +import "cosmos/msg/v1/msg.proto"; + +option go_package = "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types"; + +// Msg service for rate limit txs +service Msg { + // Gov tx to add a new rate limit + rpc AddRateLimit(MsgAddRateLimit) returns (MsgAddRateLimitResponse); + // Gov tx to update an existing rate limit + rpc UpdateRateLimit(MsgUpdateRateLimit) returns (MsgUpdateRateLimitResponse); + // Gov tx to remove a rate limit + rpc RemoveRateLimit(MsgRemoveRateLimit) returns (MsgRemoveRateLimitResponse); + // Gov tx to reset the flow on a rate limit + rpc ResetRateLimit(MsgResetRateLimit) returns (MsgResetRateLimitResponse); +} + +// Gov tx to add a new rate limit +message MsgAddRateLimit { + option (cosmos.msg.v1.signer) = "authority"; + option (amino.name) = "ratelimit/MsgAddRateLimit"; + + // Authority defines the x/gov module account + string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + // Denom for the rate limit, as it appears on the rate limited chain + // When rate limiting a non-native token, this will be an ibc denom + string denom = 2; + // ChannelId for the rate limit, on the side of the rate limited chain + string channel_id = 3; + // MaxPercentSend defines the threshold for outflows + // The threshold is defined as a percentage (e.g. 10 indicates 10%) + string max_percent_send = 4 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + // MaxPercentSend defines the threshold for inflows + // The threshold is defined as a percentage (e.g. 10 indicates 10%) + string max_percent_recv = 5 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + // DurationHours specifies the number of hours before the rate limit + // is reset (e.g. 24 indicates that the rate limit is reset each day) + uint64 duration_hours = 6; +} +message MsgAddRateLimitResponse {} + +// Gov tx to update an existing rate limit +message MsgUpdateRateLimit { + option (cosmos.msg.v1.signer) = "authority"; + option (amino.name) = "ratelimit/MsgUpdateRateLimit"; + + // Authority defines the x/gov module account + string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + // Denom for the rate limit, as it appears on the rate limited chain + // When rate limiting a non-native token, this will be an ibc denom + string denom = 2; + // ChannelId for the rate limit, on the side of the rate limited chain + string channel_id = 3; + // MaxPercentSend defines the threshold for outflows + // The threshold is defined as a percentage (e.g. 10 indicates 10%) + string max_percent_send = 4 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + // MaxPercentSend defines the threshold for inflows + // The threshold is defined as a percentage (e.g. 10 indicates 10%) + string max_percent_recv = 5 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + // DurationHours specifies the number of hours before the rate limit + // is reset (e.g. 24 indicates that the rate limit is reset each day) + uint64 duration_hours = 6; +} +message MsgUpdateRateLimitResponse {} + +// Gov tx to remove a rate limit +message MsgRemoveRateLimit { + option (cosmos.msg.v1.signer) = "authority"; + option (amino.name) = "ratelimit/MsgRemoveRateLimit"; + + // Authority defines the x/gov module account + string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + // Denom for the rate limit, as it appears on the rate limited chain + // When rate limiting a non-native token, this will be an ibc denom + string denom = 2; + // ChannelId for the rate limit, on the side of the rate limited chain + string channel_id = 3; +} +message MsgRemoveRateLimitResponse {} + +// Gov tx to reset the flow on a rate limit +message MsgResetRateLimit { + option (cosmos.msg.v1.signer) = "authority"; + option (amino.name) = "ratelimit/MsgResetRateLimit"; + + // Authority defines the x/gov module account + string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + // Denom for the rate limit, as it appears on the rate limited chain + // When rate limiting a non-native token, this will be an ibc denom + string denom = 2; + // ChannelId for the rate limit, on the side of the rate limited chain + string channel_id = 3; +} +message MsgResetRateLimitResponse {} diff --git a/modules/rate-limiting/scripts/generate.sh b/modules/rate-limiting/scripts/generate.sh new file mode 100644 index 00000000..1f0a15a2 --- /dev/null +++ b/modules/rate-limiting/scripts/generate.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +set -eo pipefail + +generate_protos() { + package="$1" + proto_dirs=$(find $package -path -prune -o -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq) + for dir in $proto_dirs; do + for file in $(find "${dir}" -maxdepth 1 -name '*.proto'); do + if grep go_package "$file" &>/dev/null; then + buf generate --template buf.gen.gogo.yaml "$file" + fi + done + done +} + +echo "Generating gogo proto code" +cd proto + +generate_protos "./ratelimit" + +cd .. + +# move proto files to the right places +# +# Note: Proto files are suffixed with the current binary version. +cp -r github.com/cosmos/ibc-apps/modules/rate-limiting/v7/* ./ +rm -rf github.com diff --git a/modules/rate-limiting/testing/app.go b/modules/rate-limiting/testing/app.go new file mode 100644 index 00000000..b747b12f --- /dev/null +++ b/modules/rate-limiting/testing/app.go @@ -0,0 +1 @@ +package ibctesting diff --git a/modules/rate-limiting/testing/simapp/ante_handler.go b/modules/rate-limiting/testing/simapp/ante_handler.go new file mode 100644 index 00000000..dc68ea4c --- /dev/null +++ b/modules/rate-limiting/testing/simapp/ante_handler.go @@ -0,0 +1,50 @@ +package simapp + +import ( + "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/auth/ante" + + ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante" + "github.com/cosmos/ibc-go/v7/modules/core/keeper" +) + +// HandlerOptions extend the SDK's AnteHandler options by requiring the IBC keeper. +type HandlerOptions struct { + ante.HandlerOptions + + IBCKeeper *keeper.Keeper +} + +// NewAnteHandler creates a new ante handler +func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { + if options.AccountKeeper == nil { + return nil, errors.Wrap(sdkerrors.ErrLogic, "account keeper is required for AnteHandler") + } + if options.BankKeeper == nil { + return nil, errors.Wrap(sdkerrors.ErrLogic, "bank keeper is required for AnteHandler") + } + if options.SignModeHandler == nil { + return nil, errors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for AnteHandler") + } + + anteDecorators := []sdk.AnteDecorator{ + ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first + ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), + ante.NewValidateBasicDecorator(), + ante.NewTxTimeoutHeightDecorator(), + ante.NewValidateMemoDecorator(options.AccountKeeper), + ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), + ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), + ante.NewSetPubKeyDecorator(options.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators + ante.NewValidateSigCountDecorator(options.AccountKeeper), + ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer), + ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), + ante.NewIncrementSequenceDecorator(options.AccountKeeper), + ibcante.NewRedundantRelayDecorator(options.IBCKeeper), + } + + return sdk.ChainAnteDecorators(anteDecorators...), nil +} diff --git a/modules/rate-limiting/testing/simapp/app.go b/modules/rate-limiting/testing/simapp/app.go new file mode 100644 index 00000000..8a12dbce --- /dev/null +++ b/modules/rate-limiting/testing/simapp/app.go @@ -0,0 +1,896 @@ +package simapp + +import ( + "encoding/json" + "io" + "net/http" + "os" + "path/filepath" + + ratelimit "github.com/cosmos/ibc-apps/modules/rate-limiting/v7" + ratelimitkeeper "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/keeper" + ratelimittypes "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + "github.com/gorilla/mux" + "github.com/rakyll/statik/fs" + "github.com/spf13/cast" + "github.com/stretchr/testify/require" + + _ "github.com/cosmos/cosmos-sdk/client/docs/statik" // this is used for serving docs + + autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" + reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client" + nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node" + "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/runtime" + runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services" + "github.com/cosmos/cosmos-sdk/server/api" + "github.com/cosmos/cosmos-sdk/server/config" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/store/streaming" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/ante" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" + authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/auth/vesting" + vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + "github.com/cosmos/cosmos-sdk/x/authz" + authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" + authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module" + "github.com/cosmos/cosmos-sdk/x/bank" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/capability" + capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + "github.com/cosmos/cosmos-sdk/x/consensus" + consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" + consensusparamtypes "github.com/cosmos/cosmos-sdk/x/consensus/types" + "github.com/cosmos/cosmos-sdk/x/crisis" + crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper" + crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" + distr "github.com/cosmos/cosmos-sdk/x/distribution" + distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/cosmos/cosmos-sdk/x/evidence" + evidencekeeper "github.com/cosmos/cosmos-sdk/x/evidence/keeper" + evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" + "github.com/cosmos/cosmos-sdk/x/feegrant" + feegrantkeeper "github.com/cosmos/cosmos-sdk/x/feegrant/keeper" + feegrantmodule "github.com/cosmos/cosmos-sdk/x/feegrant/module" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + "github.com/cosmos/cosmos-sdk/x/gov" + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" + govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + "github.com/cosmos/cosmos-sdk/x/group" + groupkeeper "github.com/cosmos/cosmos-sdk/x/group/keeper" + groupmodule "github.com/cosmos/cosmos-sdk/x/group/module" + "github.com/cosmos/cosmos-sdk/x/mint" + mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/cosmos/cosmos-sdk/x/params" + paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" + paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + paramproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" + "github.com/cosmos/cosmos-sdk/x/slashing" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + "github.com/cosmos/cosmos-sdk/x/staking" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/cosmos-sdk/x/upgrade" + upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" + upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + + dbm "github.com/cometbft/cometbft-db" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/libs/log" + tmos "github.com/cometbft/cometbft/libs/os" + + "github.com/cosmos/ibc-go/v7/modules/apps/transfer" + ibctransferkeeper "github.com/cosmos/ibc-go/v7/modules/apps/transfer/keeper" + ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v7/modules/core" + ibcclient "github.com/cosmos/ibc-go/v7/modules/core/02-client" + ibcclientclient "github.com/cosmos/ibc-go/v7/modules/core/02-client/client" + ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + ibcporttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" + ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" + solomachine "github.com/cosmos/ibc-go/v7/modules/light-clients/06-solomachine" + ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v7/testing" + ibctestingtypes "github.com/cosmos/ibc-go/v7/testing/types" +) + +const appName = "SimApp" + +var ( + // DefaultNodeHome default home directories for the application daemon + DefaultNodeHome string + + // ModuleBasics defines the module BasicManager is in charge of setting up basic, + // non-dependant module elements, such as codec registration + // and genesis verification. + ModuleBasics = module.NewBasicManager( + auth.AppModuleBasic{}, + genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), + bank.AppModuleBasic{}, + capability.AppModuleBasic{}, + staking.AppModuleBasic{}, + mint.AppModuleBasic{}, + distr.AppModuleBasic{}, + gov.NewAppModuleBasic( + []govclient.ProposalHandler{ + paramsclient.ProposalHandler, + upgradeclient.LegacyProposalHandler, + upgradeclient.LegacyCancelProposalHandler, + ibcclientclient.UpdateClientProposalHandler, + ibcclientclient.UpgradeProposalHandler, + }, + ), + groupmodule.AppModuleBasic{}, + params.AppModuleBasic{}, + crisis.AppModuleBasic{}, + slashing.AppModuleBasic{}, + feegrantmodule.AppModuleBasic{}, + upgrade.AppModuleBasic{}, + evidence.AppModuleBasic{}, + authzmodule.AppModuleBasic{}, + vesting.AppModuleBasic{}, + consensus.AppModuleBasic{}, + + // non standard + ibc.AppModuleBasic{}, + ibctm.AppModuleBasic{}, + solomachine.AppModuleBasic{}, + transfer.AppModuleBasic{}, + + // rate limit + ratelimit.AppModuleBasic{}, + ) + + // module account permissions + maccPerms = map[string][]string{ + authtypes.FeeCollectorName: nil, + distrtypes.ModuleName: nil, + minttypes.ModuleName: {authtypes.Minter}, + stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, + stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, + govtypes.ModuleName: {authtypes.Burner}, + ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + } +) + +var ( + _ servertypes.Application = (*SimApp)(nil) + _ runtime.AppI = (*SimApp)(nil) +) + +// SimApp extends an ABCI application, but with most of its parameters exported. +// They are exported for convenience in creating helper functions, as object +// capabilities aren't needed for testing. +type SimApp struct { + *baseapp.BaseApp + legacyAmino *codec.LegacyAmino + appCodec codec.Codec + interfaceRegistry types.InterfaceRegistry + + invCheckPeriod uint + + // keys to access the substores + keys map[string]*storetypes.KVStoreKey + tkeys map[string]*storetypes.TransientStoreKey + memKeys map[string]*storetypes.MemoryStoreKey + + // keepers + AccountKeeper authkeeper.AccountKeeper + BankKeeper bankkeeper.Keeper + CapabilityKeeper *capabilitykeeper.Keeper + StakingKeeper *stakingkeeper.Keeper + SlashingKeeper slashingkeeper.Keeper + MintKeeper mintkeeper.Keeper + DistrKeeper distrkeeper.Keeper + GovKeeper govkeeper.Keeper + GroupKeeper groupkeeper.Keeper + CrisisKeeper *crisiskeeper.Keeper + UpgradeKeeper *upgradekeeper.Keeper + ParamsKeeper paramskeeper.Keeper + AuthzKeeper authzkeeper.Keeper + IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly + EvidenceKeeper evidencekeeper.Keeper + TransferKeeper ibctransferkeeper.Keeper + FeeGrantKeeper feegrantkeeper.Keeper + ConsensusParamsKeeper consensusparamkeeper.Keeper + + RatelimitKeeper ratelimitkeeper.Keeper + + // make scoped keepers public for test purposes + ScopedIBCKeeper capabilitykeeper.ScopedKeeper + ScopedTransferKeeper capabilitykeeper.ScopedKeeper + + // the module manager + mm *module.Manager + + // simulation manager + sm *module.SimulationManager + + // the configurator + configurator module.Configurator +} + +func init() { + userHomeDir, err := os.UserHomeDir() + if err != nil { + panic(err) + } + + DefaultNodeHome = filepath.Join(userHomeDir, ".simapp") +} + +// NewSimApp returns a reference to an initialized SimApp. +func NewSimApp( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + loadLatest bool, + skipUpgradeHeights map[int64]bool, + homePath string, + invCheckPeriod uint, + appOpts servertypes.AppOptions, + baseAppOptions ...func(*baseapp.BaseApp), +) *SimApp { + encodingConfig := MakeEncodingConfig() + + appCodec := encodingConfig.Marshaler + legacyAmino := encodingConfig.Amino + interfaceRegistry := encodingConfig.InterfaceRegistry + + authority := authtypes.NewModuleAddress(govtypes.ModuleName).String() + + bApp := baseapp.NewBaseApp(appName, logger, db, encodingConfig.TxConfig.TxDecoder(), baseAppOptions...) + bApp.SetCommitMultiStoreTracer(traceStore) + bApp.SetVersion(version.Version) + bApp.SetInterfaceRegistry(interfaceRegistry) + bApp.SetTxEncoder(encodingConfig.TxConfig.TxEncoder()) + + keys := sdk.NewKVStoreKeys( + authtypes.StoreKey, + banktypes.StoreKey, + stakingtypes.StoreKey, + crisistypes.StoreKey, + minttypes.StoreKey, + distrtypes.StoreKey, + slashingtypes.StoreKey, + govtypes.StoreKey, + group.StoreKey, + paramstypes.StoreKey, + consensusparamtypes.StoreKey, + ibcexported.StoreKey, + upgradetypes.StoreKey, + feegrant.StoreKey, + evidencetypes.StoreKey, + ibctransfertypes.StoreKey, + authzkeeper.StoreKey, + capabilitytypes.StoreKey, + ratelimittypes.StoreKey, + ) + tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) + // NOTE: The testingkey is just mounted for testing purposes. Actual applications should + // not include this key. + memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) + + // load state streaming if enabled + if _, _, err := streaming.LoadStreamingServices(bApp, appOpts, appCodec, logger, keys); err != nil { + logger.Error("failed to load state streaming", "err", err) + os.Exit(1) + } + + app := &SimApp{ + BaseApp: bApp, + legacyAmino: legacyAmino, + appCodec: appCodec, + interfaceRegistry: interfaceRegistry, + invCheckPeriod: invCheckPeriod, + keys: keys, + tkeys: tkeys, + memKeys: memKeys, + } + + app.ParamsKeeper = initParamsKeeper(appCodec, legacyAmino, keys[paramstypes.StoreKey], tkeys[paramstypes.TStoreKey]) + + // set the BaseApp's parameter store + app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper(appCodec, keys[upgradetypes.StoreKey], authority) + bApp.SetParamStore(&app.ConsensusParamsKeeper) + + // add capability keeper and ScopeToModule for ibc module + app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey]) + scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibcexported.ModuleName) + scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) + + // seal capability keeper after scoping modules + app.CapabilityKeeper.Seal() + + // SDK module keepers + app.AccountKeeper = authkeeper.NewAccountKeeper( + appCodec, + keys[authtypes.StoreKey], + authtypes.ProtoBaseAccount, + maccPerms, + sdk.GetConfig().GetBech32AccountAddrPrefix(), + authority, + ) + app.BankKeeper = bankkeeper.NewBaseKeeper( + appCodec, + keys[banktypes.StoreKey], + app.AccountKeeper, + app.ModuleAccountAddrs(), + authority, + ) + app.StakingKeeper = stakingkeeper.NewKeeper( + appCodec, + keys[stakingtypes.StoreKey], + app.AccountKeeper, + app.BankKeeper, + authority, + ) + app.MintKeeper = mintkeeper.NewKeeper( + appCodec, + keys[minttypes.StoreKey], + app.StakingKeeper, + app.AccountKeeper, + app.BankKeeper, + authtypes.FeeCollectorName, + authority, + ) + app.DistrKeeper = distrkeeper.NewKeeper( + appCodec, + keys[distrtypes.StoreKey], + app.AccountKeeper, + app.BankKeeper, + app.StakingKeeper, + authtypes.FeeCollectorName, + authority, + ) + + app.SlashingKeeper = slashingkeeper.NewKeeper( + appCodec, app.legacyAmino, keys[slashingtypes.StoreKey], app.StakingKeeper, authority, + ) + app.CrisisKeeper = crisiskeeper.NewKeeper( + appCodec, + keys[crisistypes.StoreKey], + invCheckPeriod, + app.BankKeeper, + authtypes.FeeCollectorName, + authority, + ) + + app.FeeGrantKeeper = feegrantkeeper.NewKeeper(appCodec, keys[feegrant.StoreKey], app.AccountKeeper) + app.UpgradeKeeper = upgradekeeper.NewKeeper( + skipUpgradeHeights, + keys[upgradetypes.StoreKey], + appCodec, + homePath, + app.BaseApp, + authority, + ) + + // register the staking hooks + // NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks + app.StakingKeeper.SetHooks( + stakingtypes.NewMultiStakingHooks(app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks()), + ) + + app.AuthzKeeper = authzkeeper.NewKeeper(keys[authzkeeper.StoreKey], appCodec, app.MsgServiceRouter(), app.AccountKeeper) + + // IBC Keepers + app.IBCKeeper = ibckeeper.NewKeeper( + appCodec, keys[ibcexported.StoreKey], + app.GetSubspace(ibcexported.ModuleName), + app.StakingKeeper, + app.UpgradeKeeper, + scopedIBCKeeper, + ) + + // Register the proposal types + // Deprecated: Avoid adding new handlers, instead use the new proposal flow + // by granting the governance module the right to execute the message. + // See: https://docs.cosmos.network/main/modules/gov#proposal-messages + govRouter := govv1beta1.NewRouter() + govRouter.AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler). + AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)). + AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)). + AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)) + + govConfig := govtypes.DefaultConfig() + govConfig.MaxMetadataLen = 10_000 + + govKeeper := govkeeper.NewKeeper( + appCodec, keys[govtypes.StoreKey], app.AccountKeeper, app.BankKeeper, + app.StakingKeeper, app.MsgServiceRouter(), govConfig, authority, + ) + + // Set legacy router for backwards compatibility with gov v1beta1 + govKeeper.SetLegacyRouter(govRouter) + + app.GovKeeper = *govKeeper.SetHooks( + govtypes.NewMultiGovHooks( + // register the governance hooks + ), + ) + + groupConfig := group.DefaultConfig() + groupConfig.MaxMetadataLen = 1000 + app.GroupKeeper = groupkeeper.NewKeeper(keys[group.StoreKey], appCodec, app.MsgServiceRouter(), app.AccountKeeper, groupConfig) + + // Create the rate limit keeper + app.RatelimitKeeper = *ratelimitkeeper.NewKeeper( + appCodec, + keys[ratelimittypes.StoreKey], + app.GetSubspace(ratelimittypes.ModuleName), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + app.BankKeeper, + app.IBCKeeper.ChannelKeeper, + app.IBCKeeper.ChannelKeeper, // ICS4Wrapper + ) + + // create the IBC Router + ibcRouter := ibcporttypes.NewRouter() + + // Transfer Keeper + app.TransferKeeper = ibctransferkeeper.NewKeeper( + appCodec, keys[ibctransfertypes.StoreKey], + app.GetSubspace(ibctransfertypes.ModuleName), + app.RatelimitKeeper, // ICS4Wrapper + app.IBCKeeper.ChannelKeeper, + &app.IBCKeeper.PortKeeper, + app.AccountKeeper, + app.BankKeeper, + scopedTransferKeeper, + ) + + // Create Transfer Stack + // - IBC + // - ratelimit + // - transfer + // - base app + var transferStack ibcporttypes.IBCModule = transfer.NewIBCModule(app.TransferKeeper) + transferStack = ratelimit.NewIBCMiddleware(app.RatelimitKeeper, transferStack) + + // Add IBC Router + ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) + + // Seal the IBC Router + app.IBCKeeper.SetRouter(ibcRouter) + + // create evidence keeper with router + evidenceKeeper := evidencekeeper.NewKeeper( + appCodec, keys[evidencetypes.StoreKey], app.StakingKeeper, app.SlashingKeeper, + ) + // If evidence needs to be handled for the app, set routes in router here and seal + app.EvidenceKeeper = *evidenceKeeper + + /**** Module Options ****/ + + // NOTE: we may consider parsing `appOpts` inside module constructors. For the moment + // we prefer to be more strict in what arguments the modules expect. + skipGenesisInvariants := cast.ToBool(appOpts.Get(crisis.FlagSkipGenesisInvariants)) + + // NOTE: Any module instantiated in the module manager that is later modified + // must be passed by reference here. + app.mm = module.NewManager( + // SDK app modules + genutil.NewAppModule( + app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx, + encodingConfig.TxConfig, + ), + auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), + vesting.NewAppModule(app.AccountKeeper, app.BankKeeper), + bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), + capability.NewAppModule(appCodec, *app.CapabilityKeeper, false), + crisis.NewAppModule(app.CrisisKeeper, skipGenesisInvariants, app.GetSubspace(crisistypes.ModuleName)), + feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry), + gov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(govtypes.ModuleName)), + groupmodule.NewAppModule(appCodec, app.GroupKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), + mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil, app.GetSubspace(minttypes.ModuleName)), + slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(slashingtypes.ModuleName)), + distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(distrtypes.ModuleName)), + staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)), + upgrade.NewAppModule(app.UpgradeKeeper), + evidence.NewAppModule(app.EvidenceKeeper), + params.NewAppModule(app.ParamsKeeper), + authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), + consensus.NewAppModule(appCodec, app.ConsensusParamsKeeper), + + // IBC modules + ibc.NewAppModule(app.IBCKeeper), + transfer.NewAppModule(app.TransferKeeper), + + // Rate limit + ratelimit.NewAppModule(appCodec, app.RatelimitKeeper), + ) + + // During begin block slashing happens after distr.BeginBlocker so that + // there is nothing left over in the validator fee pool, so as to keep the + // CanWithdrawInvariant invariant. + // NOTE: staking module is required if HistoricalEntries param > 0 + // NOTE: capability module's beginblocker must come before any modules using capabilities (e.g. IBC) + app.mm.SetOrderBeginBlockers( + upgradetypes.ModuleName, + capabilitytypes.ModuleName, + minttypes.ModuleName, + distrtypes.ModuleName, + slashingtypes.ModuleName, + evidencetypes.ModuleName, + stakingtypes.ModuleName, + ibcexported.ModuleName, + ibctransfertypes.StoreKey, + authtypes.ModuleName, + banktypes.ModuleName, + govtypes.ModuleName, + crisistypes.ModuleName, + genutiltypes.ModuleName, + authz.ModuleName, + feegrant.ModuleName, + paramstypes.ModuleName, + vestingtypes.ModuleName, + group.ModuleName, + consensusparamtypes.ModuleName, + ratelimittypes.ModuleName, + ) + app.mm.SetOrderEndBlockers( + crisistypes.ModuleName, + govtypes.ModuleName, + stakingtypes.ModuleName, + ibcexported.ModuleName, + ibctransfertypes.StoreKey, + capabilitytypes.ModuleName, + authtypes.ModuleName, + banktypes.ModuleName, + distrtypes.ModuleName, + slashingtypes.ModuleName, + minttypes.ModuleName, + genutiltypes.ModuleName, + evidencetypes.ModuleName, + authz.ModuleName, + feegrant.ModuleName, + paramstypes.ModuleName, + upgradetypes.ModuleName, + vestingtypes.ModuleName, + group.ModuleName, + consensusparamtypes.ModuleName, + ratelimittypes.ModuleName, + ) + + // NOTE: The genutils module must occur after staking so that pools are + // properly initialized with tokens from genesis accounts. + // NOTE: The genutils module must also occur after auth so that it can access the params from auth. + // NOTE: Capability module must occur first so that it can initialize any capabilities + // so that other modules that want to create or claim capabilities afterwards in InitChain + // can do so safely. + genesisModuleOrder := []string{ + capabilitytypes.ModuleName, + authtypes.ModuleName, + banktypes.ModuleName, + distrtypes.ModuleName, + stakingtypes.ModuleName, + ibcexported.ModuleName, + slashingtypes.ModuleName, + govtypes.ModuleName, + minttypes.ModuleName, + crisistypes.ModuleName, + genutiltypes.ModuleName, + evidencetypes.ModuleName, + authz.ModuleName, + ibctransfertypes.StoreKey, + feegrant.ModuleName, + paramstypes.ModuleName, + upgradetypes.ModuleName, + vestingtypes.ModuleName, + group.ModuleName, + consensusparamtypes.ModuleName, + ratelimittypes.ModuleName, + } + + app.mm.SetOrderInitGenesis(genesisModuleOrder...) + app.mm.SetOrderExportGenesis(genesisModuleOrder...) + + app.mm.RegisterInvariants(app.CrisisKeeper) + app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter()) + app.mm.RegisterServices(app.configurator) + + // add test gRPC service for testing gRPC queries in isolation + autocliv1.RegisterQueryServer(app.GRPCQueryRouter(), runtimeservices.NewAutoCLIQueryService(app.mm.Modules)) + + reflectionSvc, err := runtimeservices.NewReflectionService() + if err != nil { + panic(err) + } + reflectionv1.RegisterReflectionServiceServer(app.GRPCQueryRouter(), reflectionSvc) + + // create the simulation manager and define the order of the modules for deterministic simulations + // + // NOTE: this is not required apps that don't use the simulator for fuzz testing + // transactions + overrideModules := map[string]module.AppModuleSimulation{ + authtypes.ModuleName: auth.NewAppModule(app.appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), + } + app.sm = module.NewSimulationManagerFromAppModules(app.mm.Modules, overrideModules) + + app.sm.RegisterStoreDecoders() + + // initialize stores + app.MountKVStores(keys) + app.MountTransientStores(tkeys) + app.MountMemoryStores(memKeys) + + // register upgrade + app.setupUpgradeHandlers() + app.setupUpgradeStoreLoaders() + + // initialize BaseApp + app.SetInitChainer(app.InitChainer) + app.SetBeginBlocker(app.BeginBlocker) + anteHandler, err := NewAnteHandler( + HandlerOptions{ + HandlerOptions: ante.HandlerOptions{ + AccountKeeper: app.AccountKeeper, + BankKeeper: app.BankKeeper, + SignModeHandler: encodingConfig.TxConfig.SignModeHandler(), + FeegrantKeeper: app.FeeGrantKeeper, + SigGasConsumer: ante.DefaultSigVerificationGasConsumer, + }, + IBCKeeper: app.IBCKeeper, + }, + ) + if err != nil { + panic(err) + } + + app.SetAnteHandler(anteHandler) + + app.SetEndBlocker(app.EndBlocker) + + if loadLatest { + if err := app.LoadLatestVersion(); err != nil { + tmos.Exit(err.Error()) + } + } + + app.ScopedIBCKeeper = scopedIBCKeeper + app.ScopedTransferKeeper = scopedTransferKeeper + + return app +} + +// Name returns the name of the App +func (app *SimApp) Name() string { return app.BaseApp.Name() } + +// BeginBlocker application updates every begin block +func (app *SimApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock { + return app.mm.BeginBlock(ctx, req) +} + +// EndBlocker application updates every end block +func (app *SimApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { + return app.mm.EndBlock(ctx, req) +} + +// InitChainer application update at chain initialization +func (app *SimApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { + var genesisState GenesisState + if err := json.Unmarshal(req.AppStateBytes, &genesisState); err != nil { + panic(err) + } + app.UpgradeKeeper.SetModuleVersionMap(ctx, app.mm.GetVersionMap()) + return app.mm.InitGenesis(ctx, app.appCodec, genesisState) +} + +// LoadHeight loads a particular height +func (app *SimApp) LoadHeight(height int64) error { + return app.LoadVersion(height) +} + +// ModuleAccountAddrs returns all the app's module account addresses. +func (app *SimApp) ModuleAccountAddrs() map[string]bool { + modAccAddrs := make(map[string]bool) + for acc := range maccPerms { + modAccAddrs[authtypes.NewModuleAddress(acc).String()] = true + } + + return modAccAddrs +} + +// GetModuleManager returns the app module manager +// NOTE: used for testing purposes +func (app *SimApp) GetModuleManager() *module.Manager { + return app.mm +} + +// LegacyAmino returns SimApp's amino codec. +// +// NOTE: This is solely to be used for testing purposes as it may be desirable +// for modules to register their own custom testing types. +func (app *SimApp) LegacyAmino() *codec.LegacyAmino { + return app.legacyAmino +} + +// AppCodec returns SimApp's app codec. +// +// NOTE: This is solely to be used for testing purposes as it may be desirable +// for modules to register their own custom testing types. +func (app *SimApp) AppCodec() codec.Codec { + return app.appCodec +} + +// InterfaceRegistry returns SimApp's InterfaceRegistry +func (app *SimApp) InterfaceRegistry() types.InterfaceRegistry { + return app.interfaceRegistry +} + +// GetKey returns the KVStoreKey for the provided store key. +// +// NOTE: This is solely to be used for testing purposes. +func (app *SimApp) GetKey(storeKey string) *storetypes.KVStoreKey { + return app.keys[storeKey] +} + +// GetTKey returns the TransientStoreKey for the provided store key. +// +// NOTE: This is solely to be used for testing purposes. +func (app *SimApp) GetTKey(storeKey string) *storetypes.TransientStoreKey { + return app.tkeys[storeKey] +} + +// GetMemKey returns the MemStoreKey for the provided mem key. +// +// NOTE: This is solely used for testing purposes. +func (app *SimApp) GetMemKey(storeKey string) *storetypes.MemoryStoreKey { + return app.memKeys[storeKey] +} + +// GetSubspace returns a param subspace for a given module name. +// +// NOTE: This is solely to be used for testing purposes. +func (app *SimApp) GetSubspace(moduleName string) paramstypes.Subspace { + subspace, _ := app.ParamsKeeper.GetSubspace(moduleName) + return subspace +} + +// TestingApp functions + +// GetBaseApp implements the TestingApp interface. +func (app *SimApp) GetBaseApp() *baseapp.BaseApp { + return app.BaseApp +} + +// GetStakingKeeper implements the TestingApp interface. +func (app *SimApp) GetStakingKeeper() ibctestingtypes.StakingKeeper { + return app.StakingKeeper +} + +// GetIBCKeeper implements the TestingApp interface. +func (app *SimApp) GetIBCKeeper() *ibckeeper.Keeper { + return app.IBCKeeper +} + +// GetScopedIBCKeeper implements the TestingApp interface. +func (app *SimApp) GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper { + return app.ScopedIBCKeeper +} + +// GetTxConfig implements the TestingApp interface. +func (app *SimApp) GetTxConfig() client.TxConfig { + return moduletestutil.MakeTestEncodingConfig().TxConfig +} + +// SimulationManager implements the SimulationApp interface +func (app *SimApp) SimulationManager() *module.SimulationManager { + return app.sm +} + +func (app *SimApp) setupUpgradeHandlers() {} + +func (app *SimApp) setupUpgradeStoreLoaders() {} + +// RegisterAPIRoutes registers all application module routes with the provided +// API server. +func (app *SimApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) { + clientCtx := apiSvr.ClientCtx + // Register new tx routes from grpc-gateway. + authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + + // Register new tendermint queries routes from grpc-gateway. + tmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + + // Register node gRPC service for grpc-gateway. + nodeservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + + // Register legacy and grpc-gateway routes for all modules. + ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + + // register swagger API from root so that other applications can override easily + if apiConfig.Swagger { + RegisterSwaggerAPI(clientCtx, apiSvr.Router) + } +} + +// RegisterTxService implements the Application.RegisterTxService method. +func (app *SimApp) RegisterTxService(clientCtx client.Context) { + authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry) +} + +// RegisterTendermintService implements the Application.RegisterTendermintService method. +func (app *SimApp) RegisterTendermintService(clientCtx client.Context) { + tmservice.RegisterTendermintService( + clientCtx, + app.BaseApp.GRPCQueryRouter(), + app.interfaceRegistry, + app.Query, + ) +} + +// RegisterSwaggerAPI registers swagger route with API Server +func RegisterSwaggerAPI(_ client.Context, rtr *mux.Router) { + statikFS, err := fs.New() + if err != nil { + panic(err) + } + + staticServer := http.FileServer(statikFS) + rtr.PathPrefix("/swagger/").Handler(http.StripPrefix("/swagger/", staticServer)) +} + +func (app *SimApp) RegisterNodeService(context client.Context) { + nodeservice.RegisterNodeService(context, app.GRPCQueryRouter()) +} + +// initParamsKeeper init params keeper and its subspaces +func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey) paramskeeper.Keeper { + paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey) + + paramsKeeper.Subspace(authtypes.ModuleName) + paramsKeeper.Subspace(banktypes.ModuleName) + paramsKeeper.Subspace(stakingtypes.ModuleName) + paramsKeeper.Subspace(minttypes.ModuleName) + paramsKeeper.Subspace(distrtypes.ModuleName) + paramsKeeper.Subspace(slashingtypes.ModuleName) + paramsKeeper.Subspace(govtypes.ModuleName) + paramsKeeper.Subspace(crisistypes.ModuleName) + paramsKeeper.Subspace(ibcexported.ModuleName) + paramsKeeper.Subspace(ibctransfertypes.ModuleName) + paramsKeeper.Subspace(ratelimittypes.ModuleName) + + return paramsKeeper +} + +// EmptyAppOptions is a stub implementing AppOptions +type EmptyAppOptions struct{} + +// Get implements AppOptions +func (ao EmptyAppOptions) Get(_ string) interface{} { + return nil +} + +func GetSimApp(chain *ibctesting.TestChain) *SimApp { + app, ok := chain.App.(*SimApp) + require.True(chain.T, ok) + + return app +} diff --git a/modules/rate-limiting/testing/simapp/apptesting/test_helpers.go b/modules/rate-limiting/testing/simapp/apptesting/test_helpers.go new file mode 100644 index 00000000..37d972b5 --- /dev/null +++ b/modules/rate-limiting/testing/simapp/apptesting/test_helpers.go @@ -0,0 +1,74 @@ +package apptesting + +import ( + app "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/testing/simapp" + "github.com/stretchr/testify/suite" + + "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/crypto/ed25519" + tmtypesproto "github.com/cometbft/cometbft/proto/tendermint/types" +) + +const ( + TestChainId = "chain-0" +) + +type AppTestHelper struct { + suite.Suite + + App *app.SimApp + QueryHelper *baseapp.QueryServiceTestHelper + TestAccs []sdk.AccAddress + Ctx sdk.Context +} + +// AppTestHelper Constructor +func (s *AppTestHelper) Setup() { + s.App = app.InitTestingApp() + s.Ctx = s.App.BaseApp.NewContext(false, tmtypesproto.Header{Height: 1, ChainID: TestChainId}) + s.QueryHelper = &baseapp.QueryServiceTestHelper{ + GRPCQueryRouter: s.App.GRPCQueryRouter(), + Ctx: s.Ctx, + } + s.TestAccs = CreateRandomAccounts(3) +} + +// Generate random account addresss +func CreateRandomAccounts(numAccts int) []sdk.AccAddress { + testAddrs := make([]sdk.AccAddress, numAccts) + for i := 0; i < numAccts; i++ { + pk := ed25519.GenPrivKey().PubKey() + testAddrs[i] = sdk.AccAddress(pk.Address()) + } + + return testAddrs +} + +// Helper function to confirm the upgrade block processes without error +func (s *AppTestHelper) ConfirmUpgradeSucceededs(upgradeName string, upgradeHeight int64) { + s.Ctx = s.Ctx.WithBlockHeight(upgradeHeight - 1) + plan := upgradetypes.Plan{ + Name: upgradeName, + Height: upgradeHeight, + } + + err := s.App.UpgradeKeeper.ScheduleUpgrade(s.Ctx, plan) + s.Require().NoError(err) + _, exists := s.App.UpgradeKeeper.GetUpgradePlan(s.Ctx) + s.Require().True(exists) + + s.Ctx = s.Ctx.WithBlockHeight(upgradeHeight) + s.Require().NotPanics(func() { + beginBlockRequest := abci.RequestBeginBlock{} + s.App.BeginBlocker(s.Ctx, beginBlockRequest) + }) +} + +// Modifies sdk config to have stride address prefixes (used for non-keeper tests) +func SetupConfig() { + app.SetupConfig() +} diff --git a/modules/rate-limiting/testing/simapp/encoding.go b/modules/rate-limiting/testing/simapp/encoding.go new file mode 100644 index 00000000..65deeffa --- /dev/null +++ b/modules/rate-limiting/testing/simapp/encoding.go @@ -0,0 +1,16 @@ +package simapp + +import ( + appparams "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/testing/simapp/params" + + "github.com/cosmos/cosmos-sdk/std" +) + +func MakeEncodingConfig() appparams.EncodingConfig { + encodingConfig := appparams.MakeEncodingConfig() + std.RegisterLegacyAminoCodec(encodingConfig.Amino) + std.RegisterInterfaces(encodingConfig.InterfaceRegistry) + ModuleBasics.RegisterLegacyAminoCodec(encodingConfig.Amino) + ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry) + return encodingConfig +} diff --git a/modules/rate-limiting/testing/simapp/export.go b/modules/rate-limiting/testing/simapp/export.go new file mode 100644 index 00000000..fde51952 --- /dev/null +++ b/modules/rate-limiting/testing/simapp/export.go @@ -0,0 +1,203 @@ +package simapp + +import ( + "encoding/json" + "log" + + servertypes "github.com/cosmos/cosmos-sdk/server/types" + sdk "github.com/cosmos/cosmos-sdk/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + "github.com/cosmos/cosmos-sdk/x/staking" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" +) + +// ExportAppStateAndValidators exports the state of the application for a genesis +// file. +func (app *SimApp) ExportAppStateAndValidators( + forZeroHeight bool, + jailAllowedAddrs []string, + modulesToExport []string, +) (servertypes.ExportedApp, error) { + // as if they could withdraw from the start of the next block + ctx := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}) + + // We export at last height + 1, because that's the height at which + // Tendermint will start InitChain. + height := app.LastBlockHeight() + 1 + if forZeroHeight { + height = 0 + app.prepForZeroHeightGenesis(ctx, jailAllowedAddrs) + } + + app.mm.ExportGenesisForModules(ctx, app.appCodec, modulesToExport) + + genState := app.mm.ExportGenesis(ctx, app.appCodec) + appState, err := json.MarshalIndent(genState, "", " ") + if err != nil { + return servertypes.ExportedApp{}, err + } + + validators, err := staking.WriteValidators(ctx, app.StakingKeeper) + return servertypes.ExportedApp{ + AppState: appState, + Validators: validators, + Height: height, + ConsensusParams: app.BaseApp.GetConsensusParams(ctx), + }, err +} + +// prepare for fresh start at zero height +// NOTE zero height genesis is a temporary feature which will be deprecated +// in favour of export at a block height +func (app *SimApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []string) { + applyAllowedAddrs := false + + // check if there is a allowed address list + if len(jailAllowedAddrs) > 0 { + applyAllowedAddrs = true + } + + allowedAddrsMap := make(map[string]bool) + + for _, addr := range jailAllowedAddrs { + _, err := sdk.ValAddressFromBech32(addr) + if err != nil { + log.Fatal(err) + } + allowedAddrsMap[addr] = true + } + + /* Just to be safe, assert the invariants on current state. */ + app.CrisisKeeper.AssertInvariants(ctx) + + /* Handle fee distribution state. */ + + // withdraw all validator commission + app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) { + _, _ = app.DistrKeeper.WithdrawValidatorCommission(ctx, val.GetOperator()) + return false + }) + + // withdraw all delegator rewards + dels := app.StakingKeeper.GetAllDelegations(ctx) + for _, delegation := range dels { + valAddr, err := sdk.ValAddressFromBech32(delegation.ValidatorAddress) + if err != nil { + panic(err) + } + + delAddr, err := sdk.AccAddressFromBech32(delegation.DelegatorAddress) + if err != nil { + panic(err) + } + _, _ = app.DistrKeeper.WithdrawDelegationRewards(ctx, delAddr, valAddr) + } + + // clear validator slash events + app.DistrKeeper.DeleteAllValidatorSlashEvents(ctx) + + // clear validator historical rewards + app.DistrKeeper.DeleteAllValidatorHistoricalRewards(ctx) + + // set context height to zero + height := ctx.BlockHeight() + ctx = ctx.WithBlockHeight(0) + + // reinitialize all validators + app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) { + // donate any unwithdrawn outstanding reward fraction tokens to the community pool + scraps := app.DistrKeeper.GetValidatorOutstandingRewardsCoins(ctx, val.GetOperator()) + feePool := app.DistrKeeper.GetFeePool(ctx) + feePool.CommunityPool = feePool.CommunityPool.Add(scraps...) + app.DistrKeeper.SetFeePool(ctx, feePool) + + err := app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator()) + return err != nil + }) + + // reinitialize all delegations + for _, del := range dels { + valAddr, err := sdk.ValAddressFromBech32(del.ValidatorAddress) + if err != nil { + panic(err) + } + delAddr, err := sdk.AccAddressFromBech32(del.DelegatorAddress) + if err != nil { + panic(err) + } + err = app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, delAddr, valAddr) + if err != nil { + panic(err) + } + err = app.DistrKeeper.Hooks().AfterDelegationModified(ctx, delAddr, valAddr) + if err != nil { + panic(err) + } + } + + // reset context height + ctx = ctx.WithBlockHeight(height) + + /* Handle staking state. */ + + // iterate through redelegations, reset creation height + app.StakingKeeper.IterateRedelegations(ctx, func(_ int64, red stakingtypes.Redelegation) (stop bool) { + for i := range red.Entries { + red.Entries[i].CreationHeight = 0 + } + app.StakingKeeper.SetRedelegation(ctx, red) + return false + }) + + // iterate through unbonding delegations, reset creation height + app.StakingKeeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd stakingtypes.UnbondingDelegation) (stop bool) { + for i := range ubd.Entries { + ubd.Entries[i].CreationHeight = 0 + } + app.StakingKeeper.SetUnbondingDelegation(ctx, ubd) + return false + }) + + // Iterate through validators by power descending, reset bond heights, and + // update bond intra-tx counters. + store := ctx.KVStore(app.keys[stakingtypes.StoreKey]) + iter := sdk.KVStoreReversePrefixIterator(store, stakingtypes.ValidatorsKey) + counter := int16(0) + + for ; iter.Valid(); iter.Next() { + addr := sdk.ValAddress(stakingtypes.AddressFromValidatorsKey(iter.Key())) + validator, found := app.StakingKeeper.GetValidator(ctx, addr) + if !found { + panic("expected validator, not found") + } + + validator.UnbondingHeight = 0 + if applyAllowedAddrs && !allowedAddrsMap[addr.String()] { + validator.Jailed = true + } + + app.StakingKeeper.SetValidator(ctx, validator) + counter++ + } + + iter.Close() + + _, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + if err != nil { + log.Fatal(err) + } + + /* Handle slashing state. */ + + // reset start height on signing infos + app.SlashingKeeper.IterateValidatorSigningInfos( + ctx, + func(addr sdk.ConsAddress, info slashingtypes.ValidatorSigningInfo) (stop bool) { + info.StartHeight = 0 + app.SlashingKeeper.SetValidatorSigningInfo(ctx, addr, info) + return false + }, + ) +} diff --git a/modules/rate-limiting/testing/simapp/genesis.go b/modules/rate-limiting/testing/simapp/genesis.go new file mode 100644 index 00000000..5a8f18b1 --- /dev/null +++ b/modules/rate-limiting/testing/simapp/genesis.go @@ -0,0 +1,20 @@ +package simapp + +import ( + "encoding/json" +) + +// The genesis state of the blockchain is represented here as a map of raw json +// messages key'd by a identifier string. +// The identifier is used to determine which module genesis information belongs +// to so it may be appropriately routed during init chain. +// Within this application default genesis information is retrieved from +// the ModuleBasicManager which populates json from each BasicModule +// object provided to it during init. +type GenesisState map[string]json.RawMessage + +// NewDefaultGenesisState generates the default state for the application. +func NewDefaultGenesisState() GenesisState { + encCfg := MakeEncodingConfig() + return ModuleBasics.DefaultGenesis(encCfg.Marshaler) +} diff --git a/modules/rate-limiting/testing/simapp/params/encoding.go b/modules/rate-limiting/testing/simapp/params/encoding.go new file mode 100644 index 00000000..773becb3 --- /dev/null +++ b/modules/rate-limiting/testing/simapp/params/encoding.go @@ -0,0 +1,32 @@ +package params + +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/x/auth/tx" +) + +// EncodingConfig specifies the concrete encoding types to use for a given app. +// This is provided for compatibility between protobuf and amino implementations. +type EncodingConfig struct { + InterfaceRegistry types.InterfaceRegistry + Marshaler codec.Codec + TxConfig client.TxConfig + Amino *codec.LegacyAmino +} + +// MakeEncodingConfig creates an EncodingConfig for an amino based test configuration. +func MakeEncodingConfig() EncodingConfig { + amino := codec.NewLegacyAmino() + interfaceRegistry := types.NewInterfaceRegistry() + marshaler := codec.NewProtoCodec(interfaceRegistry) + txCfg := tx.NewTxConfig(marshaler, tx.DefaultSignModes) + + return EncodingConfig{ + InterfaceRegistry: interfaceRegistry, + Marshaler: marshaler, + TxConfig: txCfg, + Amino: amino, + } +} diff --git a/modules/rate-limiting/testing/simapp/simd/main.go b/modules/rate-limiting/testing/simapp/simd/main.go new file mode 100644 index 00000000..9db7292e --- /dev/null +++ b/modules/rate-limiting/testing/simapp/simd/main.go @@ -0,0 +1,20 @@ +package main + +import ( + "os" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/testing/simapp" + + "cosmossdk.io/log" + + svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" +) + +func main() { + rootCmd, _ := NewRootCmd() + + if err := svrcmd.Execute(rootCmd, "", simapp.DefaultNodeHome); err != nil { + log.NewLogger(rootCmd.OutOrStderr()).Error("failure when running app", "err", err) + os.Exit(1) + } +} diff --git a/modules/rate-limiting/testing/simapp/simd/root.go b/modules/rate-limiting/testing/simapp/simd/root.go new file mode 100644 index 00000000..884b4d94 --- /dev/null +++ b/modules/rate-limiting/testing/simapp/simd/root.go @@ -0,0 +1,264 @@ +package main + +import ( + "errors" + "io" + "os" + + app "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/testing/simapp" + appparams "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/testing/simapp/params" + "github.com/spf13/cast" + "github.com/spf13/cobra" + + rosettaCmd "cosmossdk.io/tools/rosetta/cmd" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/config" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/keys" + "github.com/cosmos/cosmos-sdk/client/pruning" + "github.com/cosmos/cosmos-sdk/client/rpc" + "github.com/cosmos/cosmos-sdk/server" + serverconfig "github.com/cosmos/cosmos-sdk/server/config" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/version" + authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/crisis" + genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" + + dbm "github.com/cometbft/cometbft-db" + tmcfg "github.com/cometbft/cometbft/config" + tmcli "github.com/cometbft/cometbft/libs/cli" + "github.com/cometbft/cometbft/libs/log" +) + +// NewRootCmd creates a new root command for simd. It is called once in the +// main function. +func NewRootCmd() (*cobra.Command, appparams.EncodingConfig) { + encodingConfig := app.MakeEncodingConfig() + + cfg := sdk.GetConfig() + cfg.Seal() + + initClientCtx := client.Context{}. + WithCodec(encodingConfig.Marshaler). + WithInterfaceRegistry(encodingConfig.InterfaceRegistry). + WithTxConfig(encodingConfig.TxConfig). + WithLegacyAmino(encodingConfig.Amino). + WithInput(os.Stdin). + WithAccountRetriever(authtypes.AccountRetriever{}). + WithBroadcastMode(flags.FlagBroadcastMode). + WithHomeDir(app.DefaultNodeHome). + WithViper("") + + rootCmd := &cobra.Command{ + Use: version.AppName, + Short: "PFM", + PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { + // set the default command outputs + cmd.SetOut(cmd.OutOrStdout()) + cmd.SetErr(cmd.ErrOrStderr()) + + initClientCtx, err := client.ReadPersistentCommandFlags(initClientCtx, cmd.Flags()) + if err != nil { + return err + } + + initClientCtx, err = config.ReadFromClientConfig(initClientCtx) + if err != nil { + return err + } + + if err := client.SetCmdClientContextHandler(initClientCtx, cmd); err != nil { + return err + } + + customTMConfig := initTendermintConfig() + + return server.InterceptConfigsPreRunHandler(cmd, "", serverconfig.DefaultConfig(), customTMConfig) + }, + } + + initRootCmd(rootCmd, encodingConfig) + + return rootCmd, encodingConfig +} + +// initTendermintConfig helps to override default Tendermint Config values. +// return tmcfg.DefaultConfig if no custom configuration is required for the application. +func initTendermintConfig() *tmcfg.Config { + cfg := tmcfg.DefaultConfig() + + // these values put a higher strain on node memory + // cfg.P2P.MaxNumInboundPeers = 100 + // cfg.P2P.MaxNumOutboundPeers = 40 + + return cfg +} + +func initRootCmd(rootCmd *cobra.Command, encodingConfig appparams.EncodingConfig) { + ac := appCreator{ + encCfg: encodingConfig, + } + + rootCmd.AddCommand( + genutilcli.InitCmd(app.ModuleBasics, app.DefaultNodeHome), + tmcli.NewCompletionCmd(rootCmd, true), + pruning.PruningCmd(ac.newApp), + ) + + server.AddCommands(rootCmd, app.DefaultNodeHome, ac.newApp, ac.appExport, addModuleInitFlags) + + // add keybase, auxiliary RPC, query, and tx child commands + rootCmd.AddCommand( + rpc.StatusCommand(), + genesisCommand(encodingConfig), + queryCommand(), + txCommand(), + keys.Commands(app.DefaultNodeHome), + ) + // add rosetta + rootCmd.AddCommand(rosettaCmd.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Marshaler)) +} + +func addModuleInitFlags(startCmd *cobra.Command) { + crisis.AddModuleInitFlags(startCmd) +} + +// genesisCommand builds genesis-related `simd genesis` command. Users may provide application specific commands as a parameter +func genesisCommand(encodingConfig appparams.EncodingConfig, cmds ...*cobra.Command) *cobra.Command { + cmd := genutilcli.GenesisCoreCommand(encodingConfig.TxConfig, app.ModuleBasics, app.DefaultNodeHome) + + for _, subCmd := range cmds { + cmd.AddCommand(subCmd) + } + return cmd +} + +func queryCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "query", + Aliases: []string{"q"}, + Short: "Querying subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + authcmd.GetAccountCmd(), + rpc.ValidatorCommand(), + rpc.BlockCommand(), + authcmd.QueryTxsByEventsCmd(), + authcmd.QueryTxCmd(), + ) + + app.ModuleBasics.AddQueryCommands(cmd) + cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") + + return cmd +} + +func txCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "tx", + Short: "Transactions subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + authcmd.GetSignCommand(), + authcmd.GetSignBatchCommand(), + authcmd.GetMultiSignCommand(), + authcmd.GetMultiSignBatchCmd(), + authcmd.GetValidateSignaturesCommand(), + flags.LineBreak, + authcmd.GetBroadcastCommand(), + authcmd.GetEncodeCommand(), + authcmd.GetDecodeCommand(), + authcmd.GetAuxToFeeCommand(), + ) + + app.ModuleBasics.AddTxCommands(cmd) + cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") + + return cmd +} + +type appCreator struct { + encCfg appparams.EncodingConfig +} + +func (ac appCreator) newApp( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + appOpts servertypes.AppOptions, +) servertypes.Application { + skipUpgradeHeights := make(map[int64]bool) + for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { + skipUpgradeHeights[int64(h)] = true + } + + loadLatest := true + + baseappOptions := server.DefaultBaseappOptions(appOpts) + return app.NewSimApp( + logger, + db, + traceStore, + loadLatest, + skipUpgradeHeights, + app.DefaultNodeHome, + uint(1), + appOpts, + baseappOptions..., + ) +} + +func (ac appCreator) appExport( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + height int64, + forZeroHeight bool, + jailAllowedAddrs []string, + appOpts servertypes.AppOptions, + modulesToExport []string, +) (servertypes.ExportedApp, error) { + var pfmApp *app.SimApp + homePath, ok := appOpts.Get(flags.FlagHome).(string) + if !ok || homePath == "" { + return servertypes.ExportedApp{}, errors.New("application home is not set") + } + + skipUpgradeHeights := make(map[int64]bool) + for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { + skipUpgradeHeights[int64(h)] = true + } + + loadLatest := height == -1 + pfmApp = app.NewSimApp( + logger, + db, + traceStore, + loadLatest, + skipUpgradeHeights, + homePath, + uint(1), + appOpts, + nil, + ) + + if height != -1 { + if err := pfmApp.LoadHeight(height); err != nil { + return servertypes.ExportedApp{}, err + } + } + + return pfmApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) +} diff --git a/modules/rate-limiting/testing/simapp/test_setup.go b/modules/rate-limiting/testing/simapp/test_setup.go new file mode 100644 index 00000000..5833b620 --- /dev/null +++ b/modules/rate-limiting/testing/simapp/test_setup.go @@ -0,0 +1,165 @@ +package simapp + +import ( + "encoding/json" + "time" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + "github.com/cosmos/cosmos-sdk/testutil/mock" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + cometbftdb "github.com/cometbft/cometbft-db" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/crypto/secp256k1" + "github.com/cometbft/cometbft/libs/log" + tmtypes "github.com/cometbft/cometbft/types" +) + +const Bech32Prefix = "stride" + +func init() { + SetupConfig() +} + +func SetupConfig() { + config := sdk.GetConfig() + valoper := sdk.PrefixValidator + sdk.PrefixOperator + valoperpub := sdk.PrefixValidator + sdk.PrefixOperator + sdk.PrefixPublic + config.SetBech32PrefixForAccount(Bech32Prefix, Bech32Prefix+sdk.PrefixPublic) + config.SetBech32PrefixForValidator(Bech32Prefix+valoper, Bech32Prefix+valoperpub) + config.SetAddressVerifier(func(bytes []byte) error { + if len(bytes) == 0 { + return errorsmod.Wrap(sdkerrors.ErrUnknownAddress, "addresses cannot be empty") + } + + if len(bytes) > address.MaxAddrLen { + return errorsmod.Wrapf(sdkerrors.ErrUnknownAddress, "address max length is %d, got %d", address.MaxAddrLen, len(bytes)) + } + + // TODO: Do we want to allow addresses of lengths other than 20 and 32 bytes? + if len(bytes) != 20 && len(bytes) != 32 { + return errorsmod.Wrapf(sdkerrors.ErrUnknownAddress, "address length must be 20 or 32 bytes, got %d", len(bytes)) + } + + return nil + }) +} + +// Initializes a new SimApp for testing +func InitTestingApp() *SimApp { + db := cometbftdb.NewMemDB() + app := NewSimApp( + log.NewNopLogger(), + db, + nil, + true, + map[int64]bool{}, + DefaultNodeHome, + 5, + simtestutil.EmptyAppOptions{}, + ) + + genesisState := GenesisStateWithValSet(app) + stateBytes, err := json.MarshalIndent(genesisState, "", " ") + if err != nil { + panic(err) + } + + app.InitChain( + abci.RequestInitChain{ + Validators: []abci.ValidatorUpdate{}, + ConsensusParams: simtestutil.DefaultConsensusParams, + AppStateBytes: stateBytes, + }, + ) + + return app +} + +func GenesisStateWithValSet(app *SimApp) GenesisState { + privVal := mock.NewPV() + pubKey, _ := privVal.GetPubKey() + validator := tmtypes.NewValidator(pubKey, 1) + valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + + senderPrivKey := secp256k1.GenPrivKey() + senderPrivKey.PubKey().Address() + acc := authtypes.NewBaseAccountWithAddress(senderPrivKey.PubKey().Address().Bytes()) + balance := banktypes.Balance{ + Address: acc.GetAddress().String(), + Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100000000000000))), + } + + balances := []banktypes.Balance{balance} + genesisState := NewDefaultGenesisState() + genAccs := []authtypes.GenesisAccount{acc} + authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) + genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis) + + validators := make([]stakingtypes.Validator, 0, len(valSet.Validators)) + delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators)) + + bondAmt := sdk.DefaultPowerReduction + + for _, val := range valSet.Validators { + pk, _ := cryptocodec.FromTmPubKeyInterface(val.PubKey) + pkAny, _ := codectypes.NewAnyWithValue(pk) + validator := stakingtypes.Validator{ + OperatorAddress: sdk.ValAddress(val.Address).String(), + ConsensusPubkey: pkAny, + Jailed: false, + Status: stakingtypes.Bonded, + Tokens: bondAmt, + DelegatorShares: sdk.OneDec(), + Description: stakingtypes.Description{}, + UnbondingHeight: int64(0), + UnbondingTime: time.Unix(0, 0).UTC(), + Commission: stakingtypes.NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), + MinSelfDelegation: sdkmath.ZeroInt(), + } + validators = append(validators, validator) + delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec())) + } + // set validators and delegations + stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations) + genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(stakingGenesis) + + totalSupply := sdk.NewCoins() + for _, b := range balances { + // add genesis acc tokens to total supply + totalSupply = totalSupply.Add(b.Coins...) + } + + for range delegations { + // add delegated tokens to total supply + totalSupply = totalSupply.Add(sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)) + } + + // add bonded amount to bonded pool module account + balances = append(balances, banktypes.Balance{ + Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(), + Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)}, + }) + + // update total supply + bankGenesis := banktypes.NewGenesisState( + banktypes.DefaultGenesisState().Params, + balances, + totalSupply, + []banktypes.Metadata{}, + []banktypes.SendEnabled{}, + ) + genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis) + + return genesisState +} diff --git a/modules/rate-limiting/types/codec.go b/modules/rate-limiting/types/codec.go new file mode 100644 index 00000000..bf126f3e --- /dev/null +++ b/modules/rate-limiting/types/codec.go @@ -0,0 +1,43 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/legacy" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" + govcodec "github.com/cosmos/cosmos-sdk/x/gov/codec" +) + +func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + legacy.RegisterAminoMsg(cdc, &MsgAddRateLimit{}, "ratelimit/MsgAddRateLimit") + legacy.RegisterAminoMsg(cdc, &MsgUpdateRateLimit{}, "ratelimit/MsgUpdateRateLimit") + legacy.RegisterAminoMsg(cdc, &MsgRemoveRateLimit{}, "ratelimit/MsgRemoveRateLimit") + legacy.RegisterAminoMsg(cdc, &MsgResetRateLimit{}, "ratelimit/MsgResetRateLimit") +} + +func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgAddRateLimit{}, + &MsgUpdateRateLimit{}, + &MsgRemoveRateLimit{}, + &MsgResetRateLimit{}, + ) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +var ( + amino = codec.NewLegacyAmino() + ModuleCdc = codec.NewAminoCodec(amino) +) + +func init() { + RegisterLegacyAminoCodec(amino) + cryptocodec.RegisterCrypto(amino) + sdk.RegisterLegacyAminoCodec(amino) + + // Register all Amino interfaces and concrete types on the authz and gov Amino codec so that this can later be + // used to properly serialize MsgSubmitProposal instances + RegisterLegacyAminoCodec(govcodec.Amino) +} diff --git a/modules/rate-limiting/types/errors.go b/modules/rate-limiting/types/errors.go new file mode 100644 index 00000000..3ec52ce3 --- /dev/null +++ b/modules/rate-limiting/types/errors.go @@ -0,0 +1,24 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" +) + +// x/ratelimit module sentinel errors +var ( + ErrRateLimitAlreadyExists = errorsmod.Register(ModuleName, 1, + "ratelimit key duplicated") + ErrRateLimitNotFound = errorsmod.Register(ModuleName, 2, + "rate limit not found") + ErrZeroChannelValue = errorsmod.Register(ModuleName, 3, + "channel value is zero") + ErrQuotaExceeded = errorsmod.Register(ModuleName, 4, + "quota exceeded") + ErrInvalidClientState = errorsmod.Register(ModuleName, 5, + "unable to determine client state from channelId") + ErrChannelNotFound = errorsmod.Register(ModuleName, 6, + "channel does not exist") + ErrDenomIsBlacklisted = errorsmod.Register(ModuleName, 7, + "denom is blacklisted", + ) +) diff --git a/modules/rate-limiting/types/events.go b/modules/rate-limiting/types/events.go new file mode 100644 index 00000000..d99c0cec --- /dev/null +++ b/modules/rate-limiting/types/events.go @@ -0,0 +1,16 @@ +package types + +var ( + EventTransferDenied = "transfer_denied" + + EventRateLimitExceeded = "rate_limit_exceeded" + EventBlacklistedDenom = "blacklisted_denom" + + AttributeKeyReason = "reason" + AttributeKeyModule = "module" + AttributeKeyAction = "action" + AttributeKeyDenom = "denom" + AttributeKeyChannel = "channel" + AttributeKeyAmount = "amount" + AttributeKeyError = "error" +) diff --git a/modules/rate-limiting/types/expected_keepers.go b/modules/rate-limiting/types/expected_keepers.go new file mode 100644 index 00000000..0917b554 --- /dev/null +++ b/modules/rate-limiting/types/expected_keepers.go @@ -0,0 +1,38 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" +) + +// BankKeeper defines the banking contract that must be fulfilled when +// creating a x/ratelimit keeper. +type BankKeeper interface { + GetSupply(ctx sdk.Context, denom string) sdk.Coin +} + +// ChannelKeeper defines the channel contract that must be fulfilled when +// creating a x/ratelimit keeper. +type ChannelKeeper interface { + GetChannel(ctx sdk.Context, portID string, channelID string) (channeltypes.Channel, bool) + GetChannelClientState(ctx sdk.Context, portID string, channelID string) (string, ibcexported.ClientState, error) +} + +// ICS4Wrapper defines the expected ICS4Wrapper for middleware +type ICS4Wrapper interface { + WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, acknowledgement ibcexported.Acknowledgement) error + SendPacket( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + sourcePort string, + sourceChannel string, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + data []byte, + ) (sequence uint64, err error) + GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) +} diff --git a/modules/rate-limiting/types/flow.go b/modules/rate-limiting/types/flow.go new file mode 100644 index 00000000..db68fe8c --- /dev/null +++ b/modules/rate-limiting/types/flow.go @@ -0,0 +1,47 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" +) + +// Initializes a new flow from the channel value +func NewFlow(channelValue sdkmath.Int) Flow { + flow := Flow{ + ChannelValue: channelValue, + Inflow: sdkmath.ZeroInt(), + Outflow: sdkmath.ZeroInt(), + } + + return flow +} + +// Adds an amount to the rate limit's flow after an incoming packet was received +// Returns an error if the new inflow will cause the rate limit to exceed its quota +func (f *Flow) AddInflow(amount sdkmath.Int, quota Quota) error { + netInflow := f.Inflow.Sub(f.Outflow).Add(amount) + + if quota.CheckExceedsQuota(PACKET_RECV, netInflow, f.ChannelValue) { + return errorsmod.Wrapf(ErrQuotaExceeded, + "Inflow exceeds quota - Net Inflow: %v, Channel Value: %v, Threshold: %v%%", + netInflow, f.ChannelValue, quota.MaxPercentRecv) + } + + f.Inflow = f.Inflow.Add(amount) + return nil +} + +// Adds an amount to the rate limit's flow after a packet was sent +// Returns an error if the new outflow will cause the rate limit to exceed its quota +func (f *Flow) AddOutflow(amount sdkmath.Int, quota Quota) error { + netOutflow := f.Outflow.Sub(f.Inflow).Add(amount) + + if quota.CheckExceedsQuota(PACKET_SEND, netOutflow, f.ChannelValue) { + return errorsmod.Wrapf(ErrQuotaExceeded, + "Outflow exceeds quota - Net Outflow: %v, Channel Value: %v, Threshold: %v%%", + netOutflow, f.ChannelValue, quota.MaxPercentSend) + } + + f.Outflow = f.Outflow.Add(amount) + return nil +} diff --git a/modules/rate-limiting/types/flow_test.go b/modules/rate-limiting/types/flow_test.go new file mode 100644 index 00000000..eca7a714 --- /dev/null +++ b/modules/rate-limiting/types/flow_test.go @@ -0,0 +1,228 @@ +package types_test + +import ( + "testing" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + "github.com/stretchr/testify/require" + + sdkmath "cosmossdk.io/math" +) + +func TestAddInflow(t *testing.T) { + totalValue := sdkmath.NewInt(100) + quota := types.Quota{ + MaxPercentRecv: sdkmath.NewInt(10), + MaxPercentSend: sdkmath.NewInt(10), + DurationHours: uint64(1), + } + + tests := []struct { + name string + flow types.Flow + expectedFlow types.Flow + amount sdkmath.Int + succeeds bool + }{ + { + name: "AddInflow__Successful__Zero inflow and outflow", + flow: types.Flow{ + Inflow: sdkmath.ZeroInt(), + Outflow: sdkmath.ZeroInt(), + ChannelValue: totalValue, + }, + amount: sdkmath.NewInt(5), + expectedFlow: types.Flow{ + Inflow: sdkmath.NewInt(5), + Outflow: sdkmath.ZeroInt(), + ChannelValue: totalValue, + }, + succeeds: true, + }, + { + name: "AddInflow__Successful__Nonzero inflow and outflow", + flow: types.Flow{ + Inflow: sdkmath.NewInt(100), + Outflow: sdkmath.NewInt(100), + ChannelValue: totalValue, + }, + amount: sdkmath.NewInt(5), + expectedFlow: types.Flow{ + Inflow: sdkmath.NewInt(105), + Outflow: sdkmath.NewInt(100), + ChannelValue: totalValue, + }, + succeeds: true, + }, + { + name: "AddInflow__Failure__Zero inflow and outflow", + flow: types.Flow{ + Inflow: sdkmath.ZeroInt(), + Outflow: sdkmath.ZeroInt(), + ChannelValue: totalValue, + }, + amount: sdkmath.NewInt(15), + succeeds: false, + }, + { + name: "AddInflow__Failure__Nonzero inflow and outflow", + flow: types.Flow{ + Inflow: sdkmath.NewInt(100), + Outflow: sdkmath.NewInt(100), + ChannelValue: totalValue, + }, + amount: sdkmath.NewInt(15), + succeeds: false, + }, + { + name: "AddInflow__Successful__Large amount but net outflow", + flow: types.Flow{ + Inflow: sdkmath.NewInt(1), + Outflow: sdkmath.NewInt(10), + ChannelValue: totalValue, + }, + amount: sdkmath.NewInt(15), + expectedFlow: types.Flow{ + Inflow: sdkmath.NewInt(16), + Outflow: sdkmath.NewInt(10), + ChannelValue: totalValue, + }, + succeeds: true, + }, + { + name: "AddInflow__Failure__Small amount but net inflow", + flow: types.Flow{ + Inflow: sdkmath.NewInt(10), + Outflow: sdkmath.NewInt(1), + ChannelValue: totalValue, + }, + amount: sdkmath.NewInt(5), + succeeds: false, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + initialFlow := test.flow + err := test.flow.AddInflow(test.amount, quota) + actualFlow := test.flow + + if test.succeeds { + require.NoError(t, err) + require.Equal(t, test.expectedFlow, actualFlow) + } else { + require.ErrorContains(t, err, "Inflow exceeds quota", "test: %v", test.name) + require.Equal(t, initialFlow, actualFlow) + } + }) + } +} + +func TestOutInflow(t *testing.T) { + totalValue := sdkmath.NewInt(100) + quota := types.Quota{ + MaxPercentRecv: sdkmath.NewInt(10), + MaxPercentSend: sdkmath.NewInt(10), + DurationHours: uint64(1), + } + + tests := []struct { + name string + flow types.Flow + expectedFlow types.Flow + amount sdkmath.Int + succeeds bool + }{ + { + name: "AddOutflow__Successful__Zero inflow and outflow", + flow: types.Flow{ + Inflow: sdkmath.ZeroInt(), + Outflow: sdkmath.ZeroInt(), + ChannelValue: totalValue, + }, + amount: sdkmath.NewInt(5), + expectedFlow: types.Flow{ + Inflow: sdkmath.ZeroInt(), + Outflow: sdkmath.NewInt(5), + ChannelValue: totalValue, + }, + succeeds: true, + }, + { + name: "AddOutflow__Successful__Nonzero inflow and outflow", + flow: types.Flow{ + Inflow: sdkmath.NewInt(100), + Outflow: sdkmath.NewInt(100), + ChannelValue: totalValue, + }, + amount: sdkmath.NewInt(5), + expectedFlow: types.Flow{ + Inflow: sdkmath.NewInt(100), + Outflow: sdkmath.NewInt(105), + ChannelValue: totalValue, + }, + succeeds: true, + }, + { + name: "AddOutflow__Failure__Zero inflow and outflow", + flow: types.Flow{ + Inflow: sdkmath.ZeroInt(), + Outflow: sdkmath.ZeroInt(), + ChannelValue: totalValue, + }, + amount: sdkmath.NewInt(15), + succeeds: false, + }, + { + name: "AddOutflow__Failure__Nonzero inflow and outflow", + flow: types.Flow{ + Inflow: sdkmath.NewInt(100), + Outflow: sdkmath.NewInt(100), + ChannelValue: totalValue, + }, + amount: sdkmath.NewInt(15), + succeeds: false, + }, + { + name: "AddOutflow__Succeesful__Large amount but net inflow", + flow: types.Flow{ + Inflow: sdkmath.NewInt(10), + Outflow: sdkmath.NewInt(1), + ChannelValue: totalValue, + }, + amount: sdkmath.NewInt(15), + expectedFlow: types.Flow{ + Inflow: sdkmath.NewInt(10), + Outflow: sdkmath.NewInt(16), + ChannelValue: totalValue, + }, + succeeds: true, + }, + { + name: "AddOutflow__Failure__Small amount but net outflow", + flow: types.Flow{ + Inflow: sdkmath.NewInt(1), + Outflow: sdkmath.NewInt(10), + ChannelValue: totalValue, + }, + amount: sdkmath.NewInt(5), + succeeds: false, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + initialFlow := test.flow + err := test.flow.AddOutflow(test.amount, quota) + actualFlow := test.flow + + if test.succeeds { + require.NoError(t, err) + require.Equal(t, test.expectedFlow, actualFlow) + } else { + require.ErrorContains(t, err, "Outflow exceeds quota", "test: %v", test.name) + require.Equal(t, initialFlow, actualFlow) + } + }) + } +} diff --git a/modules/rate-limiting/types/genesis.go b/modules/rate-limiting/types/genesis.go new file mode 100644 index 00000000..b36a206b --- /dev/null +++ b/modules/rate-limiting/types/genesis.go @@ -0,0 +1,80 @@ +package types + +import ( + "errors" + fmt "fmt" + "strconv" + "strings" + time "time" + + errorsmod "cosmossdk.io/errors" +) + +// Splits a pending send packet of the form {channelId}/{sequenceNumber} into the channel Id +// and sequence number respectively +func ParsePendingPacketId(pendingPacketId string) (channelId string, sequence uint64, err error) { + splits := strings.Split(pendingPacketId, "/") + if len(splits) != 2 { + return "", 0, fmt.Errorf("invalid pending send packet (%s), must be of form: {channelId}/{sequenceNumber}", pendingPacketId) + } + channelId = splits[0] + sequenceString := splits[1] + + if !strings.HasPrefix(channelId, "channel-") { + return "", 0, fmt.Errorf("invalid channel ID (%s) in pending send packet", channelId) + } + sequence, err = strconv.ParseUint(sequenceString, 10, 64) + if err != nil { + return "", 0, errorsmod.Wrapf(err, "unable to parse sequence number (%s) from pending send packet, %s", sequenceString, err) + } + + return channelId, sequence, nil +} + +// DefaultGenesis returns the default Capability genesis state +func DefaultGenesis() *GenesisState { + return &GenesisState{ + Params: DefaultParams(), + RateLimits: []RateLimit{}, + WhitelistedAddressPairs: []WhitelistedAddressPair{}, + BlacklistedDenoms: []string{}, + PendingSendPacketSequenceNumbers: []string{}, + HourEpoch: HourEpoch{ + EpochNumber: 0, + Duration: time.Hour, + }, + } +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + // Validate params + if err := gs.Params.Validate(); err != nil { + return err + } + + // Validate the format of the pending send packets + for _, pendingPacketId := range gs.PendingSendPacketSequenceNumbers { + if _, _, err := ParsePendingPacketId(pendingPacketId); err != nil { + return err + } + } + + // Verify the epoch hour duration is specified + if gs.HourEpoch.Duration == 0 { + return errors.New("hour epoch duration must be specified") + } + + // If the hour epoch has been initialized already (epoch number != 0), validate and then use it + if gs.HourEpoch.EpochNumber > 0 { + if gs.HourEpoch.EpochStartTime.Equal(time.Time{}) { + return errors.New("if hour epoch number is non-empty, epoch time must be initialized") + } + if gs.HourEpoch.EpochStartHeight == 0 { + return errors.New("if hour epoch number is non-empty, epoch height must be initialized") + } + } + + return nil +} diff --git a/modules/rate-limiting/types/genesis.pb.go b/modules/rate-limiting/types/genesis.pb.go new file mode 100644 index 00000000..d9a194ab --- /dev/null +++ b/modules/rate-limiting/types/genesis.pb.go @@ -0,0 +1,623 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ratelimit/v1/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the ratelimit module's genesis state. +type GenesisState struct { + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params" yaml:"params"` + RateLimits []RateLimit `protobuf:"bytes,2,rep,name=rate_limits,json=rateLimits,proto3" json:"rate_limits" yaml:"rate_limits"` + WhitelistedAddressPairs []WhitelistedAddressPair `protobuf:"bytes,3,rep,name=whitelisted_address_pairs,json=whitelistedAddressPairs,proto3" json:"whitelisted_address_pairs" yaml:"whitelisted_address_pairs"` + BlacklistedDenoms []string `protobuf:"bytes,4,rep,name=blacklisted_denoms,json=blacklistedDenoms,proto3" json:"blacklisted_denoms,omitempty"` + PendingSendPacketSequenceNumbers []string `protobuf:"bytes,5,rep,name=pending_send_packet_sequence_numbers,json=pendingSendPacketSequenceNumbers,proto3" json:"pending_send_packet_sequence_numbers,omitempty"` + HourEpoch HourEpoch `protobuf:"bytes,6,opt,name=hour_epoch,json=hourEpoch,proto3" json:"hour_epoch" yaml:"hour_epoch"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_fbb08d6119688a03, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func (m *GenesisState) GetRateLimits() []RateLimit { + if m != nil { + return m.RateLimits + } + return nil +} + +func (m *GenesisState) GetWhitelistedAddressPairs() []WhitelistedAddressPair { + if m != nil { + return m.WhitelistedAddressPairs + } + return nil +} + +func (m *GenesisState) GetBlacklistedDenoms() []string { + if m != nil { + return m.BlacklistedDenoms + } + return nil +} + +func (m *GenesisState) GetPendingSendPacketSequenceNumbers() []string { + if m != nil { + return m.PendingSendPacketSequenceNumbers + } + return nil +} + +func (m *GenesisState) GetHourEpoch() HourEpoch { + if m != nil { + return m.HourEpoch + } + return HourEpoch{} +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "ratelimit.v1.GenesisState") +} + +func init() { proto.RegisterFile("ratelimit/v1/genesis.proto", fileDescriptor_fbb08d6119688a03) } + +var fileDescriptor_fbb08d6119688a03 = []byte{ + // 448 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xb1, 0x6e, 0xd3, 0x40, + 0x1c, 0xc6, 0x63, 0x52, 0x22, 0xf5, 0x52, 0x86, 0x5a, 0x45, 0x75, 0x2c, 0xe4, 0x5a, 0x56, 0x87, + 0x2c, 0xb1, 0xd5, 0x32, 0x20, 0xd8, 0x08, 0x20, 0x18, 0x50, 0x15, 0x1c, 0x24, 0x24, 0x16, 0xeb, + 0x6c, 0xff, 0x65, 0x9f, 0x1a, 0xfb, 0x8e, 0xfb, 0x9f, 0x53, 0xf5, 0x0d, 0x10, 0x13, 0x8f, 0xd5, + 0xb1, 0x23, 0x53, 0x85, 0x92, 0x37, 0xe0, 0x09, 0x90, 0xef, 0x4c, 0x93, 0x20, 0xd8, 0x6c, 0x7d, + 0xbf, 0xdf, 0xf7, 0xe9, 0xec, 0x23, 0xae, 0xa4, 0x0a, 0x16, 0xac, 0x62, 0x2a, 0x5a, 0x9e, 0x45, + 0x05, 0xd4, 0x80, 0x0c, 0x43, 0x21, 0xb9, 0xe2, 0xf6, 0xc1, 0x7d, 0x16, 0x2e, 0xcf, 0xdc, 0xa3, + 0x82, 0x17, 0x5c, 0x07, 0x51, 0xfb, 0x64, 0x18, 0x77, 0xb4, 0xe3, 0x0b, 0x2a, 0x69, 0xd5, 0xe9, + 0xee, 0x93, 0x9d, 0x68, 0xd3, 0xa5, 0xd3, 0xe0, 0xeb, 0x1e, 0x39, 0x78, 0x6b, 0xe6, 0xe6, 0x8a, + 0x2a, 0xb0, 0x5f, 0x91, 0x81, 0xd1, 0x1d, 0xcb, 0xb7, 0xc6, 0xc3, 0xf3, 0xa3, 0x70, 0x7b, 0x3e, + 0x9c, 0xe9, 0x6c, 0xfa, 0xf8, 0xe6, 0xee, 0xa4, 0xf7, 0xeb, 0xee, 0xe4, 0xd1, 0x35, 0xad, 0x16, + 0x2f, 0x02, 0x63, 0x04, 0x71, 0xa7, 0xda, 0x1f, 0xc9, 0xb0, 0xb5, 0x12, 0xad, 0xa1, 0xf3, 0xc0, + 0xef, 0x8f, 0x87, 0xe7, 0xc7, 0xbb, 0x4d, 0x31, 0x55, 0xf0, 0xbe, 0x7d, 0x99, 0xba, 0x5d, 0x99, + 0x6d, 0xca, 0xb6, 0xcc, 0x20, 0x26, 0xf2, 0x0f, 0x86, 0xf6, 0x37, 0x8b, 0x8c, 0xae, 0x4a, 0xd6, + 0x76, 0xa0, 0x82, 0x3c, 0xa1, 0x79, 0x2e, 0x01, 0x31, 0x11, 0x94, 0x49, 0x74, 0xfa, 0x7a, 0xe4, + 0x74, 0x77, 0xe4, 0xd3, 0x06, 0x7f, 0x69, 0xe8, 0x19, 0x65, 0x72, 0x3a, 0xee, 0x16, 0x7d, 0xb3, + 0xf8, 0xdf, 0xd2, 0x20, 0x3e, 0xbe, 0xfa, 0x67, 0x03, 0xda, 0x13, 0x62, 0xa7, 0x0b, 0x9a, 0x5d, + 0x76, 0x5a, 0x0e, 0x35, 0xaf, 0xd0, 0xd9, 0xf3, 0xfb, 0xe3, 0xfd, 0xf8, 0x70, 0x2b, 0x79, 0xad, + 0x03, 0xfb, 0x82, 0x9c, 0x0a, 0xa8, 0x73, 0x56, 0x17, 0x09, 0x42, 0x9d, 0x27, 0x82, 0x66, 0x97, + 0xa0, 0x12, 0x84, 0x2f, 0x0d, 0xd4, 0x19, 0x24, 0x75, 0x53, 0xa5, 0x20, 0xd1, 0x79, 0xa8, 0x0b, + 0xfc, 0x8e, 0x9d, 0x43, 0x9d, 0xcf, 0x34, 0x39, 0xef, 0xc0, 0x0b, 0xc3, 0xd9, 0x1f, 0x08, 0x29, + 0x79, 0x23, 0x13, 0x10, 0x3c, 0x2b, 0x9d, 0x81, 0xfe, 0x55, 0x7f, 0x7d, 0xe0, 0x77, 0xbc, 0x91, + 0x6f, 0xda, 0x78, 0x3a, 0xea, 0x8e, 0x7b, 0x68, 0x8e, 0xbb, 0x11, 0x83, 0x78, 0xbf, 0xbc, 0xa7, + 0xe6, 0x37, 0x2b, 0xcf, 0xba, 0x5d, 0x79, 0xd6, 0xcf, 0x95, 0x67, 0x7d, 0x5f, 0x7b, 0xbd, 0xdb, + 0xb5, 0xd7, 0xfb, 0xb1, 0xf6, 0x7a, 0x9f, 0x9f, 0x17, 0x4c, 0x95, 0x4d, 0x1a, 0x66, 0xbc, 0x8a, + 0x32, 0x8e, 0x15, 0xc7, 0x88, 0xa5, 0xd9, 0x84, 0x0a, 0x81, 0x51, 0xc5, 0xf3, 0x66, 0x01, 0xa8, + 0x2f, 0xd6, 0x44, 0x6f, 0xb3, 0xba, 0x88, 0x96, 0xcf, 0x22, 0x75, 0x2d, 0x00, 0xd3, 0x81, 0xbe, + 0x66, 0x4f, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0x77, 0xf2, 0xc9, 0xad, 0xe1, 0x02, 0x00, 0x00, +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.HourEpoch.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + if len(m.PendingSendPacketSequenceNumbers) > 0 { + for iNdEx := len(m.PendingSendPacketSequenceNumbers) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.PendingSendPacketSequenceNumbers[iNdEx]) + copy(dAtA[i:], m.PendingSendPacketSequenceNumbers[iNdEx]) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.PendingSendPacketSequenceNumbers[iNdEx]))) + i-- + dAtA[i] = 0x2a + } + } + if len(m.BlacklistedDenoms) > 0 { + for iNdEx := len(m.BlacklistedDenoms) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.BlacklistedDenoms[iNdEx]) + copy(dAtA[i:], m.BlacklistedDenoms[iNdEx]) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.BlacklistedDenoms[iNdEx]))) + i-- + dAtA[i] = 0x22 + } + } + if len(m.WhitelistedAddressPairs) > 0 { + for iNdEx := len(m.WhitelistedAddressPairs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.WhitelistedAddressPairs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.RateLimits) > 0 { + for iNdEx := len(m.RateLimits) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.RateLimits[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.RateLimits) > 0 { + for _, e := range m.RateLimits { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.WhitelistedAddressPairs) > 0 { + for _, e := range m.WhitelistedAddressPairs { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.BlacklistedDenoms) > 0 { + for _, s := range m.BlacklistedDenoms { + l = len(s) + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.PendingSendPacketSequenceNumbers) > 0 { + for _, s := range m.PendingSendPacketSequenceNumbers { + l = len(s) + n += 1 + l + sovGenesis(uint64(l)) + } + } + l = m.HourEpoch.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RateLimits", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RateLimits = append(m.RateLimits, RateLimit{}) + if err := m.RateLimits[len(m.RateLimits)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WhitelistedAddressPairs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.WhitelistedAddressPairs = append(m.WhitelistedAddressPairs, WhitelistedAddressPair{}) + if err := m.WhitelistedAddressPairs[len(m.WhitelistedAddressPairs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlacklistedDenoms", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BlacklistedDenoms = append(m.BlacklistedDenoms, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PendingSendPacketSequenceNumbers", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PendingSendPacketSequenceNumbers = append(m.PendingSendPacketSequenceNumbers, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HourEpoch", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.HourEpoch.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/rate-limiting/types/genesis_test.go b/modules/rate-limiting/types/genesis_test.go new file mode 100644 index 00000000..d8dd191d --- /dev/null +++ b/modules/rate-limiting/types/genesis_test.go @@ -0,0 +1,103 @@ +package types_test + +import ( + "testing" + "time" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + "github.com/stretchr/testify/require" +) + +func TestValidateGenesis(t *testing.T) { + currentHour := 13 + blockTime := time.Date(2024, 1, 1, currentHour, 55, 8, 0, time.UTC) // 13:55:08 + + testCases := []struct { + name string + genesisState types.GenesisState + expectedError string + }{ + { + name: "valid default state", + genesisState: *types.DefaultGenesis(), + }, + { + name: "valid custom state", + genesisState: types.GenesisState{ + WhitelistedAddressPairs: []types.WhitelistedAddressPair{ + {Sender: "senderA", Receiver: "receiverA"}, + {Sender: "senderB", Receiver: "receiverB"}, + }, + BlacklistedDenoms: []string{"denomA", "denomB"}, + PendingSendPacketSequenceNumbers: []string{"channel-0/1", "channel-2/3"}, + HourEpoch: types.HourEpoch{ + EpochNumber: 1, + EpochStartTime: blockTime, + Duration: time.Minute, + EpochStartHeight: 1, + }, + }, + }, + { + name: "invalid packet sequence - wrong delimiter", + genesisState: types.GenesisState{ + PendingSendPacketSequenceNumbers: []string{"channel-0/1", "channel-2|3"}, + }, + expectedError: "invalid pending send packet (channel-2|3), must be of form: {channelId}/{sequenceNumber}", + }, + { + name: "invalid packet sequence - invalid channel ID", + genesisState: types.GenesisState{ + PendingSendPacketSequenceNumbers: []string{"channelX/1", "channel-2/3"}, + }, + expectedError: "invalid channel ID (channelX) in pending send packet", + }, + { + name: "invalid packet sequence - invalid sequence", + genesisState: types.GenesisState{ + PendingSendPacketSequenceNumbers: []string{"channel-0/1", "channel-2/X"}, + }, + expectedError: "unable to parse sequence number (X) from pending send packet", + }, + { + name: "invalid hour epoch - no duration", + genesisState: types.GenesisState{ + HourEpoch: types.HourEpoch{}, + }, + expectedError: "hour epoch duration must be specified", + }, + { + name: "invalid hour epoch - no epoch time", + genesisState: types.GenesisState{ + HourEpoch: types.HourEpoch{ + EpochNumber: 1, + EpochStartHeight: 1, + Duration: time.Minute, + }, + }, + expectedError: "if hour epoch number is non-empty, epoch time must be initialized", + }, + { + name: "invalid hour epoch - no epoch height", + genesisState: types.GenesisState{ + HourEpoch: types.HourEpoch{ + EpochNumber: 1, + EpochStartTime: blockTime, + Duration: time.Minute, + }, + }, + expectedError: "if hour epoch number is non-empty, epoch height must be initialized", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.genesisState.Validate() + if tc.expectedError != "" { + require.ErrorContains(t, err, tc.expectedError) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/modules/rate-limiting/types/keys.go b/modules/rate-limiting/types/keys.go new file mode 100644 index 00000000..81609d04 --- /dev/null +++ b/modules/rate-limiting/types/keys.go @@ -0,0 +1,54 @@ +package types + +import "encoding/binary" + +const ( + ModuleName = "ratelimit" + + // StoreKey defines the primary module store key + StoreKey = ModuleName + + // RouterKey is the message route for slashing + RouterKey = ModuleName + + // QuerierRoute defines the module's query routing key + QuerierRoute = ModuleName +) + +func KeyPrefix(p string) []byte { + return []byte(p) +} + +var ( + PathKeyPrefix = KeyPrefix("path") + RateLimitKeyPrefix = KeyPrefix("rate-limit") + PendingSendPacketPrefix = KeyPrefix("pending-send-packet") + DenomBlacklistKeyPrefix = KeyPrefix("denom-blacklist") + AddressWhitelistKeyPrefix = KeyPrefix("address-blacklist") + HourEpochKey = KeyPrefix("hour-epoch") + + PendingSendPacketChannelLength int = 16 +) + +// Get the rate limit byte key built from the denom and channelId +func GetRateLimitItemKey(denom string, channelId string) []byte { + return append(KeyPrefix(denom), KeyPrefix(channelId)...) +} + +// Get the pending send packet key from the channel ID and sequence number +// The channel ID must be fixed length to allow for extracting the underlying +// values from a key +func GetPendingSendPacketKey(channelId string, sequenceNumber uint64) []byte { + channelIdBz := make([]byte, PendingSendPacketChannelLength) + copy(channelIdBz, channelId) + + sequenceNumberBz := make([]byte, 8) + binary.BigEndian.PutUint64(sequenceNumberBz, sequenceNumber) + + return append(channelIdBz, sequenceNumberBz...) +} + +// Get the whitelist path key from a sender and receiver address +func GetAddressWhitelistKey(sender, receiver string) []byte { + return append(KeyPrefix(sender), KeyPrefix(receiver)...) +} diff --git a/modules/rate-limiting/types/msgs.go b/modules/rate-limiting/types/msgs.go new file mode 100644 index 00000000..38ba6c62 --- /dev/null +++ b/modules/rate-limiting/types/msgs.go @@ -0,0 +1,292 @@ +package types + +import ( + "regexp" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" +) + +const ( + TypeMsgAddRateLimit = "AddRateLimit" + TypeMsgUpdateRateLimit = "UpdateRateLimit" + TypeMsgRemoveRateLimit = "RemoveRateLimit" + TypeMsgResetRateLimit = "ResetRateLimit" +) + +var ( + _ sdk.Msg = &MsgAddRateLimit{} + _ sdk.Msg = &MsgUpdateRateLimit{} + _ sdk.Msg = &MsgRemoveRateLimit{} + _ sdk.Msg = &MsgResetRateLimit{} + + // Implement legacy interface for ledger support + _ legacytx.LegacyMsg = &MsgAddRateLimit{} + _ legacytx.LegacyMsg = &MsgUpdateRateLimit{} + _ legacytx.LegacyMsg = &MsgRemoveRateLimit{} + _ legacytx.LegacyMsg = &MsgResetRateLimit{} +) + +// ---------------------------------------------- +// MsgAddRateLimit +// ---------------------------------------------- + +func NewMsgAddRateLimit(denom, channelId string, maxPercentSend sdkmath.Int, maxPercentRecv sdkmath.Int, durationHours uint64) *MsgAddRateLimit { + return &MsgAddRateLimit{ + Denom: denom, + ChannelId: channelId, + MaxPercentSend: maxPercentSend, + MaxPercentRecv: maxPercentRecv, + DurationHours: durationHours, + } +} + +func (msg MsgAddRateLimit) Type() string { + return TypeMsgAddRateLimit +} + +func (msg MsgAddRateLimit) Route() string { + return RouterKey +} + +func (msg *MsgAddRateLimit) GetSigners() []sdk.AccAddress { + staker, err := sdk.AccAddressFromBech32(msg.Authority) + if err != nil { + panic(err) + } + return []sdk.AccAddress{staker} +} + +func (msg *MsgAddRateLimit) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgAddRateLimit) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Authority) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid authority address (%s)", err) + } + + if msg.Denom == "" { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "invalid denom (%s)", msg.Denom) + } + + matched, err := regexp.MatchString(`^channel-\d+$`, msg.ChannelId) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unable to verify channel-id (%s)", msg.ChannelId) + } + if !matched { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, + "invalid channel-id (%s), must be of the format 'channel-{N}'", msg.ChannelId) + } + + if msg.MaxPercentSend.GT(sdkmath.NewInt(100)) || msg.MaxPercentSend.LT(sdkmath.ZeroInt()) { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, + "max-percent-send percent must be between 0 and 100 (inclusively), Provided: %v", msg.MaxPercentSend) + } + + if msg.MaxPercentRecv.GT(sdkmath.NewInt(100)) || msg.MaxPercentRecv.LT(sdkmath.ZeroInt()) { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, + "max-percent-recv percent must be between 0 and 100 (inclusively), Provided: %v", msg.MaxPercentRecv) + } + + if msg.MaxPercentRecv.IsZero() && msg.MaxPercentSend.IsZero() { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, + "either the max send or max receive threshold must be greater than 0") + } + + if msg.DurationHours == 0 { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "duration can not be zero") + } + + return nil +} + +// ---------------------------------------------- +// MsgUpdateRateLimit +// ---------------------------------------------- + +func NewMsgUpdateRateLimit(denom, channelId string, maxPercentSend sdkmath.Int, maxPercentRecv sdkmath.Int, durationHours uint64) *MsgUpdateRateLimit { + return &MsgUpdateRateLimit{ + Denom: denom, + ChannelId: channelId, + MaxPercentSend: maxPercentSend, + MaxPercentRecv: maxPercentRecv, + DurationHours: durationHours, + } +} + +func (msg MsgUpdateRateLimit) Type() string { + return TypeMsgUpdateRateLimit +} + +func (msg MsgUpdateRateLimit) Route() string { + return RouterKey +} + +func (msg *MsgUpdateRateLimit) GetSigners() []sdk.AccAddress { + staker, err := sdk.AccAddressFromBech32(msg.Authority) + if err != nil { + panic(err) + } + return []sdk.AccAddress{staker} +} + +func (msg *MsgUpdateRateLimit) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgUpdateRateLimit) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Authority) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid authority address (%s)", err) + } + + if msg.Denom == "" { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "invalid denom (%s)", msg.Denom) + } + + matched, err := regexp.MatchString(`^channel-\d+$`, msg.ChannelId) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unable to verify channel-id (%s)", msg.ChannelId) + } + if !matched { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, + "invalid channel-id (%s), must be of the format 'channel-{N}'", msg.ChannelId) + } + + if msg.MaxPercentSend.GT(sdkmath.NewInt(100)) || msg.MaxPercentSend.LT(sdkmath.ZeroInt()) { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, + "max-percent-send percent must be between 0 and 100 (inclusively), Provided: %v", msg.MaxPercentSend) + } + + if msg.MaxPercentRecv.GT(sdkmath.NewInt(100)) || msg.MaxPercentRecv.LT(sdkmath.ZeroInt()) { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, + "max-percent-recv percent must be between 0 and 100 (inclusively), Provided: %v", msg.MaxPercentRecv) + } + + if msg.MaxPercentRecv.IsZero() && msg.MaxPercentSend.IsZero() { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, + "either the max send or max receive threshold must be greater than 0") + } + + if msg.DurationHours == 0 { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "duration can not be zero") + } + + return nil +} + +// ---------------------------------------------- +// MsgRemoveRateLimit +// ---------------------------------------------- + +func NewMsgRemoveRateLimit(denom, channelId string) *MsgRemoveRateLimit { + return &MsgRemoveRateLimit{ + Denom: denom, + ChannelId: channelId, + } +} + +func (msg MsgRemoveRateLimit) Type() string { + return TypeMsgRemoveRateLimit +} + +func (msg MsgRemoveRateLimit) Route() string { + return RouterKey +} + +func (msg *MsgRemoveRateLimit) GetSigners() []sdk.AccAddress { + staker, err := sdk.AccAddressFromBech32(msg.Authority) + if err != nil { + panic(err) + } + return []sdk.AccAddress{staker} +} + +func (msg *MsgRemoveRateLimit) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgRemoveRateLimit) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Authority) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid authority address (%s)", err) + } + + if msg.Denom == "" { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "invalid denom (%s)", msg.Denom) + } + + matched, err := regexp.MatchString(`^channel-\d+$`, msg.ChannelId) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unable to verify channel-id (%s)", msg.ChannelId) + } + if !matched { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, + "invalid channel-id (%s), must be of the format 'channel-{N}'", msg.ChannelId) + } + + return nil +} + +// ---------------------------------------------- +// MsgResetRateLimit +// ---------------------------------------------- + +func NewMsgResetRateLimit(denom, channelId string) *MsgResetRateLimit { + return &MsgResetRateLimit{ + Denom: denom, + ChannelId: channelId, + } +} + +func (msg MsgResetRateLimit) Type() string { + return TypeMsgResetRateLimit +} + +func (msg MsgResetRateLimit) Route() string { + return RouterKey +} + +func (msg *MsgResetRateLimit) GetSigners() []sdk.AccAddress { + staker, err := sdk.AccAddressFromBech32(msg.Authority) + if err != nil { + panic(err) + } + return []sdk.AccAddress{staker} +} + +func (msg *MsgResetRateLimit) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgResetRateLimit) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Authority) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid authority address (%s)", err) + } + + if msg.Denom == "" { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "invalid denom (%s)", msg.Denom) + } + + matched, err := regexp.MatchString(`^channel-\d+$`, msg.ChannelId) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unable to verify channel-id (%s)", msg.ChannelId) + } + if !matched { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, + "invalid channel-id (%s), must be of the format 'channel-{N}'", msg.ChannelId) + } + + return nil +} diff --git a/modules/rate-limiting/types/msgs_test.go b/modules/rate-limiting/types/msgs_test.go new file mode 100644 index 00000000..3b256c29 --- /dev/null +++ b/modules/rate-limiting/types/msgs_test.go @@ -0,0 +1,467 @@ +package types_test + +import ( + "testing" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/testing/simapp/apptesting" + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + "github.com/stretchr/testify/require" + + sdkmath "cosmossdk.io/math" + + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" +) + +const ( + validChannelId = "channel-0" + validDenom = "denom" +) + +// ---------------------------------------------- +// MsgAddRateLimit +// ---------------------------------------------- + +func TestMsgAddRateLimit(t *testing.T) { + apptesting.SetupConfig() + + validAuthority := authtypes.NewModuleAddress(govtypes.ModuleName).String() + validMaxPercentSend := sdkmath.NewInt(10) + validMaxPercentRecv := sdkmath.NewInt(10) + validDurationHours := uint64(60) + + testCases := []struct { + name string + msg types.MsgAddRateLimit + err string + }{ + { + name: "successful proposal", + msg: types.MsgAddRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: validChannelId, + MaxPercentSend: validMaxPercentSend, + MaxPercentRecv: validMaxPercentRecv, + DurationHours: validDurationHours, + }, + }, + { + name: "invalid authority", + msg: types.MsgAddRateLimit{ + Authority: "invalid_address", + Denom: validDenom, + ChannelId: validChannelId, + MaxPercentSend: validMaxPercentSend, + MaxPercentRecv: validMaxPercentRecv, + DurationHours: validDurationHours, + }, + err: "invalid authority", + }, + { + name: "invalid denom", + msg: types.MsgAddRateLimit{ + Authority: validAuthority, + Denom: "", + ChannelId: validChannelId, + MaxPercentSend: validMaxPercentSend, + MaxPercentRecv: validMaxPercentRecv, + DurationHours: validDurationHours, + }, + err: "invalid denom", + }, + { + name: "invalid channel-id", + msg: types.MsgAddRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: "channel-", + MaxPercentSend: validMaxPercentSend, + MaxPercentRecv: validMaxPercentRecv, + DurationHours: validDurationHours, + }, + err: "invalid channel-id", + }, + { + name: "invalid send percent (lt 0)", + msg: types.MsgAddRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: validChannelId, + MaxPercentSend: sdkmath.NewInt(-1), + MaxPercentRecv: validMaxPercentRecv, + DurationHours: validDurationHours, + }, + err: "percent must be between 0 and 100", + }, + { + name: "invalid send percent (gt 100)", + msg: types.MsgAddRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: validChannelId, + MaxPercentSend: sdkmath.NewInt(101), + MaxPercentRecv: validMaxPercentRecv, + DurationHours: validDurationHours, + }, + err: "percent must be between 0 and 100", + }, + { + name: "invalid receive percent (lt 0)", + msg: types.MsgAddRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: validChannelId, + MaxPercentSend: validMaxPercentSend, + MaxPercentRecv: sdkmath.NewInt(-1), + DurationHours: validDurationHours, + }, + err: "percent must be between 0 and 100", + }, + { + name: "invalid receive percent (gt 100)", + msg: types.MsgAddRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: validChannelId, + MaxPercentSend: validMaxPercentSend, + MaxPercentRecv: sdkmath.NewInt(101), + DurationHours: validDurationHours, + }, + err: "percent must be between 0 and 100", + }, + { + name: "invalid send and receive percent", + msg: types.MsgAddRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: validChannelId, + MaxPercentSend: sdkmath.ZeroInt(), + MaxPercentRecv: sdkmath.ZeroInt(), + DurationHours: validDurationHours, + }, + err: "either the max send or max receive threshold must be greater than 0", + }, + { + name: "invalid duration", + msg: types.MsgAddRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: validChannelId, + MaxPercentSend: validMaxPercentSend, + MaxPercentRecv: validMaxPercentRecv, + DurationHours: 0, + }, + err: "duration can not be zero", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if tc.err == "" { + require.NoError(t, tc.msg.ValidateBasic(), "test: %v", tc.name) + require.Equal(t, tc.msg.Denom, validDenom, "denom") + require.Equal(t, tc.msg.ChannelId, validChannelId, "channel-id") + require.Equal(t, tc.msg.MaxPercentSend, validMaxPercentSend, "maxPercentSend") + require.Equal(t, tc.msg.MaxPercentRecv, validMaxPercentRecv, "maxPercentRecv") + require.Equal(t, tc.msg.DurationHours, validDurationHours, "durationHours") + + require.Equal(t, tc.msg.Type(), types.TypeMsgAddRateLimit, "type") + require.Equal(t, tc.msg.Route(), types.ModuleName, "route") + } else { + require.ErrorContains(t, tc.msg.ValidateBasic(), tc.err, "test: %v", tc.name) + } + }) + } +} + +// ---------------------------------------------- +// MsgUpdateRateLimit +// ---------------------------------------------- + +func TestMsgUpdateRateLimit(t *testing.T) { + apptesting.SetupConfig() + + validAuthority := authtypes.NewModuleAddress(govtypes.ModuleName).String() + validMaxPercentSend := sdkmath.NewInt(10) + validMaxPercentRecv := sdkmath.NewInt(10) + validDurationHours := uint64(60) + + testCases := []struct { + name string + msg types.MsgUpdateRateLimit + err string + }{ + { + name: "successful proposal", + msg: types.MsgUpdateRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: validChannelId, + MaxPercentSend: validMaxPercentSend, + MaxPercentRecv: validMaxPercentRecv, + DurationHours: validDurationHours, + }, + }, + { + name: "invalid authority", + msg: types.MsgUpdateRateLimit{ + Authority: "invalid_address", + Denom: validDenom, + ChannelId: validChannelId, + MaxPercentSend: validMaxPercentSend, + MaxPercentRecv: validMaxPercentRecv, + DurationHours: validDurationHours, + }, + err: "invalid authority", + }, + { + name: "invalid denom", + msg: types.MsgUpdateRateLimit{ + Authority: validAuthority, + Denom: "", + ChannelId: validChannelId, + MaxPercentSend: validMaxPercentSend, + MaxPercentRecv: validMaxPercentRecv, + DurationHours: validDurationHours, + }, + err: "invalid denom", + }, + { + name: "invalid channel-id", + msg: types.MsgUpdateRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: "channel-", + MaxPercentSend: validMaxPercentSend, + MaxPercentRecv: validMaxPercentRecv, + DurationHours: validDurationHours, + }, + err: "invalid channel-id", + }, + { + name: "invalid send percent (lt 0)", + msg: types.MsgUpdateRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: validChannelId, + MaxPercentSend: sdkmath.NewInt(-1), + MaxPercentRecv: validMaxPercentRecv, + DurationHours: validDurationHours, + }, + err: "percent must be between 0 and 100", + }, + { + name: "invalid send percent (gt 100)", + msg: types.MsgUpdateRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: validChannelId, + MaxPercentSend: sdkmath.NewInt(101), + MaxPercentRecv: validMaxPercentRecv, + DurationHours: validDurationHours, + }, + err: "percent must be between 0 and 100", + }, + { + name: "invalid receive percent (lt 0)", + msg: types.MsgUpdateRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: validChannelId, + MaxPercentSend: validMaxPercentSend, + MaxPercentRecv: sdkmath.NewInt(-1), + DurationHours: validDurationHours, + }, + err: "percent must be between 0 and 100", + }, + { + name: "invalid receive percent (gt 100)", + msg: types.MsgUpdateRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: validChannelId, + MaxPercentSend: validMaxPercentSend, + MaxPercentRecv: sdkmath.NewInt(101), + DurationHours: validDurationHours, + }, + err: "percent must be between 0 and 100", + }, + { + name: "invalid send and receive percent", + msg: types.MsgUpdateRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: validChannelId, + MaxPercentSend: sdkmath.ZeroInt(), + MaxPercentRecv: sdkmath.ZeroInt(), + DurationHours: validDurationHours, + }, + err: "either the max send or max receive threshold must be greater than 0", + }, + { + name: "invalid duration", + msg: types.MsgUpdateRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: validChannelId, + MaxPercentSend: validMaxPercentSend, + MaxPercentRecv: validMaxPercentRecv, + DurationHours: 0, + }, + err: "duration can not be zero", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if tc.err == "" { + require.NoError(t, tc.msg.ValidateBasic(), "test: %v", tc.name) + require.Equal(t, tc.msg.Denom, validDenom, "denom") + require.Equal(t, tc.msg.ChannelId, validChannelId, "channel-id") + require.Equal(t, tc.msg.MaxPercentSend, validMaxPercentSend, "maxPercentSend") + require.Equal(t, tc.msg.MaxPercentRecv, validMaxPercentRecv, "maxPercentRecv") + require.Equal(t, tc.msg.DurationHours, validDurationHours, "durationHours") + + require.Equal(t, tc.msg.Type(), types.TypeMsgUpdateRateLimit, "type") + require.Equal(t, tc.msg.Route(), types.ModuleName, "route") + } else { + require.ErrorContains(t, tc.msg.ValidateBasic(), tc.err, "test: %v", tc.name) + } + }) + } +} + +// ---------------------------------------------- +// MsgRemoveRateLimit +// ---------------------------------------------- + +func TestMsgRemoveRateLimit(t *testing.T) { + apptesting.SetupConfig() + + validAuthority := authtypes.NewModuleAddress(govtypes.ModuleName).String() + + testCases := []struct { + name string + msg types.MsgRemoveRateLimit + err string + }{ + { + name: "successful message", + msg: types.MsgRemoveRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: validChannelId, + }, + }, + { + name: "invalid authority", + msg: types.MsgRemoveRateLimit{ + Authority: "invalid_address", + Denom: validDenom, + ChannelId: validChannelId, + }, + err: "invalid authority", + }, + { + name: "invalid denom", + msg: types.MsgRemoveRateLimit{ + Authority: validAuthority, + Denom: "", + ChannelId: validChannelId, + }, + err: "invalid denom", + }, + { + name: "invalid channel-id", + msg: types.MsgRemoveRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: "chan-1", + }, + err: "invalid channel-id", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if tc.err == "" { + require.NoError(t, tc.msg.ValidateBasic(), "test: %v", tc.name) + require.Equal(t, tc.msg.Denom, validDenom, "denom") + require.Equal(t, tc.msg.ChannelId, validChannelId, "channelId") + + require.Equal(t, tc.msg.Type(), types.TypeMsgRemoveRateLimit, "type") + require.Equal(t, tc.msg.Route(), types.ModuleName, "route") + } else { + require.ErrorContains(t, tc.msg.ValidateBasic(), tc.err, "test: %v", tc.name) + } + }) + } +} + +// ---------------------------------------------- +// MsgResetRateLimit +// ---------------------------------------------- + +func TestMsgResetRateLimit(t *testing.T) { + apptesting.SetupConfig() + + validAuthority := authtypes.NewModuleAddress(govtypes.ModuleName).String() + + testCases := []struct { + name string + msg types.MsgResetRateLimit + err string + }{ + { + name: "successful message", + msg: types.MsgResetRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: validChannelId, + }, + }, + { + name: "invalid authority", + msg: types.MsgResetRateLimit{ + Authority: "invalid_address", + Denom: validDenom, + ChannelId: validChannelId, + }, + err: "invalid authority", + }, + { + name: "invalid denom", + msg: types.MsgResetRateLimit{ + Authority: validAuthority, + Denom: "", + ChannelId: validChannelId, + }, + err: "invalid denom", + }, + { + name: "invalid channel-id", + msg: types.MsgResetRateLimit{ + Authority: validAuthority, + Denom: validDenom, + ChannelId: "chan-1", + }, + err: "invalid channel-id", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if tc.err == "" { + require.NoError(t, tc.msg.ValidateBasic(), "test: %v", tc.name) + require.Equal(t, tc.msg.Denom, validDenom, "denom") + require.Equal(t, tc.msg.ChannelId, validChannelId, "channelId") + + require.Equal(t, tc.msg.Type(), types.TypeMsgResetRateLimit, "type") + require.Equal(t, tc.msg.Route(), types.ModuleName, "route") + } else { + require.ErrorContains(t, tc.msg.ValidateBasic(), tc.err, "test: %v", tc.name) + } + }) + } +} diff --git a/modules/rate-limiting/types/params.go b/modules/rate-limiting/types/params.go new file mode 100644 index 00000000..4f3215e3 --- /dev/null +++ b/modules/rate-limiting/types/params.go @@ -0,0 +1,32 @@ +package types + +import ( + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" +) + +var _ paramtypes.ParamSet = (*Params)(nil) + +// ParamKeyTable the param key table for launch module +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +// NewParams creates a new Params instance +func NewParams() Params { + return Params{} +} + +// DefaultParams returns a default set of parameters +func DefaultParams() Params { + return NewParams() +} + +// ParamSetPairs get the params.ParamSet +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{} +} + +// Validate validates the set of params +func (p Params) Validate() error { + return nil +} diff --git a/modules/rate-limiting/types/params.pb.go b/modules/rate-limiting/types/params.pb.go new file mode 100644 index 00000000..614e4046 --- /dev/null +++ b/modules/rate-limiting/types/params.pb.go @@ -0,0 +1,264 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ratelimit/v1/params.proto + +package types + +import ( + fmt "fmt" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Params defines the ratelimit module's parameters. +type Params struct { +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_3a98f618ae7612ca, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func init() { + proto.RegisterType((*Params)(nil), "ratelimit.v1.Params") +} + +func init() { proto.RegisterFile("ratelimit/v1/params.proto", fileDescriptor_3a98f618ae7612ca) } + +var fileDescriptor_3a98f618ae7612ca = []byte{ + // 152 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x2c, 0x4a, 0x2c, 0x49, + 0xcd, 0xc9, 0xcc, 0xcd, 0x2c, 0xd1, 0x2f, 0x33, 0xd4, 0x2f, 0x48, 0x2c, 0x4a, 0xcc, 0x2d, 0xd6, + 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x81, 0x4b, 0xe9, 0x95, 0x19, 0x2a, 0x71, 0x70, 0xb1, + 0x05, 0x80, 0x65, 0x9d, 0x82, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, + 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0xca, + 0x32, 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x57, 0x3f, 0x39, 0xbf, 0x38, 0x37, + 0xbf, 0x58, 0x3f, 0x33, 0x29, 0x59, 0x37, 0xb1, 0xa0, 0xa0, 0x58, 0x3f, 0x37, 0x3f, 0xa5, 0x34, + 0x27, 0xb5, 0x58, 0x1f, 0x64, 0xa8, 0x2e, 0xd8, 0xd4, 0xcc, 0xbc, 0x74, 0xfd, 0x32, 0x73, 0xfd, + 0x92, 0xca, 0x82, 0xd4, 0xe2, 0x24, 0x36, 0xb0, 0x9d, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x82, 0xed, 0x7a, 0x68, 0x90, 0x00, 0x00, 0x00, +} + +func (m *Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintParams(dAtA []byte, offset int, v uint64) int { + offset -= sovParams(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovParams(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozParams(x uint64) (n int) { + return sovParams(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipParams(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthParams + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipParams(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthParams + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupParams + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthParams + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthParams = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowParams = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupParams = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/rate-limiting/types/query.pb.go b/modules/rate-limiting/types/query.pb.go new file mode 100644 index 00000000..655f14e5 --- /dev/null +++ b/modules/rate-limiting/types/query.pb.go @@ -0,0 +1,2463 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ratelimit/v1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Queries all rate limits +type QueryAllRateLimitsRequest struct { +} + +func (m *QueryAllRateLimitsRequest) Reset() { *m = QueryAllRateLimitsRequest{} } +func (m *QueryAllRateLimitsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryAllRateLimitsRequest) ProtoMessage() {} +func (*QueryAllRateLimitsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_d909918e357d6d0b, []int{0} +} +func (m *QueryAllRateLimitsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllRateLimitsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllRateLimitsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllRateLimitsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllRateLimitsRequest.Merge(m, src) +} +func (m *QueryAllRateLimitsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryAllRateLimitsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllRateLimitsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllRateLimitsRequest proto.InternalMessageInfo + +type QueryAllRateLimitsResponse struct { + RateLimits []RateLimit `protobuf:"bytes,1,rep,name=rate_limits,json=rateLimits,proto3" json:"rate_limits"` +} + +func (m *QueryAllRateLimitsResponse) Reset() { *m = QueryAllRateLimitsResponse{} } +func (m *QueryAllRateLimitsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryAllRateLimitsResponse) ProtoMessage() {} +func (*QueryAllRateLimitsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d909918e357d6d0b, []int{1} +} +func (m *QueryAllRateLimitsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllRateLimitsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllRateLimitsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllRateLimitsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllRateLimitsResponse.Merge(m, src) +} +func (m *QueryAllRateLimitsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryAllRateLimitsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllRateLimitsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllRateLimitsResponse proto.InternalMessageInfo + +func (m *QueryAllRateLimitsResponse) GetRateLimits() []RateLimit { + if m != nil { + return m.RateLimits + } + return nil +} + +// Queries a specific rate limit by channel ID and denom +type QueryRateLimitRequest struct { + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` +} + +func (m *QueryRateLimitRequest) Reset() { *m = QueryRateLimitRequest{} } +func (m *QueryRateLimitRequest) String() string { return proto.CompactTextString(m) } +func (*QueryRateLimitRequest) ProtoMessage() {} +func (*QueryRateLimitRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_d909918e357d6d0b, []int{2} +} +func (m *QueryRateLimitRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryRateLimitRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryRateLimitRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryRateLimitRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryRateLimitRequest.Merge(m, src) +} +func (m *QueryRateLimitRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryRateLimitRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryRateLimitRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryRateLimitRequest proto.InternalMessageInfo + +func (m *QueryRateLimitRequest) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func (m *QueryRateLimitRequest) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + +type QueryRateLimitResponse struct { + RateLimit *RateLimit `protobuf:"bytes,1,opt,name=rate_limit,json=rateLimit,proto3" json:"rate_limit,omitempty"` +} + +func (m *QueryRateLimitResponse) Reset() { *m = QueryRateLimitResponse{} } +func (m *QueryRateLimitResponse) String() string { return proto.CompactTextString(m) } +func (*QueryRateLimitResponse) ProtoMessage() {} +func (*QueryRateLimitResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d909918e357d6d0b, []int{3} +} +func (m *QueryRateLimitResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryRateLimitResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryRateLimitResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryRateLimitResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryRateLimitResponse.Merge(m, src) +} +func (m *QueryRateLimitResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryRateLimitResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryRateLimitResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryRateLimitResponse proto.InternalMessageInfo + +func (m *QueryRateLimitResponse) GetRateLimit() *RateLimit { + if m != nil { + return m.RateLimit + } + return nil +} + +// Queries all the rate limits for a given chain +type QueryRateLimitsByChainIdRequest struct { + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` +} + +func (m *QueryRateLimitsByChainIdRequest) Reset() { *m = QueryRateLimitsByChainIdRequest{} } +func (m *QueryRateLimitsByChainIdRequest) String() string { return proto.CompactTextString(m) } +func (*QueryRateLimitsByChainIdRequest) ProtoMessage() {} +func (*QueryRateLimitsByChainIdRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_d909918e357d6d0b, []int{4} +} +func (m *QueryRateLimitsByChainIdRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryRateLimitsByChainIdRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryRateLimitsByChainIdRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryRateLimitsByChainIdRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryRateLimitsByChainIdRequest.Merge(m, src) +} +func (m *QueryRateLimitsByChainIdRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryRateLimitsByChainIdRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryRateLimitsByChainIdRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryRateLimitsByChainIdRequest proto.InternalMessageInfo + +func (m *QueryRateLimitsByChainIdRequest) GetChainId() string { + if m != nil { + return m.ChainId + } + return "" +} + +type QueryRateLimitsByChainIdResponse struct { + RateLimits []RateLimit `protobuf:"bytes,1,rep,name=rate_limits,json=rateLimits,proto3" json:"rate_limits"` +} + +func (m *QueryRateLimitsByChainIdResponse) Reset() { *m = QueryRateLimitsByChainIdResponse{} } +func (m *QueryRateLimitsByChainIdResponse) String() string { return proto.CompactTextString(m) } +func (*QueryRateLimitsByChainIdResponse) ProtoMessage() {} +func (*QueryRateLimitsByChainIdResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d909918e357d6d0b, []int{5} +} +func (m *QueryRateLimitsByChainIdResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryRateLimitsByChainIdResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryRateLimitsByChainIdResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryRateLimitsByChainIdResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryRateLimitsByChainIdResponse.Merge(m, src) +} +func (m *QueryRateLimitsByChainIdResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryRateLimitsByChainIdResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryRateLimitsByChainIdResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryRateLimitsByChainIdResponse proto.InternalMessageInfo + +func (m *QueryRateLimitsByChainIdResponse) GetRateLimits() []RateLimit { + if m != nil { + return m.RateLimits + } + return nil +} + +// Queries all the rate limits for a given channel ID +type QueryRateLimitsByChannelIdRequest struct { + ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` +} + +func (m *QueryRateLimitsByChannelIdRequest) Reset() { *m = QueryRateLimitsByChannelIdRequest{} } +func (m *QueryRateLimitsByChannelIdRequest) String() string { return proto.CompactTextString(m) } +func (*QueryRateLimitsByChannelIdRequest) ProtoMessage() {} +func (*QueryRateLimitsByChannelIdRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_d909918e357d6d0b, []int{6} +} +func (m *QueryRateLimitsByChannelIdRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryRateLimitsByChannelIdRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryRateLimitsByChannelIdRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryRateLimitsByChannelIdRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryRateLimitsByChannelIdRequest.Merge(m, src) +} +func (m *QueryRateLimitsByChannelIdRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryRateLimitsByChannelIdRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryRateLimitsByChannelIdRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryRateLimitsByChannelIdRequest proto.InternalMessageInfo + +func (m *QueryRateLimitsByChannelIdRequest) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + +type QueryRateLimitsByChannelIdResponse struct { + RateLimits []RateLimit `protobuf:"bytes,1,rep,name=rate_limits,json=rateLimits,proto3" json:"rate_limits"` +} + +func (m *QueryRateLimitsByChannelIdResponse) Reset() { *m = QueryRateLimitsByChannelIdResponse{} } +func (m *QueryRateLimitsByChannelIdResponse) String() string { return proto.CompactTextString(m) } +func (*QueryRateLimitsByChannelIdResponse) ProtoMessage() {} +func (*QueryRateLimitsByChannelIdResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d909918e357d6d0b, []int{7} +} +func (m *QueryRateLimitsByChannelIdResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryRateLimitsByChannelIdResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryRateLimitsByChannelIdResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryRateLimitsByChannelIdResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryRateLimitsByChannelIdResponse.Merge(m, src) +} +func (m *QueryRateLimitsByChannelIdResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryRateLimitsByChannelIdResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryRateLimitsByChannelIdResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryRateLimitsByChannelIdResponse proto.InternalMessageInfo + +func (m *QueryRateLimitsByChannelIdResponse) GetRateLimits() []RateLimit { + if m != nil { + return m.RateLimits + } + return nil +} + +// Queries all blacklisted denoms +type QueryAllBlacklistedDenomsRequest struct { +} + +func (m *QueryAllBlacklistedDenomsRequest) Reset() { *m = QueryAllBlacklistedDenomsRequest{} } +func (m *QueryAllBlacklistedDenomsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryAllBlacklistedDenomsRequest) ProtoMessage() {} +func (*QueryAllBlacklistedDenomsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_d909918e357d6d0b, []int{8} +} +func (m *QueryAllBlacklistedDenomsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllBlacklistedDenomsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllBlacklistedDenomsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllBlacklistedDenomsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllBlacklistedDenomsRequest.Merge(m, src) +} +func (m *QueryAllBlacklistedDenomsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryAllBlacklistedDenomsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllBlacklistedDenomsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllBlacklistedDenomsRequest proto.InternalMessageInfo + +type QueryAllBlacklistedDenomsResponse struct { + Denoms []string `protobuf:"bytes,1,rep,name=denoms,proto3" json:"denoms,omitempty"` +} + +func (m *QueryAllBlacklistedDenomsResponse) Reset() { *m = QueryAllBlacklistedDenomsResponse{} } +func (m *QueryAllBlacklistedDenomsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryAllBlacklistedDenomsResponse) ProtoMessage() {} +func (*QueryAllBlacklistedDenomsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d909918e357d6d0b, []int{9} +} +func (m *QueryAllBlacklistedDenomsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllBlacklistedDenomsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllBlacklistedDenomsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllBlacklistedDenomsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllBlacklistedDenomsResponse.Merge(m, src) +} +func (m *QueryAllBlacklistedDenomsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryAllBlacklistedDenomsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllBlacklistedDenomsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllBlacklistedDenomsResponse proto.InternalMessageInfo + +func (m *QueryAllBlacklistedDenomsResponse) GetDenoms() []string { + if m != nil { + return m.Denoms + } + return nil +} + +// Queries all whitelisted address pairs +type QueryAllWhitelistedAddressesRequest struct { +} + +func (m *QueryAllWhitelistedAddressesRequest) Reset() { *m = QueryAllWhitelistedAddressesRequest{} } +func (m *QueryAllWhitelistedAddressesRequest) String() string { return proto.CompactTextString(m) } +func (*QueryAllWhitelistedAddressesRequest) ProtoMessage() {} +func (*QueryAllWhitelistedAddressesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_d909918e357d6d0b, []int{10} +} +func (m *QueryAllWhitelistedAddressesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllWhitelistedAddressesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllWhitelistedAddressesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllWhitelistedAddressesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllWhitelistedAddressesRequest.Merge(m, src) +} +func (m *QueryAllWhitelistedAddressesRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryAllWhitelistedAddressesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllWhitelistedAddressesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllWhitelistedAddressesRequest proto.InternalMessageInfo + +type QueryAllWhitelistedAddressesResponse struct { + AddressPairs []WhitelistedAddressPair `protobuf:"bytes,1,rep,name=address_pairs,json=addressPairs,proto3" json:"address_pairs"` +} + +func (m *QueryAllWhitelistedAddressesResponse) Reset() { *m = QueryAllWhitelistedAddressesResponse{} } +func (m *QueryAllWhitelistedAddressesResponse) String() string { return proto.CompactTextString(m) } +func (*QueryAllWhitelistedAddressesResponse) ProtoMessage() {} +func (*QueryAllWhitelistedAddressesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d909918e357d6d0b, []int{11} +} +func (m *QueryAllWhitelistedAddressesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllWhitelistedAddressesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllWhitelistedAddressesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllWhitelistedAddressesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllWhitelistedAddressesResponse.Merge(m, src) +} +func (m *QueryAllWhitelistedAddressesResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryAllWhitelistedAddressesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllWhitelistedAddressesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllWhitelistedAddressesResponse proto.InternalMessageInfo + +func (m *QueryAllWhitelistedAddressesResponse) GetAddressPairs() []WhitelistedAddressPair { + if m != nil { + return m.AddressPairs + } + return nil +} + +func init() { + proto.RegisterType((*QueryAllRateLimitsRequest)(nil), "ratelimit.v1.QueryAllRateLimitsRequest") + proto.RegisterType((*QueryAllRateLimitsResponse)(nil), "ratelimit.v1.QueryAllRateLimitsResponse") + proto.RegisterType((*QueryRateLimitRequest)(nil), "ratelimit.v1.QueryRateLimitRequest") + proto.RegisterType((*QueryRateLimitResponse)(nil), "ratelimit.v1.QueryRateLimitResponse") + proto.RegisterType((*QueryRateLimitsByChainIdRequest)(nil), "ratelimit.v1.QueryRateLimitsByChainIdRequest") + proto.RegisterType((*QueryRateLimitsByChainIdResponse)(nil), "ratelimit.v1.QueryRateLimitsByChainIdResponse") + proto.RegisterType((*QueryRateLimitsByChannelIdRequest)(nil), "ratelimit.v1.QueryRateLimitsByChannelIdRequest") + proto.RegisterType((*QueryRateLimitsByChannelIdResponse)(nil), "ratelimit.v1.QueryRateLimitsByChannelIdResponse") + proto.RegisterType((*QueryAllBlacklistedDenomsRequest)(nil), "ratelimit.v1.QueryAllBlacklistedDenomsRequest") + proto.RegisterType((*QueryAllBlacklistedDenomsResponse)(nil), "ratelimit.v1.QueryAllBlacklistedDenomsResponse") + proto.RegisterType((*QueryAllWhitelistedAddressesRequest)(nil), "ratelimit.v1.QueryAllWhitelistedAddressesRequest") + proto.RegisterType((*QueryAllWhitelistedAddressesResponse)(nil), "ratelimit.v1.QueryAllWhitelistedAddressesResponse") +} + +func init() { proto.RegisterFile("ratelimit/v1/query.proto", fileDescriptor_d909918e357d6d0b) } + +var fileDescriptor_d909918e357d6d0b = []byte{ + // 712 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x4f, 0x4f, 0xdb, 0x4a, + 0x10, 0x8f, 0x79, 0x0f, 0x1e, 0x19, 0xe0, 0xb2, 0x8f, 0x3f, 0xc1, 0x8f, 0x17, 0xa8, 0xa1, 0x2a, + 0x97, 0x64, 0x0b, 0xa8, 0xad, 0x2a, 0x5a, 0x04, 0xa1, 0xaa, 0xa0, 0x42, 0x2a, 0x0d, 0x87, 0x4a, + 0x55, 0xa5, 0x68, 0x6d, 0xaf, 0x92, 0x55, 0x1d, 0xaf, 0xf1, 0x3a, 0xa0, 0xa8, 0xe2, 0xd2, 0x4f, + 0x50, 0xa9, 0x1f, 0xa0, 0xd7, 0x7e, 0x88, 0x1e, 0x7b, 0xe0, 0x88, 0xd4, 0x4b, 0x4f, 0x55, 0x05, + 0x7c, 0x90, 0xca, 0xeb, 0x8d, 0x5d, 0x83, 0x13, 0x02, 0xe2, 0xb6, 0xde, 0x99, 0xf9, 0xcd, 0xef, + 0x37, 0x3b, 0x33, 0x32, 0x14, 0x7c, 0x12, 0x50, 0x87, 0x35, 0x59, 0x80, 0x0f, 0x96, 0xf0, 0x7e, + 0x8b, 0xfa, 0xed, 0xb2, 0xe7, 0xf3, 0x80, 0xa3, 0xd1, 0xd8, 0x52, 0x3e, 0x58, 0xd2, 0x67, 0x52, + 0x7e, 0x89, 0x49, 0xfa, 0xea, 0x33, 0x75, 0xce, 0xeb, 0x0e, 0xc5, 0xc4, 0x63, 0x98, 0xb8, 0x2e, + 0x0f, 0x48, 0xc0, 0xb8, 0x2b, 0x94, 0x75, 0xbc, 0xce, 0xeb, 0x5c, 0x1e, 0x71, 0x78, 0x8a, 0x6e, + 0x8d, 0xff, 0x60, 0xfa, 0x55, 0x98, 0x6e, 0xc3, 0x71, 0xaa, 0x24, 0xa0, 0x3b, 0x21, 0x9c, 0xa8, + 0xd2, 0xfd, 0x16, 0x15, 0x81, 0xf1, 0x16, 0xf4, 0x2c, 0xa3, 0xf0, 0xb8, 0x2b, 0x28, 0x5a, 0x83, + 0x91, 0x90, 0x41, 0x4d, 0x52, 0x10, 0x05, 0x6d, 0xee, 0xaf, 0xc5, 0x91, 0xe5, 0xa9, 0xf2, 0x9f, + 0x84, 0xcb, 0x71, 0x58, 0xe5, 0xef, 0xe3, 0x9f, 0xb3, 0xb9, 0x2a, 0xf8, 0x31, 0x8e, 0xb1, 0x03, + 0x13, 0x12, 0x3d, 0xf6, 0x51, 0x69, 0xd1, 0x38, 0x0c, 0xda, 0xd4, 0xe5, 0xcd, 0x82, 0x36, 0xa7, + 0x2d, 0xe6, 0xab, 0xd1, 0x07, 0xfa, 0x1f, 0xc0, 0x6a, 0x10, 0xd7, 0xa5, 0x4e, 0x8d, 0xd9, 0x85, + 0x01, 0x69, 0xca, 0xab, 0x9b, 0x6d, 0xdb, 0xd8, 0x85, 0xc9, 0x8b, 0x68, 0x8a, 0xe7, 0x43, 0x80, + 0x84, 0xa7, 0xc4, 0xec, 0x4e, 0xb3, 0x9a, 0x8f, 0x09, 0x1a, 0x4f, 0x60, 0x36, 0x8d, 0x28, 0x2a, + 0xed, 0xcd, 0x06, 0x61, 0xee, 0xb6, 0xdd, 0x61, 0x3a, 0x0d, 0xc3, 0x56, 0x78, 0x13, 0x32, 0x8a, + 0xc8, 0xfe, 0x63, 0x45, 0x1e, 0x86, 0x09, 0x73, 0xdd, 0xa3, 0x6f, 0xa9, 0x82, 0x15, 0xb8, 0x93, + 0x95, 0x23, 0xaa, 0x48, 0x87, 0x63, 0xba, 0x6e, 0xda, 0xc5, 0xba, 0xd9, 0x60, 0xf4, 0xc2, 0xb8, + 0x25, 0xa6, 0x86, 0xaa, 0xc6, 0x86, 0xe3, 0x54, 0x1c, 0x62, 0xbd, 0x73, 0x98, 0x08, 0xa8, 0xfd, + 0x2c, 0x7c, 0xd8, 0xb8, 0xdb, 0x56, 0x95, 0x9a, 0x6c, 0x1f, 0x45, 0x64, 0x12, 0x86, 0x64, 0x3b, + 0x44, 0x1c, 0xf2, 0x55, 0xf5, 0x65, 0xdc, 0x85, 0xf9, 0x4e, 0xf0, 0xeb, 0x06, 0x0b, 0x59, 0x85, + 0xc1, 0x1b, 0xb6, 0xed, 0x53, 0x21, 0x68, 0x9c, 0xe3, 0x10, 0x16, 0x7a, 0xbb, 0xa9, 0x34, 0x2f, + 0x61, 0x8c, 0x44, 0x97, 0x35, 0x8f, 0x30, 0xbf, 0xa3, 0x78, 0x21, 0xad, 0xf8, 0x32, 0xc4, 0x2e, + 0x61, 0xbe, 0x92, 0x3f, 0x4a, 0x92, 0x2b, 0xb1, 0x7c, 0x3e, 0x0c, 0x83, 0x32, 0x33, 0xfa, 0xac, + 0xc1, 0x58, 0x6a, 0xa0, 0xd0, 0xbd, 0x34, 0x6a, 0xd7, 0x79, 0xd4, 0x17, 0xaf, 0x76, 0x8c, 0xf8, + 0x1b, 0xab, 0x1f, 0xbe, 0x9f, 0x7f, 0x1a, 0x78, 0x80, 0x56, 0xf0, 0x5e, 0xe0, 0x33, 0x9b, 0x96, + 0x76, 0x88, 0x29, 0x30, 0x33, 0xad, 0x52, 0x88, 0x50, 0x92, 0x10, 0xcc, 0xad, 0x27, 0x2b, 0x24, + 0x39, 0x09, 0xf4, 0x45, 0x83, 0x7c, 0x8c, 0x89, 0xe6, 0x33, 0x92, 0x5e, 0x1c, 0x59, 0x7d, 0xa1, + 0xb7, 0x93, 0x62, 0xb5, 0x2b, 0x59, 0xbd, 0x40, 0x5b, 0xd7, 0x67, 0x85, 0xdf, 0x27, 0x4d, 0x7c, + 0x84, 0xcd, 0x76, 0x2d, 0x5a, 0x0a, 0x5f, 0x35, 0xf8, 0x37, 0x63, 0xc2, 0x50, 0xa9, 0x17, 0x9f, + 0x4b, 0x73, 0xac, 0x97, 0xfb, 0x75, 0x57, 0x42, 0x9e, 0x4b, 0x21, 0xeb, 0x68, 0xed, 0x06, 0xe5, + 0x95, 0x4a, 0xe4, 0xca, 0x38, 0x42, 0xdf, 0x34, 0x98, 0xc8, 0x1c, 0x3c, 0x84, 0xaf, 0x66, 0x94, + 0x1a, 0x73, 0xfd, 0x7e, 0xff, 0x01, 0x4a, 0xc4, 0x96, 0x14, 0x51, 0x41, 0xeb, 0x37, 0x15, 0xd1, + 0x79, 0x8e, 0xf0, 0x15, 0xc6, 0xb3, 0xa6, 0x16, 0x95, 0xb3, 0x1b, 0xb6, 0xdb, 0x0a, 0xd0, 0x71, + 0xdf, 0xfe, 0x4a, 0xc3, 0xa6, 0xd4, 0xf0, 0x14, 0xad, 0xf6, 0xad, 0xc1, 0x4c, 0xb0, 0xa2, 0x1e, + 0x12, 0xe8, 0x58, 0x83, 0xa9, 0x2e, 0x0b, 0x01, 0x2d, 0x65, 0x33, 0xea, 0xb1, 0x63, 0xf4, 0xe5, + 0xeb, 0x84, 0xdc, 0xb8, 0xa1, 0x0e, 0x13, 0xb8, 0x1a, 0xe9, 0xe0, 0x55, 0xf6, 0x8e, 0x4f, 0x8b, + 0xda, 0xc9, 0x69, 0x51, 0xfb, 0x75, 0x5a, 0xd4, 0x3e, 0x9e, 0x15, 0x73, 0x27, 0x67, 0xc5, 0xdc, + 0x8f, 0xb3, 0x62, 0xee, 0xcd, 0xe3, 0x3a, 0x0b, 0x1a, 0x2d, 0xb3, 0x6c, 0xf1, 0x26, 0xb6, 0xb8, + 0x68, 0xf2, 0x08, 0x9e, 0x78, 0x9e, 0xc0, 0x4d, 0x6e, 0xb7, 0x1c, 0x2a, 0x70, 0x3a, 0xd7, 0xc1, + 0x23, 0x1c, 0xb4, 0x3d, 0x2a, 0xcc, 0x21, 0xf9, 0xab, 0xb0, 0xf2, 0x3b, 0x00, 0x00, 0xff, 0xff, + 0x0e, 0x6e, 0x7b, 0x27, 0xa6, 0x08, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // Queries all rate limits + AllRateLimits(ctx context.Context, in *QueryAllRateLimitsRequest, opts ...grpc.CallOption) (*QueryAllRateLimitsResponse, error) + // Queries a specific rate limit by channel ID and denom + // Ex: + // - /ratelimit/{channel_id}/by_denom?denom={denom} + RateLimit(ctx context.Context, in *QueryRateLimitRequest, opts ...grpc.CallOption) (*QueryRateLimitResponse, error) + // Queries all the rate limits for a given chain + RateLimitsByChainId(ctx context.Context, in *QueryRateLimitsByChainIdRequest, opts ...grpc.CallOption) (*QueryRateLimitsByChainIdResponse, error) + // Queries all the rate limits for a given channel ID + RateLimitsByChannelId(ctx context.Context, in *QueryRateLimitsByChannelIdRequest, opts ...grpc.CallOption) (*QueryRateLimitsByChannelIdResponse, error) + // Queries all blacklisted denoms + AllBlacklistedDenoms(ctx context.Context, in *QueryAllBlacklistedDenomsRequest, opts ...grpc.CallOption) (*QueryAllBlacklistedDenomsResponse, error) + // Queries all whitelisted address pairs + AllWhitelistedAddresses(ctx context.Context, in *QueryAllWhitelistedAddressesRequest, opts ...grpc.CallOption) (*QueryAllWhitelistedAddressesResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) AllRateLimits(ctx context.Context, in *QueryAllRateLimitsRequest, opts ...grpc.CallOption) (*QueryAllRateLimitsResponse, error) { + out := new(QueryAllRateLimitsResponse) + err := c.cc.Invoke(ctx, "/ratelimit.v1.Query/AllRateLimits", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) RateLimit(ctx context.Context, in *QueryRateLimitRequest, opts ...grpc.CallOption) (*QueryRateLimitResponse, error) { + out := new(QueryRateLimitResponse) + err := c.cc.Invoke(ctx, "/ratelimit.v1.Query/RateLimit", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) RateLimitsByChainId(ctx context.Context, in *QueryRateLimitsByChainIdRequest, opts ...grpc.CallOption) (*QueryRateLimitsByChainIdResponse, error) { + out := new(QueryRateLimitsByChainIdResponse) + err := c.cc.Invoke(ctx, "/ratelimit.v1.Query/RateLimitsByChainId", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) RateLimitsByChannelId(ctx context.Context, in *QueryRateLimitsByChannelIdRequest, opts ...grpc.CallOption) (*QueryRateLimitsByChannelIdResponse, error) { + out := new(QueryRateLimitsByChannelIdResponse) + err := c.cc.Invoke(ctx, "/ratelimit.v1.Query/RateLimitsByChannelId", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) AllBlacklistedDenoms(ctx context.Context, in *QueryAllBlacklistedDenomsRequest, opts ...grpc.CallOption) (*QueryAllBlacklistedDenomsResponse, error) { + out := new(QueryAllBlacklistedDenomsResponse) + err := c.cc.Invoke(ctx, "/ratelimit.v1.Query/AllBlacklistedDenoms", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) AllWhitelistedAddresses(ctx context.Context, in *QueryAllWhitelistedAddressesRequest, opts ...grpc.CallOption) (*QueryAllWhitelistedAddressesResponse, error) { + out := new(QueryAllWhitelistedAddressesResponse) + err := c.cc.Invoke(ctx, "/ratelimit.v1.Query/AllWhitelistedAddresses", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // Queries all rate limits + AllRateLimits(context.Context, *QueryAllRateLimitsRequest) (*QueryAllRateLimitsResponse, error) + // Queries a specific rate limit by channel ID and denom + // Ex: + // - /ratelimit/{channel_id}/by_denom?denom={denom} + RateLimit(context.Context, *QueryRateLimitRequest) (*QueryRateLimitResponse, error) + // Queries all the rate limits for a given chain + RateLimitsByChainId(context.Context, *QueryRateLimitsByChainIdRequest) (*QueryRateLimitsByChainIdResponse, error) + // Queries all the rate limits for a given channel ID + RateLimitsByChannelId(context.Context, *QueryRateLimitsByChannelIdRequest) (*QueryRateLimitsByChannelIdResponse, error) + // Queries all blacklisted denoms + AllBlacklistedDenoms(context.Context, *QueryAllBlacklistedDenomsRequest) (*QueryAllBlacklistedDenomsResponse, error) + // Queries all whitelisted address pairs + AllWhitelistedAddresses(context.Context, *QueryAllWhitelistedAddressesRequest) (*QueryAllWhitelistedAddressesResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) AllRateLimits(ctx context.Context, req *QueryAllRateLimitsRequest) (*QueryAllRateLimitsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AllRateLimits not implemented") +} +func (*UnimplementedQueryServer) RateLimit(ctx context.Context, req *QueryRateLimitRequest) (*QueryRateLimitResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RateLimit not implemented") +} +func (*UnimplementedQueryServer) RateLimitsByChainId(ctx context.Context, req *QueryRateLimitsByChainIdRequest) (*QueryRateLimitsByChainIdResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RateLimitsByChainId not implemented") +} +func (*UnimplementedQueryServer) RateLimitsByChannelId(ctx context.Context, req *QueryRateLimitsByChannelIdRequest) (*QueryRateLimitsByChannelIdResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RateLimitsByChannelId not implemented") +} +func (*UnimplementedQueryServer) AllBlacklistedDenoms(ctx context.Context, req *QueryAllBlacklistedDenomsRequest) (*QueryAllBlacklistedDenomsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AllBlacklistedDenoms not implemented") +} +func (*UnimplementedQueryServer) AllWhitelistedAddresses(ctx context.Context, req *QueryAllWhitelistedAddressesRequest) (*QueryAllWhitelistedAddressesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AllWhitelistedAddresses not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_AllRateLimits_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryAllRateLimitsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).AllRateLimits(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ratelimit.v1.Query/AllRateLimits", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).AllRateLimits(ctx, req.(*QueryAllRateLimitsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_RateLimit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryRateLimitRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).RateLimit(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ratelimit.v1.Query/RateLimit", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).RateLimit(ctx, req.(*QueryRateLimitRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_RateLimitsByChainId_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryRateLimitsByChainIdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).RateLimitsByChainId(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ratelimit.v1.Query/RateLimitsByChainId", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).RateLimitsByChainId(ctx, req.(*QueryRateLimitsByChainIdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_RateLimitsByChannelId_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryRateLimitsByChannelIdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).RateLimitsByChannelId(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ratelimit.v1.Query/RateLimitsByChannelId", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).RateLimitsByChannelId(ctx, req.(*QueryRateLimitsByChannelIdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_AllBlacklistedDenoms_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryAllBlacklistedDenomsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).AllBlacklistedDenoms(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ratelimit.v1.Query/AllBlacklistedDenoms", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).AllBlacklistedDenoms(ctx, req.(*QueryAllBlacklistedDenomsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_AllWhitelistedAddresses_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryAllWhitelistedAddressesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).AllWhitelistedAddresses(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ratelimit.v1.Query/AllWhitelistedAddresses", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).AllWhitelistedAddresses(ctx, req.(*QueryAllWhitelistedAddressesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "ratelimit.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AllRateLimits", + Handler: _Query_AllRateLimits_Handler, + }, + { + MethodName: "RateLimit", + Handler: _Query_RateLimit_Handler, + }, + { + MethodName: "RateLimitsByChainId", + Handler: _Query_RateLimitsByChainId_Handler, + }, + { + MethodName: "RateLimitsByChannelId", + Handler: _Query_RateLimitsByChannelId_Handler, + }, + { + MethodName: "AllBlacklistedDenoms", + Handler: _Query_AllBlacklistedDenoms_Handler, + }, + { + MethodName: "AllWhitelistedAddresses", + Handler: _Query_AllWhitelistedAddresses_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "ratelimit/v1/query.proto", +} + +func (m *QueryAllRateLimitsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAllRateLimitsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllRateLimitsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryAllRateLimitsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAllRateLimitsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllRateLimitsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.RateLimits) > 0 { + for iNdEx := len(m.RateLimits) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.RateLimits[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryRateLimitRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryRateLimitRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryRateLimitRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0x12 + } + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryRateLimitResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryRateLimitResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryRateLimitResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.RateLimit != nil { + { + size, err := m.RateLimit.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryRateLimitsByChainIdRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryRateLimitsByChainIdRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryRateLimitsByChainIdRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ChainId) > 0 { + i -= len(m.ChainId) + copy(dAtA[i:], m.ChainId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ChainId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryRateLimitsByChainIdResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryRateLimitsByChainIdResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryRateLimitsByChainIdResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.RateLimits) > 0 { + for iNdEx := len(m.RateLimits) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.RateLimits[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryRateLimitsByChannelIdRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryRateLimitsByChannelIdRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryRateLimitsByChannelIdRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryRateLimitsByChannelIdResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryRateLimitsByChannelIdResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryRateLimitsByChannelIdResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.RateLimits) > 0 { + for iNdEx := len(m.RateLimits) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.RateLimits[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryAllBlacklistedDenomsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAllBlacklistedDenomsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllBlacklistedDenomsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryAllBlacklistedDenomsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAllBlacklistedDenomsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllBlacklistedDenomsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Denoms) > 0 { + for iNdEx := len(m.Denoms) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Denoms[iNdEx]) + copy(dAtA[i:], m.Denoms[iNdEx]) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Denoms[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryAllWhitelistedAddressesRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAllWhitelistedAddressesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllWhitelistedAddressesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryAllWhitelistedAddressesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAllWhitelistedAddressesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllWhitelistedAddressesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AddressPairs) > 0 { + for iNdEx := len(m.AddressPairs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.AddressPairs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryAllRateLimitsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryAllRateLimitsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.RateLimits) > 0 { + for _, e := range m.RateLimits { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryRateLimitRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryRateLimitResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.RateLimit != nil { + l = m.RateLimit.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryRateLimitsByChainIdRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryRateLimitsByChainIdResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.RateLimits) > 0 { + for _, e := range m.RateLimits { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryRateLimitsByChannelIdRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryRateLimitsByChannelIdResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.RateLimits) > 0 { + for _, e := range m.RateLimits { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryAllBlacklistedDenomsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryAllBlacklistedDenomsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Denoms) > 0 { + for _, s := range m.Denoms { + l = len(s) + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryAllWhitelistedAddressesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryAllWhitelistedAddressesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.AddressPairs) > 0 { + for _, e := range m.AddressPairs { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryAllRateLimitsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAllRateLimitsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllRateLimitsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAllRateLimitsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAllRateLimitsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllRateLimitsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RateLimits", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RateLimits = append(m.RateLimits, RateLimit{}) + if err := m.RateLimits[len(m.RateLimits)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryRateLimitRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryRateLimitRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryRateLimitRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryRateLimitResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryRateLimitResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryRateLimitResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RateLimit", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.RateLimit == nil { + m.RateLimit = &RateLimit{} + } + if err := m.RateLimit.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryRateLimitsByChainIdRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryRateLimitsByChainIdRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryRateLimitsByChainIdRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryRateLimitsByChainIdResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryRateLimitsByChainIdResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryRateLimitsByChainIdResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RateLimits", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RateLimits = append(m.RateLimits, RateLimit{}) + if err := m.RateLimits[len(m.RateLimits)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryRateLimitsByChannelIdRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryRateLimitsByChannelIdRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryRateLimitsByChannelIdRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryRateLimitsByChannelIdResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryRateLimitsByChannelIdResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryRateLimitsByChannelIdResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RateLimits", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RateLimits = append(m.RateLimits, RateLimit{}) + if err := m.RateLimits[len(m.RateLimits)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAllBlacklistedDenomsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAllBlacklistedDenomsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllBlacklistedDenomsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAllBlacklistedDenomsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAllBlacklistedDenomsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllBlacklistedDenomsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denoms", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denoms = append(m.Denoms, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAllWhitelistedAddressesRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAllWhitelistedAddressesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllWhitelistedAddressesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAllWhitelistedAddressesResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAllWhitelistedAddressesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllWhitelistedAddressesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AddressPairs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AddressPairs = append(m.AddressPairs, WhitelistedAddressPair{}) + if err := m.AddressPairs[len(m.AddressPairs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/rate-limiting/types/query.pb.gw.go b/modules/rate-limiting/types/query.pb.gw.go new file mode 100644 index 00000000..365ed66d --- /dev/null +++ b/modules/rate-limiting/types/query.pb.gw.go @@ -0,0 +1,604 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: ratelimit/v1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_Query_AllRateLimits_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllRateLimitsRequest + var metadata runtime.ServerMetadata + + msg, err := client.AllRateLimits(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_AllRateLimits_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllRateLimitsRequest + var metadata runtime.ServerMetadata + + msg, err := server.AllRateLimits(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_RateLimit_0 = &utilities.DoubleArray{Encoding: map[string]int{"channel_id": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_Query_RateLimit_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryRateLimitRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + } + + protoReq.ChannelId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_RateLimit_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.RateLimit(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_RateLimit_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryRateLimitRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + } + + protoReq.ChannelId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_RateLimit_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.RateLimit(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_RateLimitsByChainId_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryRateLimitsByChainIdRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["chain_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "chain_id") + } + + protoReq.ChainId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "chain_id", err) + } + + msg, err := client.RateLimitsByChainId(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_RateLimitsByChainId_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryRateLimitsByChainIdRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["chain_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "chain_id") + } + + protoReq.ChainId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "chain_id", err) + } + + msg, err := server.RateLimitsByChainId(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_RateLimitsByChannelId_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryRateLimitsByChannelIdRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + } + + protoReq.ChannelId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + } + + msg, err := client.RateLimitsByChannelId(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_RateLimitsByChannelId_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryRateLimitsByChannelIdRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + } + + protoReq.ChannelId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + } + + msg, err := server.RateLimitsByChannelId(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_AllBlacklistedDenoms_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllBlacklistedDenomsRequest + var metadata runtime.ServerMetadata + + msg, err := client.AllBlacklistedDenoms(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_AllBlacklistedDenoms_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllBlacklistedDenomsRequest + var metadata runtime.ServerMetadata + + msg, err := server.AllBlacklistedDenoms(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_AllWhitelistedAddresses_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllWhitelistedAddressesRequest + var metadata runtime.ServerMetadata + + msg, err := client.AllWhitelistedAddresses(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_AllWhitelistedAddresses_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllWhitelistedAddressesRequest + var metadata runtime.ServerMetadata + + msg, err := server.AllWhitelistedAddresses(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_AllRateLimits_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_AllRateLimits_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AllRateLimits_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_RateLimit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_RateLimit_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_RateLimit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_RateLimitsByChainId_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_RateLimitsByChainId_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_RateLimitsByChainId_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_RateLimitsByChannelId_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_RateLimitsByChannelId_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_RateLimitsByChannelId_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AllBlacklistedDenoms_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_AllBlacklistedDenoms_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AllBlacklistedDenoms_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AllWhitelistedAddresses_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_AllWhitelistedAddresses_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AllWhitelistedAddresses_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_AllRateLimits_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_AllRateLimits_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AllRateLimits_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_RateLimit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_RateLimit_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_RateLimit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_RateLimitsByChainId_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_RateLimitsByChainId_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_RateLimitsByChainId_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_RateLimitsByChannelId_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_RateLimitsByChannelId_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_RateLimitsByChannelId_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AllBlacklistedDenoms_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_AllBlacklistedDenoms_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AllBlacklistedDenoms_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AllWhitelistedAddresses_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_AllWhitelistedAddresses_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AllWhitelistedAddresses_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_AllRateLimits_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"Stride-Labs", "ibc-rate-limiting", "ratelimit", "ratelimits"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_RateLimit_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"Stride-Labs", "ibc-rate-limiting", "ratelimit", "channel_id", "by_denom"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_RateLimitsByChainId_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"Stride-Labs", "ibc-rate-limiting", "ratelimit", "ratelimits", "chain_id"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_RateLimitsByChannelId_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"Stride-Labs", "ibc-rate-limiting", "ratelimit", "ratelimits", "channel_id"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_AllBlacklistedDenoms_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"Stride-Labs", "ibc-rate-limiting", "ratelimit", "blacklisted_denoms"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_AllWhitelistedAddresses_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"Stride-Labs", "ibc-rate-limiting", "ratelimit", "whitelisted_addresses"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_AllRateLimits_0 = runtime.ForwardResponseMessage + + forward_Query_RateLimit_0 = runtime.ForwardResponseMessage + + forward_Query_RateLimitsByChainId_0 = runtime.ForwardResponseMessage + + forward_Query_RateLimitsByChannelId_0 = runtime.ForwardResponseMessage + + forward_Query_AllBlacklistedDenoms_0 = runtime.ForwardResponseMessage + + forward_Query_AllWhitelistedAddresses_0 = runtime.ForwardResponseMessage +) diff --git a/modules/rate-limiting/types/quota.go b/modules/rate-limiting/types/quota.go new file mode 100644 index 00000000..caf3bafe --- /dev/null +++ b/modules/rate-limiting/types/quota.go @@ -0,0 +1,22 @@ +package types + +import ( + sdkmath "cosmossdk.io/math" +) + +// CheckExceedsQuota checks if new in/out flow is going to reach the max in/out or not +func (q *Quota) CheckExceedsQuota(direction PacketDirection, amount sdkmath.Int, totalValue sdkmath.Int) bool { + // If there's no channel value (this should be almost impossible), it means there is no + // supply of the asset, so we shoudn't prevent inflows/outflows + if totalValue.IsZero() { + return false + } + var threshold sdkmath.Int + if direction == PACKET_RECV { + threshold = totalValue.Mul(q.MaxPercentRecv).Quo(sdkmath.NewInt(100)) + } else { + threshold = totalValue.Mul(q.MaxPercentSend).Quo(sdkmath.NewInt(100)) + } + + return amount.GT(threshold) +} diff --git a/modules/rate-limiting/types/quota_test.go b/modules/rate-limiting/types/quota_test.go new file mode 100644 index 00000000..61e61e40 --- /dev/null +++ b/modules/rate-limiting/types/quota_test.go @@ -0,0 +1,79 @@ +package types_test + +import ( + "testing" + + "github.com/cosmos/ibc-apps/modules/rate-limiting/v7/types" + "github.com/stretchr/testify/require" + + sdkmath "cosmossdk.io/math" +) + +func TestCheckExceedsQuota(t *testing.T) { + totalValue := sdkmath.NewInt(100) + amountUnderThreshold := sdkmath.NewInt(5) + amountOverThreshold := sdkmath.NewInt(15) + quota := types.Quota{ + MaxPercentRecv: sdkmath.NewInt(10), + MaxPercentSend: sdkmath.NewInt(10), + DurationHours: uint64(1), + } + + tests := []struct { + name string + direction types.PacketDirection + amount sdkmath.Int + totalValue sdkmath.Int + exceeded bool + }{ + { + name: "inflow exceeded threshold", + direction: types.PACKET_RECV, + amount: amountOverThreshold, + totalValue: totalValue, + exceeded: true, + }, + { + name: "inflow did not exceed threshold", + direction: types.PACKET_RECV, + amount: amountUnderThreshold, + totalValue: totalValue, + exceeded: false, + }, + { + name: "outflow exceeded threshold", + direction: types.PACKET_SEND, + amount: amountOverThreshold, + totalValue: totalValue, + exceeded: true, + }, + { + name: "outflow did not exceed threshold", + direction: types.PACKET_SEND, + amount: amountUnderThreshold, + totalValue: totalValue, + exceeded: false, + }, + { + name: "zero channel value send", + direction: types.PACKET_SEND, + amount: amountOverThreshold, + totalValue: sdkmath.ZeroInt(), + exceeded: false, + }, + { + name: "zero channel value recv", + direction: types.PACKET_RECV, + amount: amountOverThreshold, + totalValue: sdkmath.ZeroInt(), + exceeded: false, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + res := quota.CheckExceedsQuota(test.direction, test.amount, test.totalValue) + require.Equal(t, res, test.exceeded, "test: %s", test.name) + }) + } +} diff --git a/modules/rate-limiting/types/ratelimit.pb.go b/modules/rate-limiting/types/ratelimit.pb.go new file mode 100644 index 00000000..00011c3e --- /dev/null +++ b/modules/rate-limiting/types/ratelimit.pb.go @@ -0,0 +1,1772 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ratelimit/v1/ratelimit.proto + +package types + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + _ "github.com/cosmos/gogoproto/types" + github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types" + io "io" + math "math" + math_bits "math/bits" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// PacketDirection defines whether the transfer packet is being sent from +// this chain or is being received on this chain +type PacketDirection int32 + +const ( + PACKET_SEND PacketDirection = 0 + PACKET_RECV PacketDirection = 1 +) + +var PacketDirection_name = map[int32]string{ + 0: "PACKET_SEND", + 1: "PACKET_RECV", +} + +var PacketDirection_value = map[string]int32{ + "PACKET_SEND": 0, + "PACKET_RECV": 1, +} + +func (x PacketDirection) String() string { + return proto.EnumName(PacketDirection_name, int32(x)) +} + +func (PacketDirection) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_a3afe8dd489c3bd2, []int{0} +} + +// Path holds the denom and channelID that define the rate limited route +type Path struct { + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` +} + +func (m *Path) Reset() { *m = Path{} } +func (m *Path) String() string { return proto.CompactTextString(m) } +func (*Path) ProtoMessage() {} +func (*Path) Descriptor() ([]byte, []int) { + return fileDescriptor_a3afe8dd489c3bd2, []int{0} +} +func (m *Path) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Path) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Path.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Path) XXX_Merge(src proto.Message) { + xxx_messageInfo_Path.Merge(m, src) +} +func (m *Path) XXX_Size() int { + return m.Size() +} +func (m *Path) XXX_DiscardUnknown() { + xxx_messageInfo_Path.DiscardUnknown(m) +} + +var xxx_messageInfo_Path proto.InternalMessageInfo + +func (m *Path) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func (m *Path) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + +// Quota defines the rate limit thresholds for transfer packets +type Quota struct { + // MaxPercentSend defines the threshold for outflows + // The threshold is defined as a percentage (e.g. 10 indicates 10%) + MaxPercentSend github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=max_percent_send,json=maxPercentSend,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"max_percent_send"` + // MaxPercentSend defines the threshold for inflows + // The threshold is defined as a percentage (e.g. 10 indicates 10%) + MaxPercentRecv github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=max_percent_recv,json=maxPercentRecv,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"max_percent_recv"` + // DurationHours specifies the number of hours before the rate limit + // is reset (e.g. 24 indicates that the rate limit is reset each day) + DurationHours uint64 `protobuf:"varint,3,opt,name=duration_hours,json=durationHours,proto3" json:"duration_hours,omitempty"` +} + +func (m *Quota) Reset() { *m = Quota{} } +func (m *Quota) String() string { return proto.CompactTextString(m) } +func (*Quota) ProtoMessage() {} +func (*Quota) Descriptor() ([]byte, []int) { + return fileDescriptor_a3afe8dd489c3bd2, []int{1} +} +func (m *Quota) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Quota) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Quota.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Quota) XXX_Merge(src proto.Message) { + xxx_messageInfo_Quota.Merge(m, src) +} +func (m *Quota) XXX_Size() int { + return m.Size() +} +func (m *Quota) XXX_DiscardUnknown() { + xxx_messageInfo_Quota.DiscardUnknown(m) +} + +var xxx_messageInfo_Quota proto.InternalMessageInfo + +func (m *Quota) GetDurationHours() uint64 { + if m != nil { + return m.DurationHours + } + return 0 +} + +type Flow struct { + // Inflow defines the total amount of inbound transfers for the given + // rate limit in the current window + Inflow github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=inflow,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"inflow"` + // Outflow defines the total amount of outbound transfers for the given + // rate limit in the current window + Outflow github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=outflow,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"outflow"` + // ChannelValue stores the total supply of the denom at the start of + // the rate limit. This is used as the denominator when checking + // the rate limit threshold + // The ChannelValue is fixed for the duration of the rate limit window + ChannelValue github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=channel_value,json=channelValue,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"channel_value"` +} + +func (m *Flow) Reset() { *m = Flow{} } +func (m *Flow) String() string { return proto.CompactTextString(m) } +func (*Flow) ProtoMessage() {} +func (*Flow) Descriptor() ([]byte, []int) { + return fileDescriptor_a3afe8dd489c3bd2, []int{2} +} +func (m *Flow) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Flow) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Flow.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Flow) XXX_Merge(src proto.Message) { + xxx_messageInfo_Flow.Merge(m, src) +} +func (m *Flow) XXX_Size() int { + return m.Size() +} +func (m *Flow) XXX_DiscardUnknown() { + xxx_messageInfo_Flow.DiscardUnknown(m) +} + +var xxx_messageInfo_Flow proto.InternalMessageInfo + +// RateLimit stores all the context about a given rate limit, including +// the relevant denom and channel, rate limit thresholds, and current +// progress towards the limits +type RateLimit struct { + Path *Path `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` + Quota *Quota `protobuf:"bytes,2,opt,name=quota,proto3" json:"quota,omitempty"` + Flow *Flow `protobuf:"bytes,3,opt,name=flow,proto3" json:"flow,omitempty"` +} + +func (m *RateLimit) Reset() { *m = RateLimit{} } +func (m *RateLimit) String() string { return proto.CompactTextString(m) } +func (*RateLimit) ProtoMessage() {} +func (*RateLimit) Descriptor() ([]byte, []int) { + return fileDescriptor_a3afe8dd489c3bd2, []int{3} +} +func (m *RateLimit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RateLimit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RateLimit.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RateLimit) XXX_Merge(src proto.Message) { + xxx_messageInfo_RateLimit.Merge(m, src) +} +func (m *RateLimit) XXX_Size() int { + return m.Size() +} +func (m *RateLimit) XXX_DiscardUnknown() { + xxx_messageInfo_RateLimit.DiscardUnknown(m) +} + +var xxx_messageInfo_RateLimit proto.InternalMessageInfo + +func (m *RateLimit) GetPath() *Path { + if m != nil { + return m.Path + } + return nil +} + +func (m *RateLimit) GetQuota() *Quota { + if m != nil { + return m.Quota + } + return nil +} + +func (m *RateLimit) GetFlow() *Flow { + if m != nil { + return m.Flow + } + return nil +} + +// WhitelistedAddressPair represents a sender-receiver combo that is +// not subject to rate limit restrictions +type WhitelistedAddressPair struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + Receiver string `protobuf:"bytes,2,opt,name=receiver,proto3" json:"receiver,omitempty"` +} + +func (m *WhitelistedAddressPair) Reset() { *m = WhitelistedAddressPair{} } +func (m *WhitelistedAddressPair) String() string { return proto.CompactTextString(m) } +func (*WhitelistedAddressPair) ProtoMessage() {} +func (*WhitelistedAddressPair) Descriptor() ([]byte, []int) { + return fileDescriptor_a3afe8dd489c3bd2, []int{4} +} +func (m *WhitelistedAddressPair) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *WhitelistedAddressPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_WhitelistedAddressPair.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *WhitelistedAddressPair) XXX_Merge(src proto.Message) { + xxx_messageInfo_WhitelistedAddressPair.Merge(m, src) +} +func (m *WhitelistedAddressPair) XXX_Size() int { + return m.Size() +} +func (m *WhitelistedAddressPair) XXX_DiscardUnknown() { + xxx_messageInfo_WhitelistedAddressPair.DiscardUnknown(m) +} + +var xxx_messageInfo_WhitelistedAddressPair proto.InternalMessageInfo + +func (m *WhitelistedAddressPair) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *WhitelistedAddressPair) GetReceiver() string { + if m != nil { + return m.Receiver + } + return "" +} + +type HourEpoch struct { + EpochNumber uint64 `protobuf:"varint,1,opt,name=epoch_number,json=epochNumber,proto3" json:"epoch_number,omitempty"` + Duration time.Duration `protobuf:"bytes,2,opt,name=duration,proto3,stdduration" json:"duration,omitempty"` + EpochStartTime time.Time `protobuf:"bytes,3,opt,name=epoch_start_time,json=epochStartTime,proto3,stdtime" json:"epoch_start_time"` + EpochStartHeight int64 `protobuf:"varint,4,opt,name=epoch_start_height,json=epochStartHeight,proto3" json:"epoch_start_height,omitempty"` +} + +func (m *HourEpoch) Reset() { *m = HourEpoch{} } +func (m *HourEpoch) String() string { return proto.CompactTextString(m) } +func (*HourEpoch) ProtoMessage() {} +func (*HourEpoch) Descriptor() ([]byte, []int) { + return fileDescriptor_a3afe8dd489c3bd2, []int{5} +} +func (m *HourEpoch) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *HourEpoch) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_HourEpoch.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *HourEpoch) XXX_Merge(src proto.Message) { + xxx_messageInfo_HourEpoch.Merge(m, src) +} +func (m *HourEpoch) XXX_Size() int { + return m.Size() +} +func (m *HourEpoch) XXX_DiscardUnknown() { + xxx_messageInfo_HourEpoch.DiscardUnknown(m) +} + +var xxx_messageInfo_HourEpoch proto.InternalMessageInfo + +func (m *HourEpoch) GetEpochNumber() uint64 { + if m != nil { + return m.EpochNumber + } + return 0 +} + +func (m *HourEpoch) GetDuration() time.Duration { + if m != nil { + return m.Duration + } + return 0 +} + +func (m *HourEpoch) GetEpochStartTime() time.Time { + if m != nil { + return m.EpochStartTime + } + return time.Time{} +} + +func (m *HourEpoch) GetEpochStartHeight() int64 { + if m != nil { + return m.EpochStartHeight + } + return 0 +} + +func init() { + proto.RegisterEnum("ratelimit.v1.PacketDirection", PacketDirection_name, PacketDirection_value) + proto.RegisterType((*Path)(nil), "ratelimit.v1.Path") + proto.RegisterType((*Quota)(nil), "ratelimit.v1.Quota") + proto.RegisterType((*Flow)(nil), "ratelimit.v1.Flow") + proto.RegisterType((*RateLimit)(nil), "ratelimit.v1.RateLimit") + proto.RegisterType((*WhitelistedAddressPair)(nil), "ratelimit.v1.WhitelistedAddressPair") + proto.RegisterType((*HourEpoch)(nil), "ratelimit.v1.HourEpoch") +} + +func init() { proto.RegisterFile("ratelimit/v1/ratelimit.proto", fileDescriptor_a3afe8dd489c3bd2) } + +var fileDescriptor_a3afe8dd489c3bd2 = []byte{ + // 674 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x94, 0x4f, 0x4f, 0xd4, 0x4e, + 0x18, 0xc7, 0xb7, 0xb0, 0xf0, 0x63, 0x67, 0xf9, 0xb3, 0x99, 0x1f, 0x21, 0xeb, 0x46, 0xbb, 0xb8, + 0x89, 0x04, 0x0d, 0xb4, 0x01, 0x0f, 0x86, 0x78, 0x62, 0x61, 0x09, 0x44, 0x42, 0xd6, 0x2e, 0xa2, + 0xf1, 0xd2, 0xcc, 0xb6, 0x0f, 0xed, 0x84, 0xb6, 0x53, 0xdb, 0x69, 0x81, 0xb3, 0x89, 0xf1, 0xc8, + 0xd1, 0xbb, 0x6f, 0x86, 0x23, 0x47, 0xe3, 0x01, 0xcd, 0x72, 0x33, 0xf1, 0x3d, 0x98, 0x99, 0xb6, + 0x80, 0xe0, 0x45, 0x3c, 0x6d, 0x9f, 0x7f, 0x9f, 0xed, 0x77, 0xe6, 0xfb, 0x14, 0xdd, 0x8f, 0x08, + 0x07, 0x8f, 0xfa, 0x94, 0xeb, 0xe9, 0x92, 0x7e, 0x19, 0x68, 0x61, 0xc4, 0x38, 0xc3, 0xe3, 0x57, + 0x89, 0x74, 0xa9, 0x31, 0xed, 0x30, 0x87, 0xc9, 0x82, 0x2e, 0x9e, 0xb2, 0x9e, 0x86, 0xea, 0x30, + 0xe6, 0x78, 0xa0, 0xcb, 0xa8, 0x9f, 0xec, 0xeb, 0x76, 0x12, 0x11, 0x4e, 0x59, 0x90, 0xd7, 0x9b, + 0x37, 0xeb, 0x9c, 0xfa, 0x10, 0x73, 0xe2, 0x87, 0x59, 0x43, 0xeb, 0x39, 0x2a, 0x77, 0x09, 0x77, + 0xf1, 0x34, 0x1a, 0xb1, 0x21, 0x60, 0x7e, 0x5d, 0x99, 0x55, 0xe6, 0x2b, 0x46, 0x16, 0xe0, 0x07, + 0x08, 0x59, 0x2e, 0x09, 0x02, 0xf0, 0x4c, 0x6a, 0xd7, 0x87, 0x64, 0xa9, 0x92, 0x67, 0xb6, 0xec, + 0xd6, 0x40, 0x41, 0x23, 0x2f, 0x13, 0xc6, 0x09, 0x7e, 0x83, 0x6a, 0x3e, 0x39, 0x32, 0x43, 0x88, + 0x2c, 0x08, 0xb8, 0x19, 0x43, 0x60, 0x67, 0xa4, 0xb6, 0x76, 0x7a, 0xde, 0x2c, 0x7d, 0x3d, 0x6f, + 0xce, 0x39, 0x94, 0xbb, 0x49, 0x5f, 0xb3, 0x98, 0xaf, 0x5b, 0x2c, 0xf6, 0x59, 0x9c, 0xff, 0x2c, + 0xc6, 0xf6, 0x81, 0xce, 0x8f, 0x43, 0x88, 0xb5, 0xad, 0x80, 0x1b, 0x93, 0x3e, 0x39, 0xea, 0x66, + 0x98, 0x1e, 0x04, 0xf6, 0x4d, 0x72, 0x04, 0x56, 0x9a, 0xbd, 0xc8, 0xbf, 0x90, 0x0d, 0xb0, 0x52, + 0xfc, 0x08, 0x4d, 0x16, 0xa7, 0x65, 0xba, 0x2c, 0x89, 0xe2, 0xfa, 0xf0, 0xac, 0x32, 0x5f, 0x36, + 0x26, 0x8a, 0xec, 0xa6, 0x48, 0xb6, 0x7e, 0x2a, 0xa8, 0xbc, 0xe1, 0xb1, 0x43, 0xbc, 0x81, 0x46, + 0x69, 0xb0, 0xef, 0xb1, 0xc3, 0x3b, 0x2a, 0xcb, 0xa7, 0xf1, 0x26, 0xfa, 0x8f, 0x25, 0x5c, 0x82, + 0xee, 0x26, 0xa4, 0x18, 0xc7, 0x3d, 0x34, 0x51, 0x5c, 0x4f, 0x4a, 0xbc, 0x04, 0xa4, 0x80, 0xbf, + 0xe7, 0x8d, 0xe7, 0x90, 0x3d, 0xc1, 0x68, 0x7d, 0x50, 0x50, 0xc5, 0x20, 0x1c, 0xb6, 0x85, 0xf3, + 0xf0, 0x1c, 0x2a, 0x87, 0x84, 0xbb, 0x52, 0x72, 0x75, 0x19, 0x6b, 0xd7, 0x3d, 0xa9, 0x09, 0xe7, + 0x18, 0xb2, 0x8e, 0x1f, 0xa3, 0x91, 0x77, 0xc2, 0x09, 0x52, 0x52, 0x75, 0xf9, 0xff, 0xdf, 0x1b, + 0xa5, 0x49, 0x8c, 0xac, 0x43, 0x20, 0xa5, 0xf8, 0xe1, 0x3f, 0x21, 0xc5, 0x49, 0x1b, 0xb2, 0xde, + 0xda, 0x46, 0x33, 0xaf, 0x5d, 0x2a, 0x6a, 0x31, 0x07, 0x7b, 0xd5, 0xb6, 0x23, 0x88, 0xe3, 0x2e, + 0xa1, 0x11, 0x9e, 0x41, 0xa3, 0xc2, 0x61, 0x10, 0xe5, 0x6e, 0xcd, 0x23, 0xdc, 0x40, 0x63, 0x11, + 0x58, 0x40, 0x53, 0x88, 0x72, 0xb3, 0x5e, 0xc6, 0xad, 0xf7, 0x43, 0xa8, 0x22, 0x2e, 0xb4, 0x13, + 0x32, 0xcb, 0xc5, 0x0f, 0xd1, 0x38, 0x88, 0x07, 0x33, 0x48, 0xfc, 0x7e, 0xce, 0x29, 0x1b, 0x55, + 0x99, 0xdb, 0x91, 0x29, 0xfc, 0x0a, 0x8d, 0x15, 0x46, 0xc8, 0x45, 0xdd, 0xd3, 0xb2, 0x6d, 0xd2, + 0x8a, 0x6d, 0xd2, 0xd6, 0xf3, 0x86, 0xb6, 0x2a, 0x8e, 0xfc, 0xc7, 0x79, 0x13, 0x17, 0x23, 0x0b, + 0xcc, 0xa7, 0x1c, 0xfc, 0x90, 0x1f, 0x7f, 0xfa, 0xd6, 0x54, 0x8c, 0x4b, 0x14, 0xde, 0x41, 0xb5, + 0xec, 0x9f, 0x63, 0x4e, 0x22, 0x6e, 0x8a, 0x7d, 0xcc, 0x4f, 0xa2, 0x71, 0x0b, 0xbf, 0x5b, 0x2c, + 0x6b, 0x7b, 0x4c, 0xf0, 0x4f, 0x04, 0x69, 0x52, 0x4e, 0xf7, 0xc4, 0xb0, 0x28, 0xe3, 0x05, 0x84, + 0xaf, 0xf3, 0x5c, 0xa0, 0x8e, 0xcb, 0xeb, 0xe5, 0x59, 0x65, 0x7e, 0xd8, 0xa8, 0x5d, 0xf5, 0x6e, + 0xca, 0xfc, 0x93, 0x15, 0x34, 0xd5, 0x25, 0xd6, 0x01, 0xf0, 0x75, 0x1a, 0x81, 0x25, 0x5f, 0x68, + 0x0a, 0x55, 0xbb, 0xab, 0x6b, 0x2f, 0x3a, 0xbb, 0x66, 0xaf, 0xb3, 0xb3, 0x5e, 0x2b, 0x5d, 0x4b, + 0x18, 0x9d, 0xb5, 0xbd, 0x9a, 0xd2, 0x28, 0x7f, 0xfc, 0xac, 0x96, 0xda, 0xbd, 0xd3, 0x81, 0xaa, + 0x9c, 0x0d, 0x54, 0xe5, 0xfb, 0x40, 0x55, 0x4e, 0x2e, 0xd4, 0xd2, 0xd9, 0x85, 0x5a, 0xfa, 0x72, + 0xa1, 0x96, 0xde, 0xae, 0xdc, 0xf6, 0x19, 0xed, 0x5b, 0x8b, 0x24, 0x0c, 0x63, 0xdd, 0x67, 0x76, + 0xe2, 0x41, 0x2c, 0x3f, 0x6e, 0x8b, 0xf2, 0x96, 0x69, 0xe0, 0xe8, 0xe9, 0xb3, 0xcc, 0x7e, 0xfd, + 0x51, 0xa9, 0xf5, 0xe9, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9b, 0x5b, 0x94, 0x5d, 0x0a, 0x05, + 0x00, 0x00, +} + +func (m *Path) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Path) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Path) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintRatelimit(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0x12 + } + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintRatelimit(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Quota) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Quota) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Quota) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.DurationHours != 0 { + i = encodeVarintRatelimit(dAtA, i, uint64(m.DurationHours)) + i-- + dAtA[i] = 0x18 + } + { + size := m.MaxPercentRecv.Size() + i -= size + if _, err := m.MaxPercentRecv.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintRatelimit(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size := m.MaxPercentSend.Size() + i -= size + if _, err := m.MaxPercentSend.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintRatelimit(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *Flow) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Flow) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Flow) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.ChannelValue.Size() + i -= size + if _, err := m.ChannelValue.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintRatelimit(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size := m.Outflow.Size() + i -= size + if _, err := m.Outflow.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintRatelimit(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size := m.Inflow.Size() + i -= size + if _, err := m.Inflow.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintRatelimit(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *RateLimit) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RateLimit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RateLimit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Flow != nil { + { + size, err := m.Flow.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRatelimit(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.Quota != nil { + { + size, err := m.Quota.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRatelimit(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.Path != nil { + { + size, err := m.Path.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRatelimit(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *WhitelistedAddressPair) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *WhitelistedAddressPair) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *WhitelistedAddressPair) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Receiver) > 0 { + i -= len(m.Receiver) + copy(dAtA[i:], m.Receiver) + i = encodeVarintRatelimit(dAtA, i, uint64(len(m.Receiver))) + i-- + dAtA[i] = 0x12 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintRatelimit(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *HourEpoch) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *HourEpoch) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *HourEpoch) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.EpochStartHeight != 0 { + i = encodeVarintRatelimit(dAtA, i, uint64(m.EpochStartHeight)) + i-- + dAtA[i] = 0x20 + } + n4, err4 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.EpochStartTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.EpochStartTime):]) + if err4 != nil { + return 0, err4 + } + i -= n4 + i = encodeVarintRatelimit(dAtA, i, uint64(n4)) + i-- + dAtA[i] = 0x1a + n5, err5 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.Duration, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.Duration):]) + if err5 != nil { + return 0, err5 + } + i -= n5 + i = encodeVarintRatelimit(dAtA, i, uint64(n5)) + i-- + dAtA[i] = 0x12 + if m.EpochNumber != 0 { + i = encodeVarintRatelimit(dAtA, i, uint64(m.EpochNumber)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintRatelimit(dAtA []byte, offset int, v uint64) int { + offset -= sovRatelimit(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Path) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovRatelimit(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovRatelimit(uint64(l)) + } + return n +} + +func (m *Quota) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.MaxPercentSend.Size() + n += 1 + l + sovRatelimit(uint64(l)) + l = m.MaxPercentRecv.Size() + n += 1 + l + sovRatelimit(uint64(l)) + if m.DurationHours != 0 { + n += 1 + sovRatelimit(uint64(m.DurationHours)) + } + return n +} + +func (m *Flow) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Inflow.Size() + n += 1 + l + sovRatelimit(uint64(l)) + l = m.Outflow.Size() + n += 1 + l + sovRatelimit(uint64(l)) + l = m.ChannelValue.Size() + n += 1 + l + sovRatelimit(uint64(l)) + return n +} + +func (m *RateLimit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Path != nil { + l = m.Path.Size() + n += 1 + l + sovRatelimit(uint64(l)) + } + if m.Quota != nil { + l = m.Quota.Size() + n += 1 + l + sovRatelimit(uint64(l)) + } + if m.Flow != nil { + l = m.Flow.Size() + n += 1 + l + sovRatelimit(uint64(l)) + } + return n +} + +func (m *WhitelistedAddressPair) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovRatelimit(uint64(l)) + } + l = len(m.Receiver) + if l > 0 { + n += 1 + l + sovRatelimit(uint64(l)) + } + return n +} + +func (m *HourEpoch) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.EpochNumber != 0 { + n += 1 + sovRatelimit(uint64(m.EpochNumber)) + } + l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.Duration) + n += 1 + l + sovRatelimit(uint64(l)) + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.EpochStartTime) + n += 1 + l + sovRatelimit(uint64(l)) + if m.EpochStartHeight != 0 { + n += 1 + sovRatelimit(uint64(m.EpochStartHeight)) + } + return n +} + +func sovRatelimit(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozRatelimit(x uint64) (n int) { + return sovRatelimit(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Path) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Path: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Path: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRatelimit + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRatelimit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRatelimit + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRatelimit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRatelimit(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRatelimit + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Quota) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Quota: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Quota: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxPercentSend", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRatelimit + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRatelimit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxPercentSend.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxPercentRecv", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRatelimit + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRatelimit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxPercentRecv.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DurationHours", wireType) + } + m.DurationHours = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DurationHours |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipRatelimit(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRatelimit + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Flow) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Flow: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Flow: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Inflow", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRatelimit + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRatelimit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Inflow.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Outflow", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRatelimit + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRatelimit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Outflow.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelValue", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRatelimit + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRatelimit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ChannelValue.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRatelimit(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRatelimit + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RateLimit) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RateLimit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RateLimit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Path", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRatelimit + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRatelimit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Path == nil { + m.Path = &Path{} + } + if err := m.Path.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Quota", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRatelimit + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRatelimit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Quota == nil { + m.Quota = &Quota{} + } + if err := m.Quota.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Flow", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRatelimit + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRatelimit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Flow == nil { + m.Flow = &Flow{} + } + if err := m.Flow.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRatelimit(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRatelimit + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *WhitelistedAddressPair) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: WhitelistedAddressPair: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: WhitelistedAddressPair: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRatelimit + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRatelimit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRatelimit + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRatelimit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Receiver = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRatelimit(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRatelimit + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *HourEpoch) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: HourEpoch: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HourEpoch: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EpochNumber", wireType) + } + m.EpochNumber = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EpochNumber |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Duration", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRatelimit + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRatelimit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.Duration, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EpochStartTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRatelimit + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRatelimit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.EpochStartTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EpochStartHeight", wireType) + } + m.EpochStartHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRatelimit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EpochStartHeight |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipRatelimit(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRatelimit + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipRatelimit(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRatelimit + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRatelimit + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRatelimit + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthRatelimit + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupRatelimit + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthRatelimit + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthRatelimit = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowRatelimit = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupRatelimit = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/rate-limiting/types/tx.pb.go b/modules/rate-limiting/types/tx.pb.go new file mode 100644 index 00000000..6f870c28 --- /dev/null +++ b/modules/rate-limiting/types/tx.pb.go @@ -0,0 +1,2231 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ratelimit/v1/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/cosmos-sdk/types/msgservice" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Gov tx to add a new rate limit +type MsgAddRateLimit struct { + // Authority defines the x/gov module account + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // Denom for the rate limit, as it appears on the rate limited chain + // When rate limiting a non-native token, this will be an ibc denom + Denom string `protobuf:"bytes,2,opt,name=denom,proto3" json:"denom,omitempty"` + // ChannelId for the rate limit, on the side of the rate limited chain + ChannelId string `protobuf:"bytes,3,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + // MaxPercentSend defines the threshold for outflows + // The threshold is defined as a percentage (e.g. 10 indicates 10%) + MaxPercentSend github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=max_percent_send,json=maxPercentSend,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"max_percent_send"` + // MaxPercentSend defines the threshold for inflows + // The threshold is defined as a percentage (e.g. 10 indicates 10%) + MaxPercentRecv github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,5,opt,name=max_percent_recv,json=maxPercentRecv,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"max_percent_recv"` + // DurationHours specifies the number of hours before the rate limit + // is reset (e.g. 24 indicates that the rate limit is reset each day) + DurationHours uint64 `protobuf:"varint,6,opt,name=duration_hours,json=durationHours,proto3" json:"duration_hours,omitempty"` +} + +func (m *MsgAddRateLimit) Reset() { *m = MsgAddRateLimit{} } +func (m *MsgAddRateLimit) String() string { return proto.CompactTextString(m) } +func (*MsgAddRateLimit) ProtoMessage() {} +func (*MsgAddRateLimit) Descriptor() ([]byte, []int) { + return fileDescriptor_415b1435b4efaad0, []int{0} +} +func (m *MsgAddRateLimit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAddRateLimit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAddRateLimit.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgAddRateLimit) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAddRateLimit.Merge(m, src) +} +func (m *MsgAddRateLimit) XXX_Size() int { + return m.Size() +} +func (m *MsgAddRateLimit) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAddRateLimit.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAddRateLimit proto.InternalMessageInfo + +func (m *MsgAddRateLimit) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgAddRateLimit) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func (m *MsgAddRateLimit) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + +func (m *MsgAddRateLimit) GetDurationHours() uint64 { + if m != nil { + return m.DurationHours + } + return 0 +} + +type MsgAddRateLimitResponse struct { +} + +func (m *MsgAddRateLimitResponse) Reset() { *m = MsgAddRateLimitResponse{} } +func (m *MsgAddRateLimitResponse) String() string { return proto.CompactTextString(m) } +func (*MsgAddRateLimitResponse) ProtoMessage() {} +func (*MsgAddRateLimitResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_415b1435b4efaad0, []int{1} +} +func (m *MsgAddRateLimitResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAddRateLimitResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAddRateLimitResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgAddRateLimitResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAddRateLimitResponse.Merge(m, src) +} +func (m *MsgAddRateLimitResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgAddRateLimitResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAddRateLimitResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAddRateLimitResponse proto.InternalMessageInfo + +// Gov tx to update an existing rate limit +type MsgUpdateRateLimit struct { + // Authority defines the x/gov module account + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // Denom for the rate limit, as it appears on the rate limited chain + // When rate limiting a non-native token, this will be an ibc denom + Denom string `protobuf:"bytes,2,opt,name=denom,proto3" json:"denom,omitempty"` + // ChannelId for the rate limit, on the side of the rate limited chain + ChannelId string `protobuf:"bytes,3,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + // MaxPercentSend defines the threshold for outflows + // The threshold is defined as a percentage (e.g. 10 indicates 10%) + MaxPercentSend github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=max_percent_send,json=maxPercentSend,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"max_percent_send"` + // MaxPercentSend defines the threshold for inflows + // The threshold is defined as a percentage (e.g. 10 indicates 10%) + MaxPercentRecv github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,5,opt,name=max_percent_recv,json=maxPercentRecv,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"max_percent_recv"` + // DurationHours specifies the number of hours before the rate limit + // is reset (e.g. 24 indicates that the rate limit is reset each day) + DurationHours uint64 `protobuf:"varint,6,opt,name=duration_hours,json=durationHours,proto3" json:"duration_hours,omitempty"` +} + +func (m *MsgUpdateRateLimit) Reset() { *m = MsgUpdateRateLimit{} } +func (m *MsgUpdateRateLimit) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateRateLimit) ProtoMessage() {} +func (*MsgUpdateRateLimit) Descriptor() ([]byte, []int) { + return fileDescriptor_415b1435b4efaad0, []int{2} +} +func (m *MsgUpdateRateLimit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateRateLimit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateRateLimit.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpdateRateLimit) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateRateLimit.Merge(m, src) +} +func (m *MsgUpdateRateLimit) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateRateLimit) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateRateLimit.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateRateLimit proto.InternalMessageInfo + +func (m *MsgUpdateRateLimit) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgUpdateRateLimit) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func (m *MsgUpdateRateLimit) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + +func (m *MsgUpdateRateLimit) GetDurationHours() uint64 { + if m != nil { + return m.DurationHours + } + return 0 +} + +type MsgUpdateRateLimitResponse struct { +} + +func (m *MsgUpdateRateLimitResponse) Reset() { *m = MsgUpdateRateLimitResponse{} } +func (m *MsgUpdateRateLimitResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateRateLimitResponse) ProtoMessage() {} +func (*MsgUpdateRateLimitResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_415b1435b4efaad0, []int{3} +} +func (m *MsgUpdateRateLimitResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateRateLimitResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateRateLimitResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpdateRateLimitResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateRateLimitResponse.Merge(m, src) +} +func (m *MsgUpdateRateLimitResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateRateLimitResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateRateLimitResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateRateLimitResponse proto.InternalMessageInfo + +// Gov tx to remove a rate limit +type MsgRemoveRateLimit struct { + // Authority defines the x/gov module account + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // Denom for the rate limit, as it appears on the rate limited chain + // When rate limiting a non-native token, this will be an ibc denom + Denom string `protobuf:"bytes,2,opt,name=denom,proto3" json:"denom,omitempty"` + // ChannelId for the rate limit, on the side of the rate limited chain + ChannelId string `protobuf:"bytes,3,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` +} + +func (m *MsgRemoveRateLimit) Reset() { *m = MsgRemoveRateLimit{} } +func (m *MsgRemoveRateLimit) String() string { return proto.CompactTextString(m) } +func (*MsgRemoveRateLimit) ProtoMessage() {} +func (*MsgRemoveRateLimit) Descriptor() ([]byte, []int) { + return fileDescriptor_415b1435b4efaad0, []int{4} +} +func (m *MsgRemoveRateLimit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRemoveRateLimit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRemoveRateLimit.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRemoveRateLimit) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRemoveRateLimit.Merge(m, src) +} +func (m *MsgRemoveRateLimit) XXX_Size() int { + return m.Size() +} +func (m *MsgRemoveRateLimit) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRemoveRateLimit.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRemoveRateLimit proto.InternalMessageInfo + +func (m *MsgRemoveRateLimit) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgRemoveRateLimit) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func (m *MsgRemoveRateLimit) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + +type MsgRemoveRateLimitResponse struct { +} + +func (m *MsgRemoveRateLimitResponse) Reset() { *m = MsgRemoveRateLimitResponse{} } +func (m *MsgRemoveRateLimitResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRemoveRateLimitResponse) ProtoMessage() {} +func (*MsgRemoveRateLimitResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_415b1435b4efaad0, []int{5} +} +func (m *MsgRemoveRateLimitResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRemoveRateLimitResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRemoveRateLimitResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRemoveRateLimitResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRemoveRateLimitResponse.Merge(m, src) +} +func (m *MsgRemoveRateLimitResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgRemoveRateLimitResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRemoveRateLimitResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRemoveRateLimitResponse proto.InternalMessageInfo + +// Gov tx to reset the flow on a rate limit +type MsgResetRateLimit struct { + // Authority defines the x/gov module account + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // Denom for the rate limit, as it appears on the rate limited chain + // When rate limiting a non-native token, this will be an ibc denom + Denom string `protobuf:"bytes,2,opt,name=denom,proto3" json:"denom,omitempty"` + // ChannelId for the rate limit, on the side of the rate limited chain + ChannelId string `protobuf:"bytes,3,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` +} + +func (m *MsgResetRateLimit) Reset() { *m = MsgResetRateLimit{} } +func (m *MsgResetRateLimit) String() string { return proto.CompactTextString(m) } +func (*MsgResetRateLimit) ProtoMessage() {} +func (*MsgResetRateLimit) Descriptor() ([]byte, []int) { + return fileDescriptor_415b1435b4efaad0, []int{6} +} +func (m *MsgResetRateLimit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgResetRateLimit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgResetRateLimit.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgResetRateLimit) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgResetRateLimit.Merge(m, src) +} +func (m *MsgResetRateLimit) XXX_Size() int { + return m.Size() +} +func (m *MsgResetRateLimit) XXX_DiscardUnknown() { + xxx_messageInfo_MsgResetRateLimit.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgResetRateLimit proto.InternalMessageInfo + +func (m *MsgResetRateLimit) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgResetRateLimit) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func (m *MsgResetRateLimit) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + +type MsgResetRateLimitResponse struct { +} + +func (m *MsgResetRateLimitResponse) Reset() { *m = MsgResetRateLimitResponse{} } +func (m *MsgResetRateLimitResponse) String() string { return proto.CompactTextString(m) } +func (*MsgResetRateLimitResponse) ProtoMessage() {} +func (*MsgResetRateLimitResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_415b1435b4efaad0, []int{7} +} +func (m *MsgResetRateLimitResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgResetRateLimitResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgResetRateLimitResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgResetRateLimitResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgResetRateLimitResponse.Merge(m, src) +} +func (m *MsgResetRateLimitResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgResetRateLimitResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgResetRateLimitResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgResetRateLimitResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgAddRateLimit)(nil), "ratelimit.v1.MsgAddRateLimit") + proto.RegisterType((*MsgAddRateLimitResponse)(nil), "ratelimit.v1.MsgAddRateLimitResponse") + proto.RegisterType((*MsgUpdateRateLimit)(nil), "ratelimit.v1.MsgUpdateRateLimit") + proto.RegisterType((*MsgUpdateRateLimitResponse)(nil), "ratelimit.v1.MsgUpdateRateLimitResponse") + proto.RegisterType((*MsgRemoveRateLimit)(nil), "ratelimit.v1.MsgRemoveRateLimit") + proto.RegisterType((*MsgRemoveRateLimitResponse)(nil), "ratelimit.v1.MsgRemoveRateLimitResponse") + proto.RegisterType((*MsgResetRateLimit)(nil), "ratelimit.v1.MsgResetRateLimit") + proto.RegisterType((*MsgResetRateLimitResponse)(nil), "ratelimit.v1.MsgResetRateLimitResponse") +} + +func init() { proto.RegisterFile("ratelimit/v1/tx.proto", fileDescriptor_415b1435b4efaad0) } + +var fileDescriptor_415b1435b4efaad0 = []byte{ + // 579 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x55, 0x4f, 0x6b, 0x13, 0x41, + 0x1c, 0xcd, 0x36, 0x6d, 0xa1, 0x43, 0x4d, 0xed, 0x12, 0xe9, 0x66, 0xdb, 0x6e, 0x42, 0xa0, 0x1a, + 0x8a, 0xd9, 0xa5, 0x0a, 0x8a, 0xde, 0xda, 0x93, 0x05, 0x03, 0xb2, 0x51, 0x90, 0x82, 0x84, 0xcd, + 0xce, 0xb0, 0x19, 0xcc, 0xcc, 0x2c, 0x3b, 0xb3, 0x4b, 0x7a, 0xf5, 0x22, 0x08, 0x82, 0x1f, 0x25, + 0x88, 0x1f, 0xa2, 0xc7, 0xe2, 0x49, 0x3c, 0x14, 0x49, 0x0e, 0xfd, 0x04, 0xde, 0x65, 0xff, 0xe4, + 0x4f, 0x67, 0xab, 0x39, 0x28, 0xf4, 0xe2, 0x25, 0xc9, 0xbc, 0xdf, 0x9b, 0xf7, 0xdb, 0x37, 0x2f, + 0xbf, 0x59, 0x70, 0x27, 0x70, 0x04, 0xea, 0x63, 0x82, 0x85, 0x15, 0x1d, 0x58, 0x62, 0x60, 0xfa, + 0x01, 0x13, 0x4c, 0x5d, 0x9f, 0xc2, 0x66, 0x74, 0xa0, 0x97, 0x3d, 0xe6, 0xb1, 0xa4, 0x60, 0xc5, + 0xbf, 0x52, 0x8e, 0xbe, 0xe9, 0x10, 0x4c, 0x99, 0x95, 0x7c, 0x66, 0x50, 0xc5, 0x65, 0x9c, 0x30, + 0xde, 0x49, 0xb9, 0xe9, 0x22, 0x2b, 0x6d, 0xa5, 0x2b, 0x8b, 0x70, 0x2f, 0xee, 0x44, 0xb8, 0x97, + 0x16, 0xea, 0xef, 0x8b, 0x60, 0xa3, 0xc5, 0xbd, 0x43, 0x08, 0x6d, 0x47, 0xa0, 0xe7, 0x71, 0x4f, + 0xf5, 0x11, 0x58, 0x73, 0x42, 0xd1, 0x63, 0x01, 0x16, 0xa7, 0x9a, 0x52, 0x53, 0x1a, 0x6b, 0x47, + 0xda, 0xd7, 0x2f, 0xcd, 0x72, 0xa6, 0x78, 0x08, 0x61, 0x80, 0x38, 0x6f, 0x8b, 0x00, 0x53, 0xcf, + 0x9e, 0x51, 0xd5, 0x32, 0x58, 0x81, 0x88, 0x32, 0xa2, 0x2d, 0xc5, 0x7b, 0xec, 0x74, 0xa1, 0xee, + 0x02, 0xe0, 0xf6, 0x1c, 0x4a, 0x51, 0xbf, 0x83, 0xa1, 0x56, 0x4c, 0x4a, 0x6b, 0x19, 0x72, 0x0c, + 0xd5, 0xd7, 0xe0, 0x36, 0x71, 0x06, 0x1d, 0x1f, 0x05, 0x2e, 0xa2, 0xa2, 0xc3, 0x11, 0x85, 0xda, + 0x72, 0xd2, 0xd3, 0x3c, 0xbb, 0xa8, 0x16, 0xbe, 0x5f, 0x54, 0xef, 0x7a, 0x58, 0xf4, 0xc2, 0xae, + 0xe9, 0x32, 0x92, 0x99, 0xca, 0xbe, 0x9a, 0x1c, 0xbe, 0xb5, 0xc4, 0xa9, 0x8f, 0xb8, 0x79, 0x4c, + 0x85, 0x5d, 0x22, 0xce, 0xe0, 0x45, 0x2a, 0xd3, 0x46, 0x34, 0xa7, 0x1c, 0x20, 0x37, 0xd2, 0x56, + 0xfe, 0x56, 0xd9, 0x46, 0x6e, 0xa4, 0xee, 0x81, 0x12, 0x0c, 0x03, 0x47, 0x60, 0x46, 0x3b, 0x3d, + 0x16, 0x06, 0x5c, 0x5b, 0xad, 0x29, 0x8d, 0x65, 0xfb, 0xd6, 0x04, 0x7d, 0x16, 0x83, 0x4f, 0xef, + 0xbf, 0xbb, 0x1c, 0xee, 0xcf, 0xce, 0xe7, 0xc3, 0xe5, 0x70, 0xbf, 0x32, 0x0b, 0x5c, 0x3a, 0xf5, + 0x7a, 0x05, 0x6c, 0x49, 0x90, 0x8d, 0xb8, 0xcf, 0x28, 0x47, 0xf5, 0x8f, 0x45, 0xa0, 0xb6, 0xb8, + 0xf7, 0xca, 0x87, 0x8e, 0x40, 0xff, 0x73, 0xfa, 0xd7, 0x39, 0x59, 0xf9, 0x9c, 0x76, 0xae, 0xe4, + 0x24, 0x1d, 0x7c, 0x7d, 0x07, 0xe8, 0x79, 0x74, 0x9a, 0xd6, 0x67, 0x25, 0x49, 0xcb, 0x46, 0x84, + 0x45, 0x37, 0x94, 0xd6, 0x62, 0x4b, 0xd2, 0xd3, 0x65, 0x96, 0x24, 0x74, 0x6a, 0x69, 0xa8, 0x80, + 0xcd, 0xa4, 0xcc, 0x91, 0xb8, 0x21, 0x47, 0x66, 0xde, 0xd1, 0xb6, 0xe4, 0x68, 0xfe, 0xe1, 0xea, + 0xdb, 0xa0, 0x92, 0x03, 0x27, 0x7e, 0x1e, 0xfc, 0x5c, 0x02, 0xc5, 0x16, 0xf7, 0xd4, 0x97, 0x60, + 0xfd, 0xca, 0xcd, 0xb7, 0x6b, 0xce, 0xdf, 0xbc, 0xa6, 0x34, 0x8f, 0xfa, 0xde, 0x1f, 0xcb, 0x13, + 0x75, 0xf5, 0x0d, 0xd8, 0x90, 0x47, 0xb5, 0x96, 0xdb, 0x29, 0x31, 0xf4, 0xc6, 0x22, 0xc6, 0xbc, + 0xbc, 0xfc, 0xdf, 0xca, 0xcb, 0x4b, 0x8c, 0x6b, 0xe4, 0x7f, 0x93, 0xb5, 0x7a, 0x02, 0x4a, 0x52, + 0xce, 0xd5, 0x6b, 0xf6, 0xce, 0x13, 0xf4, 0x7b, 0x0b, 0x08, 0x13, 0xed, 0xa3, 0xf6, 0xd9, 0xc8, + 0x50, 0xce, 0x47, 0x86, 0xf2, 0x63, 0x64, 0x28, 0x9f, 0xc6, 0x46, 0xe1, 0x7c, 0x6c, 0x14, 0xbe, + 0x8d, 0x8d, 0xc2, 0xc9, 0x93, 0xfc, 0x88, 0xe3, 0xae, 0xdb, 0x74, 0x7c, 0x9f, 0x5b, 0x84, 0xc1, + 0xb0, 0x8f, 0xb8, 0x15, 0x37, 0x69, 0x26, 0x5d, 0x30, 0xf5, 0xac, 0xe8, 0x71, 0x3a, 0xf9, 0xdd, + 0xd5, 0xe4, 0x4d, 0xf6, 0xf0, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa8, 0xbb, 0x0d, 0xc4, 0x4d, + 0x07, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + // Gov tx to add a new rate limit + AddRateLimit(ctx context.Context, in *MsgAddRateLimit, opts ...grpc.CallOption) (*MsgAddRateLimitResponse, error) + // Gov tx to update an existing rate limit + UpdateRateLimit(ctx context.Context, in *MsgUpdateRateLimit, opts ...grpc.CallOption) (*MsgUpdateRateLimitResponse, error) + // Gov tx to remove a rate limit + RemoveRateLimit(ctx context.Context, in *MsgRemoveRateLimit, opts ...grpc.CallOption) (*MsgRemoveRateLimitResponse, error) + // Gov tx to reset the flow on a rate limit + ResetRateLimit(ctx context.Context, in *MsgResetRateLimit, opts ...grpc.CallOption) (*MsgResetRateLimitResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) AddRateLimit(ctx context.Context, in *MsgAddRateLimit, opts ...grpc.CallOption) (*MsgAddRateLimitResponse, error) { + out := new(MsgAddRateLimitResponse) + err := c.cc.Invoke(ctx, "/ratelimit.v1.Msg/AddRateLimit", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) UpdateRateLimit(ctx context.Context, in *MsgUpdateRateLimit, opts ...grpc.CallOption) (*MsgUpdateRateLimitResponse, error) { + out := new(MsgUpdateRateLimitResponse) + err := c.cc.Invoke(ctx, "/ratelimit.v1.Msg/UpdateRateLimit", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) RemoveRateLimit(ctx context.Context, in *MsgRemoveRateLimit, opts ...grpc.CallOption) (*MsgRemoveRateLimitResponse, error) { + out := new(MsgRemoveRateLimitResponse) + err := c.cc.Invoke(ctx, "/ratelimit.v1.Msg/RemoveRateLimit", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) ResetRateLimit(ctx context.Context, in *MsgResetRateLimit, opts ...grpc.CallOption) (*MsgResetRateLimitResponse, error) { + out := new(MsgResetRateLimitResponse) + err := c.cc.Invoke(ctx, "/ratelimit.v1.Msg/ResetRateLimit", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // Gov tx to add a new rate limit + AddRateLimit(context.Context, *MsgAddRateLimit) (*MsgAddRateLimitResponse, error) + // Gov tx to update an existing rate limit + UpdateRateLimit(context.Context, *MsgUpdateRateLimit) (*MsgUpdateRateLimitResponse, error) + // Gov tx to remove a rate limit + RemoveRateLimit(context.Context, *MsgRemoveRateLimit) (*MsgRemoveRateLimitResponse, error) + // Gov tx to reset the flow on a rate limit + ResetRateLimit(context.Context, *MsgResetRateLimit) (*MsgResetRateLimitResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) AddRateLimit(ctx context.Context, req *MsgAddRateLimit) (*MsgAddRateLimitResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddRateLimit not implemented") +} +func (*UnimplementedMsgServer) UpdateRateLimit(ctx context.Context, req *MsgUpdateRateLimit) (*MsgUpdateRateLimitResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateRateLimit not implemented") +} +func (*UnimplementedMsgServer) RemoveRateLimit(ctx context.Context, req *MsgRemoveRateLimit) (*MsgRemoveRateLimitResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RemoveRateLimit not implemented") +} +func (*UnimplementedMsgServer) ResetRateLimit(ctx context.Context, req *MsgResetRateLimit) (*MsgResetRateLimitResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ResetRateLimit not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_AddRateLimit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgAddRateLimit) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).AddRateLimit(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ratelimit.v1.Msg/AddRateLimit", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).AddRateLimit(ctx, req.(*MsgAddRateLimit)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_UpdateRateLimit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateRateLimit) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateRateLimit(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ratelimit.v1.Msg/UpdateRateLimit", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateRateLimit(ctx, req.(*MsgUpdateRateLimit)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_RemoveRateLimit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRemoveRateLimit) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).RemoveRateLimit(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ratelimit.v1.Msg/RemoveRateLimit", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).RemoveRateLimit(ctx, req.(*MsgRemoveRateLimit)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_ResetRateLimit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgResetRateLimit) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ResetRateLimit(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ratelimit.v1.Msg/ResetRateLimit", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ResetRateLimit(ctx, req.(*MsgResetRateLimit)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "ratelimit.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AddRateLimit", + Handler: _Msg_AddRateLimit_Handler, + }, + { + MethodName: "UpdateRateLimit", + Handler: _Msg_UpdateRateLimit_Handler, + }, + { + MethodName: "RemoveRateLimit", + Handler: _Msg_RemoveRateLimit_Handler, + }, + { + MethodName: "ResetRateLimit", + Handler: _Msg_ResetRateLimit_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "ratelimit/v1/tx.proto", +} + +func (m *MsgAddRateLimit) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgAddRateLimit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgAddRateLimit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.DurationHours != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.DurationHours)) + i-- + dAtA[i] = 0x30 + } + { + size := m.MaxPercentRecv.Size() + i -= size + if _, err := m.MaxPercentRecv.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + { + size := m.MaxPercentSend.Size() + i -= size + if _, err := m.MaxPercentSend.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintTx(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0x1a + } + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintTx(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0x12 + } + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgAddRateLimitResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgAddRateLimitResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgAddRateLimitResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgUpdateRateLimit) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateRateLimit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateRateLimit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.DurationHours != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.DurationHours)) + i-- + dAtA[i] = 0x30 + } + { + size := m.MaxPercentRecv.Size() + i -= size + if _, err := m.MaxPercentRecv.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + { + size := m.MaxPercentSend.Size() + i -= size + if _, err := m.MaxPercentSend.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintTx(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0x1a + } + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintTx(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0x12 + } + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateRateLimitResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateRateLimitResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateRateLimitResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgRemoveRateLimit) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRemoveRateLimit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRemoveRateLimit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintTx(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0x1a + } + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintTx(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0x12 + } + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgRemoveRateLimitResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRemoveRateLimitResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRemoveRateLimitResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgResetRateLimit) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgResetRateLimit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgResetRateLimit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintTx(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0x1a + } + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintTx(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0x12 + } + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgResetRateLimitResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgResetRateLimitResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgResetRateLimitResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgAddRateLimit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.MaxPercentSend.Size() + n += 1 + l + sovTx(uint64(l)) + l = m.MaxPercentRecv.Size() + n += 1 + l + sovTx(uint64(l)) + if m.DurationHours != 0 { + n += 1 + sovTx(uint64(m.DurationHours)) + } + return n +} + +func (m *MsgAddRateLimitResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgUpdateRateLimit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.MaxPercentSend.Size() + n += 1 + l + sovTx(uint64(l)) + l = m.MaxPercentRecv.Size() + n += 1 + l + sovTx(uint64(l)) + if m.DurationHours != 0 { + n += 1 + sovTx(uint64(m.DurationHours)) + } + return n +} + +func (m *MsgUpdateRateLimitResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgRemoveRateLimit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgRemoveRateLimitResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgResetRateLimit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgResetRateLimitResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgAddRateLimit) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgAddRateLimit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAddRateLimit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxPercentSend", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxPercentSend.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxPercentRecv", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxPercentRecv.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DurationHours", wireType) + } + m.DurationHours = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DurationHours |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgAddRateLimitResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgAddRateLimitResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAddRateLimitResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateRateLimit) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateRateLimit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateRateLimit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxPercentSend", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxPercentSend.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxPercentRecv", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxPercentRecv.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DurationHours", wireType) + } + m.DurationHours = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DurationHours |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateRateLimitResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateRateLimitResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateRateLimitResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRemoveRateLimit) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRemoveRateLimit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRemoveRateLimit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRemoveRateLimitResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRemoveRateLimitResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRemoveRateLimitResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgResetRateLimit) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgResetRateLimit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgResetRateLimit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgResetRateLimitResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgResetRateLimitResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgResetRateLimitResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +)