diff --git a/.github/mergify.yml b/.github/mergify.yml index d5228ffd826..54110ab1c91 100644 --- a/.github/mergify.yml +++ b/.github/mergify.yml @@ -16,8 +16,8 @@ pull_request_rules: name: default method: squash commit_message_template: | - {{ title }} (#{{ number }}) - {{ body }} + {{ title }} (#{{ number }}) + {{ body }} - name: backport patches to v1.0.x capability branch conditions: - base=main diff --git a/.github/workflows/golangci-feature.yml b/.github/workflows/golangci-feature.yml new file mode 100644 index 00000000000..2237a2ea736 --- /dev/null +++ b/.github/workflows/golangci-feature.yml @@ -0,0 +1,31 @@ +# golangci-feature runs on pull requests from branches that do not target main. +# +# Working on feature branches (PRs where the PR base-ref != main) is a common +# workflow used, in order to make the merging of PRs easier certain lints are excluded +# when it makes sense. Currently, unused lints are excluded since many PRs will add +# unused code that will be used in a later PR. +name: golangci-lint feature branch +on: + pull_request: + # Ignore if the target is main. (Negation of golanci-lint.yml) + branches-ignore: + - main +permissions: + contents: read + # Optional: allow read access to pull request. Use with `only-new-issues` option. + # pull-requests: read + +jobs: + golangci: + name: lint + runs-on: ubuntu-latest + steps: + - uses: actions/setup-go@v4 + with: + go-version: '1.21' + - uses: actions/checkout@v4 + - name: golangci-lint + uses: golangci/golangci-lint-action@v3.7.0 + with: + version: v1.54.2 + args: --timeout 10m \ No newline at end of file diff --git a/.github/workflows/link-check-config.json b/.github/workflows/link-check-config.json deleted file mode 100644 index 8493d1c3355..00000000000 --- a/.github/workflows/link-check-config.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "ignorePatterns": [ - { - "pattern": "(localhost)" - } - ], - "replacementPatterns": [ - { - "pattern": "(^\\/(architecture|event)[^#]*)(#.*|$)", - "replacement": "$1.md$3" - }, - { - "pattern": "^(\\/|@site\\/)", - "replacement": "{{BASEURL}}/docs/" - } - ], - "retryOn429": true, - "retryCount": 3, - "fallbackRetryDelay": "10s" -} diff --git a/.github/workflows/link-check.yml b/.github/workflows/link-check.yml deleted file mode 100644 index 214e1a14541..00000000000 --- a/.github/workflows/link-check.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: Check Markdown links -on: - pull_request: - paths: - - "**.md" - - "!.github/**" -jobs: - markdown-link-check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: gaurav-nelson/github-action-markdown-link-check@v1 - with: - config-file: '.github/workflows/link-check-config.json' diff --git a/CHANGELOG.md b/CHANGELOG.md index 36c2dc374e3..71a0727f32d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,7 +34,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ # Changelog -## [Unreleased] +## [[Unreleased]] ### Dependencies @@ -43,11 +43,78 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### State Machine Breaking ### Improvements +* (core/ante) [\#6302](https://github.com/cosmos/ibc-go/pull/6302) Performance: Skip app callbacks during RecvPacket execution in checkTx within the redundant relay ante handler. +* (core/ante) [\#6280](https://github.com/cosmos/ibc-go/pull/6280) Performance: Skip redundant proof checking in RecvPacket execution in reCheckTx within the redundant relay ante handler. ### Features ### Bug Fixes +## [v8.3.0](https://github.com/cosmos/ibc-go/releases/tag/v8.3.0) - 2024-05-16 + +### Dependencies + +* [\#6300](https://github.com/cosmos/ibc-go/pull/6300) Bump Cosmos SDK to v0.50.6 and CometBFT to v0.38.7. + +### State Machine Breaking + +* (light-clients/07-tendermint) [\#6276](https://github.com/cosmos/ibc-go/pull/6276) Fix: No-op to avoid panicking on `UpdateState` for invalid misbehaviour submissions. + +### Improvements + +* (apps/27-interchain-accounts, apps/tranfer, apps/29-fee) [\#6253](https://github.com/cosmos/ibc-go/pull/6253) Allow channel handshake to succeed if fee middleware is wired up on one side, but not the other. +* (apps/27-interchain-accounts) [\#6251](https://github.com/cosmos/ibc-go/pull/6251) Use `UNORDERED` as the default ordering for new ICA channels. +* (apps/transfer) [\#6268](https://github.com/cosmos/ibc-go/pull/6268) Use memo strings instead of JSON keys in `AllowedPacketData` of transfer authorization. +* (core/ante) [\#6278](https://github.com/cosmos/ibc-go/pull/6278) Performance: Exclude pruning from tendermint client updates in ante handler executions. + +### Features + +* (core) [\#6055](https://github.com/cosmos/ibc-go/pull/6055) Introduce a new interface `ConsensusHost` used to validate an IBC `ClientState` and `ConsensusState` against the host chain's underlying consensus parameters. +* (core/02-client) [\#5821](https://github.com/cosmos/ibc-go/pull/5821) Add rpc `VerifyMembershipProof` (querier approach for conditional clients). +* (core/04-channel) [\#5788](https://github.com/cosmos/ibc-go/pull/5788) Add `NewErrorAcknowledgementWithCodespace` to allow codespaces in ack errors. +* (apps/27-interchain-accounts) [\#5785](https://github.com/cosmos/ibc-go/pull/5785) Introduce a new tx message that ICA host submodule can use to query the chain (only those marked with `module_query_safe`) and write the responses to the acknowledgement. + +### Bug Fixes + +* (apps/27-interchain-accounts) [\#6167](https://github.com/cosmos/ibc-go/pull/6167) Fixed an edge case bug where migrating params for a pre-existing ica module which implemented controller functionality only could panic when migrating params for newly added host, and align controller param migration with host. +* (app/29-fee) [\#6255](https://github.com/cosmos/ibc-go/pull/6255) Delete refunded fees from state if some fee(s) cannot be refunded on channel closure. + +## [v8.2.0](https://github.com/cosmos/ibc-go/releases/tag/v8.2.0) - 2024-04-05 + +### Dependencies + +* [\#5975](https://github.com/cosmos/ibc-go/pull/5975) Bump Cosmos SDK to v0.50.5. + +### Improvements + +* (proto) [\#5987](https://github.com/cosmos/ibc-go/pull/5987) Add wasm proto files. + +## [v8.1.0](https://github.com/cosmos/ibc-go/releases/tag/v8.1.0) - 2024-01-31 + +### Dependencies + +* [\#5663](https://github.com/cosmos/ibc-go/pull/5663) Bump Cosmos SDK to v0.50.3 and CometBFT to v0.38.2. + +### State Machine Breaking + +* (apps/27-interchain-accounts) [\#5442](https://github.com/cosmos/ibc-go/pull/5442) Increase the maximum allowed length for the memo field of `InterchainAccountPacketData`. + +### Improvements + +* (core/02-client) [\#5429](https://github.com/cosmos/ibc-go/pull/5429) Add wildcard `"*"` to allow all clients in `AllowedClients` param. +* (core) [\#5541](https://github.com/cosmos/ibc-go/pull/5541) Enable emission of events on erroneous IBC application callbacks by appending a prefix to all event type and attribute keys. + +### Features + +* (core/04-channel) [\#1613](https://github.com/cosmos/ibc-go/pull/1613) Channel upgradability. +* (apps/transfer) [\#5280](https://github.com/cosmos/ibc-go/pull/5280) Add list of allowed packet data keys to `Allocation` of `TransferAuthorization`. +* (apps/27-interchain-accounts) [\#5633](https://github.com/cosmos/ibc-go/pull/5633) Allow setting new and upgrading existing ICA (ordered) channels to use unordered ordering. + +### Bug Fixes + +* (apps/27-interchain-accounts) [\#5343](https://github.com/cosmos/ibc-go/pull/5343) Add check if controller is enabled in `sendTx` before sending packet to host. +* (apps/29-fee) [\#5441](https://github.com/cosmos/ibc-go/pull/5441) Allow setting the relayer address as payee. + ## [v8.0.0](https://github.com/cosmos/ibc-go/releases/tag/v8.0.0) - 2023-11-10 ### Dependencies diff --git a/README.md b/README.md index 0f6db93ec16..bb933781a34 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ This IBC implementation in Golang is built as a Cosmos SDK module. To understand ## Roadmap -For an overview of upcoming changes to ibc-go take a look at the [roadmap](./docs/docs/01-ibc/09-roadmap.md). +For an overview of upcoming changes to ibc-go take a look at the [roadmap](./docs/docs/01-ibc/10-roadmap.md). This roadmap is also available as a [project board](https://github.com/orgs/cosmos/projects/7/views/25). diff --git a/docs/.gitignore b/docs/.gitignore deleted file mode 100644 index b2d6de30624..00000000000 --- a/docs/.gitignore +++ /dev/null @@ -1,20 +0,0 @@ -# Dependencies -/node_modules - -# Production -/build - -# Generated files -.docusaurus -.cache-loader - -# Misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 00e11144e3e..00000000000 --- a/docs/README.md +++ /dev/null @@ -1,268 +0,0 @@ -# IBC-Go Documentation - -Welcome to the IBC-Go documentation! This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. - -## Table of Contents - -- [IBC-Go Documentation](#ibc-go-documentation) - - [Table of Contents](#table-of-contents) - - [Configuration](#configuration) - - [Local Development and Deployment](#local-development-and-deployment) - - [Installation](#installation) - - [Local Development](#local-development) - - [Build](#build) - - [Serve](#serve) - - [Updating the Documentation](#updating-the-documentation) - - [Best practices](#best-practices) - - [File and Directory Naming Conventions](#file-and-directory-naming-conventions) - - [Code Blocks](#code-blocks) - - [Links](#links) - - [Multi-Documentation Linking](#multi-documentation-linking) - - [Static Assets](#static-assets) - - [Raw Assets](#raw-assets) - - [Technical writing course](#technical-writing-course) - - [Versioning](#versioning) - - [Terminology](#terminology) - - [Overview](#overview) - - [Tagging a new version](#tagging-a-new-version) - - [Adding a new version](#adding-a-new-version) - - [Updating an existing version](#updating-an-existing-version) - - [Deleting a version](#deleting-a-version) - -## Configuration - -Docusaurus configuration file is located at `./docusaurus.config.js`. This file contains the configuration for the sidebar, navbar, footer, and other settings. Sidebars are created in `./sidebars.js`. - -## Local Development and Deployment - -### Installation - -```bash -npm install -``` - -### Local Development - -```bash -npm start -``` - -This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. However, in the local development environment, some plugins like `@docusaurus/plugin-client-redirects`, will not work at all. This is why the landing page is an error page in the local development environment, and why you have to click on the correct docs version to see the documentation. This is not the case in the production environment. To view the production environment, you must [build](#build) and [serve](#serve) the website locally. - -### Build - -```bash -npm run build -``` - -This command generates static content into the `build` directory and can be served using any static contents hosting service. - -### Serve - -```bash -npm run serve -``` - -This command starts a local production server and opens up a browser window. - -## Updating the Documentation - -The documentation website is autogenerated from the markdown files found in [docs](./docs) directory. Each directory in `./docs/` represents a category to be displayed in the sidebar. If you create a new directory, you must create a `_category_.json` file in that directory with the following contents: - -```json -{ - "label": "Sidebar Label", - "position": 1, // position of the category in the sidebar - "link": null -} -``` - -The `position` key above is used to order the categories in the sidebar. This position key pertains to the order of this category in the parent directory. - -If you create a new markdown file within a category (`.docs/` directory is itself a category), you must add the following frontmatter to the top of the markdown file: - -```yaml ---- -title: Title of the file # title of the file in the sidebar -sidebar_label: Sidebar Label # title of the file in the sidebar -sidebar_position: 1 # position of the file in the sidebar -slug: /migrations/v5-to-v6 # the url of the file ---- -``` - -The `link` key in `_category_.json` determines if the category has an introductory page that comes before any content pages. If `link` is `null`, then the category does not have an introductory page. If there is a markdown file you wish to link, you should do - -```json -{ - "label": "Sidebar Label", - "position": 1, // position of the category in the sidebar - "link": { "type": "doc", "id": "intro" } -} -``` - -The `id` key can be defined in the frontmatter of the markdown file. Or, you can use the id tag as an extension to the url of the current page. For example, the following frontmatter on a markdown file in the same directory as the `_category_.json` file shown above will link to the markdown file: - -```yaml ---- -title: Title -sidebar_label: Sidebar Label -sidebar_position: 0 # should be zero for intro pages -slug: /ibc/upgrades/intro ---- -``` - -## Best practices - -- Check the spelling and grammar, even if you have to copy and paste from an external source. -- Use simple sentences. Easy-to-read sentences mean the reader can quickly use the guidance you share. -- Try to express your thoughts in a concise and clean way. -- Either Leave a space or use a `-` between the acronyms ADR and ICS and the corresponding number (e.g. ADR 008 or ADR-008, and ICS 27 or ICS-27). -- Don't overuse `code` format when writing in plain English. -- Follow Google developer documentation [style guide](https://developers.google.com/style). -- Check the meaning of words in Microsoft's [A-Z word list and term collections](https://docs.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/term-collections/accessibility-terms) (use the search input!). -- We recommend using RFC keywords in user documentation (lowercase). The RFC keywords are: "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL. They are to be interpreted as described in [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119). -- Lint the markdown files for documentation with [markdownlint-cli](https://github.com/igorshubovych/markdownlint-cli). Run `make docs-lint` (you will need to have `markdownlint-cli` installed, so please follow the [installation instructions](https://github.com/igorshubovych/markdownlint-cli#installation)). - -### File and Directory Naming Conventions - -Inside `/docs/docs/`: - -- All files should be named in `kebab-case`. -- All files should have a two digit prefix, indicating the order in which they should be read and displayed in their respective categories. For example, `01-overview.md` should be read before `02-integration.md`. If this order changes, the prefix should be updated. Note that the ordering is enforced by the frontmatter and not the file name. -- **All files that end in `.template.md` will be ignored by the build process.** -- The prefix `00-` is reserved for root links of categories (if a category has a root link this should be defined in `_category_.json`). For example, see [`docs/01-ibc/05-upgrades/00-intro.md`](./docs/01-ibc/05-upgrades/00-intro.md) and [`docs/01-ibc/05-upgrades/_category_.json`](./docs/01-ibc/05-upgrades/_category_.json). -- All category directories should be named in `kebab-case`. -- All category directories must have a `_category_.json` file. -- All category directories should have a two digit prefix (except for the root `./docs` category), indicating the order in which they should be read and displayed in their respective categories. For example, contents of `./docs/01-ibc/03-apps/` should be read before `./docs/01-ibc/07-relayer.md`. If this order changes, the prefix should be updated. Note that the ordering is enforced by the frontmatter of the markdown files and `_category_.json` files, not the file name. -- The images for each documentation should be kept in the same directory as the markdown file that uses them. This will likely require creating a new directory for each new category. The goal of this is to make versioning easier, discourage repeated use of the image, and make it easier to find images. - -### Code Blocks - -Code blocks in docusaurus are super-powered, read more about them [here](https://docusaurus.io/docs/markdown-features/code-blocks). Three most important features for us are: - -1. We can add a `title` to the code block, which will be displayed above the code block. (This should be used to display the file path of the code block.) -2. We can add a `reference` tag to the code block, which will reference github to create the code block. **You should always use hyperlinks in reference codeblocks.** Here is what a typical code block should look like: - -````ignore -```go reference title="modules/apps/transfer/keeper/keeper.go" -https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/apps/transfer/keeper/keeper.go#L19-L31 -``` -```` - -3. We can highlight lines in the code block by adding `// highlight-next-line` before the line we want to highlight. For example, we should use this to highlight diffs. Here is an example: - -````ignore -```go -import ( - ... - // highlight-next-line -+ ibctm "github.com/cosmos/ibc-go/v6/modules/light-clients/07-tendermint" - ... -) -``` -```` - -### Links - -In docusaurus, there are three ways to link to other pages: - -1. File Paths (relative or absolute) -2. URLs (relative or absolute) -3. Hyperlinks - -In this section, we will discuss when to use each. - -#### Multi-Documentation Linking - -Technically, there are four docs being maintained in this repo: - -1. Found in `docs/docs/` (this is the one displayed on the website in the "Documentation" tab) -2. Found in `docs/architecture/` (this is the one displayed on the website in the "Architecture Decision Records" tab) -3. Found in `docs/events/` (depreciated, this is not displayed on the website, but is hosted under `/events/` url) -4. Found in `docs/params/` (depreciated, this is not displayed on the website, but is hosted under `/params/` url) - -When referencing a markdown file, you should use relative file paths if they are in the same docs directory from above. For example, if you are in `docs/docs/01-ibc` and want to link to `docs/docs/02-apps/01-transfer/01-overview.md`, you should use the relative link `../02-apps/01-transfer/01-overview.md`. - -If the file you are referencing is in a different docs directory, you should use a absolute URL. For example, if you are in `docs/docs/01-ibc` and want to link to `docs/architecture/adr-001-coin-source-tracing.md`, you should use the absolute URL (not absolute file path), in this case `/architecture/adr-001-coin-source-tracing`. You can find the absolute URL by looking at the slug in the frontmatter of the markdown file you want to link to. If the frontmatter slug is not set (such as in `docs/architecture/adr-001-coin-source-tracing.md`), you should use the url that docusaurus generates for it. You can find this by looking at the url of the page in the browser. - -Note that when referencing any file outside of the parent `docs/` directory, you should always use a hyperlink. - -#### Static Assets - -Static assets are the non-code files that are directly copied to the build output. They include **images**, stylesheets, favicons, fonts, etc. - -By default, you are suggested to put these assets in the `static/` directory. Every file you put into that directory will be copied into the root of the generated build folder with the directory hierarchy preserved. E.g. if you add a file named `sun.jpg` to the static folder, it will be copied to `build/sun.jpg`. - -These assets should be referenced using absolute URLs. For example, if you have an image in `static/img/cosmos-logo-bw.png`, you should reference it using `/img/cosmos-logo-bw.png`. - -#### Raw Assets - -If you want to link a raw file, you should link to it using `@site` + its base path. For example, if you want to link to the raw markdown file `/architecture/adr.template.md`, you should use the absolute URL `@site/architecture/adr.template.md`. - -### Technical writing course - -Google provides a free [course](https://developers.google.com/tech-writing/overview) for technical writing. - -## Versioning - -Versioning only applies to documentation and not the ADRs found in the `./architecture/` directory. - -### Terminology - -- Current version: The version placed in the `.docs/` folder. This version is the one that is displayed on the website by default, referred to as next. -- Latest version: This version is defined in `./docusaurus.config.js` file under the `lastVersion` key. - -### Overview - -A typical versioned doc site looks like below: - -```ignore -docs/ -├── sidebars.json # sidebar for the current docs version -├── docs/ # docs directory for the current docs version -│ ├── 01-foo/ -│ │ └── 01-bar.md # https://mysite.com/docs/next/01-foo/01-bar -│ └── 00-intro.md # https://mysite.com/docs/next/00-intro -├── versions.json # file to indicate what versions are available -├── versioned_docs/ -│ ├── version-v1.1.0/ -│ │ ├── 01-foo/ -│ │ │ └── 01-bar.md # https://mysite.com/docs/01-foo/01-bar -│ │ └── 00-intro.md -│ └── version-v1.0.0/ -│ ├── 01-foo/ -│ │ └── 01-bar.md # https://mysite.com/docs/v1.0.0/01-foo/01-bar -│ └── 00-intro.md -├── versioned_sidebars/ -│ ├── version-v1.1.0-sidebars.json -│ └── version-v1.0.0-sidebars.json -├── docusaurus.config.js -└── package.json -``` - -The `./versions.json` file is a list of version names, ordered from newest to oldest. - -### Tagging a new version - -It is possible to tag the current version of the docs as a new version. This will create the appropriate files in `./versioned_docs/` and `./versioned_sidebars/` directories, and modify the `./versions.json` file. To do this, run the following command: - -```bash -npm run docusaurus docs:version v7.1.0 -``` - -### Adding a new version - -To add a new version: - -1. Create a new directory in `./versioned_docs/` called `version-vX.Y.Z` where `X.Y.Z` is the version number. This directory should contain the markdown files for the new version. -2. Create a new file in `./versioned_sidebars/` called `version-vX.Y.Z-sidebars.json`. This file should contain the sidebar for the new version. -3. Add the version to the `./versions.json` file. The list should be ordered from newest to oldest. -4. If needed, make any configuration changes in `./docusaurus.config.js`. For example, updating the `lastVersion` key in `./docusaurus.config.js` to the latest version. - -### Updating an existing version - -You can update multiple docs versions at the same time because each directory in `./versioned_docs/` represents specific routes when published. Make changes by editing the markdown files in the appropriate version directory. - -### Deleting a version - -When a version is no longer supported, you can delete it by removing it from `versions.json` and deleting the corresponding files in `./versioned_docs/` and `./versioned_sidebars/`. diff --git a/docs/architecture/README.md b/docs/architecture/README.md deleted file mode 100644 index cae7778356f..00000000000 --- a/docs/architecture/README.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -sidebar_position: 1 ---- - -# Architecture Decision Records (ADR) - -This is a location to record all high-level architecture decisions in the ibc-go project. - -You can read more about the ADR concept in this [blog post](https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0#.78xhdix6t). - -An ADR should provide: - -- Context on the relevant goals and the current state -- Proposed changes to achieve the goals -- Summary of pros and cons -- References -- Changelog - -Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and -justification for a change in architecture, or for the architecture of something -new. The spec is much more compressed and streamlined summary of everything as -it is or should be. - -If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match. - -Note the context/background should be written in the present tense. - -To suggest an ADR, please make use of the [ADR template](@site/architecture/adr.template.md) provided. - -## Table of Contents - -| ADR \# | Description | Status | -| ------ | ----------- | ------ | -| [001](./adr-001-coin-source-tracing.md) | ICS-20 coin denomination format | Accepted, Implemented | -| [002](./adr-002-go-module-versioning.md) | Go module versioning | Accepted | -| [003](./adr-003-ics27-acknowledgement.md) | ICS27 acknowledgement format | Accepted | -| [004](./adr-004-ics29-lock-fee-module.md) | ICS29 module locking upon escrow out of balance | Accepted | -| [005](./adr-005-consensus-height-events.md) | `UpdateClient` events - `ClientState` consensus heights | Accepted | -| [006](./adr-006-02-client-refactor.md) | ICS02 client refactor | Accepted | -| [007](./adr-007-solomachine-signbytes.md) | ICS06 Solo machine sign bytes | -| [008](./adr-008-app-caller-cbs.md) | Callback to IBC ACtors | Accepted | -| [009](./adr-009-v6-ics27-msgserver.md) | ICS27 message server addition | Accepted | -| [010](./adr-010-light-clients-as-sdk-modules.md) | IBC light clients as SDK modules | Accepted | -| [011](./adr-011-transfer-total-escrow-state-entry.md) | ICS20 state entry for total amount of tokens in escrow | Accepted | -| [015](./adr-015-ibc-packet-receiver.md) | IBC Packet Routing | Accepted | -| [025](./adr-025-ibc-passive-channels.md) | IBC passive channels | Deprecated | -| [026](./adr-026-ibc-client-recovery-mechanisms.md) | IBC client recovery mechansisms | Accepted | -| [027](./adr-027-ibc-wasm.md) | Wasm based light clients | Accepted | diff --git a/docs/architecture/adr-001-coin-source-tracing.md b/docs/architecture/adr-001-coin-source-tracing.md deleted file mode 100644 index 7fb0999c290..00000000000 --- a/docs/architecture/adr-001-coin-source-tracing.md +++ /dev/null @@ -1,375 +0,0 @@ -# ADR 001: Coin Source Tracing - -## Changelog - -- 2020-07-09: Initial Draft -- 2020-08-11: Implementation changes - -## Status - -Accepted, Implemented - -## Context - -The specification for IBC cross-chain fungible token transfers -([ICS20](https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer)), needs to -be aware of the origin of any token denomination in order to relay a `Packet` which contains the sender -and recipient addressed in the -[`FungibleTokenPacketData`](https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures). - -The Packet relay sending works based in 2 cases (per -[specification](https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#packet-relay) and [Colin Axnér](https://github.com/colin-axner)'s description): - -1. Sender chain is acting as the source zone. The coins are transferred -to an escrow address (i.e locked) on the sender chain and then transferred -to the receiving chain through IBC TAO logic. It is expected that the -receiving chain will mint vouchers to the receiving address. - -2. Sender chain is acting as the sink zone. The coins (vouchers) are burned -on the sender chain and then transferred to the receiving chain though IBC -TAO logic. It is expected that the receiving chain, which had previously -sent the original denomination, will unescrow the fungible token and send -it to the receiving address. - -Another way of thinking of source and sink zones is through the token's -timeline. Each send to any chain other than the one it was previously -received from is a movement forwards in the token's timeline. This causes -trace to be added to the token's history and the destination port and -destination channel to be prefixed to the denomination. In these instances -the sender chain is acting as the source zone. When the token is sent back -to the chain it previously received from, the prefix is removed. This is -a backwards movement in the token's timeline and the sender chain -is acting as the sink zone. - -### Example - -Assume the following channel connections exist and that all channels use the port ID `transfer`: - -- chain `A` has channels with chain `B` and chain `C` with the IDs `channelToB` and `channelToC`, respectively -- chain `B` has channels with chain `A` and chain `C` with the IDs `channelToA` and `channelToC`, respectively -- chain `C` has channels with chain `A` and chain `B` with the IDs `channelToA` and `channelToB`, respectively - -These steps of transfer between chains occur in the following order: `A -> B -> C -> A -> C`. In particular: - -1. `A -> B`: sender chain is source zone. `A` sends packet with `denom` (escrowed on `A`), `B` receives `denom` and mints and sends voucher `transfer/channelToA/denom` to recipient. -2. `B -> C`: sender chain is source zone. `B` sends packet with `transfer/channelToA/denom` (escrowed on `B`), `C` receives `transfer/channelToA/denom` and mints and sends voucher `transfer/channelToB/transfer/channelToA/denom` to recipient. -3. `C -> A`: sender chain is source zone. `C` sends packet with `transfer/channelToB/transfer/channelToA/denom` (escrowed on `C`), `A` receives `transfer/channelToB/transfer/channelToA/denom` and mints and sends voucher `transfer/channelToC/transfer/channelToB/transfer/channelToA/denom` to recipient. -4. `A -> C`: sender chain is sink zone. `A` sends packet with `transfer/channelToC/transfer/channelToB/transfer/channelToA/denom` (burned on `A`), `C` receives `transfer/channelToC/transfer/channelToB/transfer/channelToA/denom`, and unescrows and sends `transfer/channelToB/transfer/channelToA/denom` to recipient. - -The token has a final denomination on chain `C` of `transfer/channelToB/transfer/channelToA/denom`, where `transfer/channelToB/transfer/channelToA` is the trace information. - -In this context, upon a receive of a cross-chain fungible token transfer, if the sender chain is the source of the token, the protocol prefixes the denomination with the port and channel identifiers in the following format: - -```typescript -prefix + denom = {destPortN}/{destChannelN}/.../{destPort0}/{destChannel0}/denom -``` - -Example: transferring `100 uatom` from port `HubPort` and channel `HubChannel` on the Hub to -Ethermint's port `EthermintPort` and channel `EthermintChannel` results in `100 -EthermintPort/EthermintChannel/uatom`, where `EthermintPort/EthermintChannel/uatom` is the new -denomination on the receiving chain. - -In the case those tokens are transferred back to the Hub (i.e the **source** chain), the prefix is -trimmed and the token denomination updated to the original one. - -### Problem - -The problem of adding additional information to the coin denomination is twofold: - -1. The ever increasing length if tokens are transferred to zones other than the source: - -If a token is transferred `n` times via IBC to a sink chain, the token denom will contain `n` pairs -of prefixes, as shown on the format example above. This poses a problem because, while port and -channel identifiers have a maximum length of 64 each, the SDK `Coin` type only accepts denoms up to -64 characters. Thus, a single cross-chain token, which again, is composed by the port and channels -identifiers plus the base denomination, can exceed the length validation for the SDK `Coins`. - -This can result in undesired behaviours such as tokens not being able to be transferred to multiple -sink chains if the denomination exceeds the length or unexpected `panics` due to denomination -validation failing on the receiving chain. - -2. The existence of special characters and uppercase letters on the denomination: - -In the SDK every time a `Coin` is initialized through the constructor function `NewCoin`, a validation -of a coin's denom is performed according to a -[Regex](https://github.com/cosmos/cosmos-sdk/blob/a940214a4923a3bf9a9161cd14bd3072299cd0c9/types/coin.go#L583), -where only lowercase alphanumeric characters are accepted. While this is desirable for native denominations -to keep a clean UX, it presents a challenge for IBC as ports and channels might be randomly -generated with special and uppercase characters as per the [ICS 024 - Host -Requirements](https://github.com/cosmos/ibc/tree/master/spec/core/ics-024-host-requirements#paths-identifiers-separators) -specification. - -## Decision - -The issues outlined above, are applicable only to SDK-based chains, and thus the proposed solution -are do not require specification changes that would result in modification to other implementations -of the ICS20 spec. - -Instead of adding the identifiers on the coin denomination directly, the proposed solution hashes -the denomination prefix in order to get a consistent length for all the cross-chain fungible tokens. - -This will be used for internal storage only, and when transferred via IBC to a different chain, the -denomination specified on the packed data will be the full prefix path of the identifiers needed to -trace the token back to the originating chain, as specified on ICS20. - -The new proposed format will be the following: - -```go -ibcDenom = "ibc/" + hash(trace path + "/" + base denom) -``` - -The hash function will be a SHA256 hash of the fields of the `DenomTrace`: - -```protobuf -// DenomTrace contains the base denomination for ICS20 fungible tokens and the source tracing -// information -message DenomTrace { - // chain of port/channel identifiers used for tracing the source of the fungible token - string path = 1; - // base denomination of the relayed fungible token - string base_denom = 2; -} -``` - -The `IBCDenom` function constructs the `Coin` denomination used when creating the ICS20 fungible token packet data: - -```go -// Hash returns the hex bytes of the SHA256 hash of the DenomTrace fields using the following formula: -// -// hash = sha256(tracePath + "/" + baseDenom) -func (dt DenomTrace) Hash() tmbytes.HexBytes { - return tmhash.Sum(dt.Path + "/" + dt.BaseDenom) -} - -// IBCDenom a coin denomination for an ICS20 fungible token in the format 'ibc/{hash(tracePath + baseDenom)}'. -// If the trace is empty, it will return the base denomination. -func (dt DenomTrace) IBCDenom() string { - if dt.Path != "" { - return fmt.Sprintf("ibc/%s", dt.Hash()) - } - return dt.BaseDenom -} -``` - -### `x/ibc-transfer` Changes - -In order to retrieve the trace information from an IBC denomination, a lookup table needs to be -added to the `ibc-transfer` module. These values need to also be persisted between upgrades, meaning -that a new `[]DenomTrace` `GenesisState` field state needs to be added to the module: - -```go -// GetDenomTrace retrieves the full identifiers trace and base denomination from the store. -func (k Keeper) GetDenomTrace(ctx Context, denomTraceHash []byte) (DenomTrace, bool) { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.KeyDenomTrace(traceHash)) - if bz == nil { - return &DenomTrace, false - } - - var denomTrace DenomTrace - k.cdc.MustUnmarshalBinaryBare(bz, &denomTrace) - return denomTrace, true -} - -// HasDenomTrace checks if a the key with the given trace hash exists on the store. -func (k Keeper) HasDenomTrace(ctx Context, denomTraceHash []byte) bool { - store := ctx.KVStore(k.storeKey) - return store.Has(types.KeyTrace(denomTraceHash)) -} - -// SetDenomTrace sets a new {trace hash -> trace} pair to the store. -func (k Keeper) SetDenomTrace(ctx Context, denomTrace DenomTrace) { - store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(&denomTrace) - store.Set(types.KeyTrace(denomTrace.Hash()), bz) -} -``` - -The `MsgTransfer` will validate that the `Coin` denomination from the `Token` field contains a valid -hash, if the trace info is provided, or that the base denominations matches: - -```go -func (msg MsgTransfer) ValidateBasic() error { - // ... - return ValidateIBCDenom(msg.Token.Denom) -} -``` - -```go -// ValidateIBCDenom validates that the given denomination is either: -// -// - A valid base denomination (eg: 'uatom') -// - A valid fungible token representation (i.e 'ibc/{hash}') per ADR 001 https://github.com/cosmos/ibc-go/blob/main/docs/architecture/adr-001-coin-source-tracing.md -func ValidateIBCDenom(denom string) error { - denomSplit := strings.SplitN(denom, "/", 2) - - switch { - case strings.TrimSpace(denom) == "", - len(denomSplit) == 1 && denomSplit[0] == "ibc", - len(denomSplit) == 2 && (denomSplit[0] != "ibc" || strings.TrimSpace(denomSplit[1]) == ""): - return sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "denomination should be prefixed with the format 'ibc/{hash(trace + \"/\" + %s)}'", denom) - - case denomSplit[0] == denom && strings.TrimSpace(denom) != "": - return sdk.ValidateDenom(denom) - } - - if _, err := ParseHexHash(denomSplit[1]); err != nil { - return Wrapf(err, "invalid denom trace hash %s", denomSplit[1]) - } - - return nil -} -``` - -The denomination trace info only needs to be updated when token is received: - -- Receiver is **source** chain: The receiver created the token and must have the trace lookup already stored (if necessary *ie* native token case wouldn't need a lookup). -- Receiver is **not source** chain: Store the received info. For example, during step 1, when chain `B` receives `transfer/channelToA/denom`. - -```go -// SendTransfer -// ... - - fullDenomPath := token.Denom - -// deconstruct the token denomination into the denomination trace info -// to determine if the sender is the source chain -if strings.HasPrefix(token.Denom, "ibc/") { - fullDenomPath, err = k.DenomPathFromHash(ctx, token.Denom) - if err != nil { - return err - } -} - -if types.SenderChainIsSource(sourcePort, sourceChannel, fullDenomPath) { -//... -``` - -```go -// DenomPathFromHash returns the full denomination path prefix from an ibc denom with a hash -// component. -func (k Keeper) DenomPathFromHash(ctx sdk.Context, denom string) (string, error) { - hexHash := denom[4:] - hash, err := ParseHexHash(hexHash) - if err != nil { - return "", Wrap(ErrInvalidDenomForTransfer, err.Error()) - } - - denomTrace, found := k.GetDenomTrace(ctx, hash) - if !found { - return "", Wrap(ErrTraceNotFound, hexHash) - } - - fullDenomPath := denomTrace.GetFullDenomPath() - return fullDenomPath, nil -} -``` - -```go -// OnRecvPacket -// ... - -// This is the prefix that would have been prefixed to the denomination -// on sender chain IF and only if the token originally came from the -// receiving chain. -// -// NOTE: We use SourcePort and SourceChannel here, because the counterparty -// chain would have prefixed with DestPort and DestChannel when originally -// receiving this coin as seen in the "sender chain is the source" condition. -if ReceiverChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), data.Denom) { - // sender chain is not the source, unescrow tokens - - // remove prefix added by sender chain - voucherPrefix := types.GetDenomPrefix(packet.GetSourcePort(), packet.GetSourceChannel()) - unprefixedDenom := data.Denom[len(voucherPrefix):] - token := sdk.NewCoin(unprefixedDenom, sdk.NewIntFromUint64(data.Amount)) - - // unescrow tokens - escrowAddress := types.GetEscrowAddress(packet.GetDestPort(), packet.GetDestChannel()) - return k.bankKeeper.SendCoins(ctx, escrowAddress, receiver, sdk.NewCoins(token)) -} - -// sender chain is the source, mint vouchers - -// since SendPacket did not prefix the denomination, we must prefix denomination here -sourcePrefix := types.GetDenomPrefix(packet.GetDestPort(), packet.GetDestChannel()) -// NOTE: sourcePrefix contains the trailing "/" -prefixedDenom := sourcePrefix + data.Denom - -// construct the denomination trace from the full raw denomination -denomTrace := types.ParseDenomTrace(prefixedDenom) - -// set the value to the lookup table if not stored already -traceHash := denomTrace.Hash() -if !k.HasDenomTrace(ctx, traceHash) { - k.SetDenomTrace(ctx, traceHash, denomTrace) -} - -voucherDenom := denomTrace.IBCDenom() -voucher := sdk.NewCoin(voucherDenom, sdk.NewIntFromUint64(data.Amount)) - -// mint new tokens if the source of the transfer is the same chain -if err := k.bankKeeper.MintCoins( - ctx, types.ModuleName, sdk.NewCoins(voucher), -); err != nil { - return err -} - -// send to receiver -return k.bankKeeper.SendCoinsFromModuleToAccount( - ctx, types.ModuleName, receiver, sdk.NewCoins(voucher), -) -``` - -```go -func NewDenomTraceFromRawDenom(denom string) DenomTrace{ - denomSplit := strings.Split(denom, "/") - trace := "" - if len(denomSplit) > 1 { - trace = strings.Join(denomSplit[:len(denomSplit)-1], "/") - } - return DenomTrace{ - BaseDenom: denomSplit[len(denomSplit)-1], - Trace: trace, - } -} -``` - -One final remark is that the `FungibleTokenPacketData` will remain the same, i.e with the prefixed full denomination, since the receiving chain may not be an SDK-based chain. - -### Coin Changes - -The coin denomination validation will need to be updated to reflect these changes. In particular, the denomination validation -function will now: - -- Accept slash separators (`"/"`) and uppercase characters (due to the `HexBytes` format) -- Bump the maximum character length to 128, as the hex representation used by Tendermint's - `HexBytes` type contains 64 characters. - -Additional validation logic, such as verifying the length of the hash, the may be added to the bank module in the future if the [custom base denomination validation](https://github.com/cosmos/cosmos-sdk/pull/6755) is integrated into the SDK. - -### Positive - -- Clearer separation of the source tracing behaviour of the token (transfer prefix) from the original - `Coin` denomination -- Consistent validation of `Coin` fields (i.e no special characters, fixed max length) -- Cleaner `Coin` and standard denominations for IBC -- No additional fields to SDK `Coin` - -### Negative - -- Store each set of tracing denomination identifiers on the `ibc-transfer` module store -- Clients will have to fetch the base denomination every time they receive a new relayed fungible token over IBC. This can be mitigated using a map/cache for already seen hashes on the client side. Other forms of mitigation, would be opening a websocket connection subscribe to incoming events. - -### Neutral - -- Slight difference with the ICS20 spec -- Additional validation logic for IBC coins on the `ibc-transfer` module -- Additional genesis fields -- Slightly increases the gas usage on cross-chain transfers due to access to the store. This should - be inter-block cached if transfers are frequent. - -## References - -- [ICS 20 - Fungible token transfer](https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer) -- [Custom Coin Denomination validation](https://github.com/cosmos/cosmos-sdk/pull/6755) diff --git a/docs/architecture/adr-002-go-module-versioning.md b/docs/architecture/adr-002-go-module-versioning.md deleted file mode 100644 index 62e4a47c835..00000000000 --- a/docs/architecture/adr-002-go-module-versioning.md +++ /dev/null @@ -1,112 +0,0 @@ -# ADR 002: Go module versioning - -## Changelog - -- 05/01/2022: initial draft - -## Status - -Accepted - -## Context - -The IBC module was originally developed in the Cosmos SDK and released during with the Stargate release series (v0.42). -It was subsequently migrated to its own repository, ibc-go. -The first official release on ibc-go was v1.0.0. -v1.0.0 was decided to be used instead of v0.1.0 primarily for the following reasons: - -- Maintaining compatibility with the IBC specification v1 requires stronger support/guarantees. -- Using the major, minor, and patch numbers allows for easier communication of what breaking changes are included in a release. -- The IBC module is being used by numerous high value projects which require stability. - -### Problems - -#### Go module version must be incremented - -When a Go module is released under v1.0.0, all following releases must follow Go semantic versioning. -Thus when the go API is broken, the Go module major version **must** be incremented. -For example, changing the go package version from `v2` to `v3` bumps the import from `github.com/cosmos/ibc-go/v2` to `github.com/cosmos/ibc-go/v3`. - -If the Go module version is not incremented then attempting to go get a module @v3.0.0 without the suffix results in: -`invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v3` - -Version validation was added in Go 1.13. This means is that in order to release a v3.0.0 git tag without a /v3 suffix on the module definition, the tag must explicitly **not** contain a go.mod file. -Not including a go.mod in our release is not a viable option. - -#### Attempting to import multiple go module versions for ibc-go - -Attempting to import two versions of ibc-go, such as `github.com/cosmos/ibc-go/v2` and `github.com/cosmos/ibc-go/v3`, will result in multiple issues. - -The Cosmos SDK does global registration of error and governance proposal types. -The errors and proposals used in ibc-go would need to now register their naming based on the go module version. - -The more concerning problem is that protobuf definitions will also reach a namespace collision. -ibc-go and the Cosmos SDK in general rely heavily on using extended functions for go structs generated from protobuf definitions. -This requires the go structs to be defined in the same package as the extended functions. -Thus, bumping the import versioning causes the protobuf definitions to be generated in two places (in v2 and v3). -When registering these types at compile time, the go compiler will panic. -The generated types need to be registered against the proto codec, but there exist two definitions for the same name. - -The protobuf conflict policy can be overriden via the environment variable `GOLANG_PROTOBUF_REGISTRATION_CONFLICT`, but it is possible this could lead to various runtime errors or unexpected behaviour (see [here](https://github.com/protocolbuffers/protobuf-go/blob/master/reflect/protoregistry/registry.go#L46)). -More information [here](https://developers.google.com/protocol-buffers/docs/reference/go/faq#namespace-conflict) on namespace conflicts for protobuf versioning. - -### Potential solutions - -#### Changing the protobuf definition version - -The protobuf definitions all have a type URL containing the protobuf version for this type. -Changing the protobuf version would solve the namespace collision which arise from importing multiple versions of ibc-go, but it leads to new issues. - -In the Cosmos SDK, `Any`s are unpacked and decoded using the type URL. -Changing the type URL thus is creating a distinctly different type. -The same registration on the proto codec cannot be used to unpack the new type. -For example: - -All Cosmos SDK messages are packed into `Any`s. If we incremented the protobuf version for our IBC messages, clients which submitted the v1 of our Cosmos SDK messages would now be rejected since the old type is not registered on the codec. -The clients must know to submit the v2 of these messages. This pushes the burden of versioning onto relayers and wallets. - -A more serious problem is that the `ClientState` and `ConsensusState` are packed as `Any`s. Changing the protobuf versioning of these types would break compatibility with IBC specification v1. - -#### Moving protobuf definitions to their own go module - -The protobuf definitions could be moved to their own go module which uses 0.x versioning and will never go to 1.0. -This prevents the Go module version from being incremented with breaking changes. -It also requires all extended functions to live in the same Go module, disrupting the existing code structure. - -The version that implements this change will still be incompatible with previous versions, but future versions could be imported together without namespace collisions. -For example, lets say this solution is implemented in v3. Then - -`github.com/cosmos/ibc-go/v2` cannot be imported with any other ibc-go version - -`github.com/cosmos/ibc-go/v3` cannot be imported with any previous ibc-go versions - -`github.com/cosmos/ibc-go/v4` may be imported with ibc-go versions v3+ - -`github.com/cosmos/ibc-go/v5` may be imported with ibc-go versions v3+ - -## Decision - -Supporting importing multiple versions of ibc-go requires a non-trivial amount of complexity. -It is unclear when a user of the ibc-go code would need multiple versions of ibc-go. -Until there is an overwhelming reason to support importing multiple versions of ibc-go: - -**Major releases cannot be imported simultaneously**. -Releases should focus on keeping backwards compatibility for go code clients, within reason. -Old functionality should be marked as deprecated and there should exist upgrade paths between major versions. -Deprecated functionality may be removed when no clients rely on that functionality. -How this is determined is to be decided. - -**Error and proposal type registration will not be changed between go module version increments**. -This explicitly stops external clients from trying to import two major versions (potentially risking a bug due to the instability of proto name collisions override). - -## Consequences - -This only affects clients relying directly on the go code. - -### Positive - -### Negative - -Multiple ibc-go versions cannot be imported. - -### Neutral diff --git a/docs/architecture/adr-003-ics27-acknowledgement.md b/docs/architecture/adr-003-ics27-acknowledgement.md deleted file mode 100644 index 635d5e8fc12..00000000000 --- a/docs/architecture/adr-003-ics27-acknowledgement.md +++ /dev/null @@ -1,120 +0,0 @@ -# ADR 003: ICS27 Acknowledgement Format - -## Changelog - -- January 28th, 2022: Initial Draft - -## Status - -Accepted - -## Context - -Upon receiving an IBC packet, an IBC application can optionally return an acknowledgement. -This acknowledgement will be hashed and written into state. Thus any changes to the information included in an acknowledgement are state machine breaking. - -ICS27 executes transactions on behalf of a controller chain. Information such as the message result or message error may be returned from other SDK modules outside the control of the ICS27 module. -It might be very valuable to return message execution information inside the ICS27 acknowledgement so that controller chain interchain account auth modules can act upon this information. -Only determinstic information returned from the message execution is allowed to be returned in the packet acknowledgement otherwise the network will halt due to a fork in the expected app hash. - -## Decision - -At the time of this writing, Tendermint includes the following information in the [ABCI.ResponseDeliverTx](https://github.com/tendermint/tendermint/blob/release/v0.34.13/types/results.go#L47-#L53): - -```go -// deterministicResponseDeliverTx strips non-deterministic fields from -// ResponseDeliverTx and returns another ResponseDeliverTx. -func deterministicResponseDeliverTx(response *abci.ResponseDeliverTx) *abci.ResponseDeliverTx { - return &abci.ResponseDeliverTx{ - Code: response.Code, - Data: response.Data, - GasWanted: response.GasWanted, - GasUsed: response.GasUsed, - } -} -``` - -### Successful acknowledgements - -Successful acknowledgements should return information about the transaction execution. -Given the determinstic fields in the `abci.ResponseDeliverTx`, the transaction `Data` can be used to indicate information about the transaction execution. -The `abci.ResponseDeliverTx.Data` will be set in the ICS27 packet acknowledgement upon successful transaction execution. - -The format for the `abci.ResponseDeliverTx.Data` is constructed by the SDK. - -At the time of this writing, the next major release of the SDK will change the format for constructing the transaction response data. - -#### v0.45 format - -The current version, v0.45 constructs the transaction response as follows: - -```go -proto.Marshal(&sdk.TxMsgData{ - Data: []*sdk.MsgData{msgResponses...}, -} -``` - -Where `msgResponses` is a slice of `*sdk.MsgData`. -The `MsgData.MsgType` contains the `sdk.MsgTypeURL` of the `sdk.Msg` being executed. -The `MsgData.Data` contains the proto marshaled `MsgResponse` for the associated message executed. - -#### Next major version format - -The next major version will construct the transaction response as follows: - -```go -proto.Marshal(&sdk.TxMsgData{ - MsgResponses: []*codectypes.Any{msgResponses...}, -} -``` - -Where `msgResponses` is a slice of the `MsgResponse`s packed into `Any`s. - -#### Forwards compatible approach - -A forwards compatible approach was deemed infeasible. -The `handler` provided by the `MsgServiceRouter` will only include the `*sdk.Result` and an error (if one occurred). -In v0.45 of the SDK, the `*sdk.Result.Data` will contain the MsgResponse marshaled data. -However, the MsgResponse is not packed and marshaled as a `*codectypes.Any`, thus making it impossible from a generalized point of view to unmarshal the bytes. -If the bytes could be unmarshaled, then they could be packed into an `*codectypes.Any` in anticipation of the upcoming format. - -Intercepting the MsgResponse before it becomes marshaled requires replicating this [code](https://github.com/cosmos/cosmos-sdk/blob/dfd47f5b449f558a855da284a9a7eabbfbad435d/baseapp/msg_service_router.go#L109-#L128). -It may not even be possible to replicate the linked code. The method handler would need to be accessed somehow. - -For these reasons it is deemed infeasible to attempt a fowards compatible approach. - -ICA auth developers can interpret which format was used when constructing the transaction response by checking if the `sdk.TxMsgData.Data` field is non-empty. -If the `sdk.TxMsgData.Data` field is not empty then the format for v0.45 was used, otherwise ICA auth developers can assume the transaction response uses the newer format. - -#### Decision - -Replicate the transaction response format as provided by the current SDK verison. -When the SDK version changes, adjust the transaction response format to use the updated transaction response format. -Include the transaction response bytes in the result channel acknowledgement. - -A test has been [written](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/ibc_module_test.go#L716-#L774) to fail if the `MsgResponse` is no longer included in consensus. - -### Error acknowledgements - -As indicated above, the `abci.ResponseDeliverTx.Code` is determinstic. -Upon transaction execution errors, an error acknowledgement should be returned including the abci code. - -A test has been [written](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/types/ack_test.go#L41-#L82) to fail if the ABCI code is no longer determinstic. - -## Consequences - -> This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones. - -### Positive - -- interchain account auth modules can act upon transaction results without requiring a query module -- transaction results align with those returned by execution of a normal SDK message. - -### Negative - -- the security assumptions of this decision rest on the inclusion of the ABCI error code and the Msg response in the ResponseDeliverTx hash created by Tendermint -- events are non-determinstic and cannot be included in the packet acknowledgement - -### Neutral - -No neutral consequences. diff --git a/docs/architecture/adr-004-ics29-lock-fee-module.md b/docs/architecture/adr-004-ics29-lock-fee-module.md deleted file mode 100644 index 5e6a0e927d8..00000000000 --- a/docs/architecture/adr-004-ics29-lock-fee-module.md +++ /dev/null @@ -1,58 +0,0 @@ -# ADR 004: Lock fee module upon escrow out of balance - -## Changelog - -- 03/03/2022: initial draft - -## Status - -Accepted - -## Context - -The fee module maintains an escrow account for all fees escrowed to incentivize packet relays. -It also tracks each packet fee escrowed separately from the escrow account. This is because the escrow account only maintains a total balance. It has no reference for which coins belonged to which packet fee. -In the presence of a severe bug, it is possible the escrow balance will become out of sync with the packet fees marked as escrowed. -The ICS29 module should be capable of elegantly handling such a scenario. - -## Decision - -We will allow for the ICS29 module to become "locked" if the escrow balance is determined to be out of sync with the packet fees marked as escrowed. -A "locked" fee module will not allow for packet escrows to occur nor will it distribute fees. All IBC callbacks will skip performing fee logic, similar to fee disabled channels. - -Manual intervention will be needed to unlock the fee module. - -### Sending side - -Special behaviour will have to be accounted for in `OnAcknowledgementPacket`. Since the counterparty will continue to send incentivized acknowledgements for fee enabled channels, the acknowledgement will still need to be unmarshalled into an incentivized acknowledgement before calling the underlying application `OnAcknowledgePacket` callback. - -When distributing fees, a cached context should be used. If the escrow account balance would become negative, the current state changes should be discarded and the fee module should be locked using the uncached context. This prevents fees from being partially distributed for a given packetID. - -### Receiving side - -`OnRecvPacket` should remain unaffected by the fee module becoming locked since escrow accounts only affect the sending side. - -## Consequences - -### Positive - -The fee module can be elegantly disabled in the presence of severe bugs. - -### Negative - -Extra logic is added to account for edge cases which are only possible in the presence of bugs. - -### Neutral - -## References - -Issues: - -- [#821](https://github.com/cosmos/ibc-go/issues/821) -- [#860](https://github.com/cosmos/ibc-go/issues/860) - -PR's: - -- [#1031](https://github.com/cosmos/ibc-go/pull/1031) -- [#1029](https://github.com/cosmos/ibc-go/pull/1029) -- [#1056](https://github.com/cosmos/ibc-go/pull/1056) diff --git a/docs/architecture/adr-005-consensus-height-events.md b/docs/architecture/adr-005-consensus-height-events.md deleted file mode 100644 index eb0527b4532..00000000000 --- a/docs/architecture/adr-005-consensus-height-events.md +++ /dev/null @@ -1,92 +0,0 @@ -# ADR 005: UpdateClient Events - ClientState Consensus Heights - -## Changelog - -- 25/04/2022: initial draft - -## Status - -Accepted - -## Context - -The `ibc-go` implementation leverages the [Cosmos-SDK's EventManager](https://github.com/cosmos/cosmos-sdk/blob/v0.45.4/docs/core/events.md#EventManager) to provide subscribers a method of reacting to application specific events. -Some IBC relayers depend on the [`consensus_height`](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/core/02-client/keeper/events.go#L33) attribute emitted as part of `UpdateClient` events in order to run `07-tendermint` misbehaviour detection by cross-checking the details of the *Header* emitted at a given consensus height against those of the *Header* from the originating chain. This includes such details as: - -- The `SignedHeader` containing the commitment root. -- The `ValidatorSet` that signed the *Header*. -- The `TrustedHeight` seen by the client at less than or equal to the height of *Header*. -- The last `TrustedValidatorSet` at the trusted height. - -Following the refactor of the `02-client` submodule and associated `ClientState` interfaces, it will now be possible for -light client implementations to perform such actions as batch updates, inserting `N` number of `ConsensusState`s into the application state tree with a single `UpdateClient` message. This flexibility is provided in `ibc-go` by the usage of the [Protobuf `Any`](https://developers.google.com/protocol-buffers/docs/proto3#any) field contained within the [`UpdateClient`](https://github.com/cosmos/ibc-go/blob/v3.0.0/proto/ibc/core/client/v1/tx.proto#L44) message. -For example, a batched client update message serialized as a Protobuf `Any` type for the `07-tendermint` lightclient implementation could be defined as follows: - -```protobuf -message BatchedHeaders { - repeated Header headers = 1; -} -``` - -To complement this flexibility, the `UpdateClient` handler will now support the submission of [client misbehaviour](https://github.com/cosmos/ibc/tree/master/spec/core/ics-002-client-semantics#misbehaviour) by consolidating the `Header` and `Misbehaviour` interfaces into a single `ClientMessage` interface type: - -```go -// ClientMessage is an interface used to update an IBC client. -// The update may be done by a single header, a batch of headers, misbehaviour, or any type which when verified produces -// a change to state of the IBC client -type ClientMessage interface { - proto.Message - - ClientType() string - ValidateBasic() error -} -``` - -To support this functionality the `GetHeight()` method has been omitted from the new `ClientMessage` interface. -Emission of standardised events from the `02-client` submodule now becomes problematic and is two-fold: - -1. The `02-client` submodule previously depended upon the `GetHeight()` method of `Header` types in order to [retrieve the updated consensus height](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/core/02-client/keeper/client.go#L90). -2. Emitting a single `consensus_height` event attribute is not sufficient in the case of a batched client update containing multiple *Headers*. - -## Decision - -The following decisions have been made in order to provide flexibility to consumers of `UpdateClient` events in a non-breaking fashion: - -1. Return a list of updated consensus heights `[]exported.Height` from the new `UpdateState` method of the `ClientState` interface. - -```go -// UpdateState updates and stores as necessary any associated information for an IBC client, such as the ClientState and corresponding ConsensusState. -// Upon successful update, a list of consensus heights is returned. It assumes the ClientMessage has already been verified. -UpdateState(sdk.Context, codec.BinaryCodec, sdk.KVStore, ClientMessage) []Height -``` - -2. Maintain the `consensus_height` event attribute emitted from the `02-client` update handler, but mark as deprecated for future removal. For example, with tendermint lightclients this will simply be `consensusHeights[0]` following a successful update using a single *Header*. - -3. Add an additional `consensus_heights` event attribute, containing a comma separated list of updated heights. This provides flexibility for emitting a single consensus height or multiple consensus heights in the example use-case of batched header updates. - -## Consequences - -### Positive - -- Subscribers of IBC core events can act upon `UpdateClient` events containing one or more consensus heights. -- Deprecation of the existing `consensus_height` attribute allows consumers to continue to process `UpdateClient` events as normal, with a path to upgrade to using the `consensus_heights` attribute moving forward. - -### Negative - -- Consumers of IBC core `UpdateClient` events are forced to make future code changes. - -### Neutral - -## References - -Discussions: - -- [#1208](https://github.com/cosmos/ibc-go/pull/1208#discussion_r839691927) - -Issues: - -- [#594](https://github.com/cosmos/ibc-go/issues/594) - -PRs: - -- [#1285](https://github.com/cosmos/ibc-go/pull/1285) diff --git a/docs/architecture/adr-006-02-client-refactor.md b/docs/architecture/adr-006-02-client-refactor.md deleted file mode 100644 index 33dd9977959..00000000000 --- a/docs/architecture/adr-006-02-client-refactor.md +++ /dev/null @@ -1,203 +0,0 @@ -# ADR 006: ICS-02 client refactor - -## Changelog - -- 2022-08-01: Initial Draft - -## Status - -Accepted and applied in v7 of ibc-go - -## Context - -During the initial development of the 02-client submodule, each light client supported (06-solomachine, 07-tendermint, 09-localhost) was referenced through hardcoding. -Here is an example of the [code](https://github.com/cosmos/cosmos-sdk/commit/b93300288e3a04faef9c0774b75c13b24450ba1c#diff-c5f6b956947375f28d611f18d0e670cf28f8f305300a89c5a9b239b0eeec5064R83) that existed in the 02-client submodule: - -```go -func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.Header) (exported.ClientState, error) { - ... - - switch clientType { - case exported.Tendermint: - clientState, consensusState, err = tendermint.CheckValidityAndUpdateState( - clientState, header, ctx.BlockTime(), - ) - case exported.Localhost: - // override client state and update the block height - clientState = localhosttypes.NewClientState( - ctx.ChainID(), // use the chain ID from context since the client is from the running chain (i.e self). - ctx.BlockHeight(), - ) - default: - err = types.ErrInvalidClientType - } -``` - -To add additional light clients, code would need to be added directly to the 02-client submodule. -Evidently, this would likely become problematic as IBC scaled to many chains using consensus mechanisms beyond the initial supported light clients. -Issue [#6064](https://github.com/cosmos/cosmos-sdk/issues/6064) on the SDK addressed this problem by creating a more modular 02-client submodule. -The 02-client submodule would now interact with each light client via an interface. -While, this change was positive in development, increasing the flexibility and adoptability of IBC, it also opened the door to new problems. - -The difficulty of generalizing light clients became apparent once changes to those light clients were required. -Each light client represents a different consensus algorithm which may contain a host of complexity and nuances. -Here are some examples of issues which arose for light clients that are not applicable to all the light clients supported (06-solomachine, 07-tendermint, 09-localhost): - -### Tendermint non-zero height upgrades - -Before the launch of IBC, it was determined that the golang implementation of [tendermint](https://github.com/tendermint/tendermint) would not be capable of supporting non-zero height upgrades. -This implies that any upgrade would require changing of the chain ID and resetting the height to 0. -A chain is uniquely identified by its chain-id and validator set. -Two different chain ID's can be viewed as different chains and thus a normal update produced by a validator set cannot change the chain ID. -To work around the lack of support for non-zero height upgrades, an abstract height type was created along with an upgrade mechanism. -This type would indicate the revision number (the number of times the chain ID has been changed) and revision height (the current height of the blockchain). - -Refs: - -- Issue [#439](https://github.com/cosmos/ibc/issues/439) on IBC specification repository. -- Specification changes in [#447](https://github.com/cosmos/ibc/pull/447) -- Implementation changes for the abstract height type, [SDK#7211](https://github.com/cosmos/cosmos-sdk/pull/7211) - -### Tendermint requires misbehaviour detection during updates - -The initial release of the IBC module and the 07-tendermint light client implementation did not support misbehaviour detection during update nor did it prevent overwriting of previous updates. -Despite the fact that we designed the `ClientState` interface and developed the 07-tendermint client, we failed to detect even a duplicate update that constituted misbehaviour and thus should freeze the client. -This was fixed in PR [#141](https://github.com/cosmos/ibc-go/pull/141) which required light client implementations to be aware that they must handle duplicate updates and misbehaviour detection. -Misbehaviour detection during updates is not applicable to the solomachine nor localhost. -It is also not obvious that `CheckHeaderAndUpdateState` should be performing this functionality. - -### Localhost requires access to the entire client store - -The localhost has been broken since the initial version of the IBC module. -The localhost tried to be developed underneath the 02-client interfaces without special exception, but this proved to be impossible. -The issues were outlined in [#27](https://github.com/cosmos/ibc-go/issues/27) and further discussed in the attempted ADR in [#75](https://github.com/cosmos/ibc-go/pull/75). -Unlike all other clients, the localhost requires access to the entire IBC store and not just the prefixed client store. - -### Solomachine doesn't set consensus states - -The 06-solomachine does not set the consensus states within the prefixed client store. -It has a single consensus state that is stored within the client state. -This causes setting of the consensus state at the 02-client level to use unnecessary storage. -It also causes timeouts to fail with solo machines. -Previously, the timeout logic within IBC would obtain the consensus state at the height a timeout is being proved. -This is problematic for the solo machine as no consensus state is set. -See issue [#562](https://github.com/cosmos/ibc/issues/562) on the IBC specification repo. - -### New clients may want to do batch updates - -New light clients may not function in a similar fashion to 06-solomachine and 07-tendermint. -They may require setting many consensus states in a single update. -As @seunlanlege [states](https://github.com/cosmos/ibc-go/issues/284#issuecomment-1005583679): - -> I'm in support of these changes for 2 reasons: -> -> - This would allow light clients handle batch header updates in CheckHeaderAndUpdateState, for the special case of 11-beefy proving the finality for a batch of headers is much more space and time efficient than the space/time complexity of proving each individual headers in that batch, combined. -> -> - This also allows for a single light client instance of 11-beefy be used to prove finality for every parachain connected to the relay chain (Polkadot/Kusama). We achieve this by setting the appropriate ConsensusState for individual parachain headers in CheckHeaderAndUpdateState - -## Decision - -### Require light clients to set client and consensus states - -The IBC specification states: - -> If the provided header was valid, the client MUST also mutate internal state to store now-finalised consensus roots and update any necessary signature authority tracking (e.g. changes to the validator set) for future calls to the validity predicate. - -The initial version of the IBC go SDK based module did not fulfill this requirement. -Instead, the 02-client submodule required each light client to return the client and consensus state which should be updated in the client prefixed store. -This decision lead to the issues "Solomachine doesn't set consensus states" and "New clients may want to do batch updates". - -Each light client should be required to set its own client and consensus states on any update necessary. -The go implementation should be changed to match the specification requirements. -This will allow more flexibility for light clients to manage their own internal storage and do batch updates. - -### Merge `Header`/`Misbehaviour` interface and rename to `ClientMessage` - -Remove `GetHeight()` from the header interface (as light clients now set the client/consensus states). -This results in the `Header`/`Misbehaviour` interfaces being the same. -To reduce complexity of the codebase, the `Header`/`Misbehaviour` interfaces should be merged into `ClientMessage`. -`ClientMessage` will provide the client with some authenticated information which may result in regular updates, misbehaviour detection, batch updates, or other custom functionality a light client requires. - -### Split `CheckHeaderAndUpdateState` into 4 functions - -See [#668](https://github.com/cosmos/ibc-go/issues/668). - -Split `CheckHeaderAndUpdateState` into 4 functions: - -- `VerifyClientMessage` -- `CheckForMisbehaviour` -- `UpdateStateOnMisbehaviour` -- `UpdateState` - -`VerifyClientMessage` checks the that the structure of a `ClientMessage` is correct and that all authentication data provided is valid. - -`CheckForMisbehaviour` checks to see if a `ClientMessage` is evidence of misbehaviour. - -`UpdateStateOnMisbehaviour` freezes the client and updates its state accordingly. - -`UpdateState` performs a regular update or a no-op on duplicate updates. - -The code roughly looks like: - -```go -func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.Header) error { - ... - - if err := clientState.VerifyClientMessage(clientMessage); err != nil { - return err - } - - foundMisbehaviour := clientState.CheckForMisbehaviour(clientMessage) - if foundMisbehaviour { - clientState.UpdateStateOnMisbehaviour(header) - // emit misbehaviour event - return - } - - clientState.UpdateState(clientMessage) // expects no-op on duplicate header - // emit update event - return -} -``` - -### Add `GetTimestampAtHeight` to the client state interface - -By adding `GetTimestampAtHeight` to the ClientState interface, we allow light clients which do non-traditional consensus state/timestamp storage to process timeouts correctly. -This fixes the issues outlined for the solo machine client. - -### Add generic verification functions - -As the complexity and the functionality grows, new verification functions will be required for additional paths. -This was explained in [#684](https://github.com/cosmos/ibc/issues/684) on the specification repo. -These generic verification functions would be immediately useful for the new paths added in connection/channel upgradability as well as for custom paths defined by IBC applications such as Interchain Queries. -The old verification functions (`VerifyClientState`, `VerifyConnection`, etc) should be removed in favor of the generic verification functions. - -## Consequences - -### Positive - -- Flexibility for light client implementations -- Well defined interfaces and their required functionality -- Generic verification functions -- Applies changes necessary for future client/connection/channel upgrabability features -- Timeout processing for solo machines -- Reduced code complexity - -### Negative - -- The refactor touches on sensitive areas of the ibc-go codebase -- Changing of established naming (`Header`/`Misbehaviour` to `ClientMessage`) - -### Neutral - -No notable consequences - -## References - -Issues: - -- [#284](https://github.com/cosmos/ibc-go/issues/284) - -PRs: - -- [#1871](https://github.com/cosmos/ibc-go/pull/1871) diff --git a/docs/architecture/adr-007-solomachine-signbytes.md b/docs/architecture/adr-007-solomachine-signbytes.md deleted file mode 100644 index 7407867e44e..00000000000 --- a/docs/architecture/adr-007-solomachine-signbytes.md +++ /dev/null @@ -1,52 +0,0 @@ -# ADR 007: Solo machine sign bytes - -## Changelog - -- 2022-08-02: Initial draft - -## Status - -Accepted, applied in v7 - -## Context - -The `06-solomachine` implemention up until ibc-go v7 constructed sign bytes using a `DataType` which described what type of data was being signed. -This design decision arose from a misunderstanding of the security implications. -It was noted that the proto definitions do not [provide uniqueness](https://github.com/cosmos/cosmos-sdk/pull/7237#discussion_r484264573) which is a necessity for ensuring two signatures over different data types can never be the same. -What was missed is that the uniqueness is not provided by the proto definition, but by the usage of the proto definition. -The path provided by core IBC will be unique and is already encoded into the signature data. -Thus two different paths with the same data values will encode differently which provides signature uniqueness. - -Furthermore, the current construction does not support the proposed changes in the spec repo to support [Generic Verification functions](https://github.com/cosmos/ibc/issues/684). -This is because in order to verify a new path, a new `DataType` must be added for that path. - -## Decision - -Remove `DataType` and change the `DataType` in the `SignBytes` and `SignatureAndData` to be `Path`. -The new `Path` field should be bytes. -Remove all `...Data` proto definitions except for `HeaderData` -These `...Data` definitions were created previously for each `DataType`. -The proto version of the solo machine proto definitions should be bumped to `v3`. - -This removes an extra layer of complexity from signature construction and allows for support of generic verification. - -## Consequences - -### Positive - -- Simplification of solo machine signature construction -- Support for generic verification - -### Negative - -- Breaks existing signature construction in a non-backwards compatible way -- Solo machines must update to handle the new format -- Migration required for solo machine client and consensus states - -### Neutral - -No notable consequences - -## References - -- [#1141](https://github.com/cosmos/ibc-go/issues/1141) diff --git a/docs/architecture/adr-008-app-caller-cbs.md b/docs/architecture/adr-008-app-caller-cbs.md deleted file mode 100644 index 3304cab8971..00000000000 --- a/docs/architecture/adr-008-app-caller-cbs.md +++ /dev/null @@ -1,544 +0,0 @@ -# ADR 008: Callback to IBC Actors - -## Changelog - -- 2022-08-10: Initial Draft -- 2023-03-22: Merged -- 2023-09-13: Updated with decisions made in implementation - -## Status - -Accepted, middleware implemented - -## Context - -IBC was designed with callbacks between core IBC and IBC applications. IBC apps would send a packet to core IBC. When the result of the packet lifecycle eventually resolved into either an acknowledgement or a timeout, core IBC called a callback on the IBC application so that the IBC application could take action on the basis of the result (e.g. unescrow tokens for ICS-20). - -This setup worked well for off-chain users interacting with IBC applications. - -We are now seeing the desire for secondary applications (e.g. smart contracts, modules) to call into IBC apps as part of their state machine logic and then do some actions on the basis of the packet result. Or to receive a packet from IBC and do some logic upon receipt. - -Example Usecases: - -- Send an ICS-20 packet, and if it is successful, then send an ICA-packet to swap tokens on LP and return funds to sender -- Execute some logic upon receipt of token transfer to a smart contract address - -This requires a second layer of callbacks. The IBC application already gets the result of the packet from core IBC, but currently there is no standardized way to pass this information on to an actor module/smart contract. - -## Definitions - -- Actor: an actor is an on-chain module (this may be a hardcoded module in the chain binary or a smart contract) that wishes to execute custom logic whenever IBC receives a packet flow that it has either sent or received. It **must** be addressable by a string value. - -## Decision - -Create a middleware that can interface between IBC applications and smart contract VMs. The IBC applications and smart contract VMs will implement respective interfaces that will then be composed together by the callback middleware to allow a smart contract of any compatible VM to interact programmatically with an IBC application. - -## Data structures - -The `CallbackPacketData` struct will get constructed from custom callback data in the application packet. The `CallbackAddress` is the IBC Actor address on which the callback should be called on. The `SenderAddress` is also provided to optionally allow a VM to ensure that the sender is the same as the callback address. - -The struct also defines a `CommitGasLimit` which is the maximum gas a callback is allowed to use. If the callback exceeds this limit, the callback will panic and the tx will commit without the callback's state changes. - -The `ExecutionGasLimit` is the practical limit of the tx execution that is set in the context gas meter. It is the minimum of the `CommitGasLimit` and the gas left in the context gas meter which is determined by the relayer's choice of tx gas limit. If `ExecutionGasLimit < CommitGasLimit`, then an out-of-gas error will revert the entire transaction without committing anything, allowing for a different relayer to retry with a larger tx gas limit. - -Any middleware targeting this interface for callback handling should define a global limit that caps the gas that a callback is allowed to take (especially on AcknowledgePacket and TimeoutPacket) so that a custom callback does not prevent the packet lifecycle from completing. However, since this is a global cap it is likely to be very large. Thus, users may specify a smaller limit to cap the amount of fees a relayer must pay in order to complete the packet lifecycle on the user's behalf. - -```go -// Implemented by any packet data type that wants to support PacketActor callbacks -// PacketActor's will be unable to act on any packet data type that does not implement -// this interface. -type CallbackPacketData struct { - CallbackAddress: string - ExecutionGasLimit: uint64 - SenderAddress: string - CommitGasLimit: uint64 -} -``` - -IBC Apps or middleware can then call the IBCActor callbacks like so in their own callbacks: - -### Callback Middleware - -The CallbackMiddleware wraps an underlying IBC application along with a contractKeeper that delegates the callback to a virtual machine. This allows the Callback middleware to interface any compatible IBC application with any compatible VM (e.g. EVM, WASM) so long as the application implements the `CallbacksCompatibleModule` interface and the VM implements the `ContractKeeper` interface. - -```go -// IBCMiddleware implements the ICS26 callbacks for the ibc-callbacks middleware given -// the underlying application. -type IBCMiddleware struct { - app types.CallbacksCompatibleModule - ics4Wrapper porttypes.ICS4Wrapper - - contractKeeper types.ContractKeeper - - // maxCallbackGas defines the maximum amount of gas that a callback actor can ask the - // relayer to pay for. If a callback fails due to insufficient gas, the entire tx - // is reverted if the relayer hadn't provided the minimum(userDefinedGas, maxCallbackGas). - // If the actor hasn't defined a gas limit, then it is assumed to be the maxCallbackGas. - maxCallbackGas uint64 -} -``` - -### Callback-Compatible IBC Application - -The `CallbacksCompatibleModule` extends `porttypes.IBCModule` to include an `UnmarshalPacketData` function that allows the middleware to request that the underlying app unmarshal the packet data. This will then allow the middleware to retrieve the callback specific data from an arbitrary set of IBC application packets. - -```go -// CallbacksCompatibleModule is an interface that combines the IBCModule and PacketDataUnmarshaler -// interfaces to assert that the underlying application supports both. -type CallbacksCompatibleModule interface { - porttypes.IBCModule - porttypes.PacketDataUnmarshaler -} - -// PacketDataUnmarshaler defines an optional interface which allows a middleware to -// request the packet data to be unmarshaled by the base application. -type PacketDataUnmarshaler interface { - // UnmarshalPacketData unmarshals the packet data into a concrete type - UnmarshalPacketData([]byte) (interface{}, error) -} -``` - -The application's packet data must additionally implement the following interfaces: - -```go -// PacketData defines an optional interface which an application's packet data structure may implement. -type PacketData interface { - // GetPacketSender returns the sender address of the packet data. - // If the packet sender is unknown or undefined, an empty string should be returned. - GetPacketSender(sourcePortID string) string -} - -// PacketDataProvider defines an optional interfaces for retrieving custom packet data stored on behalf of another application. -// An existing problem in the IBC middleware design is the inability for a middleware to define its own packet data type and insert packet sender provided information. -// A short term solution was introduced into several application's packet data to utilize a memo field to carry this information on behalf of another application. -// This interfaces standardizes that behaviour. Upon realization of the ability for middleware's to define their own packet data types, this interface will be deprecated and removed with time. -type PacketDataProvider interface { - // GetCustomPacketData returns the packet data held on behalf of another application. - // The name the information is stored under should be provided as the key. - // If no custom packet data exists for the key, nil should be returned. - GetCustomPacketData(key string) interface{} -} -``` - -The callback data can be embedded in an application packet by providing custom packet data for source and destination callback in the custom packet data under the appropriate key. - -```jsonc -// Custom Packet data embedded as a JSON object in the packet data - -// src callback custom data -{ - "src_callback": { - "address": "callbackAddressString", - // optional - "gas_limit": "userDefinedGasLimitString", - } -} - -// dest callback custom data -{ - "dest_callback": { - "address": "callbackAddressString", - // optional - "gas_limit": "userDefinedGasLimitString", - } -} - -// src and dest callback custom data embedded together -{ - "src_callback": { - "address": "callbackAddressString", - // optional - "gas_limit": "userDefinedGasLimitString", - }, - "dest_callback": { - "address": "callbackAddressString", - // optional - "gas_limit": "userDefinedGasLimitString", - } -} -``` - -## ContractKeeper - -The `ContractKeeper` interface must be implemented by any VM that wants to support IBC callbacks. This allows for separation of concerns -between the middleware which is handling logic intended for all VMs (e.g. setting gas meter, extracting callback data, emitting events), -while the ContractKeeper can handle the specific details of calling into the VM in question. - -The `ContractKeeper` **may** impose additional checks such as ensuring that the contract address is the same as the packet sender in source callbacks. -It may also disable certain callback methods by simply performing a no-op. - -```go -// ContractKeeper defines the entry points exposed to the VM module which invokes a smart contract -type ContractKeeper interface { - // IBCSendPacketCallback is called in the source chain when a PacketSend is executed. The - // packetSenderAddress is determined by the underlying module, and may be empty if the sender is - // unknown or undefined. The contract is expected to handle the callback within the user defined - // gas limit, and handle any errors, or panics gracefully. - // This entry point is called with a cached context. If an error is returned, then the changes in - // this context will not be persisted, and the error will be propagated to the underlying IBC - // application, resulting in a packet send failure. - // - // Implementations are provided with the packetSenderAddress and MAY choose to use this to perform - // validation on the origin of a given packet. It is recommended to perform the same validation - // on all source chain callbacks (SendPacket, AcknowledgementPacket, TimeoutPacket). This - // defensively guards against exploits due to incorrectly wired SendPacket ordering in IBC stacks. - IBCSendPacketCallback( - cachedCtx sdk.Context, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - packetData []byte, - contractAddress, - packetSenderAddress string, - ) error - // IBCOnAcknowledgementPacketCallback is called in the source chain when a packet acknowledgement - // is received. The packetSenderAddress is determined by the underlying module, and may be empty if - // the sender is unknown or undefined. The contract is expected to handle the callback within the - // user defined gas limit, and handle any errors, or panics gracefully. - // This entry point is called with a cached context. If an error is returned, then the changes in - // this context will not be persisted, but the packet lifecycle will not be blocked. - // - // Implementations are provided with the packetSenderAddress and MAY choose to use this to perform - // validation on the origin of a given packet. It is recommended to perform the same validation - // on all source chain callbacks (SendPacket, AcknowledgementPacket, TimeoutPacket). This - // defensively guards against exploits due to incorrectly wired SendPacket ordering in IBC stacks. - IBCOnAcknowledgementPacketCallback( - cachedCtx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - relayer sdk.AccAddress, - contractAddress, - packetSenderAddress string, - ) error - // IBCOnTimeoutPacketCallback is called in the source chain when a packet is not received before - // the timeout height. The packetSenderAddress is determined by the underlying module, and may be - // empty if the sender is unknown or undefined. The contract is expected to handle the callback - // within the user defined gas limit, and handle any error, out of gas, or panics gracefully. - // This entry point is called with a cached context. If an error is returned, then the changes in - // this context will not be persisted, but the packet lifecycle will not be blocked. - // - // Implementations are provided with the packetSenderAddress and MAY choose to use this to perform - // validation on the origin of a given packet. It is recommended to perform the same validation - // on all source chain callbacks (SendPacket, AcknowledgementPacket, TimeoutPacket). This - // defensively guards against exploits due to incorrectly wired SendPacket ordering in IBC stacks. - IBCOnTimeoutPacketCallback( - cachedCtx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, - contractAddress, - packetSenderAddress string, - ) error - // IBCReceivePacketCallback is called in the destination chain when a packet acknowledgement is written. - // The contract is expected to handle the callback within the user defined gas limit, and handle any errors, - // out of gas, or panics gracefully. - // This entry point is called with a cached context. If an error is returned, then the changes in - // this context will not be persisted, but the packet lifecycle will not be blocked. - IBCReceivePacketCallback( - cachedCtx sdk.Context, - packet ibcexported.PacketI, - ack ibcexported.Acknowledgement, - contractAddress string, - ) error -} -``` - -### PacketCallbacks - -The packet callbacks implemented in the middleware will first call the underlying application and then route to the IBC actor callback in the post-processing step. -It will extract the callback data from the application packet and set the callback gas meter depending on the global limit, the user limit, and the gas left in the transaction gas meter. -The callback will then be routed through the callback keeper which will either panic or return a result (success or failure). In the event of a (non-oog) panic or an error, the callback state changes -are discarded and the transaction is committed. - -If the relayer-defined gas limit is exceeded before the user-defined gas limit or global callback gas limit is exceeded, then the entire transaction is reverted to allow for resubmission. If the chain-defined or user-defined gas limit is reached, -the callback state changes are reverted and the transaction is committed. - -For the `SendPacket` callback, we will revert the entire transaction on any kind of error or panic. This is because the packet lifecycle has not yet started, so we can revert completely to avoid starting the packet lifecycle if the callback is not successful. - -```go -// SendPacket implements source callbacks for sending packets. -// It defers to the underlying application and then calls the contract callback. -// If the contract callback returns an error, panics, or runs out of gas, then -// the packet send is rejected. -func (im IBCMiddleware) SendPacket( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - data []byte, -) (uint64, error) { - // run underlying app logic first - // IBCActor logic will postprocess - seq, err := im.ics4Wrapper.SendPacket(ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) - if err != nil { - return 0, err - } - - // use underlying app to get source callback information from packet data - callbackData, err := types.GetSourceCallbackData(im.app, data, sourcePort, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) - // SendPacket is not blocked if the packet does not opt-in to callbacks - if err != nil { - return seq, nil - } - - callbackExecutor := func(cachedCtx sdk.Context) error { - return im.contractKeeper.IBCSendPacketCallback( - cachedCtx, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data, callbackData.CallbackAddress, callbackData.SenderAddress, - ) - } - - err = im.processCallback(ctx, types.CallbackTypeSendPacket, callbackData, callbackExecutor) - // contract keeper is allowed to reject the packet send. - if err != nil { - return 0, err - } - - types.EmitCallbackEvent(ctx, sourcePort, sourceChannel, seq, types.CallbackTypeSendPacket, callbackData, nil) - return seq, nil -} - -// WriteAcknowledgement implements the ReceivePacket destination callbacks for the ibc-callbacks middleware -// during asynchronous packet acknowledgement. -// It defers to the underlying application and then calls the contract callback. -// If the contract callback runs out of gas and may be retried with a higher gas limit then the state changes are -// reverted via a panic. -func (im IBCMiddleware) WriteAcknowledgement( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - packet ibcexported.PacketI, - ack ibcexported.Acknowledgement, -) error { - // run underlying app logic first - // IBCActor logic will postprocess - err := im.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, ack) - if err != nil { - return err - } - - // use underlying app to get destination callback information from packet data - callbackData, err := types.GetDestCallbackData( - im.app, packet.GetData(), packet.GetSourcePort(), ctx.GasMeter().GasRemaining(), im.maxCallbackGas, - ) - // WriteAcknowledgement is not blocked if the packet does not opt-in to callbacks - if err != nil { - return nil - } - - callbackExecutor := func(cachedCtx sdk.Context) error { - return im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, ack, callbackData.CallbackAddress) - } - - // callback execution errors are not allowed to block the packet lifecycle, they are only used in event emissions - err = im.processCallback(ctx, types.CallbackTypeReceivePacket, callbackData, callbackExecutor) - // emit events - types.EmitCallbackEvent( - ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), - types.CallbackTypeAcknowledgementPacket, callbackData, err, - ) - - return nil -} - -// Call the IBCActor recvPacket callback after processing the packet -// if the recvPacket callback exists. If the callback returns an error -// then return an error ack to revert all packet data processing. -func (im IBCMiddleware) OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) (ack exported.Acknowledgement) { - // run underlying app logic first - // IBCActor logic will postprocess - ack := im.app.OnRecvPacket(ctx, packet, relayer) - // if ack is nil (asynchronous acknowledgements), then the callback will be handled in WriteAcknowledgement - // if ack is not successful, all state changes are reverted. If a packet cannot be received, then there is - // no need to execute a callback on the receiving chain. - if ack == nil || !ack.Success() { - return ack - } - - // use underlying app to get destination callback information from packet data - callbackData, err := types.GetDestCallbackData( - im.app, packet.GetData(), packet.GetSourcePort(), ctx.GasMeter().GasRemaining(), im.maxCallbackGas, - ) - // OnRecvPacket is not blocked if the packet does not opt-in to callbacks - if err != nil { - return ack - } - - callbackExecutor := func(cachedCtx sdk.Context) error { - return im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, ack, callbackData.CallbackAddress) - } - - // callback execution errors are not allowed to block the packet lifecycle, they are only used in event emissions - err = im.processCallback(ctx, types.CallbackTypeReceivePacket, callbackData, callbackExecutor) - types.EmitCallbackEvent( - ctx, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), - types.CallbackTypeReceivePacket, callbackData, err, - ) - - return ack -} - -// Call the IBCActor acknowledgementPacket callback after processing the packet -// if the ackPacket callback exists and returns an error -// DO NOT return the error upstream. The acknowledgement must complete for the packet -// lifecycle to end, so the custom callback cannot block completion. -// Instead we emit error events and set the error in state -// so that users and on-chain logic can handle this appropriately -func (im IBCModule) OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - relayer sdk.AccAddress, -) error { - // we first call the underlying app to handle the acknowledgement - // IBCActor logic will postprocess - err := im.app.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) - if err != nil { - return err - } - - // use underlying app to get source callback information from packet data - callbackData, err := types.GetSourceCallbackData( - im.app, packet.GetData(), packet.GetSourcePort(), ctx.GasMeter().GasRemaining(), im.maxCallbackGas, - ) - // OnAcknowledgementPacket is not blocked if the packet does not opt-in to callbacks - if err != nil { - return nil - } - - callbackExecutor := func(cachedCtx sdk.Context) error { - return im.contractKeeper.IBCOnAcknowledgementPacketCallback( - cachedCtx, packet, acknowledgement, relayer, callbackData.CallbackAddress, callbackData.SenderAddress, - ) - } - - // callback execution errors are not allowed to block the packet lifecycle, they are only used in event emissions - err = im.processCallback(ctx, types.CallbackTypeAcknowledgementPacket, callbackData, callbackExecutor) - types.EmitCallbackEvent( - ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), - types.CallbackTypeAcknowledgementPacket, callbackData, err, - ) - - return nil -} - -// Call the IBCActor timeoutPacket callback after processing the packet -// if the timeoutPacket callback exists and returns an error -// DO NOT return the error upstream. The timeout must complete for the packet -// lifecycle to end, so the custom callback cannot block completion. -// Instead we emit error events and set the error in state -// so that users and on-chain logic can handle this appropriately -func (im IBCModule) OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) error { - // application-specific onTimeoutPacket logic - err := im.app.OnTimeoutPacket(ctx, packet, relayer) - if err != nil { - return err - } - - // use underlying app to get source callback information from packet data - callbackData, err := types.GetSourceCallbackData( - im.app, packet.GetData(), packet.GetSourcePort(), ctx.GasMeter().GasRemaining(), im.maxCallbackGas, - ) - // OnTimeoutPacket is not blocked if the packet does not opt-in to callbacks - if err != nil { - return nil - } - - callbackExecutor := func(cachedCtx sdk.Context) error { - return im.contractKeeper.IBCOnTimeoutPacketCallback(cachedCtx, packet, relayer, callbackData.CallbackAddress, callbackData.SenderAddress) - } - - // callback execution errors are not allowed to block the packet lifecycle, they are only used in event emissions - err = im.processCallback(ctx, types.CallbackTypeTimeoutPacket, callbackData, callbackExecutor) - types.EmitCallbackEvent( - ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), - types.CallbackTypeTimeoutPacket, callbackData, err, - ) - - return nil -} - -// processCallback executes the callbackExecutor and reverts contract changes if the callbackExecutor fails. -// -// Error Precedence and Returns: -// - oogErr: Takes the highest precedence. If the callback runs out of gas, an error wrapped with types.ErrCallbackOutOfGas is returned. -// - panicErr: Takes the second-highest precedence. If a panic occurs and it is not propagated, an error wrapped with types.ErrCallbackPanic is returned. -// - callbackErr: If the callbackExecutor returns an error, it is returned as-is. -// -// panics if -// - the contractExecutor panics for any reason, and the callbackType is SendPacket, or -// - the contractExecutor runs out of gas and the relayer has not reserved gas grater than or equal to -// CommitGasLimit. -func (IBCMiddleware) processCallback( - ctx sdk.Context, callbackType types.CallbackType, - callbackData types.CallbackData, callbackExecutor func(sdk.Context) error, -) (err error) { - cachedCtx, writeFn := ctx.CacheContext() - cachedCtx = cachedCtx.WithGasMeter(storetypes.NewGasMeter(callbackData.ExecutionGasLimit)) - - defer func() { - // consume the minimum of g.consumed and g.limit - ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackType)) - - // recover from all panics except during SendPacket callbacks - if r := recover(); r != nil { - if callbackType == types.CallbackTypeSendPacket { - panic(r) - } - err = errorsmod.Wrapf(types.ErrCallbackPanic, "ibc %s callback panicked with: %v", callbackType, r) - } - - // if the callback ran out of gas and the relayer has not reserved enough gas, then revert the state - if cachedCtx.GasMeter().IsPastLimit() { - if callbackData.AllowRetry() { - panic(storetypes.ErrorOutOfGas{Descriptor: fmt.Sprintf("ibc %s callback out of gas; commitGasLimit: %d", callbackType, callbackData.CommitGasLimit)}) - } - err = errorsmod.Wrapf(types.ErrCallbackOutOfGas, "ibc %s callback out of gas", callbackType) - } - - // allow the transaction to be committed, continuing the packet lifecycle - }() - - err = callbackExecutor(cachedCtx) - if err == nil { - writeFn() - } - - return err -} -``` - -Chains are expected to specify a `maxCallbackGas` to ensure that callbacks do not consume an arbitrary amount of gas. Thus, it should always be possible for a relayer to complete the packet lifecycle even if the actor callbacks cannot run successfully. - -## Consequences - -### Positive - -- IBC Actors can now programmatically execute logic that involves sending a packet and then performing some additional logic once the packet lifecycle is complete -- Middleware implementing ADR-8 can be generally used for any application -- Leverages a similar callback architecture to the one used between core IBC and IBC applications - -### Negative - -- Callbacks may now have unbounded gas consumption since the actor may execute arbitrary logic. Chains implementing this feature should take care to place limitations on how much gas an actor callback can consume. -- The relayer pays for the callback gas instead of the IBCActor - -### Neutral - -- Application packets that want to support ADR-8 must additionally have their packet data implement `PacketDataProvider` and `PacketData` interfaces. -- Applications must implement `PacketDataUnmarshaler` interface -- Callback receiving module must implement the `ContractKeeper` interface - -## References - -- [Original issue](https://github.com/cosmos/ibc-go/issues/1660) -- [CallbackPacketData interface implementation](https://github.com/cosmos/ibc-go/pull/3287) -- [ICS 20, ICS 27 implementations of the CallbackPacketData interface](https://github.com/cosmos/ibc-go/pull/3287) diff --git a/docs/architecture/adr-009-v6-ics27-msgserver.md b/docs/architecture/adr-009-v6-ics27-msgserver.md deleted file mode 100644 index 7a60d1fcaed..00000000000 --- a/docs/architecture/adr-009-v6-ics27-msgserver.md +++ /dev/null @@ -1,115 +0,0 @@ -# ADR 009: ICS27 message server addition - -## Changelog - -- 2022/09/07: Initial draft - -## Status - -Accepted, implemented in v6 of ibc-go - -## Context - -ICS 27 (Interchain Accounts) brought a cross-chain account management protocol built upon IBC. -It enabled chains to programatically create accounts on behalf of counterparty chains which may enable a variety of authentication methods for this interchain account. -The initial release of ICS 27 focused on enabling authentication schemes which may not require signing with a private key, such as via on-chain mechanisms like governance. - -Following the initial release of ICS 27 it became evident that: - -- a default authentication module would enable more usage of ICS 27 -- generic authentication modules should be capable of authenticating an interchain account registration -- application logic which wraps ICS 27 packet sends do not need to be associated with the authentication logic - -## Decision - -The controller module should be simplified to remove the correlation between the authentication logic for an interchain account and the application logic for an interchain account. -To minimize disruption to developers working on the original design of the ICS 27 controller module, all changes will be made in a backwards compatible fashion. - -### Msg server - -To acheive this, as stated by [@damiannolan](https://github.com/cosmos/ibc-go/issues/2026#issue-1341640594), it was proposed to: - -> Add a new `MsgServer` to `27-interchain-accounts` which exposes two distinct rpc endpoints: -> -> - `RegisterInterchainAccount` -> - `SendTx` - -This will enable any SDK (authentication) module to register interchain accounts and send transactions on their behalf. -Examples of existing SDK modules which would benefit from this change include: - -- x/auth -- x/gov -- x/group - -The existing go functions: `RegisterInterchainAccount()` and `SendTx()` will remain to operate as they did in previous release versions. - -This will be possible for SDK v0.46.x and above. - -### Allow `nil` underlying applications - -Authentication modules should interact with the controller module via the message server and should not be associated with application logic. -For now, it will be allowed to set a `nil` underlying application. -A future version may remove the underlying application entirely. - -See issue [#2040](https://github.com/cosmos/ibc-go/issues/2040) - -### Channel capability claiming - -The controller module will now claim the channel capability in `OnChanOpenInit`. -Underlying applications will be passed a `nil` capability in `OnChanOpenInit`. - -Channel capability migrations will be added in two steps: - -- Upgrade handler migration which modifies the channel capability owner from the underlying app to the controller module -- ICS 27 module automatic migration which asserts the upgrade handler channel capability migration has been performed successfully - -See issue [#2033](https://github.com/cosmos/ibc-go/issues/2033) - -### Middleware enabled channels - -In order to maintain backwards compatibility and avoid requiring underlying application developers to account for interchain accounts they did not register, a boolean mapping has been added to track the behaviour of how an account was created. - -If the account was created via the legacy API, then the underlying application callbacks will be executed. - -If the account was created with the new API (message server), then the underlying application callbacks will not be executed. - -See issue [#2145](https://github.com/cosmos/ibc-go/issues/2145) - -### Future considerations - -[ADR 008](https://github.com/cosmos/ibc-go/pull/1976) proposes the creation of a middleware which enables callers of an IBC packet send to perform application logic in conjunction with the IBC application. -The underlying application can be removed at the availablity of such a middleware as that will be the preferred method for executing application logic upon a ICS 27 packet send. - -### Miscellanous - -In order to avoid import cycles, the genesis types have been moved to their own directory. -A new protobuf package has been created for the genesis types. - -See PR [#2133](https://github.com/cosmos/ibc-go/pull/2133) - -An additional field has been added to the `ActiveChannel` type to store the `IsMiddlewareEnabled` field upon genesis import/export. - -See issue [#2165](https://github.com/cosmos/ibc-go/issues/2165) - -## Consequences - -### Positive - -- default authentication modules are provided (x/auth, x/group, x/gov) -- any SDK authentication module may now be used with ICS 27 -- separation of authentication from application logic in relation to ICS 27 -- minimized disruption to existing development around ICS 27 controller module -- underlying applications no longer have to handle capabilities -- removal of the underlying application upon the creation of ADR 008 may be done in a minimally disruptive fashion -- only underlying applications which registered the interchain account will perform application logic for that account (underlying applications do not need to be aware of accounts they did not register) - -### Negative - -- the security model has been reduced to that of the SDK. SDK modules may send packets for any interchain account. -- additional maintenance of the messages added and the middleware enabled flag -- underlying applications which will become ADR 008 modules are not required to be aware of accounts they did not register -- calling legacy API vs the new API results in different behaviour for ICS 27 application stacks which have an underlying application - -### Neutral - -- A major release is required diff --git a/docs/architecture/adr-010-light-clients-as-sdk-modules.md b/docs/architecture/adr-010-light-clients-as-sdk-modules.md deleted file mode 100644 index 83140973376..00000000000 --- a/docs/architecture/adr-010-light-clients-as-sdk-modules.md +++ /dev/null @@ -1,106 +0,0 @@ -# ADR 010: IBC light clients as SDK modules - -## Changelog - -- 12/12/2022: initial draft - -## Status - -Proposed - -## Context - -ibc-go has 3 main consumers: - -- IBC light clients -- IBC applications -- relayers - -Relayers listen and respond to events emitted by ibc-go while IBC light clients and applications are invoked by core IBC. -Currently there exists two different approaches to callbacks being invoked by core IBC. - -IBC light clients currently are invoked by a `ClientState` and `ConsensusState` interface as defined by [core IBC](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go#L36). -The 02-client submodule will retrieve the `ClientState` or `ConsensusState` from the IBC store in order to perform callbacks to the light client. -This design requires all required information for the light client to function to be stored in the `ClientState` or `ConsensusState` or potentially under metadata keys for a specific client instance. -Additional information may be provided by core IBC via the defined interface arguments if that information is generic enough to be useful to all IBC light clients. -This constraint has proved problematic as pass through clients (such as wasm) cannot maintain easy access to a VM instance. -In addition, without increasing the size of the defined `ClientState` interface, light clients are unable to take advantage of basic built-in SDK functionality such as genesis import/export and migrations. - -The other approach used to perform callback logic is via registered SDK modules. -This approach is used by core IBC to interact with IBC applications. -IBC applications will register their callbacks on the IBC router at compile time. -When a packet comes in, core IBC will use the IBC router to lookup the registered callback functions for the provided packet. -The benefit of registered callbacks opposed to interface functions is that additional information may be accessed via external keepers. -Because the IBC applications are also SDK modules, they additionally get access to a host of functionality provided by the SDK. -This includes: genesis import/export, migrations, query/transaction CLI commands, type registration, gRPC query registration, and message server registration. - -As described in [ADR 006](./adr-006-02-client-refactor.md), generalizing light client behaviour is difficult. -IBC light clients will obtain greater flexibility and control via the registered SDK module approach. - -## Decision - -Instead of using two different approaches to invoking callbacks, IBC light clients should be invoked as SDK modules. -Over time and as necessary, core IBC should adjust its interactions with light clients such that they are SDK modules as opposed to interfaces. - -One immediate decision that has already been applied is to formalize light client type registration via the inclusion of an `AppModuleBasic` within the `ModuleManager` for a chain. -The [tendermint](https://github.com/cosmos/ibc-go/pull/2825) and [solo machine](https://github.com/cosmos/ibc-go/pull/2826) clients were refactored to include this `AppModuleBasic` implementation and core IBC will no longer include either type as registered by default. - -Longer term solutions include using internal module communication as described in [ADR 033](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-033-protobuf-inter-module-comm.md) on the SDK. -The following functions should become callbacks invoked via intermodule communication: - -- `Status` -- `GetTimestampAtHeight` -- `VerifyMembership` -- `VerifyNonMembership` -- `Initialize` -- `VerifyClientMessage` -- `CheckForMisbehaviour` -- `UpdateStateOnMisbehaviour` -- `UpdateState` -- `CheckSubstituteAndUpdateState` -- `VerifyUpgradeAndUpdateState` - -The ClientState interface should eventually be trimmed down to something along the lines of: - -```go -type ClientState interface { - proto.Message - - ClientType() string - GetLatestHeight() Height - Validate() error - - ZeroCustomFields() ClientState - - // ADDITION - Route() string // route used for intermodule communication -} -``` - -For the most part, any functions which require access to the client store should likely not be an interface function of the `ClientState`. - -`ExportMetadata` should eventually be replaced by a light client's ability to import/export it's own genesis information. - -### Intermodule communication - -To keep the transition from interface callbacks to SDK module callbacks as simple as possible, intermodule communication (when available) should be used to route to light client modules. -Without intermodule communication, a routing system would need to be developed/maintained to register callbacks. -This functionality of routing to another SDK module should and will be provided by the SDK. -Once it is possible to route to SDK modules, a `ClientState` type could expose the function `Route` which returns the callback route used to call the light client module. - -## Consequences - -### Positive - -- use a single approach for interacting with callbacks -- greater flexibilty and control for IBC light clients -- does not require developing another routing system - -### Negative - -- requires breaking changes -- requires waiting for intermodule communication - -### Neutral - -N/A diff --git a/docs/architecture/adr-011-transfer-total-escrow-state-entry.md b/docs/architecture/adr-011-transfer-total-escrow-state-entry.md deleted file mode 100644 index 2747c5cb615..00000000000 --- a/docs/architecture/adr-011-transfer-total-escrow-state-entry.md +++ /dev/null @@ -1,145 +0,0 @@ -# ADR 011: ICS-20 transfer state entry for total amount of tokens in escrow - -## Changelog - -- 2023-05-24: Initial draft - -## Status - -Accepted and applied in v7.1 of ibc-go - -## Context - -Every ICS-20 transfer channel has its own escrow bank account. This account is used to lock tokens that are transferred out of a chain that acts as the source of the tokens (i.e. when the tokens being transferred have not returned to the originating chain). This design makes it easy to query the balance of the escrow accounts and find out the total amount of tokens in escrow in a particular channel. However, there are use cases where it would be useful to determine the total escrowed amount of a given denomination across all channels where those tokens have been transferred out. - -For example: assuming that there are three channels between Cosmos Hub to Osmosis and 10 ATOM have been transferred from the Cosmos Hub to Osmosis on each of those channels, then we would like to know that 30 ATOM have been transferred (i.e. are locked in the escrow accounts of each channel) without needing to iterate over each escrow account to add up the balances of each. - -For a sample use case where this feature would be useful, please refer to Osmosis' rate limiting use case described in [#2664](https://github.com/cosmos/ibc-go/issues/2664). - -## Decision - -### State entry denom -> amount - -The total amount of tokens in escrow (across all transfer channels) for a given denomination is stored in state in an entry keyed by the denomination: `totalEscrowForDenom/{denom}`. - -### Panic if amount is negative - -If a negative amount is ever attempted to be stored, then the keeper function will panic: - -```go -if coin.Amount.IsNegative() { - panic(fmt.Sprintf("amount cannot be negative: %s", coin.Amount)) -} -``` - -### Delete state entry if amount is zero - -When setting the amount for a particular denomination, the value might be zero if all tokens that were transferred out of the chain have been transferred back. If this happens, then the state entry for this particular denomination will be deleted, since Cosmos SDK's `x/bank` module prunes any non-zero balances: - -```go -if coin.Amount.IsZero() { - store.Delete(key) // delete the key since Cosmos SDK x/bank module will prune any non-zero balances - return -} -``` - -### Bundle escrow/unescrow with setting state entry - -Two new functions are implemented that bundle together the operations of escrowing/unescrowing and setting the total escrow amount in state, since these operations need to be executed together. - -For escrowing tokens: - -```go -// escrowToken will send the given token from the provided sender to the escrow address. It will also -// update the total escrowed amount by adding the escrowed token to the current total escrow. -func (k Keeper) escrowToken(ctx sdk.Context, sender, escrowAddress sdk.AccAddress, token sdk.Coin) error { - if err := k.bankKeeper.SendCoins(ctx, sender, escrowAddress, sdk.NewCoins(token)); err != nil { - // failure is expected for insufficient balances - return err - } - - // track the total amount in escrow keyed by denomination to allow for efficient iteration - currentTotalEscrow := k.GetTotalEscrowForDenom(ctx, token.GetDenom()) - newTotalEscrow := currentTotalEscrow.Add(token) - k.SetTotalEscrowForDenom(ctx, newTotalEscrow) - - return nil -} -``` - -For unescrowing tokens: - -```go -// unescrowToken will send the given token from the escrow address to the provided receiver. It will also -// update the total escrow by deducting the unescrowed token from the current total escrow. -func (k Keeper) unescrowToken(ctx sdk.Context, escrowAddress, receiver sdk.AccAddress, token sdk.Coin) error { - if err := k.bankKeeper.SendCoins(ctx, escrowAddress, receiver, sdk.NewCoins(token)); err != nil { - // NOTE: this error is only expected to occur given an unexpected bug or a malicious - // counterparty module. The bug may occur in bank or any part of the code that allows - // the escrow address to be drained. A malicious counterparty module could drain the - // escrow address by allowing more tokens to be sent back then were escrowed. - return errorsmod.Wrap(err, "unable to unescrow tokens, this may be caused by a malicious counterparty module or a bug: please open an issue on counterparty module") - } - - // track the total amount in escrow keyed by denomination to allow for efficient iteration - currentTotalEscrow := k.GetTotalEscrowForDenom(ctx, token.GetDenom()) - newTotalEscrow := currentTotalEscrow.Sub(token) - k.SetTotalEscrowForDenom(ctx, newTotalEscrow) - - return nil -} -``` - -When tokens need to be escrowed in `sendTransfer`, then `escrowToken` is called; when tokens need to be unescrowed on execution of the `OnRecvPacket`, `OnAcknowledgementPacket` or `OnTimeoutPacket` callbacks, then `unescrowToken` is called. - -### gRPC query endpoint and CLI to retrieve amount - -A gRPC query endpoint is added so that it is possible to retrieve the total amount for a given denomination: - -```proto -// TotalEscrowForDenom returns the total amount of tokens in escrow based on the denom. -rpc TotalEscrowForDenom(QueryTotalEscrowForDenomRequest) returns (QueryTotalEscrowForDenomResponse) { - option (google.api.http).get = "/ibc/apps/transfer/v1/denoms/{denom=**}/total_escrow"; -} - -// QueryTotalEscrowForDenomRequest is the request type for TotalEscrowForDenom RPC method. -message QueryTotalEscrowForDenomRequest { - string denom = 1; -} - -// QueryTotalEscrowForDenomResponse is the response type for TotalEscrowForDenom RPC method. -message QueryTotalEscrowForDenomResponse { - cosmos.base.v1beta1.Coin amount = 1 [(gogoproto.nullable) = false]; -} -``` - -And a CLI query is also available to retrieve the total amount via the command line: - -```shell -query ibc-transfer total-escrow [denom] -``` - -## Consequences - -### Positive - -- Possibility to retrieve the total amount of a particular denomination in escrow across all transfer channels without iteration. - -### Negative - -No notable consequences - -### Neutral - -- A new entry is added to state for every denomination that is transferred out of the chain. - -## References - -Issues: - -- [#2664](https://github.com/cosmos/ibc-go/issues/2664) - -PRs: - -- [#3019](https://github.com/cosmos/ibc-go/pull/3019) -- [#3558](https://github.com/cosmos/ibc-go/pull/3558) diff --git a/docs/architecture/adr-015-ibc-packet-receiver.md b/docs/architecture/adr-015-ibc-packet-receiver.md deleted file mode 100644 index 08264c6d2ee..00000000000 --- a/docs/architecture/adr-015-ibc-packet-receiver.md +++ /dev/null @@ -1,299 +0,0 @@ -# ADR 015: IBC Packet Receiver - -## Changelog - -- 2019 Oct 22: Initial Draft - -## Context - -[ICS 26 - Routing Module](https://github.com/cosmos/ibc/tree/master/spec/core/ics-026-routing-module) defines a function [`handlePacketRecv`](https://github.com/cosmos/ibc/tree/master/spec/core/ics-026-routing-module#packet-relay). - -In ICS 26, the routing module is defined as a layer above each application module -which verifies and routes messages to the destination modules. It is possible to -implement it as a separate module, however, we already have functionality to route -messages upon the destination identifiers in the baseapp. This ADR suggests -to utilize existing `baseapp.router` to route packets to application modules. - -Generally, routing module callbacks have two separate steps in them, -verification and execution. This corresponds to the `AnteHandler`-`Handler` -model inside the SDK. We can do the verification inside the `AnteHandler` -in order to increase developer ergonomics by reducing boilerplate -verification code. - -For atomic multi-message transaction, we want to keep the IBC related -state modification to be preserved even the application side state change -reverts. One of the example might be IBC token sending message following with -stake delegation which uses the tokens received by the previous packet message. -If the token receiving fails for any reason, we might not want to keep -executing the transaction, but we also don't want to abort the transaction -or the sequence and commitment will be reverted and the channel will be stuck. -This ADR suggests new `CodeType`, `CodeTxBreak`, to fix this problem. - -## Decision - -`PortKeeper` will have the capability key that is able to access only the -channels bound to the port. Entities that hold a `PortKeeper` will be -able to call the methods on it which are corresponding with the methods with -the same names on the `ChannelKeeper`, but only with the -allowed port. `ChannelKeeper.Port(string, ChannelChecker)` will be defined to -easily construct a capability-safe `PortKeeper`. This will be addressed in -another ADR and we will use insecure `ChannelKeeper` for now. - -`baseapp.runMsgs` will break the loop over the messages if one of the handlers -returns `!Result.IsOK()`. However, the outer logic will write the cached -store if `Result.IsOK() || Result.Code.IsBreak()`. `Result.Code.IsBreak()` if -`Result.Code == CodeTxBreak`. - -```go -func (app *BaseApp) runTx(tx Tx) (result Result) { - msgs := tx.GetMsgs() - - // AnteHandler - if app.anteHandler != nil { - anteCtx, msCache := app.cacheTxContext(ctx) - newCtx, err := app.anteHandler(anteCtx, tx) - if !newCtx.IsZero() { - ctx = newCtx.WithMultiStore(ms) - } - - if err != nil { - // error handling logic - return res - } - - msCache.Write() - } - - // Main Handler - runMsgCtx, msCache := app.cacheTxContext(ctx) - result = app.runMsgs(runMsgCtx, msgs) - // BEGIN modification made in this ADR - if result.IsOK() || result.IsBreak() { - // END - msCache.Write() - } - - return result -} -``` - -The Cosmos SDK will define an `AnteDecorator` for IBC packet receiving. The -`AnteDecorator` will iterate over the messages included in the transaction, type -`switch` to check whether the message contains an incoming IBC packet, and if so -verify the Merkle proof. - -```go -type ProofVerificationDecorator struct { - clientKeeper ClientKeeper - channelKeeper ChannelKeeper -} - -func (pvr ProofVerificationDecorator) AnteHandle(ctx Context, tx Tx, simulate bool, next AnteHandler) (Context, error) { - for _, msg := range tx.GetMsgs() { - var err error - switch msg := msg.(type) { - case client.MsgUpdateClient: - err = pvr.clientKeeper.UpdateClient(msg.ClientID, msg.Header) - case channel.MsgPacket: - err = pvr.channelKeeper.RecvPacket(msg.Packet, msg.Proofs, msg.ProofHeight) - case chanel.MsgAcknowledgement: - err = pvr.channelKeeper.AcknowledgementPacket(msg.Acknowledgement, msg.Proof, msg.ProofHeight) - case channel.MsgTimeoutPacket: - err = pvr.channelKeeper.TimeoutPacket(msg.Packet, msg.Proof, msg.ProofHeight, msg.NextSequenceRecv) - case channel.MsgChannelOpenInit; - err = pvr.channelKeeper.CheckOpen(msg.PortID, msg.ChannelID, msg.Channel) - default: - continue - } - - if err != nil { - return ctx, err - } - } - - return next(ctx, tx, simulate) -} -``` - -Where `MsgUpdateClient`, `MsgPacket`, `MsgAcknowledgement`, `MsgTimeoutPacket` -are `sdk.Msg` types correspond to `handleUpdateClient`, `handleRecvPacket`, -`handleAcknowledgementPacket`, `handleTimeoutPacket` of the routing module, -respectively. - -The side effects of `RecvPacket`, `VerifyAcknowledgement`, -`VerifyTimeout` will be extracted out into separated functions, -`WriteAcknowledgement`, `DeleteCommitment`, `DeleteCommitmentTimeout`, respectively, -which will be called by the application handlers after the execution. - -`WriteAcknowledgement` writes the acknowledgement to the state that can be -verified by the counter-party chain and increments the sequence to prevent -double execution. `DeleteCommitment` will delete the commitment stored, -`DeleteCommitmentTimeout` will delete the commitment and close channel in case -of ordered channel. - -```go -func (keeper ChannelKeeper) WriteAcknowledgement(ctx Context, packet Packet, ack []byte) { - keeper.SetPacketAcknowledgement(ctx, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), ack) - keeper.SetNextSequenceRecv(ctx, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) -} - -func (keeper ChannelKeeper) DeleteCommitment(ctx Context, packet Packet) { - keeper.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) -} - -func (keeper ChannelKeeper) DeleteCommitmentTimeout(ctx Context, packet Packet) { - k.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - - if channel.Ordering == types.ORDERED [ - channel.State = types.CLOSED - k.SetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), channel) - } -} -``` - -Each application handler should call respective finalization methods on the `PortKeeper` -in order to increase sequence (in case of packet) or remove the commitment -(in case of acknowledgement and timeout). -Calling those functions implies that the application logic has successfully executed. -However, the handlers can return `Result` with `CodeTxBreak` after calling those methods -which will persist the state changes that has been already done but prevent any further -messages to be executed in case of semantically invalid packet. This will keep the sequence -increased in the previous IBC packets(thus preventing double execution) without -proceeding to the following messages. -In any case the application modules should never return state reverting result, -which will make the channel unable to proceed. - -`ChannelKeeper.CheckOpen` method will be introduced. This will replace `onChanOpen*` defined -under the routing module specification. Instead of define each channel handshake callback -functions, application modules can provide `ChannelChecker` function with the `AppModule` -which will be injected to `ChannelKeeper.Port()` at the top level application. -`CheckOpen` will find the correct `ChennelChecker` using the -`PortID` and call it, which will return an error if it is unacceptable by the application. - -The `ProofVerificationDecorator` will be inserted to the top level application. -It is not safe to make each module responsible to call proof verification -logic, whereas application can misbehave(in terms of IBC protocol) by -mistake. - -The `ProofVerificationDecorator` should come right after the default sybil attack -resistent layer from the current `auth.NewAnteHandler`: - -```go -// add IBC ProofVerificationDecorator to the Chain of -func NewAnteHandler( - ak keeper.AccountKeeper, supplyKeeper types.SupplyKeeper, ibcKeeper ibc.Keeper, - sigGasConsumer SignatureVerificationGasConsumer) sdk.AnteHandler { - return sdk.ChainAnteDecorators( - NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first - ... - NewIncrementSequenceDecorator(ak), - ibcante.ProofVerificationDecorator(ibcKeeper.ClientKeeper, ibcKeeper.ChannelKeeper), // innermost AnteDecorator - ) -} -``` - -The implementation of this ADR will also create a `Data` field of the `Packet` of type `[]byte`, which can be deserialised by the receiving module into its own private type. It is up to the application modules to do this according to their own interpretation, not by the IBC keeper. This is crucial for dynamic IBC. - -Example application-side usage: - -```go -type AppModule struct {} - -// CheckChannel will be provided to the ChannelKeeper as ChannelKeeper.Port(module.CheckChannel) -func (module AppModule) CheckChannel(portID, channelID string, channel Channel) error { - if channel.Ordering != UNORDERED { - return ErrUncompatibleOrdering() - } - if channel.CounterpartyPort != "bank" { - return ErrUncompatiblePort() - } - if channel.Version != "" { - return ErrUncompatibleVersion() - } - return nil -} - -func NewHandler(k Keeper) Handler { - return func(ctx Context, msg Msg) Result { - switch msg := msg.(type) { - case MsgTransfer: - return handleMsgTransfer(ctx, k, msg) - case ibc.MsgPacket: - var data PacketDataTransfer - if err := types.ModuleCodec.UnmarshalBinaryBare(msg.GetData(), &data); err != nil { - return err - } - return handlePacketDataTransfer(ctx, k, msg, data) - case ibc.MsgTimeoutPacket: - var data PacketDataTransfer - if err := types.ModuleCodec.UnmarshalBinaryBare(msg.GetData(), &data); err != nil { - return err - } - return handleTimeoutPacketDataTransfer(ctx, k, packet) - // interface { PortID() string; ChannelID() string; Channel() ibc.Channel } - // MsgChanInit, MsgChanTry implements ibc.MsgChannelOpen - case ibc.MsgChannelOpen: - return handleMsgChannelOpen(ctx, k, msg) - } - } -} - -func handleMsgTransfer(ctx Context, k Keeper, msg MsgTransfer) Result { - err := k.SendTransfer(ctx,msg.PortID, msg.ChannelID, msg.Amount, msg.Sender, msg.Receiver) - if err != nil { - return sdk.ResultFromError(err) - } - - return sdk.Result{} -} - -func handlePacketDataTransfer(ctx Context, k Keeper, packet Packet, data PacketDataTransfer) Result { - err := k.ReceiveTransfer(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetDestinationPort(), packet.GetDestinationChannel(), data) - if err != nil { - // TODO: Source chain sent invalid packet, shutdown channel - } - k.ChannelKeeper.WriteAcknowledgement([]byte{0x00}) // WriteAcknowledgement increases the sequence, preventing double spending - return sdk.Result{} -} - -func handleCustomTimeoutPacket(ctx Context, k Keeper, packet CustomPacket) Result { - err := k.RecoverTransfer(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetDestinationPort(), packet.GetDestinationChannel(), data) - if err != nil { - // This chain sent invalid packet or cannot recover the funds - panic(err) - } - k.ChannelKeeper.DeleteCommitmentTimeout(ctx, packet) - // packet timeout should not fail - return sdk.Result{} -} - -func handleMsgChannelOpen(sdk.Context, k Keeper, msg MsgOpenChannel) Result { - k.AllocateEscrowAddress(ctx, msg.ChannelID()) - return sdk.Result{} -} -``` - -## Status - -Proposed - -## Consequences - -### Positive - -- Intuitive interface for developers - IBC handlers do not need to care about IBC authentication -- State change commitment logic is embedded into `baseapp.runTx` logic - -### Negative - -- Cannot support dynamic ports, routing is tied to the baseapp router - -### Neutral - -- Introduces new `AnteHandler` decorator. -- Dynamic ports can be supported using hierarchical port identifier, see #5290 for detail - -## References - -- Relevant comment: [cosmos/ics#289](https://github.com/cosmos/ics/issues/289#issuecomment-544533583) -- [ICS26 - Routing Module](https://github.com/cosmos/ibc/tree/master/spec/core/ics-026-routing-module) diff --git a/docs/architecture/adr-025-ibc-passive-channels.md b/docs/architecture/adr-025-ibc-passive-channels.md deleted file mode 100644 index 35449185a1b..00000000000 --- a/docs/architecture/adr-025-ibc-passive-channels.md +++ /dev/null @@ -1,141 +0,0 @@ -# ADR 025: IBC Passive Channels - -## Changelog - -- 2021-04-23: Change status to "deprecated" -- 2020-05-23: Provide sample Go code and more details -- 2020-05-18: Initial Draft - -## Status - -*deprecated* - -## Context - -The current "naive" IBC Relayer strategy currently establishes a single predetermined IBC channel atop a single connection between two clients (each potentially of a different chain). This strategy then detects packets to be relayed by watching for `send_packet` and `recv_packet` events matching that channel, and sends the necessary transactions to relay those packets. - -We wish to expand this "naive" strategy to a "passive" one which detects and relays both channel handshake messages and packets on a given connection, without the need to know each channel in advance of relaying it. - -In order to accomplish this, we propose adding more comprehensive events to expose channel metadata for each transaction sent from the `x/ibc/core/04-channel/keeper/handshake.go` and `x/ibc/core/04-channel/keeper/packet.go` modules. - -Here is an example of what would be in `ChanOpenInit`: - -```go -const ( - EventTypeChannelMeta = "channel_meta" - AttributeKeyAction = "action" - AttributeKeyHops = "hops" - AttributeKeyOrder = "order" - AttributeKeySrcPort = "src_port" - AttributeKeySrcChannel = "src_channel" - AttributeKeySrcVersion = "src_version" - AttributeKeyDstPort = "dst_port" - AttributeKeyDstChannel = "dst_channel" - AttributeKeyDstVersion = "dst_version" -) -// ... -// Emit Event with Channel metadata for the relayer to pick up and -// relay to the other chain -// This appears immediately before the successful return statement. -ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.EventTypeChannelMeta, - sdk.NewAttribute(types.AttributeKeyAction, "open_init"), - sdk.NewAttribute(types.AttributeKeySrcConnection, connectionHops[0]), - sdk.NewAttribute(types.AttributeKeyHops, strings.Join(connectionHops, ",")), - sdk.NewAttribute(types.AttributeKeyOrder, order.String()), - sdk.NewAttribute(types.AttributeKeySrcPort, portID), - sdk.NewAttribute(types.AttributeKeySrcChannel, chanenlID), - sdk.NewAttribute(types.AttributeKeySrcVersion, version), - sdk.NewAttribute(types.AttributeKeyDstPort, counterparty.GetPortID()), - sdk.NewAttribute(types.AttributeKeyDstChannel, counterparty.GetChannelID()), - // The destination version is not yet known, but a value is necessary to pad - // the event attribute offsets - sdk.NewAttribute(types.AttributeKeyDstVersion, ""), - ), -}) -``` - -These metadata events capture all the "header" information needed to route IBC channel handshake transactions without requiring the client to query any data except that of the connection ID that it is willing to relay. It is intended that `channel_meta.src_connection` is the only event key that needs to be indexed for a passive relayer to function. - -### Handling Channel Open Attempts - -In the case of the passive relayer, when one chain sends a `ChanOpenInit`, the relayer should inform the other chain of this open attempt and allow that chain to decide how (and if) it continues the handshake. Once both chains have actively approved the channel opening, then the rest of the handshake can happen as it does with the current "naive" relayer. - -To implement this behavior, we propose replacing the `cbs.OnChanOpenTry` callback with a new `cbs.OnAttemptChanOpenTry` callback which explicitly handles the `MsgChannelOpenTry`, usually by resulting in a call to `keeper.ChanOpenTry`. The typical implementation, in `x/ibc-transfer/module.go` would be compatible with the current "naive" relayer, as follows: - -```go -func (am AppModule) OnAttemptChanOpenTry( - ctx sdk.Context, - chanKeeper channel.Keeper, - portCap *capability.Capability, - msg channel.MsgChannelOpenTry, -) (*sdk.Result, error) { - // Require portID is the portID transfer module is bound to - boundPort := am.keeper.GetPort(ctx) - if boundPort != msg.PortID { - return nil, sdkerrors.Wrapf(porttypes.ErrInvalidPort, "invalid port: %s, expected %s", msg.PortID, boundPort) - } - - // BEGIN NEW CODE - // Assert our protocol version, overriding the relayer's suggestion. - msg.Version = types.Version - // Continue the ChanOpenTry. - res, chanCap, err := channel.HandleMsgChannelOpenTry(ctx, chanKeeper, portCap, msg) - if err != nil { - return nil, err - } - // END OF NEW CODE - - // ... the rest of the callback is similar to the existing OnChanOpenTry - // but uses msg.* directly. -``` - -Here is how this callback would be used, in the implementation of `x/ibc/handler.go`: - -```go -// ... -case channel.MsgChannelOpenTry: - // Lookup module by port capability - module, portCap, err := k.PortKeeper.LookupModuleByPort(ctx, msg.PortID) - if err != nil { - return nil, sdkerrors.Wrap(err, "could not retrieve module from port-id") - } - // Retrieve callbacks from router - cbs, ok := k.Router.GetRoute(module) - if !ok { - return nil, sdkerrors.Wrapf(port.ErrInvalidRoute, "route not found to module: %s", module) - } - // Delegate to the module's OnAttemptChanOpenTry. - return cbs.OnAttemptChanOpenTry(ctx, k.ChannelKeeper, portCap, msg) -``` - -The reason we do not have a more structured interaction between `x/ibc/handler.go` and the port's module (to explicitly negotiate versions, etc) is that we do not wish to constrain the app module to have to finish handling the `MsgChannelOpenTry` during this transaction or even this block. - -## Decision - -- Expose events to allow "passive" connection relayers. -- Enable application-initiated channels via such passive relayers. -- Allow port modules to control how to handle open-try messages. - -## Consequences - -### Positive - -Makes channels into a complete application-level abstraction. - -Applications have full control over initiating and accepting channels, rather than expecting a relayer to tell them when to do so. - -A passive relayer does not have to know what kind of channel (version string, ordering constraints, firewalling logic) the application supports. These are negotiated directly between applications. - -### Negative - -Increased event size for IBC messages. - -### Neutral - -More IBC events are exposed. - -## References - -- The Agoric VM's IBC handler currently [accomodates `attemptChanOpenTry`](https://github.com/Agoric/agoric-sdk/blob/904b3a0423222a1b32893453e44bbde598473960/packages/cosmic-swingset/lib/ag-solo/vats/ibc.js#L546) diff --git a/docs/architecture/adr-026-ibc-client-recovery-mechanisms.md b/docs/architecture/adr-026-ibc-client-recovery-mechanisms.md deleted file mode 100644 index 05f615a7aaf..00000000000 --- a/docs/architecture/adr-026-ibc-client-recovery-mechanisms.md +++ /dev/null @@ -1,90 +0,0 @@ -# ADR 026: IBC Client Recovery Mechanisms - -## Changelog - -- 2020/06/23: Initial version -- 2020/08/06: Revisions per review & to reference version -- 2021/01/15: Revision to support substitute clients for unfreezing -- 2021/05/20: Revision to simplify consensus state copying, remove initial height -- 2022/04/08: Revision to deprecate AllowUpdateAfterExpiry and AllowUpdateAfterMisbehaviour -- 2022/07/15: Revision to allow updating of TrustingPeriod -- 2023/09/05: Revision to migrate from gov v1beta1 to gov v1 - -## Status - -*Accepted* - -## Context - -### Summary - -At launch, IBC will be a novel protocol, without an experienced user-base. At the protocol layer, it is not possible to distinguish between client expiry or misbehaviour due to genuine faults (Byzantine behavior) and client expiry or misbehaviour due to user mistakes (failing to update a client, or accidentally double-signing). In the base IBC protocol and ICS 20 fungible token transfer implementation, if a client can no longer be updated, funds in that channel will be permanently locked and can no longer be transferred. To the degree that it is safe to do so, it would be preferable to provide users with a recovery mechanism which can be utilised in these exceptional cases. - -### Exceptional cases - -The state of concern is where a client associated with connection(s) and channel(s) can no longer be updated. This can happen for several reasons: - -1. The chain which the client is following has halted and is no longer producing blocks/headers, so no updates can be made to the client -1. The chain which the client is following has continued to operate, but no relayer has submitted a new header within the unbonding period, and the client has expired - 1. This could be due to real misbehaviour (intentional Byzantine behaviour) or merely a mistake by validators, but the client cannot distinguish these two cases -1. The chain which the client is following has experienced a misbehaviour event, and the client has been frozen & thus can no longer be updated - -### Security model - -Two-thirds of the validator set (the quorum for governance, module participation) can already sign arbitrary data, so allowing governance to manually force-update a client with a new header after a delay period does not substantially alter the security model. - -## Decision - -We elect not to deal with chains which have actually halted, which is necessarily Byzantine behaviour and in which case token recovery is not likely possible anyways (in-flight packets cannot be timed-out, but the relative impact of that is minor). - -1. Require Tendermint light clients (ICS 07) to be created with the following additional flags - 1. `allow_update_after_expiry` (boolean, default true). Note that this flag has been deprecated, it remains to signal intent but checks against this value will not be enforced. -1. Require Tendermint light clients (ICS 07) to expose the following additional internal query functions - 1. `Expired() boolean`, which returns whether or not the client has passed the trusting period since the last update (in which case no headers can be validated) -1. Require Tendermint light clients (ICS 07) & solo machine clients (ICS 06) to be created with the following additional flags - 1. `allow_update_after_misbehaviour` (boolean, default true). Note that this flag has been deprecated, it remains to signal intent but checks against this value will not be enforced. -1. Require Tendermint light clients (ICS 07) to expose the following additional state mutation functions - 1. `Unfreeze()`, which unfreezes a light client after misbehaviour and clears any frozen height previously set -1. Add a new governance proposal with `MsgRecoverClient`. - 1. Create a new Msg with two client identifiers (`string`) and a signer. - 1. The first client identifier is the proposed client to be updated. This client must be either frozen or expired. - 1. The second client is a substitute client. It carries all the state for the client which may be updated. It must have identitical client and chain parameters to the client which may be updated (except for latest height, frozen height, and chain-id). It should be continually updated during the voting period. - 1. If this governance proposal passes, the client on trial will be updated to the latest state of the substitute. - 1. The signer must be the authority set for the ibc module. - - Previously, `AllowUpdateAfterExpiry` and `AllowUpdateAfterMisbehaviour` were used to signal the recovery options for an expired or frozen client, and governance proposals were not allowed to overwrite the client if these parameters were set to false. However, this has now been deprecated because a code migration can overwrite the client and consensus states regardless of the value of these parameters. If governance would vote to overwrite a client or consensus state, it is likely that governance would also be willing to perform a code migration to do the same. - - In addition, `TrustingPeriod` was initally not allowed to be updated by a client upgrade proposal. However, due to the number of situations experienced in production where the `TrustingPeriod` of a client should be allowed to be updated because of ie: initial misconfiguration for a canonical channel, governance should be allowed to update this client parameter. - - In versions older than ibc-go v8, `MsgRecoverClient` was a governance proposal type `ClientUpdateProposal`. It has been removed and replaced by `MsgRecoverClient` in the migration from governance v1beta1 to governance v1. - - Note that this should NOT be lightly updated, as there may be a gap in time between when misbehaviour has occured and when the evidence of misbehaviour is submitted. For example, if the `UnbondingPeriod` is 2 weeks and the `TrustingPeriod` has also been set to two weeks, a validator could wait until right before `UnbondingPeriod` finishes, submit false information, then unbond and exit without being slashed for misbehaviour. Therefore, we recommend that the trusting period for the 07-tendermint client be set to 2/3 of the `UnbondingPeriod`. - -Note that clients frozen due to misbehaviour must wait for the evidence to expire to avoid becoming refrozen. - -This ADR does not address planned upgrades, which are handled separately as per the [specification](https://github.com/cosmos/ibc/tree/master/spec/client/ics-007-tendermint-client#upgrades). - -## Consequences - -### Positive - -- Establishes a mechanism for client recovery in the case of expiry -- Establishes a mechanism for client recovery in the case of misbehaviour -- Constructing an ClientUpdate Proposal is as difficult as creating a new client - -### Negative - -- Additional complexity in client creation which must be understood by the user -- Coping state of the substitute adds complexity -- Governance participants must vote on a substitute client - -### Neutral - -No neutral consequences. - -## References - -- [Prior discussion](https://github.com/cosmos/ics/issues/421) -- [Epoch number discussion](https://github.com/cosmos/ics/issues/439) -- [Upgrade plan discussion](https://github.com/cosmos/ics/issues/445) -- [Migration from gov v1beta1 to gov v1](https://github.com/cosmos/ibc-go/issues/3672) diff --git a/docs/architecture/adr-027-ibc-wasm.md b/docs/architecture/adr-027-ibc-wasm.md deleted file mode 100644 index 26ba89a1d77..00000000000 --- a/docs/architecture/adr-027-ibc-wasm.md +++ /dev/null @@ -1,179 +0,0 @@ -# ADR 27: Add support for Wasm based light client - -## Changelog - -- 26/11/2020: Initial Draft -- 26/05/2023: Update after 02-client refactor and re-implementation by Strangelove - -## Status - -*Draft, needs updates* - -## Abstract - -In the Cosmos SDK light clients are current hardcoded in Go. This makes upgrading existing IBC light clients or -adding support for new light client a multi step process involving on-chain governance which is time-consuming. - -To remedy this, we are proposing a Wasm VM to host light client bytecode, which allows easier upgrading of -existing IBC light clients as well as adding support for new IBC light clients without requiring a code release and -corresponding hard-fork event. - -## Context - -Currently in ibc-go light clients are defined as part of the codebase and are implemented as modules under -`modules/light-clients`. Adding support for new light clients or updating an existing light client in the event -of a security issue or consensus update is a multi-step process which is both time consuming and error prone. -In order to enable new IBC light client implementations it is necessary to modify the codebase of ibc-go, -re-build chains' binaries, pass a governance proposal and validators upgrade their nodes. - -Another problem stemming from the above process is that if a chain wants to upgrade its own consensus, it will -need to convince every chain or hub connected to it to upgrade its light client in order to stay connected. Due -to the time consuming process required to upgrade a light client, a chain with lots of connections needs to be -disconnected for quite some time after upgrading its consensus, which can be very expensive in terms of time and effort. - -We are proposing simplifying this workflow by integrating a Wasm light client module that makes adding support for -new light clients a simple governance-gated transaction. The light client bytecode, written in Wasm-compilable Rust, -runs inside a Wasm VM. The Wasm light client submodule exposes a proxy light client interface that routes incoming -messages to the appropriate handler function, inside the Wasm VM for execution. - -With the Wasm light client module, anybody can add new IBC light client in the form of Wasm bytecode (provided they are -able to submit the governance proposal transaction and that it passes) as well as instantiate clients using any created -client type. This allows any chain to update its own light client in other chains without going through the steps outlined above. - -## Decision - -We decided to implement the Wasm light client module as a light client proxy that will interface with the actual light client -uploaded as Wasm bytecode. To enable usage of the Wasm light client module, users need to add it to the list of allowed clients -by updating the `AllowedClients` parameter in the 02-client submodule of core IBC. - -```go -params := clientKeeper.GetParams(ctx) -params.AllowedClients = append(params.AllowedClients, exported.Wasm) -clientKeeper.SetParams(ctx, params) -``` - -Adding a new light client contract is governance-gated. To upload a new light client users need to submit -a [governance v1 proposal](https://docs.cosmos.network/main/modules/gov#proposals) that contains the `sdk.Msg` for storing -the Wasm contract's bytecode. The required message is `MsgStoreCode` and the bytecode is provided in the field `code`: - -```proto -// MsgStoreCode defines the request type for the StoreCode rpc. -message MsgStoreCode { - string signer = 1; - bytes code = 2; -} -``` - -The RPC handler processing `MsgStoreCode` will make sure that the signer of the message matches the address of authority allowed to -submit this message (which is normally the address of the governance module). - -```go -// StoreCode defines a rpc handler method for MsgStoreCode -func (k Keeper) StoreCode(goCtx context.Context, msg *types.MsgStoreCode) (*types.MsgStoreCodeResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - if k.authority != msg.Signer { - return nil, sdkerrors.Wrapf(govtypes.ErrInvalidSigner, "invalid authority: expected %s, got %s", k.authority, msg.Signer) - } - - codeHash, err := k.storeWasmCode(ctx, msg.Code) - if err != nil { - return nil, sdkerrors.Wrap(err, "storing wasm code failed") - } - - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - clienttypes.EventTypeStoreWasmCode, - sdk.NewAttribute(clienttypes.AttributeKeyWasmCodeHash, hex.EncodeToString(codeHash)), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, clienttypes.AttributeValueCategory), - ), - }) - - return &types.MsgStoreCodeResponse{ - CodeHash: codeHash, - }, nil -} -``` - -The contract's bytecode is stored in state in an entry indexed by the code hash: `codeHash/{code hash}`. The code hash is simply -the hash of the bytecode of the contract. - -### How light client proxy works? - -The light client proxy behind the scenes will call a CosmWasm smart contract instance with incoming arguments serialized -in JSON format with appropriate environment information. Data returned by the smart contract is deserialized and -returned to the caller. - -Consider the example of the `VerifyClientMessage` function of `ClientState` interface. Incoming arguments are -packaged inside a payload object that is then JSON serialized and passed to `callContract`, which execute `WasmVm.Execute` -and returns the slice of bytes returned by the smart contract. This data is deserialized and passed as return argument. - -```go -type ( - verifyClientMessageInnerPayload struct { - ClientMessage clientMessage `json:"client_message"` - } - clientMessage struct { - Header *Header `json:"header,omitempty"` - Misbehaviour *Misbehaviour `json:"misbehaviour,omitempty"` - } - verifyClientMessagePayload struct { - VerifyClientMessage verifyClientMessageInnerPayload `json:"verify_client_message"` - } -) - -// VerifyClientMessage must verify a ClientMessage. A ClientMessage could be a Header, Misbehaviour, or batch update. -// It must handle each type of ClientMessage appropriately. Calls to CheckForMisbehaviour, UpdateState, and UpdateStateOnMisbehaviour -// will assume that the content of the ClientMessage has been verified and can be trusted. An error should be returned -// if the ClientMessage fails to verify. -func (cs ClientState) VerifyClientMessage( - ctx sdk.Context, - _ codec.BinaryCodec, - clientStore sdk.KVStore, - clientMsg exported.ClientMessage -) error { - clientMsgConcrete := clientMessage{ - Header: nil, - Misbehaviour: nil, - } - switch clientMsg := clientMsg.(type) { - case *Header: - clientMsgConcrete.Header = clientMsg - case *Misbehaviour: - clientMsgConcrete.Misbehaviour = clientMsg - } - inner := verifyClientMessageInnerPayload{ - ClientMessage: clientMsgConcrete, - } - payload := verifyClientMessagePayload{ - VerifyClientMessage: inner, - } - _, err := call[contractResult](ctx, clientStore, &cs, payload) - return err -} -``` - -### Global Wasm VM variable - -The 08-wasm keeper structure keeps a reference to the Wasm VM instantiated in the keeper constructor function. The keeper uses -the Wasm VM to store the bytecode of light client contracts. However, the Wasm VM is also needed in the 08-wasm implementations of -some of the `ClientState` interface functions to initialise a contract, execute calls on the contract and query the contract. Since -the `ClientState` functions do not have access to the 08-wasm keeper, then it has been decided to keep a global pointer variable that -points to the same instance as the one in the 08-wasm keeper. This global pointer variable is then used in the implementations of -the `ClientState` functions. - -## Consequences - -### Positive - -- Adding support for new light client or upgrading existing light client is way easier than before and only requires single transaction instead of a hard-fork. -- Improves maintainability of ibc-go, since no change in codebase is required to support new client or upgrade it. -- The existence of support for Rust dependencies in light clients which may not exist in Go. - -### Negative - -- Light clients written in Rust need to be written in a subset of Rust which could compile in Wasm. -- Introspecting light client code is difficult as only compiled bytecode exists in the blockchain. diff --git a/docs/architecture/adr.template.md b/docs/architecture/adr.template.md deleted file mode 100644 index 7081756339c..00000000000 --- a/docs/architecture/adr.template.md +++ /dev/null @@ -1,38 +0,0 @@ -# ADR {ADR-NUMBER}: {TITLE} - -## Changelog - -- {date}: {changelog} - -## Status - -> A decision may be "proposed" if it hasn't been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement. - -{Deprecated|Proposed|Accepted} - -## Context - -> This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution. - -## Decision - -> This section explains all of the details of the proposed solution, including implementation details. -It should also describe affects / corollary items that may need to be changed as a part of this. -If the proposed change will be large, please also indicate a way to do the change to maximize ease of review. -(e.g. the optimal split of things to do between separate PR's) - -## Consequences - -> This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones. - -### Positive - -### Negative - -### Neutral - -## References - -> Are there any relevant PR comments, issues that led up to this, or articles referrenced for why we made the given design choice? If so link them here! - -- {reference link} diff --git a/docs/audits/Trail of Bits audit - Final Report.pdf b/docs/audits/Trail of Bits audit - Final Report.pdf deleted file mode 100644 index 3f6182e4e98..00000000000 Binary files a/docs/audits/Trail of Bits audit - Final Report.pdf and /dev/null differ diff --git a/docs/babel.config.js b/docs/babel.config.js deleted file mode 100644 index e00595dae7d..00000000000 --- a/docs/babel.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: [require.resolve('@docusaurus/core/lib/babel/preset')], -}; diff --git a/docs/client/config.json b/docs/client/config.json deleted file mode 100644 index 5c9b23da836..00000000000 --- a/docs/client/config.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "IBC-GO - gRPC Gateway docs", - "description": "A REST interface for state queries", - "version": "1.0.0" - }, - "apis": [ - { - "url": "./tmp-swagger-gen/ibc/applications/transfer/v1/query.swagger.json", - "operationIds": { - "rename": { - "Params": "TransferParams" - } - } - }, - { - "url": "./tmp-swagger-gen/ibc/applications/interchain_accounts/controller/v1/query.swagger.json", - "operationIds": { - "rename": { - "Params": "InterchainAccountsControllerParams" - } - } - }, - { - "url": "./tmp-swagger-gen/ibc/applications/interchain_accounts/host/v1/query.swagger.json", - "operationIds": { - "rename": { - "Params": "InterchainAccountsHostParams" - } - } - }, - { - "url": "./tmp-swagger-gen/ibc/applications/fee/v1/query.swagger.json", - "operationIds": { - "rename": { - "Params": "FeeParams" - } - } - }, - { - "url": "./tmp-swagger-gen/ibc/core/client/v1/query.swagger.json", - "operationIds": { - "rename": { - "Params": "ClientParams" - } - } - }, - { - "url": "./tmp-swagger-gen/ibc/core/connection/v1/query.swagger.json", - "operationIds": { - "rename": { - "Params": "ConnectionParams" - } - } - }, - { - "url": "./tmp-swagger-gen/ibc/core/channel/v1/query.swagger.json", - "operationIds": { - "rename": { - "Params": "ChannelParams" - } - } - }, - { - "url": "./tmp-swagger-gen/ibc/lightclients/wasm/v1/query.swagger.json", - "operationIds": { - "rename": { - "Params": "WasmParams" - } - } - } - ] -} diff --git a/docs/client/swagger-ui/swagger.yaml b/docs/client/swagger-ui/swagger.yaml deleted file mode 100644 index 96bfc103015..00000000000 --- a/docs/client/swagger-ui/swagger.yaml +++ /dev/null @@ -1,21393 +0,0 @@ -swagger: '2.0' -info: - title: IBC-GO - gRPC Gateway docs - description: A REST interface for state queries - version: 1.0.0 -paths: - /ibc/apps/transfer/v1/channels/{channel_id}/ports/{port_id}/escrow_address: - get: - summary: >- - EscrowAddress returns the escrow address for a particular port and - channel id. - operationId: EscrowAddress - responses: - '200': - description: A successful response. - schema: - type: object - properties: - escrow_address: - type: string - title: the escrow account address - description: >- - QueryEscrowAddressResponse is the response type of the - EscrowAddress RPC method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: channel_id - description: unique channel identifier - in: path - required: true - type: string - - name: port_id - description: unique port identifier - in: path - required: true - type: string - tags: - - Query - /ibc/apps/transfer/v1/denom_hashes/{trace}: - get: - summary: DenomHash queries a denomination hash information. - operationId: DenomHash - responses: - '200': - description: A successful response. - schema: - type: object - properties: - hash: - type: string - description: hash (in hex format) of the denomination trace information. - description: >- - QueryDenomHashResponse is the response type for the - Query/DenomHash RPC - - method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: trace - description: The denomination trace ([port_id]/[channel_id])+/[denom] - in: path - required: true - type: string - tags: - - Query - /ibc/apps/transfer/v1/denom_traces: - get: - summary: DenomTraces queries all denomination traces. - operationId: DenomTraces - responses: - '200': - description: A successful response. - schema: - type: object - properties: - denom_traces: - type: array - items: - type: object - properties: - path: - type: string - description: >- - path defines the chain of port/channel identifiers used - for tracing the - - source of the fungible token. - base_denom: - type: string - description: base denomination of the relayed fungible token. - description: >- - DenomTrace contains the base denomination for ICS20 fungible - tokens and the - - source tracing information path. - description: denom_traces returns all denominations trace information. - pagination: - description: pagination defines the pagination in the response. - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: >- - QueryConnectionsResponse is the response type for the - Query/DenomTraces RPC - - method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false - type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false - type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - - name: pagination.reverse - description: >- - reverse is set to true if results are to be returned in the - descending order. - - - Since: cosmos-sdk 0.43 - in: query - required: false - type: boolean - tags: - - Query - /ibc/apps/transfer/v1/denom_traces/{hash}: - get: - summary: DenomTrace queries a denomination trace information. - operationId: DenomTrace - responses: - '200': - description: A successful response. - schema: - type: object - properties: - denom_trace: - type: object - properties: - path: - type: string - description: >- - path defines the chain of port/channel identifiers used - for tracing the - - source of the fungible token. - base_denom: - type: string - description: base denomination of the relayed fungible token. - description: >- - DenomTrace contains the base denomination for ICS20 fungible - tokens and the - - source tracing information path. - description: >- - QueryDenomTraceResponse is the response type for the - Query/DenomTrace RPC - - method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: hash - description: >- - hash (in hex format) or denom (full denom with ibc prefix) of the - denomination trace information. - in: path - required: true - type: string - tags: - - Query - /ibc/apps/transfer/v1/denoms/{denom}/total_escrow: - get: - summary: >- - TotalEscrowForDenom returns the total amount of tokens in escrow based - on the denom. - operationId: TotalEscrowForDenom - responses: - '200': - description: A successful response. - schema: - type: object - properties: - amount: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. - - - NOTE: The amount field is an Int which implements the custom - method - - signatures required by gogoproto. - description: >- - QueryTotalEscrowForDenomResponse is the response type for - TotalEscrowForDenom RPC method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: denom - in: path - required: true - type: string - tags: - - Query - /ibc/apps/transfer/v1/params: - get: - summary: Params queries all parameters of the ibc-transfer module. - operationId: TransferParams - responses: - '200': - description: A successful response. - schema: - type: object - properties: - params: - description: params defines the parameters of the module. - type: object - properties: - send_enabled: - type: boolean - description: >- - send_enabled enables or disables all cross-chain token - transfers from this - - chain. - receive_enabled: - type: boolean - description: >- - receive_enabled enables or disables all cross-chain token - transfers to this - - chain. - description: >- - QueryParamsResponse is the response type for the Query/Params RPC - method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - tags: - - Query - /ibc/apps/interchain_accounts/controller/v1/owners/{owner}/connections/{connection_id}: - get: - summary: >- - InterchainAccount returns the interchain account address for a given - owner address on a given connection - operationId: InterchainAccount - responses: - '200': - description: A successful response. - schema: - type: object - properties: - address: - type: string - description: >- - QueryInterchainAccountResponse the response type for the - Query/InterchainAccount RPC method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: owner - in: path - required: true - type: string - - name: connection_id - in: path - required: true - type: string - tags: - - Query - /ibc/apps/interchain_accounts/controller/v1/params: - get: - summary: Params queries all parameters of the ICA controller submodule. - operationId: InterchainAccountsControllerParams - responses: - '200': - description: A successful response. - schema: - type: object - properties: - params: - description: params defines the parameters of the module. - type: object - properties: - controller_enabled: - type: boolean - description: >- - controller_enabled enables or disables the controller - submodule. - description: >- - QueryParamsResponse is the response type for the Query/Params RPC - method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - tags: - - Query - /ibc/apps/interchain_accounts/host/v1/params: - get: - summary: Params queries all parameters of the ICA host submodule. - operationId: InterchainAccountsHostParams - responses: - '200': - description: A successful response. - schema: - type: object - properties: - params: - description: params defines the parameters of the module. - type: object - properties: - host_enabled: - type: boolean - description: host_enabled enables or disables the host submodule. - allow_messages: - type: array - items: - type: string - description: >- - allow_messages defines a list of sdk message typeURLs - allowed to be executed on a host chain. - description: >- - QueryParamsResponse is the response type for the Query/Params RPC - method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - tags: - - Query - /ibc/apps/fee/v1/channels/{channel_id}/ports/{port_id}/fee_enabled: - get: - summary: >- - FeeEnabledChannel returns true if the provided port and channel - identifiers belong to a fee enabled channel - operationId: FeeEnabledChannel - responses: - '200': - description: A successful response. - schema: - type: object - properties: - fee_enabled: - type: boolean - title: boolean flag representing the fee enabled channel status - title: >- - QueryFeeEnabledChannelResponse defines the response type for the - FeeEnabledChannel rpc - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: channel_id - description: unique channel identifier - in: path - required: true - type: string - - name: port_id - description: unique port identifier - in: path - required: true - type: string - tags: - - Query - /ibc/apps/fee/v1/channels/{channel_id}/ports/{port_id}/incentivized_packets: - get: - summary: Gets all incentivized packets for a specific channel - operationId: IncentivizedPacketsForChannel - responses: - '200': - description: A successful response. - schema: - type: object - properties: - incentivized_packets: - type: array - items: - type: object - properties: - packet_id: - title: >- - unique packet identifier comprised of the channel ID, - port ID and sequence - type: object - properties: - port_id: - type: string - title: channel port identifier - channel_id: - type: string - title: channel unique identifier - sequence: - type: string - format: uint64 - title: packet sequence - packet_fees: - type: array - items: - type: object - properties: - fee: - title: >- - fee encapsulates the recv, ack and timeout fees - associated with an IBC packet - type: object - properties: - recv_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and - an amount. - - - NOTE: The amount field is an Int which - implements the custom method - - signatures required by gogoproto. - title: the packet receive fee - ack_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and - an amount. - - - NOTE: The amount field is an Int which - implements the custom method - - signatures required by gogoproto. - title: the packet acknowledgement fee - timeout_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and - an amount. - - - NOTE: The amount field is an Int which - implements the custom method - - signatures required by gogoproto. - title: the packet timeout fee - refund_address: - type: string - title: the refund address for unspent fees - relayers: - type: array - items: - type: string - title: >- - optional list of relayers permitted to receive - fees - title: >- - PacketFee contains ICS29 relayer fees, refund address - and optional list of permitted relayers - title: list of packet fees - title: >- - IdentifiedPacketFees contains a list of type PacketFee and - associated PacketId - title: Map of all incentivized_packets - pagination: - description: pagination defines the pagination in the response. - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - title: >- - QueryIncentivizedPacketsResponse defines the response type for the - incentivized packets RPC - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: channel_id - in: path - required: true - type: string - - name: port_id - in: path - required: true - type: string - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false - type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false - type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - - name: pagination.reverse - description: >- - reverse is set to true if results are to be returned in the - descending order. - - - Since: cosmos-sdk 0.43 - in: query - required: false - type: boolean - - name: query_height - description: Height to query at. - in: query - required: false - type: string - format: uint64 - tags: - - Query - /ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer}/counterparty_payee: - get: - summary: >- - CounterpartyPayee returns the registered counterparty payee for forward - relaying - operationId: CounterpartyPayee - responses: - '200': - description: A successful response. - schema: - type: object - properties: - counterparty_payee: - type: string - title: >- - the counterparty payee address used to compensate forward - relaying - title: >- - QueryCounterpartyPayeeResponse defines the response type for the - CounterpartyPayee rpc - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: channel_id - description: unique channel identifier - in: path - required: true - type: string - - name: relayer - description: the relayer address to which the counterparty is registered - in: path - required: true - type: string - tags: - - Query - /ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer}/payee: - get: - summary: >- - Payee returns the registered payee address for a specific channel given - the relayer address - operationId: Payee - responses: - '200': - description: A successful response. - schema: - type: object - properties: - payee_address: - type: string - title: the payee address to which packet fees are paid out - title: QueryPayeeResponse defines the response type for the Payee rpc - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: channel_id - description: unique channel identifier - in: path - required: true - type: string - - name: relayer - description: the relayer address to which the distribution address is registered - in: path - required: true - type: string - tags: - - Query - /ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/incentivized_packet: - get: - summary: >- - IncentivizedPacket returns all packet fees for a packet given its - identifier - operationId: IncentivizedPacket - responses: - '200': - description: A successful response. - schema: - type: object - properties: - incentivized_packet: - type: object - properties: - packet_id: - title: >- - unique packet identifier comprised of the channel ID, port - ID and sequence - type: object - properties: - port_id: - type: string - title: channel port identifier - channel_id: - type: string - title: channel unique identifier - sequence: - type: string - format: uint64 - title: packet sequence - packet_fees: - type: array - items: - type: object - properties: - fee: - title: >- - fee encapsulates the recv, ack and timeout fees - associated with an IBC packet - type: object - properties: - recv_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and - an amount. - - - NOTE: The amount field is an Int which - implements the custom method - - signatures required by gogoproto. - title: the packet receive fee - ack_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and - an amount. - - - NOTE: The amount field is an Int which - implements the custom method - - signatures required by gogoproto. - title: the packet acknowledgement fee - timeout_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and - an amount. - - - NOTE: The amount field is an Int which - implements the custom method - - signatures required by gogoproto. - title: the packet timeout fee - refund_address: - type: string - title: the refund address for unspent fees - relayers: - type: array - items: - type: string - title: optional list of relayers permitted to receive fees - title: >- - PacketFee contains ICS29 relayer fees, refund address - and optional list of permitted relayers - title: list of packet fees - title: >- - IdentifiedPacketFees contains a list of type PacketFee and - associated PacketId - title: >- - QueryIncentivizedPacketsResponse defines the response type for the - IncentivizedPacket rpc - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: packet_id.channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: packet_id.port_id - description: channel port identifier - in: path - required: true - type: string - - name: packet_id.sequence - description: packet sequence - in: path - required: true - type: string - format: uint64 - - name: query_height - description: block height at which to query. - in: query - required: false - type: string - format: uint64 - tags: - - Query - /ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/total_ack_fees: - get: - summary: >- - TotalAckFees returns the total acknowledgement fees for a packet given - its identifier - operationId: TotalAckFees - responses: - '200': - description: A successful response. - schema: - type: object - properties: - ack_fees: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. - - - NOTE: The amount field is an Int which implements the custom - method - - signatures required by gogoproto. - title: the total packet acknowledgement fees - title: >- - QueryTotalAckFeesResponse defines the response type for the - TotalAckFees rpc - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: packet_id.channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: packet_id.port_id - description: channel port identifier - in: path - required: true - type: string - - name: packet_id.sequence - description: packet sequence - in: path - required: true - type: string - format: uint64 - tags: - - Query - /ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/total_recv_fees: - get: - summary: >- - TotalRecvFees returns the total receive fees for a packet given its - identifier - operationId: TotalRecvFees - responses: - '200': - description: A successful response. - schema: - type: object - properties: - recv_fees: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. - - - NOTE: The amount field is an Int which implements the custom - method - - signatures required by gogoproto. - title: the total packet receive fees - title: >- - QueryTotalRecvFeesResponse defines the response type for the - TotalRecvFees rpc - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: packet_id.channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: packet_id.port_id - description: channel port identifier - in: path - required: true - type: string - - name: packet_id.sequence - description: packet sequence - in: path - required: true - type: string - format: uint64 - tags: - - Query - /ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/total_timeout_fees: - get: - summary: >- - TotalTimeoutFees returns the total timeout fees for a packet given its - identifier - operationId: TotalTimeoutFees - responses: - '200': - description: A successful response. - schema: - type: object - properties: - timeout_fees: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. - - - NOTE: The amount field is an Int which implements the custom - method - - signatures required by gogoproto. - title: the total packet timeout fees - title: >- - QueryTotalTimeoutFeesResponse defines the response type for the - TotalTimeoutFees rpc - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: packet_id.channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: packet_id.port_id - description: channel port identifier - in: path - required: true - type: string - - name: packet_id.sequence - description: packet sequence - in: path - required: true - type: string - format: uint64 - tags: - - Query - /ibc/apps/fee/v1/fee_enabled: - get: - summary: FeeEnabledChannels returns a list of all fee enabled channels - operationId: FeeEnabledChannels - responses: - '200': - description: A successful response. - schema: - type: object - properties: - fee_enabled_channels: - type: array - items: - type: object - properties: - port_id: - type: string - title: unique port identifier - channel_id: - type: string - title: unique channel identifier - title: >- - FeeEnabledChannel contains the PortID & ChannelID for a fee - enabled channel - title: list of fee enabled channels - pagination: - description: pagination defines the pagination in the response. - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - title: >- - QueryFeeEnabledChannelsResponse defines the response type for the - FeeEnabledChannels rpc - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false - type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false - type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - - name: pagination.reverse - description: >- - reverse is set to true if results are to be returned in the - descending order. - - - Since: cosmos-sdk 0.43 - in: query - required: false - type: boolean - - name: query_height - description: block height at which to query. - in: query - required: false - type: string - format: uint64 - tags: - - Query - /ibc/apps/fee/v1/incentivized_packets: - get: - summary: >- - IncentivizedPackets returns all incentivized packets and their - associated fees - operationId: IncentivizedPackets - responses: - '200': - description: A successful response. - schema: - type: object - properties: - incentivized_packets: - type: array - items: - type: object - properties: - packet_id: - title: >- - unique packet identifier comprised of the channel ID, - port ID and sequence - type: object - properties: - port_id: - type: string - title: channel port identifier - channel_id: - type: string - title: channel unique identifier - sequence: - type: string - format: uint64 - title: packet sequence - packet_fees: - type: array - items: - type: object - properties: - fee: - title: >- - fee encapsulates the recv, ack and timeout fees - associated with an IBC packet - type: object - properties: - recv_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and - an amount. - - - NOTE: The amount field is an Int which - implements the custom method - - signatures required by gogoproto. - title: the packet receive fee - ack_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and - an amount. - - - NOTE: The amount field is an Int which - implements the custom method - - signatures required by gogoproto. - title: the packet acknowledgement fee - timeout_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and - an amount. - - - NOTE: The amount field is an Int which - implements the custom method - - signatures required by gogoproto. - title: the packet timeout fee - refund_address: - type: string - title: the refund address for unspent fees - relayers: - type: array - items: - type: string - title: >- - optional list of relayers permitted to receive - fees - title: >- - PacketFee contains ICS29 relayer fees, refund address - and optional list of permitted relayers - title: list of packet fees - title: >- - IdentifiedPacketFees contains a list of type PacketFee and - associated PacketId - title: list of identified fees for incentivized packets - pagination: - description: pagination defines the pagination in the response. - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - title: >- - QueryIncentivizedPacketsResponse defines the response type for the - IncentivizedPackets rpc - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false - type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false - type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - - name: pagination.reverse - description: >- - reverse is set to true if results are to be returned in the - descending order. - - - Since: cosmos-sdk 0.43 - in: query - required: false - type: boolean - - name: query_height - description: block height at which to query. - in: query - required: false - type: string - format: uint64 - tags: - - Query - /ibc/core/client/v1/client_states: - get: - summary: ClientStates queries all the IBC light clients of a chain. - operationId: ClientStates - responses: - '200': - description: A successful response. - schema: - type: object - properties: - client_states: - type: array - items: - type: object - properties: - client_id: - type: string - title: client identifier - client_state: - title: client state - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the - type of the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's - path must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be - in a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the - binary all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can - optionally set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results - based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available - in the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty - scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the - above specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any - values in the form - - of utility functions or additional generated methods of - the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and - the unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will - yield type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the - regular - - representation of the deserialized, embedded message, - with an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a - custom JSON - - representation, that representation will be embedded - adding a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message - [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - description: >- - IdentifiedClientState defines a client state with an - additional client - - identifier field. - description: list of stored ClientStates of the chain. - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: >- - PageResponse is to be embedded in gRPC response messages where - the - - corresponding request message has used PageRequest. - - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - description: >- - QueryClientStatesResponse is the response type for the - Query/ClientStates RPC - - method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false - type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false - type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - - name: pagination.reverse - description: >- - reverse is set to true if results are to be returned in the - descending order. - - - Since: cosmos-sdk 0.43 - in: query - required: false - type: boolean - tags: - - Query - /ibc/core/client/v1/client_states/{client_id}: - get: - summary: ClientState queries an IBC light client. - operationId: ClientState - responses: - '200': - description: A successful response. - schema: - type: object - properties: - client_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all - types that they - - expect it to use in the context of Any. However, for URLs - which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message - along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in - the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default - use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the last - '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding a - field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: client state associated with the request identifier - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - description: >- - QueryClientStateResponse is the response type for the - Query/ClientState RPC - - method. Besides the client state, it includes a proof and the - height from - - which the proof was retrieved. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: client_id - description: client state unique identifier - in: path - required: true - type: string - tags: - - Query - /ibc/core/client/v1/client_status/{client_id}: - get: - summary: Status queries the status of an IBC client. - operationId: ClientStatus - responses: - '200': - description: A successful response. - schema: - type: object - properties: - status: - type: string - description: >- - QueryClientStatusResponse is the response type for the - Query/ClientStatus RPC - - method. It returns the current status of the IBC client. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: client_id - description: client unique identifier - in: path - required: true - type: string - tags: - - Query - /ibc/core/client/v1/consensus_states/{client_id}: - get: - summary: |- - ConsensusStates queries all the consensus state associated with a given - client. - operationId: ConsensusStates - responses: - '200': - description: A successful response. - schema: - type: object - properties: - consensus_states: - type: array - items: - type: object - properties: - height: - title: consensus state height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each - height while keeping - - RevisionNumber the same. However some consensus - algorithms may choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as - the RevisionHeight - - gets reset - consensus_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the - type of the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's - path must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be - in a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the - binary all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can - optionally set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results - based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available - in the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty - scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the - above specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any - values in the form - - of utility functions or additional generated methods of - the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and - the unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will - yield type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the - regular - - representation of the deserialized, embedded message, - with an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a - custom JSON - - representation, that representation will be embedded - adding a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message - [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: consensus state - description: >- - ConsensusStateWithHeight defines a consensus state with an - additional height - - field. - title: consensus states associated with the identifier - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: >- - PageResponse is to be embedded in gRPC response messages where - the - - corresponding request message has used PageRequest. - - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - title: |- - QueryConsensusStatesResponse is the response type for the - Query/ConsensusStates RPC method - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: client_id - description: client identifier - in: path - required: true - type: string - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false - type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false - type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - - name: pagination.reverse - description: >- - reverse is set to true if results are to be returned in the - descending order. - - - Since: cosmos-sdk 0.43 - in: query - required: false - type: boolean - tags: - - Query - /ibc/core/client/v1/consensus_states/{client_id}/heights: - get: - summary: >- - ConsensusStateHeights queries the height of every consensus states - associated with a given client. - operationId: ConsensusStateHeights - responses: - '200': - description: A successful response. - schema: - type: object - properties: - consensus_state_heights: - type: array - items: - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms - may choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: >- - Height is a monotonically increasing data type - - that can be compared against another Height for the purposes - of updating and - - freezing clients - title: consensus state heights - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: >- - PageResponse is to be embedded in gRPC response messages where - the - - corresponding request message has used PageRequest. - - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - title: |- - QueryConsensusStateHeightsResponse is the response type for the - Query/ConsensusStateHeights RPC method - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: client_id - description: client identifier - in: path - required: true - type: string - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false - type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false - type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - - name: pagination.reverse - description: >- - reverse is set to true if results are to be returned in the - descending order. - - - Since: cosmos-sdk 0.43 - in: query - required: false - type: boolean - tags: - - Query - /ibc/core/client/v1/consensus_states/{client_id}/revision/{revision_number}/height/{revision_height}: - get: - summary: >- - ConsensusState queries a consensus state associated with a client state - at - - a given height. - operationId: ConsensusState - responses: - '200': - description: A successful response. - schema: - type: object - properties: - consensus_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all - types that they - - expect it to use in the context of Any. However, for URLs - which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message - along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in - the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default - use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the last - '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding a - field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: >- - consensus state associated with the client identifier at the - given height - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: >- - Height is a monotonically increasing data type - - that can be compared against another Height for the purposes - of updating and - - freezing clients - title: >- - QueryConsensusStateResponse is the response type for the - Query/ConsensusState - - RPC method - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: client_id - description: client identifier - in: path - required: true - type: string - - name: revision_number - description: consensus state revision number - in: path - required: true - type: string - format: uint64 - - name: revision_height - description: consensus state revision height - in: path - required: true - type: string - format: uint64 - - name: latest_height - description: >- - latest_height overrides the height field and queries the latest - stored - - ConsensusState. - in: query - required: false - type: boolean - tags: - - Query - /ibc/core/client/v1/params: - get: - summary: ClientParams queries all parameters of the ibc client submodule. - operationId: ClientParams - responses: - '200': - description: A successful response. - schema: - type: object - properties: - params: - description: params defines the parameters of the module. - type: object - properties: - allowed_clients: - type: array - items: - type: string - description: >- - allowed_clients defines the list of allowed client state - types which can be created - - and interacted with. If a client type is removed from the - allowed clients list, usage - - of this client will be disabled until it is added again to - the list. - description: >- - QueryClientParamsResponse is the response type for the - Query/ClientParams RPC - - method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - tags: - - Query - /ibc/core/client/v1/upgraded_client_states: - get: - summary: UpgradedClientState queries an Upgraded IBC light client. - operationId: UpgradedClientState - responses: - '200': - description: A successful response. - schema: - type: object - properties: - upgraded_client_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all - types that they - - expect it to use in the context of Any. However, for URLs - which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message - along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in - the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default - use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the last - '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding a - field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: client state associated with the request identifier - description: |- - QueryUpgradedClientStateResponse is the response type for the - Query/UpgradedClientState RPC method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - tags: - - Query - /ibc/core/client/v1/upgraded_consensus_states: - get: - summary: UpgradedConsensusState queries an Upgraded IBC consensus state. - operationId: UpgradedConsensusState - responses: - '200': - description: A successful response. - schema: - type: object - properties: - upgraded_consensus_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all - types that they - - expect it to use in the context of Any. However, for URLs - which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message - along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in - the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default - use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the last - '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding a - field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: Consensus state associated with the request identifier - description: |- - QueryUpgradedConsensusStateResponse is the response type for the - Query/UpgradedConsensusState RPC method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - tags: - - Query - /ibc/core/client/v1/verify_membership: - post: - summary: >- - VerifyMembership queries an IBC light client for proof verification of a - value at a given key path. - operationId: VerifyMembership - responses: - '200': - description: A successful response. - schema: - type: object - properties: - success: - type: boolean - description: boolean indicating success or failure of proof verification. - title: >- - QueryVerifyMembershipResponse is the response type for the - Query/VerifyMembership RPC method - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: body - in: body - required: true - schema: - type: object - properties: - client_id: - type: string - description: client unique identifier. - proof: - type: string - format: byte - description: the proof to be verified by the client. - proof_height: - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: >- - Height is a monotonically increasing data type - - that can be compared against another Height for the purposes - of updating and - - freezing clients - merkle_path: - description: the commitment key path. - type: object - properties: - key_path: - type: array - items: - type: string - title: >- - MerklePath is the path used to verify commitment proofs, which - can be an - - arbitrary structured object (defined by a commitment type). - - MerklePath is represented from root-to-leaf - value: - type: string - format: byte - description: the value which is proven. - time_delay: - type: string - format: uint64 - title: optional time delay - block_delay: - type: string - format: uint64 - title: optional block delay - title: >- - QueryVerifyMembershipRequest is the request type for the - Query/VerifyMembership RPC method - tags: - - Query - /ibc/core/connection/v1/client_connections/{client_id}: - get: - summary: |- - ClientConnections queries the connection paths associated with a client - state. - operationId: ClientConnections - responses: - '200': - description: A successful response. - schema: - type: object - properties: - connection_paths: - type: array - items: - type: string - description: slice of all the connection paths associated with a client. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was generated - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryClientConnectionsResponse is the response type for the - Query/ClientConnections RPC method - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: client_id - description: client identifier associated with a connection - in: path - required: true - type: string - tags: - - Query - /ibc/core/connection/v1/connections: - get: - summary: Connections queries all the IBC connections of a chain. - operationId: Connections - responses: - '200': - description: A successful response. - schema: - type: object - properties: - connections: - type: array - items: - type: object - properties: - id: - type: string - description: connection identifier. - client_id: - type: string - description: client associated with this connection. - versions: - type: array - items: - type: object - properties: - identifier: - type: string - title: unique version identifier - features: - type: array - items: - type: string - title: >- - list of features compatible with the specified - identifier - description: >- - Version defines the versioning scheme used to - negotiate the IBC version in - - the connection handshake. - title: >- - IBC version which can be utilised to determine encodings - or protocols for - - channels or packets utilising this connection - state: - description: current state of the connection end. - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - default: STATE_UNINITIALIZED_UNSPECIFIED - counterparty: - description: counterparty chain associated with this connection. - type: object - properties: - client_id: - type: string - description: >- - identifies the client on the counterparty chain - associated with a given - - connection. - connection_id: - type: string - description: >- - identifies the connection end on the counterparty - chain associated with a - - given connection. - prefix: - description: commitment merkle prefix of the counterparty chain. - type: object - properties: - key_prefix: - type: string - format: byte - title: >- - MerklePrefix is merkle path prefixed to the key. - - The constructed key from the Path and the key will - be append(Path.KeyPath, - - append(Path.KeyPrefix, key...)) - delay_period: - type: string - format: uint64 - description: delay period associated with this connection. - description: >- - IdentifiedConnection defines a connection with additional - connection - - identifier field. - description: list of stored connections of the chain. - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: >- - PageResponse is to be embedded in gRPC response messages where - the - - corresponding request message has used PageRequest. - - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - height: - title: query block height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - description: >- - QueryConnectionsResponse is the response type for the - Query/Connections RPC - - method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false - type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false - type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - - name: pagination.reverse - description: >- - reverse is set to true if results are to be returned in the - descending order. - - - Since: cosmos-sdk 0.43 - in: query - required: false - type: boolean - tags: - - Query - /ibc/core/connection/v1/connections/{connection_id}: - get: - summary: Connection queries an IBC connection end. - operationId: Connection - responses: - '200': - description: A successful response. - schema: - type: object - properties: - connection: - title: connection associated with the request identifier - type: object - properties: - client_id: - type: string - description: client associated with this connection. - versions: - type: array - items: - type: object - properties: - identifier: - type: string - title: unique version identifier - features: - type: array - items: - type: string - title: >- - list of features compatible with the specified - identifier - description: >- - Version defines the versioning scheme used to negotiate - the IBC version in - - the connection handshake. - description: >- - IBC version which can be utilised to determine encodings - or protocols for - - channels or packets utilising this connection. - state: - description: current state of the connection end. - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - default: STATE_UNINITIALIZED_UNSPECIFIED - counterparty: - description: counterparty chain associated with this connection. - type: object - properties: - client_id: - type: string - description: >- - identifies the client on the counterparty chain - associated with a given - - connection. - connection_id: - type: string - description: >- - identifies the connection end on the counterparty - chain associated with a - - given connection. - prefix: - description: commitment merkle prefix of the counterparty chain. - type: object - properties: - key_prefix: - type: string - format: byte - title: >- - MerklePrefix is merkle path prefixed to the key. - - The constructed key from the Path and the key will be - append(Path.KeyPath, - - append(Path.KeyPrefix, key...)) - delay_period: - type: string - format: uint64 - description: >- - delay period that must pass before a consensus state can - be used for - - packet-verification NOTE: delay period logic is only - implemented by some - - clients. - description: >- - ConnectionEnd defines a stateful object on a chain connected - to another - - separate one. - - NOTE: there must only be 2 defined ConnectionEnds to establish - - a connection between two chains. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - description: >- - QueryConnectionResponse is the response type for the - Query/Connection RPC - - method. Besides the connection end, it includes a proof and the - height from - - which the proof was retrieved. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: connection_id - description: connection unique identifier - in: path - required: true - type: string - tags: - - Query - /ibc/core/connection/v1/connections/{connection_id}/client_state: - get: - summary: |- - ConnectionClientState queries the client state associated with the - connection. - operationId: ConnectionClientState - responses: - '200': - description: A successful response. - schema: - type: object - properties: - identified_client_state: - title: client state associated with the channel - type: object - properties: - client_id: - type: string - title: client identifier - client_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type - of the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be - in a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can - optionally set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results - based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty - scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the - above specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any - values in the form - - of utility functions or additional generated methods of - the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and - the unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will - yield type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a - custom JSON - - representation, that representation will be embedded - adding a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: client state - description: >- - IdentifiedClientState defines a client state with an - additional client - - identifier field. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryConnectionClientStateResponse is the response type for the - Query/ConnectionClientState RPC method - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: connection_id - description: connection identifier - in: path - required: true - type: string - tags: - - Query - /ibc/core/connection/v1/connections/{connection_id}/consensus_state/revision/{revision_number}/height/{revision_height}: - get: - summary: |- - ConnectionConsensusState queries the consensus state associated with the - connection. - operationId: ConnectionConsensusState - responses: - '200': - description: A successful response. - schema: - type: object - properties: - consensus_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all - types that they - - expect it to use in the context of Any. However, for URLs - which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message - along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in - the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default - use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the last - '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding a - field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: consensus state associated with the channel - client_id: - type: string - title: client ID associated with the consensus state - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryConnectionConsensusStateResponse is the response type for the - Query/ConnectionConsensusState RPC method - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: connection_id - description: connection identifier - in: path - required: true - type: string - - name: revision_number - in: path - required: true - type: string - format: uint64 - - name: revision_height - in: path - required: true - type: string - format: uint64 - tags: - - Query - /ibc/core/connection/v1/params: - get: - summary: ConnectionParams queries all parameters of the ibc connection submodule. - operationId: ConnectionParams - responses: - '200': - description: A successful response. - schema: - type: object - properties: - params: - description: params defines the parameters of the module. - type: object - properties: - max_expected_time_per_block: - type: string - format: uint64 - description: >- - maximum expected time per block (in nanoseconds), used to - enforce block delay. This parameter should reflect the - - largest amount of time that the chain might reasonably - take to produce the next block under normal operating - - conditions. A safe choice is 3-5x the expected time per - block. - description: >- - QueryConnectionParamsResponse is the response type for the - Query/ConnectionParams RPC method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - tags: - - Query - /ibc/core/channel/v1/channels: - get: - summary: Channels queries all the IBC channels of a chain. - operationId: Channels - responses: - '200': - description: A successful response. - schema: - type: object - properties: - channels: - type: array - items: - type: object - properties: - state: - title: current state of the channel end - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - - STATE_CLOSED - - STATE_FLUSHING - - STATE_FLUSHCOMPLETE - default: STATE_UNINITIALIZED_UNSPECIFIED - description: >- - State defines if a channel is in one of the following - states: - - CLOSED, INIT, TRYOPEN, OPEN, FLUSHING, FLUSHCOMPLETE or - UNINITIALIZED. - - - STATE_UNINITIALIZED_UNSPECIFIED: Default State - - STATE_INIT: A channel has just started the opening handshake. - - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. - - STATE_OPEN: A channel has completed the handshake. Open channels are - ready to send and receive packets. - - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive - packets. - - STATE_FLUSHING: A channel has just accepted the upgrade handshake attempt and is flushing in-flight packets. - - STATE_FLUSHCOMPLETE: A channel has just completed flushing any in-flight packets. - ordering: - title: whether the channel is ordered or unordered - type: string - enum: - - ORDER_NONE_UNSPECIFIED - - ORDER_UNORDERED - - ORDER_ORDERED - default: ORDER_NONE_UNSPECIFIED - description: >- - - ORDER_NONE_UNSPECIFIED: zero-value for channel - ordering - - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in - which they were sent. - - ORDER_ORDERED: packets are delivered exactly in the order which they were sent - counterparty: - title: counterparty channel end - type: object - properties: - port_id: - type: string - description: >- - port on the counterparty chain which owns the other - end of the channel. - channel_id: - type: string - title: channel end on the counterparty chain - connection_hops: - type: array - items: - type: string - title: >- - list of connection identifiers, in order, along which - packets sent on - - this channel will travel - version: - type: string - title: >- - opaque channel version, which is agreed upon during the - handshake - port_id: - type: string - title: port identifier - channel_id: - type: string - title: channel identifier - upgrade_sequence: - type: string - format: uint64 - title: >- - upgrade sequence indicates the latest upgrade attempt - performed by this channel - - the value of 0 indicates the channel has never been - upgraded - description: >- - IdentifiedChannel defines a channel with additional port and - channel - - identifier fields. - description: list of stored channels of the chain. - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: >- - PageResponse is to be embedded in gRPC response messages where - the - - corresponding request message has used PageRequest. - - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - height: - title: query block height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - description: >- - QueryChannelsResponse is the response type for the Query/Channels - RPC method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false - type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false - type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - - name: pagination.reverse - description: >- - reverse is set to true if results are to be returned in the - descending order. - - - Since: cosmos-sdk 0.43 - in: query - required: false - type: boolean - tags: - - Query - /ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}: - get: - summary: Channel queries an IBC Channel. - operationId: Channel - responses: - '200': - description: A successful response. - schema: - type: object - properties: - channel: - title: channel associated with the request identifiers - type: object - properties: - state: - title: current state of the channel end - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - - STATE_CLOSED - - STATE_FLUSHING - - STATE_FLUSHCOMPLETE - default: STATE_UNINITIALIZED_UNSPECIFIED - description: >- - State defines if a channel is in one of the following - states: - - CLOSED, INIT, TRYOPEN, OPEN, FLUSHING, FLUSHCOMPLETE or - UNINITIALIZED. - - - STATE_UNINITIALIZED_UNSPECIFIED: Default State - - STATE_INIT: A channel has just started the opening handshake. - - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. - - STATE_OPEN: A channel has completed the handshake. Open channels are - ready to send and receive packets. - - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive - packets. - - STATE_FLUSHING: A channel has just accepted the upgrade handshake attempt and is flushing in-flight packets. - - STATE_FLUSHCOMPLETE: A channel has just completed flushing any in-flight packets. - ordering: - title: whether the channel is ordered or unordered - type: string - enum: - - ORDER_NONE_UNSPECIFIED - - ORDER_UNORDERED - - ORDER_ORDERED - default: ORDER_NONE_UNSPECIFIED - description: |- - - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering - - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in - which they were sent. - - ORDER_ORDERED: packets are delivered exactly in the order which they were sent - counterparty: - title: counterparty channel end - type: object - properties: - port_id: - type: string - description: >- - port on the counterparty chain which owns the other - end of the channel. - channel_id: - type: string - title: channel end on the counterparty chain - connection_hops: - type: array - items: - type: string - title: >- - list of connection identifiers, in order, along which - packets sent on - - this channel will travel - version: - type: string - title: >- - opaque channel version, which is agreed upon during the - handshake - upgrade_sequence: - type: string - format: uint64 - title: >- - upgrade sequence indicates the latest upgrade attempt - performed by this channel - - the value of 0 indicates the channel has never been - upgraded - description: >- - Channel defines pipeline for exactly-once packet delivery - between specific - - modules on separate blockchains, which has at least one end - capable of - - sending packets and one end capable of receiving packets. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - description: >- - QueryChannelResponse is the response type for the Query/Channel - RPC method. - - Besides the Channel end, it includes a proof and the height from - which the - - proof was retrieved. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: port_id - description: port unique identifier - in: path - required: true - type: string - tags: - - Query - /ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/client_state: - get: - summary: >- - ChannelClientState queries for the client state for the channel - associated - - with the provided channel identifiers. - operationId: ChannelClientState - responses: - '200': - description: A successful response. - schema: - type: object - properties: - identified_client_state: - title: client state associated with the channel - type: object - properties: - client_id: - type: string - title: client identifier - client_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type - of the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be - in a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can - optionally set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results - based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty - scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the - above specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any - values in the form - - of utility functions or additional generated methods of - the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and - the unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will - yield type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a - custom JSON - - representation, that representation will be embedded - adding a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: client state - description: >- - IdentifiedClientState defines a client state with an - additional client - - identifier field. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryChannelClientStateResponse is the Response type for the - Query/QueryChannelClientState RPC method - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: port_id - description: port unique identifier - in: path - required: true - type: string - tags: - - Query - /ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/consensus_state/revision/{revision_number}/height/{revision_height}: - get: - summary: |- - ChannelConsensusState queries for the consensus state for the channel - associated with the provided channel identifiers. - operationId: ChannelConsensusState - responses: - '200': - description: A successful response. - schema: - type: object - properties: - consensus_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all - types that they - - expect it to use in the context of Any. However, for URLs - which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message - along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in - the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default - use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the last - '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding a - field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: consensus state associated with the channel - client_id: - type: string - title: client ID associated with the consensus state - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryChannelClientStateResponse is the Response type for the - Query/QueryChannelClientState RPC method - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: port_id - description: port unique identifier - in: path - required: true - type: string - - name: revision_number - description: revision number of the consensus state - in: path - required: true - type: string - format: uint64 - - name: revision_height - description: revision height of the consensus state - in: path - required: true - type: string - format: uint64 - tags: - - Query - /ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/next_sequence: - get: - summary: >- - NextSequenceReceive returns the next receive sequence for a given - channel. - operationId: NextSequenceReceive - responses: - '200': - description: A successful response. - schema: - type: object - properties: - next_sequence_receive: - type: string - format: uint64 - title: next sequence receive number - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QuerySequenceResponse is the response type for the - Query/QueryNextSequenceReceiveResponse RPC method - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: port_id - description: port unique identifier - in: path - required: true - type: string - tags: - - Query - /ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/next_sequence_send: - get: - summary: NextSequenceSend returns the next send sequence for a given channel. - operationId: NextSequenceSend - responses: - '200': - description: A successful response. - schema: - type: object - properties: - next_sequence_send: - type: string - format: uint64 - title: next sequence send number - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryNextSequenceSendResponse is the request type for the - Query/QueryNextSequenceSend RPC method - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: port_id - description: port unique identifier - in: path - required: true - type: string - tags: - - Query - /ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_acknowledgements: - get: - summary: >- - PacketAcknowledgements returns all the packet acknowledgements - associated - - with a channel. - operationId: PacketAcknowledgements - responses: - '200': - description: A successful response. - schema: - type: object - properties: - acknowledgements: - type: array - items: - type: object - properties: - port_id: - type: string - description: channel port identifier. - channel_id: - type: string - description: channel unique identifier. - sequence: - type: string - format: uint64 - description: packet sequence. - data: - type: string - format: byte - description: embedded data that represents packet state. - description: >- - PacketState defines the generic type necessary to retrieve - and store - - packet commitments, acknowledgements, and receipts. - - Caller is responsible for knowing the context necessary to - interpret this - - state as a commitment, acknowledgement, or a receipt. - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: >- - PageResponse is to be embedded in gRPC response messages where - the - - corresponding request message has used PageRequest. - - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - height: - title: query block height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryPacketAcknowledgemetsResponse is the request type for the - Query/QueryPacketAcknowledgements RPC method - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: port_id - description: port unique identifier - in: path - required: true - type: string - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false - type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false - type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - - name: pagination.reverse - description: >- - reverse is set to true if results are to be returned in the - descending order. - - - Since: cosmos-sdk 0.43 - in: query - required: false - type: boolean - - name: packet_commitment_sequences - description: list of packet sequences. - in: query - required: false - type: array - items: - type: string - format: uint64 - collectionFormat: multi - tags: - - Query - /ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_acks/{sequence}: - get: - summary: PacketAcknowledgement queries a stored packet acknowledgement hash. - operationId: PacketAcknowledgement - responses: - '200': - description: A successful response. - schema: - type: object - properties: - acknowledgement: - type: string - format: byte - title: packet associated with the request fields - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: >- - QueryPacketAcknowledgementResponse defines the client query - response for a - - packet which also includes a proof and the height from which the - - proof was retrieved - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: port_id - description: port unique identifier - in: path - required: true - type: string - - name: sequence - description: packet sequence - in: path - required: true - type: string - format: uint64 - tags: - - Query - /ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_commitments: - get: - summary: |- - PacketCommitments returns all the packet commitments hashes associated - with a channel. - operationId: PacketCommitments - responses: - '200': - description: A successful response. - schema: - type: object - properties: - commitments: - type: array - items: - type: object - properties: - port_id: - type: string - description: channel port identifier. - channel_id: - type: string - description: channel unique identifier. - sequence: - type: string - format: uint64 - description: packet sequence. - data: - type: string - format: byte - description: embedded data that represents packet state. - description: >- - PacketState defines the generic type necessary to retrieve - and store - - packet commitments, acknowledgements, and receipts. - - Caller is responsible for knowing the context necessary to - interpret this - - state as a commitment, acknowledgement, or a receipt. - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: >- - PageResponse is to be embedded in gRPC response messages where - the - - corresponding request message has used PageRequest. - - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - height: - title: query block height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryPacketCommitmentsResponse is the request type for the - Query/QueryPacketCommitments RPC method - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: port_id - description: port unique identifier - in: path - required: true - type: string - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false - type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false - type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - - name: pagination.reverse - description: >- - reverse is set to true if results are to be returned in the - descending order. - - - Since: cosmos-sdk 0.43 - in: query - required: false - type: boolean - tags: - - Query - /ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_commitments/{packet_ack_sequences}/unreceived_acks: - get: - summary: >- - UnreceivedAcks returns all the unreceived IBC acknowledgements - associated - - with a channel and sequences. - operationId: UnreceivedAcks - responses: - '200': - description: A successful response. - schema: - type: object - properties: - sequences: - type: array - items: - type: string - format: uint64 - title: list of unreceived acknowledgement sequences - height: - title: query block height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryUnreceivedAcksResponse is the response type for the - Query/UnreceivedAcks RPC method - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: port_id - description: port unique identifier - in: path - required: true - type: string - - name: packet_ack_sequences - description: list of acknowledgement sequences - in: path - required: true - type: array - items: - type: string - format: uint64 - collectionFormat: csv - minItems: 1 - tags: - - Query - /ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_commitments/{packet_commitment_sequences}/unreceived_packets: - get: - summary: >- - UnreceivedPackets returns all the unreceived IBC packets associated with - a - - channel and sequences. - operationId: UnreceivedPackets - responses: - '200': - description: A successful response. - schema: - type: object - properties: - sequences: - type: array - items: - type: string - format: uint64 - title: list of unreceived packet sequences - height: - title: query block height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryUnreceivedPacketsResponse is the response type for the - Query/UnreceivedPacketCommitments RPC method - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: port_id - description: port unique identifier - in: path - required: true - type: string - - name: packet_commitment_sequences - description: list of packet sequences - in: path - required: true - type: array - items: - type: string - format: uint64 - collectionFormat: csv - minItems: 1 - tags: - - Query - /ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_commitments/{sequence}: - get: - summary: PacketCommitment queries a stored packet commitment hash. - operationId: PacketCommitment - responses: - '200': - description: A successful response. - schema: - type: object - properties: - commitment: - type: string - format: byte - title: packet associated with the request fields - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: >- - QueryPacketCommitmentResponse defines the client query response - for a packet - - which also includes a proof and the height from which the proof - was - - retrieved - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: port_id - description: port unique identifier - in: path - required: true - type: string - - name: sequence - description: packet sequence - in: path - required: true - type: string - format: uint64 - tags: - - Query - /ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_receipts/{sequence}: - get: - summary: >- - PacketReceipt queries if a given packet sequence has been received on - the - - queried chain - operationId: PacketReceipt - responses: - '200': - description: A successful response. - schema: - type: object - properties: - received: - type: boolean - title: success flag for if receipt exists - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: >- - QueryPacketReceiptResponse defines the client query response for a - packet - - receipt which also includes a proof, and the height from which the - proof was - - retrieved - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: port_id - description: port unique identifier - in: path - required: true - type: string - - name: sequence - description: packet sequence - in: path - required: true - type: string - format: uint64 - tags: - - Query - /ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/upgrade: - get: - summary: Upgrade returns the upgrade for a given port and channel id. - operationId: Upgrade - responses: - '200': - description: A successful response. - schema: - type: object - properties: - upgrade: - type: object - properties: - fields: - type: object - properties: - ordering: - type: string - enum: - - ORDER_NONE_UNSPECIFIED - - ORDER_UNORDERED - - ORDER_ORDERED - default: ORDER_NONE_UNSPECIFIED - description: >- - - ORDER_NONE_UNSPECIFIED: zero-value for channel - ordering - - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in - which they were sent. - - ORDER_ORDERED: packets are delivered exactly in the order which they were sent - title: Order defines if a channel is ORDERED or UNORDERED - connection_hops: - type: array - items: - type: string - version: - type: string - description: >- - UpgradeFields are the fields in a channel end which may be - changed - - during a channel upgrade. - timeout: - type: object - properties: - height: - title: >- - block height after which the packet or upgrade times - out - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each - height while keeping - - RevisionNumber the same. However some consensus - algorithms may choose to - - reset the height in certain conditions e.g. hard - forks, state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even - as the RevisionHeight - - gets reset - timestamp: - type: string - format: uint64 - title: >- - block timestamp (in nanoseconds) after which the - packet or upgrade times out - description: >- - Timeout defines an execution deadline structure for - 04-channel handlers. - - This includes packet lifecycle handlers as well as the - upgrade handshake handlers. - - A valid Timeout contains either one or both of a timestamp - and block height (sequence). - next_sequence_send: - type: string - format: uint64 - description: >- - Upgrade is a verifiable type which contains the relevant - information - - for an attempted upgrade. It provides the proposed changes to - the channel - - end, the timeout for this upgrade attempt and the next packet - sequence - - which allows the counterparty to efficiently know the highest - sequence it has received. - - The next sequence send is used for pruning and upgrading from - unordered to ordered channels. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: >- - QueryUpgradeResponse is the response type for the - QueryUpgradeResponse RPC method - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: channel_id - in: path - required: true - type: string - - name: port_id - in: path - required: true - type: string - tags: - - Query - /ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/upgrade_error: - get: - summary: UpgradeError returns the error receipt if the upgrade handshake failed. - operationId: UpgradeError - responses: - '200': - description: A successful response. - schema: - type: object - properties: - error_receipt: - type: object - properties: - sequence: - type: string - format: uint64 - title: the channel upgrade sequence - message: - type: string - title: the error message detailing the cause of failure - description: >- - ErrorReceipt defines a type which encapsulates the upgrade - sequence and error associated with the - - upgrade handshake failure. When a channel upgrade handshake is - aborted both chains are expected to increment to the - - next sequence. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: >- - QueryUpgradeErrorResponse is the response type for the - Query/QueryUpgradeError RPC method - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: channel_id - in: path - required: true - type: string - - name: port_id - in: path - required: true - type: string - tags: - - Query - /ibc/core/channel/v1/connections/{connection}/channels: - get: - summary: |- - ConnectionChannels queries all the channels associated with a connection - end. - operationId: ConnectionChannels - responses: - '200': - description: A successful response. - schema: - type: object - properties: - channels: - type: array - items: - type: object - properties: - state: - title: current state of the channel end - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - - STATE_CLOSED - - STATE_FLUSHING - - STATE_FLUSHCOMPLETE - default: STATE_UNINITIALIZED_UNSPECIFIED - description: >- - State defines if a channel is in one of the following - states: - - CLOSED, INIT, TRYOPEN, OPEN, FLUSHING, FLUSHCOMPLETE or - UNINITIALIZED. - - - STATE_UNINITIALIZED_UNSPECIFIED: Default State - - STATE_INIT: A channel has just started the opening handshake. - - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. - - STATE_OPEN: A channel has completed the handshake. Open channels are - ready to send and receive packets. - - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive - packets. - - STATE_FLUSHING: A channel has just accepted the upgrade handshake attempt and is flushing in-flight packets. - - STATE_FLUSHCOMPLETE: A channel has just completed flushing any in-flight packets. - ordering: - title: whether the channel is ordered or unordered - type: string - enum: - - ORDER_NONE_UNSPECIFIED - - ORDER_UNORDERED - - ORDER_ORDERED - default: ORDER_NONE_UNSPECIFIED - description: >- - - ORDER_NONE_UNSPECIFIED: zero-value for channel - ordering - - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in - which they were sent. - - ORDER_ORDERED: packets are delivered exactly in the order which they were sent - counterparty: - title: counterparty channel end - type: object - properties: - port_id: - type: string - description: >- - port on the counterparty chain which owns the other - end of the channel. - channel_id: - type: string - title: channel end on the counterparty chain - connection_hops: - type: array - items: - type: string - title: >- - list of connection identifiers, in order, along which - packets sent on - - this channel will travel - version: - type: string - title: >- - opaque channel version, which is agreed upon during the - handshake - port_id: - type: string - title: port identifier - channel_id: - type: string - title: channel identifier - upgrade_sequence: - type: string - format: uint64 - title: >- - upgrade sequence indicates the latest upgrade attempt - performed by this channel - - the value of 0 indicates the channel has never been - upgraded - description: >- - IdentifiedChannel defines a channel with additional port and - channel - - identifier fields. - description: list of channels associated with a connection. - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: >- - PageResponse is to be embedded in gRPC response messages where - the - - corresponding request message has used PageRequest. - - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - height: - title: query block height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryConnectionChannelsResponse is the Response type for the - Query/QueryConnectionChannels RPC method - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: connection - description: connection unique identifier - in: path - required: true - type: string - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false - type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false - type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - - name: pagination.reverse - description: >- - reverse is set to true if results are to be returned in the - descending order. - - - Since: cosmos-sdk 0.43 - in: query - required: false - type: boolean - tags: - - Query - /ibc/core/channel/v1/params: - get: - summary: ChannelParams queries all parameters of the ibc channel submodule. - operationId: ChannelParams - responses: - '200': - description: A successful response. - schema: - type: object - properties: - params: - description: params defines the parameters of the module. - type: object - properties: - upgrade_timeout: - type: object - properties: - height: - title: >- - block height after which the packet or upgrade times - out - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each - height while keeping - - RevisionNumber the same. However some consensus - algorithms may choose to - - reset the height in certain conditions e.g. hard - forks, state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even - as the RevisionHeight - - gets reset - timestamp: - type: string - format: uint64 - title: >- - block timestamp (in nanoseconds) after which the - packet or upgrade times out - description: >- - Timeout defines an execution deadline structure for - 04-channel handlers. - - This includes packet lifecycle handlers as well as the - upgrade handshake handlers. - - A valid Timeout contains either one or both of a timestamp - and block height (sequence). - description: >- - QueryChannelParamsResponse is the response type for the - Query/ChannelParams RPC method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in - a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values - in the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding - a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - tags: - - Query - /ibc/lightclients/wasm/v1/checksums: - get: - summary: Get all Wasm checksums - operationId: Checksums - responses: - '200': - description: A successful response. - schema: - type: object - properties: - checksums: - type: array - items: - type: string - description: >- - checksums is a list of the hex encoded checksums of all wasm - codes stored. - pagination: - description: pagination defines the pagination in the response. - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: >- - QueryChecksumsResponse is the response type for the - Query/Checksums RPC method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false - type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false - type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - - name: pagination.reverse - description: >- - reverse is set to true if results are to be returned in the - descending order. - - - Since: cosmos-sdk 0.43 - in: query - required: false - type: boolean - tags: - - Query - /ibc/lightclients/wasm/v1/checksums/{checksum}/code: - get: - summary: Get Wasm code for given checksum - operationId: Code - responses: - '200': - description: A successful response. - schema: - type: object - properties: - data: - type: string - format: byte - description: >- - QueryCodeResponse is the response type for the Query/Code RPC - method. - default: - description: An unexpected error response. - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: checksum - description: checksum is a hex encoded string of the code stored. - in: path - required: true - type: string - tags: - - Query -definitions: - cosmos.base.query.v1beta1.PageRequest: - type: object - properties: - key: - type: string - format: byte - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - offset: - type: string - format: uint64 - description: |- - offset is a numeric offset that can be used when key is unavailable. - It is less efficient than using key. Only one of offset or key should - be set. - limit: - type: string - format: uint64 - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - count_total: - type: boolean - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in UIs. - - count_total is only respected when offset is used. It is ignored when - key - - is set. - reverse: - type: boolean - description: >- - reverse is set to true if results are to be returned in the descending - order. - - - Since: cosmos-sdk 0.43 - description: |- - message SomeRequest { - Foo some_parameter = 1; - PageRequest pagination = 2; - } - title: |- - PageRequest is to be embedded in gRPC request messages for efficient - pagination. Ex: - cosmos.base.query.v1beta1.PageResponse: - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: |- - total is total number of results available if PageRequest.count_total - was set, its value is undefined otherwise - description: |- - PageResponse is to be embedded in gRPC response messages where the - corresponding request message has used PageRequest. - - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - cosmos.base.v1beta1.Coin: - type: object - properties: - denom: - type: string - amount: - type: string - description: |- - Coin defines a token with a denomination and an amount. - - NOTE: The amount field is an Int which implements the custom method - signatures required by gogoproto. - google.protobuf.Any: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a canonical - form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types that - they - - expect it to use in the context of Any. However, for URLs which use - the - - scheme `http`, `https`, or no scheme, one can optionally set up a type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message along with - a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - grpc.gateway.runtime.Error: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types - that they - - expect it to use in the context of Any. However, for URLs which - use the - - scheme `http`, `https`, or no scheme, one can optionally set up - a type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs beginning - with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might - be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message along - with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the - form - - of utility functions or additional generated methods of the Any - type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - ibc.applications.transfer.v1.DenomTrace: - type: object - properties: - path: - type: string - description: >- - path defines the chain of port/channel identifiers used for tracing - the - - source of the fungible token. - base_denom: - type: string - description: base denomination of the relayed fungible token. - description: >- - DenomTrace contains the base denomination for ICS20 fungible tokens and - the - - source tracing information path. - ibc.applications.transfer.v1.Params: - type: object - properties: - send_enabled: - type: boolean - description: >- - send_enabled enables or disables all cross-chain token transfers from - this - - chain. - receive_enabled: - type: boolean - description: >- - receive_enabled enables or disables all cross-chain token transfers to - this - - chain. - description: >- - Params defines the set of IBC transfer parameters. - - NOTE: To prevent a single token from being transferred, set the - - TransfersEnabled parameter to true and then set the bank module's - SendEnabled - - parameter for the denomination to false. - ibc.applications.transfer.v1.QueryDenomHashResponse: - type: object - properties: - hash: - type: string - description: hash (in hex format) of the denomination trace information. - description: |- - QueryDenomHashResponse is the response type for the Query/DenomHash RPC - method. - ibc.applications.transfer.v1.QueryDenomTraceResponse: - type: object - properties: - denom_trace: - type: object - properties: - path: - type: string - description: >- - path defines the chain of port/channel identifiers used for - tracing the - - source of the fungible token. - base_denom: - type: string - description: base denomination of the relayed fungible token. - description: >- - DenomTrace contains the base denomination for ICS20 fungible tokens - and the - - source tracing information path. - description: |- - QueryDenomTraceResponse is the response type for the Query/DenomTrace RPC - method. - ibc.applications.transfer.v1.QueryDenomTracesResponse: - type: object - properties: - denom_traces: - type: array - items: - type: object - properties: - path: - type: string - description: >- - path defines the chain of port/channel identifiers used for - tracing the - - source of the fungible token. - base_denom: - type: string - description: base denomination of the relayed fungible token. - description: >- - DenomTrace contains the base denomination for ICS20 fungible tokens - and the - - source tracing information path. - description: denom_traces returns all denominations trace information. - pagination: - description: pagination defines the pagination in the response. - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: >- - QueryConnectionsResponse is the response type for the Query/DenomTraces - RPC - - method. - ibc.applications.transfer.v1.QueryEscrowAddressResponse: - type: object - properties: - escrow_address: - type: string - title: the escrow account address - description: >- - QueryEscrowAddressResponse is the response type of the EscrowAddress RPC - method. - ibc.applications.transfer.v1.QueryParamsResponse: - type: object - properties: - params: - description: params defines the parameters of the module. - type: object - properties: - send_enabled: - type: boolean - description: >- - send_enabled enables or disables all cross-chain token transfers - from this - - chain. - receive_enabled: - type: boolean - description: >- - receive_enabled enables or disables all cross-chain token - transfers to this - - chain. - description: QueryParamsResponse is the response type for the Query/Params RPC method. - ibc.applications.transfer.v1.QueryTotalEscrowForDenomResponse: - type: object - properties: - amount: - type: object - properties: - denom: - type: string - amount: - type: string - description: |- - Coin defines a token with a denomination and an amount. - - NOTE: The amount field is an Int which implements the custom method - signatures required by gogoproto. - description: >- - QueryTotalEscrowForDenomResponse is the response type for - TotalEscrowForDenom RPC method. - ibc.applications.interchain_accounts.controller.v1.Params: - type: object - properties: - controller_enabled: - type: boolean - description: controller_enabled enables or disables the controller submodule. - description: |- - Params defines the set of on-chain interchain accounts parameters. - The following parameters may be used to disable the controller submodule. - ibc.applications.interchain_accounts.controller.v1.QueryInterchainAccountResponse: - type: object - properties: - address: - type: string - description: >- - QueryInterchainAccountResponse the response type for the - Query/InterchainAccount RPC method. - ibc.applications.interchain_accounts.controller.v1.QueryParamsResponse: - type: object - properties: - params: - description: params defines the parameters of the module. - type: object - properties: - controller_enabled: - type: boolean - description: controller_enabled enables or disables the controller submodule. - description: QueryParamsResponse is the response type for the Query/Params RPC method. - ibc.applications.interchain_accounts.host.v1.Params: - type: object - properties: - host_enabled: - type: boolean - description: host_enabled enables or disables the host submodule. - allow_messages: - type: array - items: - type: string - description: >- - allow_messages defines a list of sdk message typeURLs allowed to be - executed on a host chain. - description: |- - Params defines the set of on-chain interchain accounts parameters. - The following parameters may be used to disable the host submodule. - ibc.applications.interchain_accounts.host.v1.QueryParamsResponse: - type: object - properties: - params: - description: params defines the parameters of the module. - type: object - properties: - host_enabled: - type: boolean - description: host_enabled enables or disables the host submodule. - allow_messages: - type: array - items: - type: string - description: >- - allow_messages defines a list of sdk message typeURLs allowed to - be executed on a host chain. - description: QueryParamsResponse is the response type for the Query/Params RPC method. - ibc.applications.fee.v1.Fee: - type: object - properties: - recv_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: |- - Coin defines a token with a denomination and an amount. - - NOTE: The amount field is an Int which implements the custom method - signatures required by gogoproto. - title: the packet receive fee - ack_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: |- - Coin defines a token with a denomination and an amount. - - NOTE: The amount field is an Int which implements the custom method - signatures required by gogoproto. - title: the packet acknowledgement fee - timeout_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: |- - Coin defines a token with a denomination and an amount. - - NOTE: The amount field is an Int which implements the custom method - signatures required by gogoproto. - title: the packet timeout fee - title: Fee defines the ICS29 receive, acknowledgement and timeout fees - ibc.applications.fee.v1.FeeEnabledChannel: - type: object - properties: - port_id: - type: string - title: unique port identifier - channel_id: - type: string - title: unique channel identifier - title: >- - FeeEnabledChannel contains the PortID & ChannelID for a fee enabled - channel - ibc.applications.fee.v1.IdentifiedPacketFees: - type: object - properties: - packet_id: - title: >- - unique packet identifier comprised of the channel ID, port ID and - sequence - type: object - properties: - port_id: - type: string - title: channel port identifier - channel_id: - type: string - title: channel unique identifier - sequence: - type: string - format: uint64 - title: packet sequence - packet_fees: - type: array - items: - type: object - properties: - fee: - title: >- - fee encapsulates the recv, ack and timeout fees associated with - an IBC packet - type: object - properties: - recv_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. - - - NOTE: The amount field is an Int which implements the - custom method - - signatures required by gogoproto. - title: the packet receive fee - ack_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. - - - NOTE: The amount field is an Int which implements the - custom method - - signatures required by gogoproto. - title: the packet acknowledgement fee - timeout_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. - - - NOTE: The amount field is an Int which implements the - custom method - - signatures required by gogoproto. - title: the packet timeout fee - refund_address: - type: string - title: the refund address for unspent fees - relayers: - type: array - items: - type: string - title: optional list of relayers permitted to receive fees - title: >- - PacketFee contains ICS29 relayer fees, refund address and optional - list of permitted relayers - title: list of packet fees - title: >- - IdentifiedPacketFees contains a list of type PacketFee and associated - PacketId - ibc.applications.fee.v1.PacketFee: - type: object - properties: - fee: - title: >- - fee encapsulates the recv, ack and timeout fees associated with an IBC - packet - type: object - properties: - recv_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. - - - NOTE: The amount field is an Int which implements the custom - method - - signatures required by gogoproto. - title: the packet receive fee - ack_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. - - - NOTE: The amount field is an Int which implements the custom - method - - signatures required by gogoproto. - title: the packet acknowledgement fee - timeout_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. - - - NOTE: The amount field is an Int which implements the custom - method - - signatures required by gogoproto. - title: the packet timeout fee - refund_address: - type: string - title: the refund address for unspent fees - relayers: - type: array - items: - type: string - title: optional list of relayers permitted to receive fees - title: >- - PacketFee contains ICS29 relayer fees, refund address and optional list of - permitted relayers - ibc.applications.fee.v1.QueryCounterpartyPayeeResponse: - type: object - properties: - counterparty_payee: - type: string - title: the counterparty payee address used to compensate forward relaying - title: >- - QueryCounterpartyPayeeResponse defines the response type for the - CounterpartyPayee rpc - ibc.applications.fee.v1.QueryFeeEnabledChannelResponse: - type: object - properties: - fee_enabled: - type: boolean - title: boolean flag representing the fee enabled channel status - title: >- - QueryFeeEnabledChannelResponse defines the response type for the - FeeEnabledChannel rpc - ibc.applications.fee.v1.QueryFeeEnabledChannelsResponse: - type: object - properties: - fee_enabled_channels: - type: array - items: - type: object - properties: - port_id: - type: string - title: unique port identifier - channel_id: - type: string - title: unique channel identifier - title: >- - FeeEnabledChannel contains the PortID & ChannelID for a fee enabled - channel - title: list of fee enabled channels - pagination: - description: pagination defines the pagination in the response. - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - title: >- - QueryFeeEnabledChannelsResponse defines the response type for the - FeeEnabledChannels rpc - ibc.applications.fee.v1.QueryIncentivizedPacketResponse: - type: object - properties: - incentivized_packet: - type: object - properties: - packet_id: - title: >- - unique packet identifier comprised of the channel ID, port ID and - sequence - type: object - properties: - port_id: - type: string - title: channel port identifier - channel_id: - type: string - title: channel unique identifier - sequence: - type: string - format: uint64 - title: packet sequence - packet_fees: - type: array - items: - type: object - properties: - fee: - title: >- - fee encapsulates the recv, ack and timeout fees associated - with an IBC packet - type: object - properties: - recv_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements the - custom method - - signatures required by gogoproto. - title: the packet receive fee - ack_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements the - custom method - - signatures required by gogoproto. - title: the packet acknowledgement fee - timeout_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements the - custom method - - signatures required by gogoproto. - title: the packet timeout fee - refund_address: - type: string - title: the refund address for unspent fees - relayers: - type: array - items: - type: string - title: optional list of relayers permitted to receive fees - title: >- - PacketFee contains ICS29 relayer fees, refund address and - optional list of permitted relayers - title: list of packet fees - title: >- - IdentifiedPacketFees contains a list of type PacketFee and associated - PacketId - title: >- - QueryIncentivizedPacketsResponse defines the response type for the - IncentivizedPacket rpc - ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelResponse: - type: object - properties: - incentivized_packets: - type: array - items: - type: object - properties: - packet_id: - title: >- - unique packet identifier comprised of the channel ID, port ID - and sequence - type: object - properties: - port_id: - type: string - title: channel port identifier - channel_id: - type: string - title: channel unique identifier - sequence: - type: string - format: uint64 - title: packet sequence - packet_fees: - type: array - items: - type: object - properties: - fee: - title: >- - fee encapsulates the recv, ack and timeout fees associated - with an IBC packet - type: object - properties: - recv_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements - the custom method - - signatures required by gogoproto. - title: the packet receive fee - ack_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements - the custom method - - signatures required by gogoproto. - title: the packet acknowledgement fee - timeout_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements - the custom method - - signatures required by gogoproto. - title: the packet timeout fee - refund_address: - type: string - title: the refund address for unspent fees - relayers: - type: array - items: - type: string - title: optional list of relayers permitted to receive fees - title: >- - PacketFee contains ICS29 relayer fees, refund address and - optional list of permitted relayers - title: list of packet fees - title: >- - IdentifiedPacketFees contains a list of type PacketFee and - associated PacketId - title: Map of all incentivized_packets - pagination: - description: pagination defines the pagination in the response. - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - title: >- - QueryIncentivizedPacketsResponse defines the response type for the - incentivized packets RPC - ibc.applications.fee.v1.QueryIncentivizedPacketsResponse: - type: object - properties: - incentivized_packets: - type: array - items: - type: object - properties: - packet_id: - title: >- - unique packet identifier comprised of the channel ID, port ID - and sequence - type: object - properties: - port_id: - type: string - title: channel port identifier - channel_id: - type: string - title: channel unique identifier - sequence: - type: string - format: uint64 - title: packet sequence - packet_fees: - type: array - items: - type: object - properties: - fee: - title: >- - fee encapsulates the recv, ack and timeout fees associated - with an IBC packet - type: object - properties: - recv_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements - the custom method - - signatures required by gogoproto. - title: the packet receive fee - ack_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements - the custom method - - signatures required by gogoproto. - title: the packet acknowledgement fee - timeout_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements - the custom method - - signatures required by gogoproto. - title: the packet timeout fee - refund_address: - type: string - title: the refund address for unspent fees - relayers: - type: array - items: - type: string - title: optional list of relayers permitted to receive fees - title: >- - PacketFee contains ICS29 relayer fees, refund address and - optional list of permitted relayers - title: list of packet fees - title: >- - IdentifiedPacketFees contains a list of type PacketFee and - associated PacketId - title: list of identified fees for incentivized packets - pagination: - description: pagination defines the pagination in the response. - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - title: >- - QueryIncentivizedPacketsResponse defines the response type for the - IncentivizedPackets rpc - ibc.applications.fee.v1.QueryPayeeResponse: - type: object - properties: - payee_address: - type: string - title: the payee address to which packet fees are paid out - title: QueryPayeeResponse defines the response type for the Payee rpc - ibc.applications.fee.v1.QueryTotalAckFeesResponse: - type: object - properties: - ack_fees: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: |- - Coin defines a token with a denomination and an amount. - - NOTE: The amount field is an Int which implements the custom method - signatures required by gogoproto. - title: the total packet acknowledgement fees - title: >- - QueryTotalAckFeesResponse defines the response type for the TotalAckFees - rpc - ibc.applications.fee.v1.QueryTotalRecvFeesResponse: - type: object - properties: - recv_fees: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: |- - Coin defines a token with a denomination and an amount. - - NOTE: The amount field is an Int which implements the custom method - signatures required by gogoproto. - title: the total packet receive fees - title: >- - QueryTotalRecvFeesResponse defines the response type for the TotalRecvFees - rpc - ibc.applications.fee.v1.QueryTotalTimeoutFeesResponse: - type: object - properties: - timeout_fees: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: |- - Coin defines a token with a denomination and an amount. - - NOTE: The amount field is an Int which implements the custom method - signatures required by gogoproto. - title: the total packet timeout fees - title: >- - QueryTotalTimeoutFeesResponse defines the response type for the - TotalTimeoutFees rpc - ibc.core.channel.v1.PacketId: - type: object - properties: - port_id: - type: string - title: channel port identifier - channel_id: - type: string - title: channel unique identifier - sequence: - type: string - format: uint64 - title: packet sequence - title: |- - PacketId is an identifier for a unique Packet - Source chains refer to packets by source port/channel - Destination chains refer to packets by destination port/channel - ibc.core.client.v1.ConsensusStateWithHeight: - type: object - properties: - height: - title: consensus state height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - consensus_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types - that they - - expect it to use in the context of Any. However, for URLs which - use the - - scheme `http`, `https`, or no scheme, one can optionally set up a - type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message along - with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the - form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: consensus state - description: >- - ConsensusStateWithHeight defines a consensus state with an additional - height - - field. - ibc.core.client.v1.Height: - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: |- - Normally the RevisionHeight is incremented at each height while keeping - RevisionNumber the same. However some consensus algorithms may choose to - reset the height in certain conditions e.g. hard forks, state-machine - breaking changes In these cases, the RevisionNumber is incremented so that - height continues to be monitonically increasing even as the RevisionHeight - gets reset - title: >- - Height is a monotonically increasing data type - - that can be compared against another Height for the purposes of updating - and - - freezing clients - ibc.core.client.v1.IdentifiedClientState: - type: object - properties: - client_id: - type: string - title: client identifier - client_state: - title: client state - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types - that they - - expect it to use in the context of Any. However, for URLs which - use the - - scheme `http`, `https`, or no scheme, one can optionally set up a - type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message along - with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the - form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - description: |- - IdentifiedClientState defines a client state with an additional client - identifier field. - ibc.core.client.v1.Params: - type: object - properties: - allowed_clients: - type: array - items: - type: string - description: >- - allowed_clients defines the list of allowed client state types which - can be created - - and interacted with. If a client type is removed from the allowed - clients list, usage - - of this client will be disabled until it is added again to the list. - description: Params defines the set of IBC light client parameters. - ibc.core.client.v1.QueryClientParamsResponse: - type: object - properties: - params: - description: params defines the parameters of the module. - type: object - properties: - allowed_clients: - type: array - items: - type: string - description: >- - allowed_clients defines the list of allowed client state types - which can be created - - and interacted with. If a client type is removed from the allowed - clients list, usage - - of this client will be disabled until it is added again to the - list. - description: >- - QueryClientParamsResponse is the response type for the Query/ClientParams - RPC - - method. - ibc.core.client.v1.QueryClientStateResponse: - type: object - properties: - client_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types - that they - - expect it to use in the context of Any. However, for URLs which - use the - - scheme `http`, `https`, or no scheme, one can optionally set up a - type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message along - with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the - form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: client state associated with the request identifier - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - description: >- - QueryClientStateResponse is the response type for the Query/ClientState - RPC - - method. Besides the client state, it includes a proof and the height from - - which the proof was retrieved. - ibc.core.client.v1.QueryClientStatesResponse: - type: object - properties: - client_states: - type: array - items: - type: object - properties: - client_id: - type: string - title: client identifier - client_state: - title: client state - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all - types that they - - expect it to use in the context of Any. However, for URLs - which use the - - scheme `http`, `https`, or no scheme, one can optionally set - up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on - the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs beginning - with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message - along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in - the form - - of utility functions or additional generated methods of the Any - type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default - use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the last - '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a - field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - description: >- - IdentifiedClientState defines a client state with an additional - client - - identifier field. - description: list of stored ClientStates of the chain. - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: |- - PageResponse is to be embedded in gRPC response messages where the - corresponding request message has used PageRequest. - - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - description: >- - QueryClientStatesResponse is the response type for the Query/ClientStates - RPC - - method. - ibc.core.client.v1.QueryClientStatusResponse: - type: object - properties: - status: - type: string - description: >- - QueryClientStatusResponse is the response type for the Query/ClientStatus - RPC - - method. It returns the current status of the IBC client. - ibc.core.client.v1.QueryConsensusStateHeightsResponse: - type: object - properties: - consensus_state_heights: - type: array - items: - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is incremented - so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: >- - Height is a monotonically increasing data type - - that can be compared against another Height for the purposes of - updating and - - freezing clients - title: consensus state heights - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: |- - PageResponse is to be embedded in gRPC response messages where the - corresponding request message has used PageRequest. - - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - title: |- - QueryConsensusStateHeightsResponse is the response type for the - Query/ConsensusStateHeights RPC method - ibc.core.client.v1.QueryConsensusStateResponse: - type: object - properties: - consensus_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types - that they - - expect it to use in the context of Any. However, for URLs which - use the - - scheme `http`, `https`, or no scheme, one can optionally set up a - type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message along - with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the - form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: >- - consensus state associated with the client identifier at the given - height - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: >- - Height is a monotonically increasing data type - - that can be compared against another Height for the purposes of - updating and - - freezing clients - title: >- - QueryConsensusStateResponse is the response type for the - Query/ConsensusState - - RPC method - ibc.core.client.v1.QueryConsensusStatesResponse: - type: object - properties: - consensus_states: - type: array - items: - type: object - properties: - height: - title: consensus state height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - consensus_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all - types that they - - expect it to use in the context of Any. However, for URLs - which use the - - scheme `http`, `https`, or no scheme, one can optionally set - up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on - the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs beginning - with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message - along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in - the form - - of utility functions or additional generated methods of the Any - type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default - use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the last - '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a - field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: consensus state - description: >- - ConsensusStateWithHeight defines a consensus state with an - additional height - - field. - title: consensus states associated with the identifier - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: |- - PageResponse is to be embedded in gRPC response messages where the - corresponding request message has used PageRequest. - - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - title: |- - QueryConsensusStatesResponse is the response type for the - Query/ConsensusStates RPC method - ibc.core.client.v1.QueryUpgradedClientStateResponse: - type: object - properties: - upgraded_client_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types - that they - - expect it to use in the context of Any. However, for URLs which - use the - - scheme `http`, `https`, or no scheme, one can optionally set up a - type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message along - with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the - form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: client state associated with the request identifier - description: |- - QueryUpgradedClientStateResponse is the response type for the - Query/UpgradedClientState RPC method. - ibc.core.client.v1.QueryUpgradedConsensusStateResponse: - type: object - properties: - upgraded_consensus_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types - that they - - expect it to use in the context of Any. However, for URLs which - use the - - scheme `http`, `https`, or no scheme, one can optionally set up a - type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message along - with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the - form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: Consensus state associated with the request identifier - description: |- - QueryUpgradedConsensusStateResponse is the response type for the - Query/UpgradedConsensusState RPC method. - ibc.core.client.v1.QueryVerifyMembershipRequest: - type: object - properties: - client_id: - type: string - description: client unique identifier. - proof: - type: string - format: byte - description: the proof to be verified by the client. - proof_height: - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: >- - Height is a monotonically increasing data type - - that can be compared against another Height for the purposes of - updating and - - freezing clients - merkle_path: - description: the commitment key path. - type: object - properties: - key_path: - type: array - items: - type: string - title: >- - MerklePath is the path used to verify commitment proofs, which can be - an - - arbitrary structured object (defined by a commitment type). - - MerklePath is represented from root-to-leaf - value: - type: string - format: byte - description: the value which is proven. - time_delay: - type: string - format: uint64 - title: optional time delay - block_delay: - type: string - format: uint64 - title: optional block delay - title: >- - QueryVerifyMembershipRequest is the request type for the - Query/VerifyMembership RPC method - ibc.core.client.v1.QueryVerifyMembershipResponse: - type: object - properties: - success: - type: boolean - description: boolean indicating success or failure of proof verification. - title: >- - QueryVerifyMembershipResponse is the response type for the - Query/VerifyMembership RPC method - ibc.core.commitment.v1.MerklePath: - type: object - properties: - key_path: - type: array - items: - type: string - title: |- - MerklePath is the path used to verify commitment proofs, which can be an - arbitrary structured object (defined by a commitment type). - MerklePath is represented from root-to-leaf - ibc.core.commitment.v1.MerklePrefix: - type: object - properties: - key_prefix: - type: string - format: byte - title: |- - MerklePrefix is merkle path prefixed to the key. - The constructed key from the Path and the key will be append(Path.KeyPath, - append(Path.KeyPrefix, key...)) - ibc.core.connection.v1.ConnectionEnd: - type: object - properties: - client_id: - type: string - description: client associated with this connection. - versions: - type: array - items: - type: object - properties: - identifier: - type: string - title: unique version identifier - features: - type: array - items: - type: string - title: list of features compatible with the specified identifier - description: >- - Version defines the versioning scheme used to negotiate the IBC - version in - - the connection handshake. - description: >- - IBC version which can be utilised to determine encodings or protocols - for - - channels or packets utilising this connection. - state: - description: current state of the connection end. - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - default: STATE_UNINITIALIZED_UNSPECIFIED - counterparty: - description: counterparty chain associated with this connection. - type: object - properties: - client_id: - type: string - description: >- - identifies the client on the counterparty chain associated with a - given - - connection. - connection_id: - type: string - description: >- - identifies the connection end on the counterparty chain associated - with a - - given connection. - prefix: - description: commitment merkle prefix of the counterparty chain. - type: object - properties: - key_prefix: - type: string - format: byte - title: >- - MerklePrefix is merkle path prefixed to the key. - - The constructed key from the Path and the key will be - append(Path.KeyPath, - - append(Path.KeyPrefix, key...)) - delay_period: - type: string - format: uint64 - description: >- - delay period that must pass before a consensus state can be used for - - packet-verification NOTE: delay period logic is only implemented by - some - - clients. - description: |- - ConnectionEnd defines a stateful object on a chain connected to another - separate one. - NOTE: there must only be 2 defined ConnectionEnds to establish - a connection between two chains. - ibc.core.connection.v1.Counterparty: - type: object - properties: - client_id: - type: string - description: >- - identifies the client on the counterparty chain associated with a - given - - connection. - connection_id: - type: string - description: >- - identifies the connection end on the counterparty chain associated - with a - - given connection. - prefix: - description: commitment merkle prefix of the counterparty chain. - type: object - properties: - key_prefix: - type: string - format: byte - title: >- - MerklePrefix is merkle path prefixed to the key. - - The constructed key from the Path and the key will be - append(Path.KeyPath, - - append(Path.KeyPrefix, key...)) - description: >- - Counterparty defines the counterparty chain associated with a connection - end. - ibc.core.connection.v1.IdentifiedConnection: - type: object - properties: - id: - type: string - description: connection identifier. - client_id: - type: string - description: client associated with this connection. - versions: - type: array - items: - type: object - properties: - identifier: - type: string - title: unique version identifier - features: - type: array - items: - type: string - title: list of features compatible with the specified identifier - description: >- - Version defines the versioning scheme used to negotiate the IBC - version in - - the connection handshake. - title: >- - IBC version which can be utilised to determine encodings or protocols - for - - channels or packets utilising this connection - state: - description: current state of the connection end. - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - default: STATE_UNINITIALIZED_UNSPECIFIED - counterparty: - description: counterparty chain associated with this connection. - type: object - properties: - client_id: - type: string - description: >- - identifies the client on the counterparty chain associated with a - given - - connection. - connection_id: - type: string - description: >- - identifies the connection end on the counterparty chain associated - with a - - given connection. - prefix: - description: commitment merkle prefix of the counterparty chain. - type: object - properties: - key_prefix: - type: string - format: byte - title: >- - MerklePrefix is merkle path prefixed to the key. - - The constructed key from the Path and the key will be - append(Path.KeyPath, - - append(Path.KeyPrefix, key...)) - delay_period: - type: string - format: uint64 - description: delay period associated with this connection. - description: |- - IdentifiedConnection defines a connection with additional connection - identifier field. - ibc.core.connection.v1.Params: - type: object - properties: - max_expected_time_per_block: - type: string - format: uint64 - description: >- - maximum expected time per block (in nanoseconds), used to enforce - block delay. This parameter should reflect the - - largest amount of time that the chain might reasonably take to produce - the next block under normal operating - - conditions. A safe choice is 3-5x the expected time per block. - description: Params defines the set of Connection parameters. - ibc.core.connection.v1.QueryClientConnectionsResponse: - type: object - properties: - connection_paths: - type: array - items: - type: string - description: slice of all the connection paths associated with a client. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was generated - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryClientConnectionsResponse is the response type for the - Query/ClientConnections RPC method - ibc.core.connection.v1.QueryConnectionClientStateResponse: - type: object - properties: - identified_client_state: - title: client state associated with the channel - type: object - properties: - client_id: - type: string - title: client identifier - client_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all - types that they - - expect it to use in the context of Any. However, for URLs - which use the - - scheme `http`, `https`, or no scheme, one can optionally set - up a type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on - the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs beginning - with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might - be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message - along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the - form - - of utility functions or additional generated methods of the Any - type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a - field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: client state - description: |- - IdentifiedClientState defines a client state with an additional client - identifier field. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryConnectionClientStateResponse is the response type for the - Query/ConnectionClientState RPC method - ibc.core.connection.v1.QueryConnectionConsensusStateResponse: - type: object - properties: - consensus_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types - that they - - expect it to use in the context of Any. However, for URLs which - use the - - scheme `http`, `https`, or no scheme, one can optionally set up a - type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message along - with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the - form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: consensus state associated with the channel - client_id: - type: string - title: client ID associated with the consensus state - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryConnectionConsensusStateResponse is the response type for the - Query/ConnectionConsensusState RPC method - ibc.core.connection.v1.QueryConnectionParamsResponse: - type: object - properties: - params: - description: params defines the parameters of the module. - type: object - properties: - max_expected_time_per_block: - type: string - format: uint64 - description: >- - maximum expected time per block (in nanoseconds), used to enforce - block delay. This parameter should reflect the - - largest amount of time that the chain might reasonably take to - produce the next block under normal operating - - conditions. A safe choice is 3-5x the expected time per block. - description: >- - QueryConnectionParamsResponse is the response type for the - Query/ConnectionParams RPC method. - ibc.core.connection.v1.QueryConnectionResponse: - type: object - properties: - connection: - title: connection associated with the request identifier - type: object - properties: - client_id: - type: string - description: client associated with this connection. - versions: - type: array - items: - type: object - properties: - identifier: - type: string - title: unique version identifier - features: - type: array - items: - type: string - title: list of features compatible with the specified identifier - description: >- - Version defines the versioning scheme used to negotiate the IBC - version in - - the connection handshake. - description: >- - IBC version which can be utilised to determine encodings or - protocols for - - channels or packets utilising this connection. - state: - description: current state of the connection end. - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - default: STATE_UNINITIALIZED_UNSPECIFIED - counterparty: - description: counterparty chain associated with this connection. - type: object - properties: - client_id: - type: string - description: >- - identifies the client on the counterparty chain associated - with a given - - connection. - connection_id: - type: string - description: >- - identifies the connection end on the counterparty chain - associated with a - - given connection. - prefix: - description: commitment merkle prefix of the counterparty chain. - type: object - properties: - key_prefix: - type: string - format: byte - title: >- - MerklePrefix is merkle path prefixed to the key. - - The constructed key from the Path and the key will be - append(Path.KeyPath, - - append(Path.KeyPrefix, key...)) - delay_period: - type: string - format: uint64 - description: >- - delay period that must pass before a consensus state can be used - for - - packet-verification NOTE: delay period logic is only implemented - by some - - clients. - description: >- - ConnectionEnd defines a stateful object on a chain connected to - another - - separate one. - - NOTE: there must only be 2 defined ConnectionEnds to establish - - a connection between two chains. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - description: >- - QueryConnectionResponse is the response type for the Query/Connection RPC - - method. Besides the connection end, it includes a proof and the height - from - - which the proof was retrieved. - ibc.core.connection.v1.QueryConnectionsResponse: - type: object - properties: - connections: - type: array - items: - type: object - properties: - id: - type: string - description: connection identifier. - client_id: - type: string - description: client associated with this connection. - versions: - type: array - items: - type: object - properties: - identifier: - type: string - title: unique version identifier - features: - type: array - items: - type: string - title: list of features compatible with the specified identifier - description: >- - Version defines the versioning scheme used to negotiate the - IBC version in - - the connection handshake. - title: >- - IBC version which can be utilised to determine encodings or - protocols for - - channels or packets utilising this connection - state: - description: current state of the connection end. - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - default: STATE_UNINITIALIZED_UNSPECIFIED - counterparty: - description: counterparty chain associated with this connection. - type: object - properties: - client_id: - type: string - description: >- - identifies the client on the counterparty chain associated - with a given - - connection. - connection_id: - type: string - description: >- - identifies the connection end on the counterparty chain - associated with a - - given connection. - prefix: - description: commitment merkle prefix of the counterparty chain. - type: object - properties: - key_prefix: - type: string - format: byte - title: >- - MerklePrefix is merkle path prefixed to the key. - - The constructed key from the Path and the key will be - append(Path.KeyPath, - - append(Path.KeyPrefix, key...)) - delay_period: - type: string - format: uint64 - description: delay period associated with this connection. - description: |- - IdentifiedConnection defines a connection with additional connection - identifier field. - description: list of stored connections of the chain. - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: |- - PageResponse is to be embedded in gRPC response messages where the - corresponding request message has used PageRequest. - - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - height: - title: query block height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - description: >- - QueryConnectionsResponse is the response type for the Query/Connections - RPC - - method. - ibc.core.connection.v1.State: - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - default: STATE_UNINITIALIZED_UNSPECIFIED - description: |- - State defines if a connection is in one of the following states: - INIT, TRYOPEN, OPEN or UNINITIALIZED. - - - STATE_UNINITIALIZED_UNSPECIFIED: Default State - - STATE_INIT: A connection end has just started the opening handshake. - - STATE_TRYOPEN: A connection end has acknowledged the handshake step on the counterparty - chain. - - STATE_OPEN: A connection end has completed the handshake. - ibc.core.connection.v1.Version: - type: object - properties: - identifier: - type: string - title: unique version identifier - features: - type: array - items: - type: string - title: list of features compatible with the specified identifier - description: |- - Version defines the versioning scheme used to negotiate the IBC version in - the connection handshake. - ibc.core.channel.v1.Channel: - type: object - properties: - state: - title: current state of the channel end - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - - STATE_CLOSED - - STATE_FLUSHING - - STATE_FLUSHCOMPLETE - default: STATE_UNINITIALIZED_UNSPECIFIED - description: |- - State defines if a channel is in one of the following states: - CLOSED, INIT, TRYOPEN, OPEN, FLUSHING, FLUSHCOMPLETE or UNINITIALIZED. - - - STATE_UNINITIALIZED_UNSPECIFIED: Default State - - STATE_INIT: A channel has just started the opening handshake. - - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. - - STATE_OPEN: A channel has completed the handshake. Open channels are - ready to send and receive packets. - - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive - packets. - - STATE_FLUSHING: A channel has just accepted the upgrade handshake attempt and is flushing in-flight packets. - - STATE_FLUSHCOMPLETE: A channel has just completed flushing any in-flight packets. - ordering: - title: whether the channel is ordered or unordered - type: string - enum: - - ORDER_NONE_UNSPECIFIED - - ORDER_UNORDERED - - ORDER_ORDERED - default: ORDER_NONE_UNSPECIFIED - description: |- - - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering - - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in - which they were sent. - - ORDER_ORDERED: packets are delivered exactly in the order which they were sent - counterparty: - title: counterparty channel end - type: object - properties: - port_id: - type: string - description: >- - port on the counterparty chain which owns the other end of the - channel. - channel_id: - type: string - title: channel end on the counterparty chain - connection_hops: - type: array - items: - type: string - title: |- - list of connection identifiers, in order, along which packets sent on - this channel will travel - version: - type: string - title: opaque channel version, which is agreed upon during the handshake - upgrade_sequence: - type: string - format: uint64 - title: >- - upgrade sequence indicates the latest upgrade attempt performed by - this channel - - the value of 0 indicates the channel has never been upgraded - description: |- - Channel defines pipeline for exactly-once packet delivery between specific - modules on separate blockchains, which has at least one end capable of - sending packets and one end capable of receiving packets. - ibc.core.channel.v1.Counterparty: - type: object - properties: - port_id: - type: string - description: >- - port on the counterparty chain which owns the other end of the - channel. - channel_id: - type: string - title: channel end on the counterparty chain - title: Counterparty defines a channel end counterparty - ibc.core.channel.v1.ErrorReceipt: - type: object - properties: - sequence: - type: string - format: uint64 - title: the channel upgrade sequence - message: - type: string - title: the error message detailing the cause of failure - description: >- - ErrorReceipt defines a type which encapsulates the upgrade sequence and - error associated with the - - upgrade handshake failure. When a channel upgrade handshake is aborted - both chains are expected to increment to the - - next sequence. - ibc.core.channel.v1.IdentifiedChannel: - type: object - properties: - state: - title: current state of the channel end - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - - STATE_CLOSED - - STATE_FLUSHING - - STATE_FLUSHCOMPLETE - default: STATE_UNINITIALIZED_UNSPECIFIED - description: |- - State defines if a channel is in one of the following states: - CLOSED, INIT, TRYOPEN, OPEN, FLUSHING, FLUSHCOMPLETE or UNINITIALIZED. - - - STATE_UNINITIALIZED_UNSPECIFIED: Default State - - STATE_INIT: A channel has just started the opening handshake. - - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. - - STATE_OPEN: A channel has completed the handshake. Open channels are - ready to send and receive packets. - - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive - packets. - - STATE_FLUSHING: A channel has just accepted the upgrade handshake attempt and is flushing in-flight packets. - - STATE_FLUSHCOMPLETE: A channel has just completed flushing any in-flight packets. - ordering: - title: whether the channel is ordered or unordered - type: string - enum: - - ORDER_NONE_UNSPECIFIED - - ORDER_UNORDERED - - ORDER_ORDERED - default: ORDER_NONE_UNSPECIFIED - description: |- - - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering - - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in - which they were sent. - - ORDER_ORDERED: packets are delivered exactly in the order which they were sent - counterparty: - title: counterparty channel end - type: object - properties: - port_id: - type: string - description: >- - port on the counterparty chain which owns the other end of the - channel. - channel_id: - type: string - title: channel end on the counterparty chain - connection_hops: - type: array - items: - type: string - title: |- - list of connection identifiers, in order, along which packets sent on - this channel will travel - version: - type: string - title: opaque channel version, which is agreed upon during the handshake - port_id: - type: string - title: port identifier - channel_id: - type: string - title: channel identifier - upgrade_sequence: - type: string - format: uint64 - title: >- - upgrade sequence indicates the latest upgrade attempt performed by - this channel - - the value of 0 indicates the channel has never been upgraded - description: |- - IdentifiedChannel defines a channel with additional port and channel - identifier fields. - ibc.core.channel.v1.Order: - type: string - enum: - - ORDER_NONE_UNSPECIFIED - - ORDER_UNORDERED - - ORDER_ORDERED - default: ORDER_NONE_UNSPECIFIED - description: |- - - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering - - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in - which they were sent. - - ORDER_ORDERED: packets are delivered exactly in the order which they were sent - title: Order defines if a channel is ORDERED or UNORDERED - ibc.core.channel.v1.PacketState: - type: object - properties: - port_id: - type: string - description: channel port identifier. - channel_id: - type: string - description: channel unique identifier. - sequence: - type: string - format: uint64 - description: packet sequence. - data: - type: string - format: byte - description: embedded data that represents packet state. - description: |- - PacketState defines the generic type necessary to retrieve and store - packet commitments, acknowledgements, and receipts. - Caller is responsible for knowing the context necessary to interpret this - state as a commitment, acknowledgement, or a receipt. - ibc.core.channel.v1.Params: - type: object - properties: - upgrade_timeout: - type: object - properties: - height: - title: block height after which the packet or upgrade times out - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is incremented - so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - timestamp: - type: string - format: uint64 - title: >- - block timestamp (in nanoseconds) after which the packet or upgrade - times out - description: >- - Timeout defines an execution deadline structure for 04-channel - handlers. - - This includes packet lifecycle handlers as well as the upgrade - handshake handlers. - - A valid Timeout contains either one or both of a timestamp and block - height (sequence). - description: Params defines the set of IBC channel parameters. - ibc.core.channel.v1.QueryChannelClientStateResponse: - type: object - properties: - identified_client_state: - title: client state associated with the channel - type: object - properties: - client_id: - type: string - title: client identifier - client_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all - types that they - - expect it to use in the context of Any. However, for URLs - which use the - - scheme `http`, `https`, or no scheme, one can optionally set - up a type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on - the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs beginning - with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might - be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message - along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the - form - - of utility functions or additional generated methods of the Any - type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a - field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: client state - description: |- - IdentifiedClientState defines a client state with an additional client - identifier field. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryChannelClientStateResponse is the Response type for the - Query/QueryChannelClientState RPC method - ibc.core.channel.v1.QueryChannelConsensusStateResponse: - type: object - properties: - consensus_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types - that they - - expect it to use in the context of Any. However, for URLs which - use the - - scheme `http`, `https`, or no scheme, one can optionally set up a - type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message along - with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the - form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: consensus state associated with the channel - client_id: - type: string - title: client ID associated with the consensus state - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryChannelClientStateResponse is the Response type for the - Query/QueryChannelClientState RPC method - ibc.core.channel.v1.QueryChannelParamsResponse: - type: object - properties: - params: - description: params defines the parameters of the module. - type: object - properties: - upgrade_timeout: - type: object - properties: - height: - title: block height after which the packet or upgrade times out - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - timestamp: - type: string - format: uint64 - title: >- - block timestamp (in nanoseconds) after which the packet or - upgrade times out - description: >- - Timeout defines an execution deadline structure for 04-channel - handlers. - - This includes packet lifecycle handlers as well as the upgrade - handshake handlers. - - A valid Timeout contains either one or both of a timestamp and - block height (sequence). - description: >- - QueryChannelParamsResponse is the response type for the - Query/ChannelParams RPC method. - ibc.core.channel.v1.QueryChannelResponse: - type: object - properties: - channel: - title: channel associated with the request identifiers - type: object - properties: - state: - title: current state of the channel end - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - - STATE_CLOSED - - STATE_FLUSHING - - STATE_FLUSHCOMPLETE - default: STATE_UNINITIALIZED_UNSPECIFIED - description: >- - State defines if a channel is in one of the following states: - - CLOSED, INIT, TRYOPEN, OPEN, FLUSHING, FLUSHCOMPLETE or - UNINITIALIZED. - - - STATE_UNINITIALIZED_UNSPECIFIED: Default State - - STATE_INIT: A channel has just started the opening handshake. - - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. - - STATE_OPEN: A channel has completed the handshake. Open channels are - ready to send and receive packets. - - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive - packets. - - STATE_FLUSHING: A channel has just accepted the upgrade handshake attempt and is flushing in-flight packets. - - STATE_FLUSHCOMPLETE: A channel has just completed flushing any in-flight packets. - ordering: - title: whether the channel is ordered or unordered - type: string - enum: - - ORDER_NONE_UNSPECIFIED - - ORDER_UNORDERED - - ORDER_ORDERED - default: ORDER_NONE_UNSPECIFIED - description: |- - - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering - - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in - which they were sent. - - ORDER_ORDERED: packets are delivered exactly in the order which they were sent - counterparty: - title: counterparty channel end - type: object - properties: - port_id: - type: string - description: >- - port on the counterparty chain which owns the other end of the - channel. - channel_id: - type: string - title: channel end on the counterparty chain - connection_hops: - type: array - items: - type: string - title: >- - list of connection identifiers, in order, along which packets sent - on - - this channel will travel - version: - type: string - title: opaque channel version, which is agreed upon during the handshake - upgrade_sequence: - type: string - format: uint64 - title: >- - upgrade sequence indicates the latest upgrade attempt performed by - this channel - - the value of 0 indicates the channel has never been upgraded - description: >- - Channel defines pipeline for exactly-once packet delivery between - specific - - modules on separate blockchains, which has at least one end capable of - - sending packets and one end capable of receiving packets. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - description: >- - QueryChannelResponse is the response type for the Query/Channel RPC - method. - - Besides the Channel end, it includes a proof and the height from which the - - proof was retrieved. - ibc.core.channel.v1.QueryChannelsResponse: - type: object - properties: - channels: - type: array - items: - type: object - properties: - state: - title: current state of the channel end - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - - STATE_CLOSED - - STATE_FLUSHING - - STATE_FLUSHCOMPLETE - default: STATE_UNINITIALIZED_UNSPECIFIED - description: >- - State defines if a channel is in one of the following states: - - CLOSED, INIT, TRYOPEN, OPEN, FLUSHING, FLUSHCOMPLETE or - UNINITIALIZED. - - - STATE_UNINITIALIZED_UNSPECIFIED: Default State - - STATE_INIT: A channel has just started the opening handshake. - - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. - - STATE_OPEN: A channel has completed the handshake. Open channels are - ready to send and receive packets. - - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive - packets. - - STATE_FLUSHING: A channel has just accepted the upgrade handshake attempt and is flushing in-flight packets. - - STATE_FLUSHCOMPLETE: A channel has just completed flushing any in-flight packets. - ordering: - title: whether the channel is ordered or unordered - type: string - enum: - - ORDER_NONE_UNSPECIFIED - - ORDER_UNORDERED - - ORDER_ORDERED - default: ORDER_NONE_UNSPECIFIED - description: |- - - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering - - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in - which they were sent. - - ORDER_ORDERED: packets are delivered exactly in the order which they were sent - counterparty: - title: counterparty channel end - type: object - properties: - port_id: - type: string - description: >- - port on the counterparty chain which owns the other end of - the channel. - channel_id: - type: string - title: channel end on the counterparty chain - connection_hops: - type: array - items: - type: string - title: >- - list of connection identifiers, in order, along which packets - sent on - - this channel will travel - version: - type: string - title: >- - opaque channel version, which is agreed upon during the - handshake - port_id: - type: string - title: port identifier - channel_id: - type: string - title: channel identifier - upgrade_sequence: - type: string - format: uint64 - title: >- - upgrade sequence indicates the latest upgrade attempt performed - by this channel - - the value of 0 indicates the channel has never been upgraded - description: |- - IdentifiedChannel defines a channel with additional port and channel - identifier fields. - description: list of stored channels of the chain. - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: |- - PageResponse is to be embedded in gRPC response messages where the - corresponding request message has used PageRequest. - - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - height: - title: query block height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - description: >- - QueryChannelsResponse is the response type for the Query/Channels RPC - method. - ibc.core.channel.v1.QueryConnectionChannelsResponse: - type: object - properties: - channels: - type: array - items: - type: object - properties: - state: - title: current state of the channel end - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - - STATE_CLOSED - - STATE_FLUSHING - - STATE_FLUSHCOMPLETE - default: STATE_UNINITIALIZED_UNSPECIFIED - description: >- - State defines if a channel is in one of the following states: - - CLOSED, INIT, TRYOPEN, OPEN, FLUSHING, FLUSHCOMPLETE or - UNINITIALIZED. - - - STATE_UNINITIALIZED_UNSPECIFIED: Default State - - STATE_INIT: A channel has just started the opening handshake. - - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. - - STATE_OPEN: A channel has completed the handshake. Open channels are - ready to send and receive packets. - - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive - packets. - - STATE_FLUSHING: A channel has just accepted the upgrade handshake attempt and is flushing in-flight packets. - - STATE_FLUSHCOMPLETE: A channel has just completed flushing any in-flight packets. - ordering: - title: whether the channel is ordered or unordered - type: string - enum: - - ORDER_NONE_UNSPECIFIED - - ORDER_UNORDERED - - ORDER_ORDERED - default: ORDER_NONE_UNSPECIFIED - description: |- - - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering - - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in - which they were sent. - - ORDER_ORDERED: packets are delivered exactly in the order which they were sent - counterparty: - title: counterparty channel end - type: object - properties: - port_id: - type: string - description: >- - port on the counterparty chain which owns the other end of - the channel. - channel_id: - type: string - title: channel end on the counterparty chain - connection_hops: - type: array - items: - type: string - title: >- - list of connection identifiers, in order, along which packets - sent on - - this channel will travel - version: - type: string - title: >- - opaque channel version, which is agreed upon during the - handshake - port_id: - type: string - title: port identifier - channel_id: - type: string - title: channel identifier - upgrade_sequence: - type: string - format: uint64 - title: >- - upgrade sequence indicates the latest upgrade attempt performed - by this channel - - the value of 0 indicates the channel has never been upgraded - description: |- - IdentifiedChannel defines a channel with additional port and channel - identifier fields. - description: list of channels associated with a connection. - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: |- - PageResponse is to be embedded in gRPC response messages where the - corresponding request message has used PageRequest. - - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - height: - title: query block height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryConnectionChannelsResponse is the Response type for the - Query/QueryConnectionChannels RPC method - ibc.core.channel.v1.QueryNextSequenceReceiveResponse: - type: object - properties: - next_sequence_receive: - type: string - format: uint64 - title: next sequence receive number - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QuerySequenceResponse is the response type for the - Query/QueryNextSequenceReceiveResponse RPC method - ibc.core.channel.v1.QueryNextSequenceSendResponse: - type: object - properties: - next_sequence_send: - type: string - format: uint64 - title: next sequence send number - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryNextSequenceSendResponse is the request type for the - Query/QueryNextSequenceSend RPC method - ibc.core.channel.v1.QueryPacketAcknowledgementResponse: - type: object - properties: - acknowledgement: - type: string - format: byte - title: packet associated with the request fields - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryPacketAcknowledgementResponse defines the client query response for a - packet which also includes a proof and the height from which the - proof was retrieved - ibc.core.channel.v1.QueryPacketAcknowledgementsResponse: - type: object - properties: - acknowledgements: - type: array - items: - type: object - properties: - port_id: - type: string - description: channel port identifier. - channel_id: - type: string - description: channel unique identifier. - sequence: - type: string - format: uint64 - description: packet sequence. - data: - type: string - format: byte - description: embedded data that represents packet state. - description: >- - PacketState defines the generic type necessary to retrieve and store - - packet commitments, acknowledgements, and receipts. - - Caller is responsible for knowing the context necessary to interpret - this - - state as a commitment, acknowledgement, or a receipt. - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: |- - PageResponse is to be embedded in gRPC response messages where the - corresponding request message has used PageRequest. - - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - height: - title: query block height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryPacketAcknowledgemetsResponse is the request type for the - Query/QueryPacketAcknowledgements RPC method - ibc.core.channel.v1.QueryPacketCommitmentResponse: - type: object - properties: - commitment: - type: string - format: byte - title: packet associated with the request fields - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: >- - QueryPacketCommitmentResponse defines the client query response for a - packet - - which also includes a proof and the height from which the proof was - - retrieved - ibc.core.channel.v1.QueryPacketCommitmentsResponse: - type: object - properties: - commitments: - type: array - items: - type: object - properties: - port_id: - type: string - description: channel port identifier. - channel_id: - type: string - description: channel unique identifier. - sequence: - type: string - format: uint64 - description: packet sequence. - data: - type: string - format: byte - description: embedded data that represents packet state. - description: >- - PacketState defines the generic type necessary to retrieve and store - - packet commitments, acknowledgements, and receipts. - - Caller is responsible for knowing the context necessary to interpret - this - - state as a commitment, acknowledgement, or a receipt. - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: |- - PageResponse is to be embedded in gRPC response messages where the - corresponding request message has used PageRequest. - - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - height: - title: query block height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryPacketCommitmentsResponse is the request type for the - Query/QueryPacketCommitments RPC method - ibc.core.channel.v1.QueryPacketReceiptResponse: - type: object - properties: - received: - type: boolean - title: success flag for if receipt exists - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: >- - QueryPacketReceiptResponse defines the client query response for a packet - - receipt which also includes a proof, and the height from which the proof - was - - retrieved - ibc.core.channel.v1.QueryUnreceivedAcksResponse: - type: object - properties: - sequences: - type: array - items: - type: string - format: uint64 - title: list of unreceived acknowledgement sequences - height: - title: query block height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryUnreceivedAcksResponse is the response type for the - Query/UnreceivedAcks RPC method - ibc.core.channel.v1.QueryUnreceivedPacketsResponse: - type: object - properties: - sequences: - type: array - items: - type: string - format: uint64 - title: list of unreceived packet sequences - height: - title: query block height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryUnreceivedPacketsResponse is the response type for the - Query/UnreceivedPacketCommitments RPC method - ibc.core.channel.v1.QueryUpgradeErrorResponse: - type: object - properties: - error_receipt: - type: object - properties: - sequence: - type: string - format: uint64 - title: the channel upgrade sequence - message: - type: string - title: the error message detailing the cause of failure - description: >- - ErrorReceipt defines a type which encapsulates the upgrade sequence - and error associated with the - - upgrade handshake failure. When a channel upgrade handshake is aborted - both chains are expected to increment to the - - next sequence. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: >- - QueryUpgradeErrorResponse is the response type for the - Query/QueryUpgradeError RPC method - ibc.core.channel.v1.QueryUpgradeResponse: - type: object - properties: - upgrade: - type: object - properties: - fields: - type: object - properties: - ordering: - type: string - enum: - - ORDER_NONE_UNSPECIFIED - - ORDER_UNORDERED - - ORDER_ORDERED - default: ORDER_NONE_UNSPECIFIED - description: |- - - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering - - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in - which they were sent. - - ORDER_ORDERED: packets are delivered exactly in the order which they were sent - title: Order defines if a channel is ORDERED or UNORDERED - connection_hops: - type: array - items: - type: string - version: - type: string - description: |- - UpgradeFields are the fields in a channel end which may be changed - during a channel upgrade. - timeout: - type: object - properties: - height: - title: block height after which the packet or upgrade times out - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - timestamp: - type: string - format: uint64 - title: >- - block timestamp (in nanoseconds) after which the packet or - upgrade times out - description: >- - Timeout defines an execution deadline structure for 04-channel - handlers. - - This includes packet lifecycle handlers as well as the upgrade - handshake handlers. - - A valid Timeout contains either one or both of a timestamp and - block height (sequence). - next_sequence_send: - type: string - format: uint64 - description: >- - Upgrade is a verifiable type which contains the relevant information - - for an attempted upgrade. It provides the proposed changes to the - channel - - end, the timeout for this upgrade attempt and the next packet sequence - - which allows the counterparty to efficiently know the highest sequence - it has received. - - The next sequence send is used for pruning and upgrading from - unordered to ordered channels. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: >- - QueryUpgradeResponse is the response type for the QueryUpgradeResponse RPC - method - ibc.core.channel.v1.State: - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - - STATE_CLOSED - - STATE_FLUSHING - - STATE_FLUSHCOMPLETE - default: STATE_UNINITIALIZED_UNSPECIFIED - description: |- - State defines if a channel is in one of the following states: - CLOSED, INIT, TRYOPEN, OPEN, FLUSHING, FLUSHCOMPLETE or UNINITIALIZED. - - - STATE_UNINITIALIZED_UNSPECIFIED: Default State - - STATE_INIT: A channel has just started the opening handshake. - - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. - - STATE_OPEN: A channel has completed the handshake. Open channels are - ready to send and receive packets. - - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive - packets. - - STATE_FLUSHING: A channel has just accepted the upgrade handshake attempt and is flushing in-flight packets. - - STATE_FLUSHCOMPLETE: A channel has just completed flushing any in-flight packets. - ibc.core.channel.v1.Timeout: - type: object - properties: - height: - title: block height after which the packet or upgrade times out - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may choose - to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so - that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - timestamp: - type: string - format: uint64 - title: >- - block timestamp (in nanoseconds) after which the packet or upgrade - times out - description: >- - Timeout defines an execution deadline structure for 04-channel handlers. - - This includes packet lifecycle handlers as well as the upgrade handshake - handlers. - - A valid Timeout contains either one or both of a timestamp and block - height (sequence). - ibc.core.channel.v1.Upgrade: - type: object - properties: - fields: - type: object - properties: - ordering: - type: string - enum: - - ORDER_NONE_UNSPECIFIED - - ORDER_UNORDERED - - ORDER_ORDERED - default: ORDER_NONE_UNSPECIFIED - description: |- - - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering - - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in - which they were sent. - - ORDER_ORDERED: packets are delivered exactly in the order which they were sent - title: Order defines if a channel is ORDERED or UNORDERED - connection_hops: - type: array - items: - type: string - version: - type: string - description: |- - UpgradeFields are the fields in a channel end which may be changed - during a channel upgrade. - timeout: - type: object - properties: - height: - title: block height after which the packet or upgrade times out - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is incremented - so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - timestamp: - type: string - format: uint64 - title: >- - block timestamp (in nanoseconds) after which the packet or upgrade - times out - description: >- - Timeout defines an execution deadline structure for 04-channel - handlers. - - This includes packet lifecycle handlers as well as the upgrade - handshake handlers. - - A valid Timeout contains either one or both of a timestamp and block - height (sequence). - next_sequence_send: - type: string - format: uint64 - description: >- - Upgrade is a verifiable type which contains the relevant information - - for an attempted upgrade. It provides the proposed changes to the channel - - end, the timeout for this upgrade attempt and the next packet sequence - - which allows the counterparty to efficiently know the highest sequence it - has received. - - The next sequence send is used for pruning and upgrading from unordered to - ordered channels. - ibc.core.channel.v1.UpgradeFields: - type: object - properties: - ordering: - type: string - enum: - - ORDER_NONE_UNSPECIFIED - - ORDER_UNORDERED - - ORDER_ORDERED - default: ORDER_NONE_UNSPECIFIED - description: |- - - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering - - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in - which they were sent. - - ORDER_ORDERED: packets are delivered exactly in the order which they were sent - title: Order defines if a channel is ORDERED or UNORDERED - connection_hops: - type: array - items: - type: string - version: - type: string - description: |- - UpgradeFields are the fields in a channel end which may be changed - during a channel upgrade. - ibc.lightclients.wasm.v1.QueryChecksumsResponse: - type: object - properties: - checksums: - type: array - items: - type: string - description: >- - checksums is a list of the hex encoded checksums of all wasm codes - stored. - pagination: - description: pagination defines the pagination in the response. - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: >- - QueryChecksumsResponse is the response type for the Query/Checksums RPC - method. - ibc.lightclients.wasm.v1.QueryCodeResponse: - type: object - properties: - data: - type: string - format: byte - description: QueryCodeResponse is the response type for the Query/Code RPC method. diff --git a/docs/dev/development-setup.md b/docs/dev/development-setup.md deleted file mode 100644 index eafeb705120..00000000000 --- a/docs/dev/development-setup.md +++ /dev/null @@ -1,62 +0,0 @@ -# Development setup - -## Dependencies - -We use [Go 1.14 Modules](https://github.com/golang/go/wiki/Modules) to manage dependency versions. - -The main branch of every Cosmos repository should just build with `go get`, which means they should be kept up-to-date with their dependencies, so we can get away with telling people they can just `go get` our software. - -Since some dependencies are not under our control, a third party may break our build, in which case we can fall back on `go mod tidy -v`. - -Other helpful commands: - -- `go get` to add a new go module (including if the existing go module is being semantic version bumped, i.e. my/module/v1 -> my/module/v2). -- `go get -u` to update an existing dependency. -- `go mod tidy` to update dependencies in `go.sum`. - -## Protobuf - -We use [Protocol Buffers](https://developers.google.com/protocol-buffers) along with [buf](https://docs.buf.build/introduction) and [gogoproto](https://github.com/gogo/protobuf) to generate code for use in ibc-go. - -For determinstic behavior around protobuf tooling, everything is containerized using Docker. Make sure to have Docker installed on your machine, or head to [Docker's website](https://docs.docker.com/get-docker/) to install it. - -For formatting code in `.proto` files, you can run the `make proto-format` command. - -For linting and checking breaking changes, we also use [buf](https://buf.build/). You can use the commands `make proto-lint` and `make proto-check-breaking` to respectively lint your proto files and check for breaking changes. - -To generate the protobuf stubs, you can run `make proto-gen`. - -We also added the `make proto-all` command to run the above commands (`proto-format`, `proto-lint` and `proto-gen`) sequentially. - -To update third-party protobuf dependencies, you can run `make proto-update-deps`. This requires `buf` to be installed in the local development environment (see [`buf`s installation documentation](https://docs.buf.build/installation) for more details). - -For generating or updating the swagger file that documents the URLs of the RESTful API that exposes the gRPC endpoints over HTTP, you can run the `proto-swagger-gen` command. - -It reads protobuf service definitions and generates a reverse-proxy server which translates a RESTful HTTP API into gRPC. - -## Developing and testing - -- The latest state of development is on `main`. -- Build the `simd` test chain binary with `make build`. -- `main` must never fail `make test`. -- No `--force` onto `main` (except when reverting a broken commit, which should seldom happen). -- Create a development branch either on `github.com/cosmos/ibc-go`, or your fork (using `git remote add fork`). -- Before submitting a pull request, begin `git rebase` on top of `main`. -- Ensure you are using the pre-commit hooks by running `make setup-pre-commit`. - -All Go tests in ibc-go can be ran by running `make test`. - -Please make sure to run `make format` before every commit - the easiest way to do this is have your editor run it for you upon saving a file. Additionally please ensure that your code is lint compliant by running `make lint-fix` (requires `golangci-lint`). - -When testing a function under a variety of different inputs, we prefer to use [table driven tests](https://github.com/golang/go/wiki/TableDrivenTests). - -All unit tests should use the testing package. Please see the testing package [README](../../testing/README.md) for more information. - -Test coverage is continuously deployed at . PRs that improve test coverage are welcome, but in general the test coverage should be used as a guidance for finding API use cases that are not covered by tests. We don't recommend adding tests that only improve coverage but not actually test a meaning use case. - -## Documentation - -- If you open a PR on ibc-go, it is mandatory to update the relevant documentation in `/docs`. -- We lint the markdown files for documentation with [markdownlint-cli](https://github.com/igorshubovych/markdownlint-cli). Please run `make docs-lint` before pushing changes in the markdown files (you will need to have `markdownlint-cli` installed, so please follow the [installation instructions](https://github.com/igorshubovych/markdownlint-cli#installation)). -- Generate the folder `docs/.vuepress/dist` with all the static files for the documentation site with `make build-docs`. -- Run the documentation site locally with `make view-docs`. diff --git a/docs/dev/go-style-guide.md b/docs/dev/go-style-guide.md deleted file mode 100644 index b4212e21fd5..00000000000 --- a/docs/dev/go-style-guide.md +++ /dev/null @@ -1,119 +0,0 @@ - -# Go style guide - -In order to keep our code looking good with lots of programmers working on it, it helps to have a "style guide", so all the code generally looks quite similar. This doesn't mean there is only one "right way" to write code, or even that this standard is better than your style. But if we agree to a number of stylistic practices, it makes it much easier to read and modify new code. Please feel free to make suggestions if there's something you would like to add or modify. - -We expect all contributors to be familiar with [Effective Go](https://golang.org/doc/effective_go.html) (and it's recommended reading for all Go programmers anyways). Additionally, we generally agree with the suggestions in [Uber's style guide](https://github.com/uber-go/guide/blob/master/style.md) and use that as a starting point. - -## Code Structure - -Perhaps more key for code readability than good commenting is having the right structure. As a rule of thumb, try to write in a logical order of importance, taking a little time to think how to order and divide the code such that someone could scroll down and understand the functionality of it just as well as you do. A loose example of such order would be: - -- Constants, global and package-level variables. -- Main struct definition. -- Options (only if they are seen as critical to the struct else they should be placed in another file). -- Initialization/start and stop of the service functions. -- Public functions (in order of most important). -- Private/helper functions. -- Auxiliary structs and function (can also be above private functions or in a separate file). - -## General - -- Use `gofumpt` to format all code upon saving it (or run `make format`). -- Think about documentation, and try to leave godoc comments, when it will help new developers. -- Every package should have a high level doc.go file to describe the purpose of that package, its main functions, and any other relevant information. -- Applications (e.g. clis/servers) should panic on unexpected unrecoverable errors and print a stack trace. - -## Comments - -- Use a space after the comment deliminter (ex. `// your comment`). -- Many comments are not sentences. These should begin with a lower case letter and end without a period. -- Conversely, sentences in comments should be sentenced-cased and end with a period. -- Comments should explain *why* something is being done rather than *what* the code is doing. For example: - - The comments in - -```go -// assign a variable foo -f := foo -// assign f to b -b := f -``` - - have little value, but the following is more useful: - -```go -f := foo -// we copy the variable f because we want to preserve the state at time of initialization -b := f -``` - -## Linting - -- Run `make lint-fix` to fix any linting errors. - -## Various - -- Functions that return functions should have the suffix `Fn`. -- Names should not [stutter](https://blog.golang.org/package-names). For example, a struct generally shouldn’t have a field named after itself; e.g., this shouldn't occur: - -```go -type middleware struct { - middleware Middleware -} -``` - -- Acronyms are all capitalized, like "RPC", "gRPC", "API". "MyID", rather than "MyId". -- Whenever it is safe to use Go's built-in `error` instantiation functions (as opposed to Cosmos SDK's error instantiation functions), prefer `errors.New()` instead of `fmt.Errorf()` unless you're actually using the format feature with arguments. - -## Importing libraries - -- Use [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports). -- Separate imports into blocks. For example: - -```go -import ( - // standard library imports - "fmt" - "testing" - - // external library imports - "github.com/stretchr/testify/require" - - // Cosmos-SDK imports - abci "github.com/cometbft/cometbft/abci/types" - - // ibc-go library imports - "github.com/cosmos/ibc-go/modules/core/23-commitment/types" -) -``` - -Run `make lint-fix` to get the imports ordered and grouped automatically. - -## Dependencies - -- Dependencies should be pinned by a release tag, or specific commit, to avoid breaking `go get` when external dependencies are updated. -- Refer to the [contributing](./development-setup.md#dependencies) document for more details. - -## Testing - -- Make use of table driven testing where possible and not-cumbersome. Read [this blog post](https://dave.cheney.net/2013/06/09/writing-table-driven-tests-in-go) for more information. See the [tests](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/apps/transfer/keeper/msg_server_test.go#L11) for [`Transfer`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/apps/transfer/keeper/msg_server.go#L15) for an example. -- Make use of Testify [assert](https://godoc.org/github.com/stretchr/testify/assert) and [require](https://godoc.org/github.com/stretchr/testify/require). -- When using mocks, it is recommended to use Testify [mock](https://pkg.go.dev/github.com/stretchr/testify/mock) along with [Mockery](https://github.com/vektra/mockery) for autogeneration. - -## Errors - -- Ensure that errors are concise, clear and traceable. -- Depending on the context, use either `cosmossdk.io/errors` or `stdlib` error packages. -- For wrapping errors, use `fmt.Errorf()` with `%w`. -- Panic is appropriate when an internal invariant of a system is broken, while all other cases (in particular, incorrect or invalid usage) should return errors. -- Error messages should be formatted as following: - -```go -sdkerrors.Wrapf( - , - "expected %s, got %s", - , - -) -``` diff --git a/docs/dev/project-structure.md b/docs/dev/project-structure.md deleted file mode 100644 index 2cf1a0faccc..00000000000 --- a/docs/dev/project-structure.md +++ /dev/null @@ -1,46 +0,0 @@ -# Project structure - -If you're not familiar with the overall module structure from the SDK modules, please check this [document](https://github.com/cosmos/cosmos-sdk/blob/main/docs/build/building-modules/11-structure.md) as prerequisite reading. - -Every Interchain Standard (ICS) has been developed in its own package. The development team separated the IBC TAO (Transport, Authentication, Ordering) ICS specifications from the IBC application level specification. The following sections describe the architecture of the most relevant directories that comprise this repository. - -## `modules` - -This folder contains implementations for the IBC TAO (`core`), IBC applications (`apps`) and light clients (`light-clients`). - -### `core` - -- `02-client`: This package is an implementation for Cosmos SDK-based chains of [ICS 02](https://github.com/cosmos/ibc/tree/main/spec/core/ics-002-client-semantics). This implementation defines the types and methods needed to operate light clients tracking other chain's consensus state. -- `03-connection`: This package is an implementation for Cosmos SDK-based chains of [ICS 03](https://github.com/cosmos/ibc/tree/main/spec/core/ics-003-connection-semantics). This implementation defines the types and methods necessary to perform connection handshake between two chains. -- `04-channel`: This package is an implementation for Cosmos SDK-based chains of [ICS 04](https://github.com/cosmos/ibc/tree/main/spec/core/ics-004-channel-and-packet-semantics). This implementation defines the types and methods necessary to perform channel handshake between two chains and ensure correct packet sending flow. -- `05-port`: This package is an implementation for Cosmos SDK-based chains of [ICS 05](https://github.com/cosmos/ibc/tree/main/spec/core/ics-005-port-allocation). This implements the port allocation system by which modules can bind to uniquely named ports. -- `23-commitment`: This package is an implementation for Cosmos SDK-based chains of [ICS 23](https://github.com/cosmos/ibc/tree/main/spec/core/ics-023-vector-commitments). This implementation defines the functions required to prove inclusion or non-inclusion of particular values at particular paths in state. -- `24-host`: This package is an implementation for Cosmos SDK-based chains of [ICS 24](https://github.com/cosmos/ibc/tree/main/spec/core/ics-024-host-requirements). - -### `apps` - -- `transfer`: This is the Cosmos SDK implementation of the [ICS 20](https://github.com/cosmos/ibc/tree/main/spec/app/ics-020-fungible-token-transfer) protocol, which enables cross-chain fungible token transfers. For more information, read the [module's docs](../docs/02-apps/01-transfer/01-overview.md) -- `27-interchain-accounts`: This is the Cosmos SDK implementation of the [ICS 27](https://github.com/cosmos/ibc/tree/main/spec/app/ics-027-interchain-accounts) protocol, which enables cross-chain account management built upon IBC. For more information, read the [module's documentation](../docs/02-apps/02-interchain-accounts/01-overview.md). -- `29-fee`: This is the Cosmos SDK implementation of the [ICS 29](https://github.com/cosmos/ibc/tree/main/spec/app/ics-029-fee-payment) middleware, which handles packet incentivisation and fee distribution on top of any ICS application protocol, enabling fee payment to relayer operators. For more information, read the [module's documentation](../docs/04-middleware/01-ics29-fee/01-overview.md). - -### `light-clients` - -- `06-solomachine`: This package implement the types for the Solo Machine light client specified in [ICS 06](https://github.com/cosmos/ibc/tree/main/spec/client/ics-006-solo-machine-client). -- `07-tendermint`: This package implement the types for the Tendermint consensus light client as specified in [ICS 07](https://github.com/cosmos/ibc/tree/main/spec/client/ics-007-tendermint-client). - -## `proto` - -This folder contains all the Protobuf files used for - -- common message type definitions, -- message type definitions related to genesis state, -- `Query` service and related message type definitions, -- `Msg` service and related message type definitions. - -## `testing` - -This package contains the implementation of the testing package used in unit and integration tests. Please read the [package's documentation](../../testing/README.md) for more information. - -## `e2e` - -This folder contains all the e2e tests of ibc-go. Please read the [module's documentation](https://github.com/cosmos/ibc-go/blob/fec07ec55ca3e35f49a62bc6b1243c27cdf7799d/e2e/README.md) for more information. diff --git a/docs/dev/pull-requests.md b/docs/dev/pull-requests.md deleted file mode 100644 index c8db90f5049..00000000000 --- a/docs/dev/pull-requests.md +++ /dev/null @@ -1,68 +0,0 @@ -# Pull request guidelines - -> To accommodate the review process we suggest that PRs are categorically broken up. Ideally each PR addresses only a single issue and does not introduce unrelated changes. Additionally, as much as possible code refactoring and cleanup should be submitted as separate PRs from bug fixes and feature additions. - -If the PR is the result of a related GitHub issue, please include `closes: #` in the PR’s description in order to auto-close the related issue once the PR is merged. This will also link the issue and the PR together so that if anyone looks at either in the future, they won’t have any problem trying to find the corresponding issue/PR as it will be recorded in the sidebar. - -If the PR is not the result of an existing issue and it fixes a bug, please provide a detailed description of the bug. For feature addtions, we recommend opening an issue first and have it discussed and agreed upon, before working on it and opening a PR. - -If possible, [tick the "Allow edits from maintainers" box](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) when opening your PR from your fork of ibc-go. This allows us to directly make minor edits / refactors and speeds up the merging process. - -If you open a PR on ibc-go, it is mandatory to update the relevant documentation in `/docs`. - -## Pull request targeting - -Ensure that you base and target your PR on the either the `main` branch or the corresponding feature branch where a large body of work is being implemented. Please make sure that the PR is made from a branch different than either `main` or the corresponding feature branch. - -All development should be then targeted against `main` or the feature branch. Bug fixes which are required for outstanding releases should be backported if the CODEOWNERS decide it is applicable. - -## Commit Messages - -Commit messages should follow the [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/). - -When opening a PR, include the proposed commit message in the PR description. - -The commit message type should be one of: - -- `feat` / `feature` for feature work. -- `bug` / `fix` for bug fixes. -- `imp` / `improvements` for improvements. -- `doc` / `docs` / `documentation` for any documentation changes. -- `test` / `e2e` for addition or improvements of unit, integration and e2e tests or their corresponding infrastructure. -- `deprecated` for deprecation changes. -- `deps` / `build` for changes to dependencies. -- `chore` / `misc` / `nit` for any miscellaneous changes that don't fit into another category. - -**Note**: If any change is breaking, the following format must be used: - -- `type` + `(api)!` for api breaking changes, e.g. `fix(api)!: api breaking fix` -- `type` + `(statemachine)!` for state machine breaking changes, e.g. `fix(statemachine)!: state machine breaking fix` - -**`api` breaking changes take precedence over `statemachine` breaking changes.** - -## Pull request review process - -All PRs require an approval from at least one CODEOWNER before merge. PRs which cause significant changes require two approvals from CODEOWNERS. When reviewing PRs please use the following review guidelines: - -- `Approval` through the GitHub UI with the following comments: - - `Concept ACK` means that you agree with the overall proposed concept, but have neither reviewed the code nor tested it. - - `LGTM` means the above and besides you have superficially reviewed the code without considering how logic affects other parts the codebase. - - `utACK` (aka. `Untested ACK`) means the above and besides have thoroughly reviewed the code and considered the safety of logic changes, but have not tested it. - - `Tested ACK` means the above and besides you have tested the code. -- If you are only making "surface level" reviews, submit any notes as `Comments` without submitting an approval. - -A thorough review means that: - -- You understand the code and make sure that documentation is updated in the right places. -- You must also think through anything which ought to be included but is not. -- You must think through whether any added code could be partially combined (DRYed) with existing code. -- You must think through any potential security issues or incentive-compatibility flaws introduced by the changes. -- Naming must be consistent with conventions and the rest of the codebase. -- Code must live in a reasonable location, considering dependency structures (e.g. not importing testing modules in production code, or including example code modules in production code). - -## Pull request merge procedure - -- Ensure pull request branch is rebased on target branch. -- Ensure all GitHub requirements pass. -- Set the changelog entry in the commit message for the pull request. -- Squash and merge pull request. diff --git a/docs/dev/release-management.md b/docs/dev/release-management.md deleted file mode 100644 index 8e168e38d11..00000000000 --- a/docs/dev/release-management.md +++ /dev/null @@ -1,87 +0,0 @@ -# Tagging a release - -## New major release branch - -Pre-requisites for creating a release branch for a new major version: - -1. Bump [Go package version](https://github.com/cosmos/ibc-go/blob/main/go.mod#L3). -2. Change all imports. For example: if the next major version is `v3`, then change all imports starting with `github.com/cosmos/ibc-go/v2` to `github.com/cosmos/ibc-go/v3`). - -Once the above pre-requisites are satified: - -1. Start on `main`. -2. Create the release branch (`release/vX.XX.X`). For example: `release/v3.0.x`. - -## New minor release branch - -1. Start on the latest release branch in the same major release line. For example: the latest release branch in the `v3` release line is `v3.2.x`. -2. Create branch from the release branch. For example: create branch `release/v3.3.x` from `v3.2.x`. - -Post-requisites for both new major and minor release branches: - -1. Add branch protection rules to new release branch. -2. Add backport task to [`mergify.yml`](https://github.com/cosmos/ibc-go/blob/main/.github/mergify.yml). -3. Create label for backport (e.g.`backport-to-v3.0.x`). - -## Point release procedure - -In order to alleviate the burden for a single person to have to cherry-pick and handle merge conflicts of all desired backporting PRs to a point release, we instead maintain a living backport branch, where all desired features and bug fixes are merged into as separate PRs. - -### Example - -Current release is `v1.0.2`. We then maintain a (living) branch `release/v1.0.x`, given `x` as the next patch release number (currently `v1.0.3`) for the `v1.0` release series. As bugs are fixed and PRs are merged into `main`, if a contributor wishes the PR to be released into the `v1.0.x` point release, the contributor must: - -1. Add the `backport-to-v1.0x` label to the PR. -2. Once the PR is merged, the Mergify GitHub application will automatically copy the changes into another branch and open a new PR agains the desired `release/v1.0.x` branch. -3. If the following has not been discussed in the original PR, then update the backport PR's description and ensure it contains the following information: - -- **[Impact]** explanation of how the bug affects users or developers. -- **[Test Case]** section with detailed instructions on how to reproduce the bug. -- **[Regression Potential]** section with a discussion how regressions are most likely to manifest, or might manifest even if it's unlikely, as a result of the change. **It is assumed that any backport PR is well-tested before it is merged in and has an overall low risk of regression**. This section should discuss the potential for state breaking changes to occur such as through out-of-gas errors. - -It is the PR's author's responsibility to fix merge conflicts, update changelog entries, and ensure CI passes. If a PR originates from an external contributor, it may be a core team member's responsibility to perform this process instead of the original author. Lastly, it is core team's responsibility to ensure that the PR meets all the backport criteria. - -Finally, when a point release is ready to be made: - -1. Checkout the release branch (e.g. `release/v1.0.x`). -2. In `CHANGELOG.md`: - -- Ensure changelog entries are verified. -- Remove any sections of the changelog that do not have any entries (e.g. if the release does not have any bug fixes, then remove the section). -- Remove the `[Unreleased]` title. -- Add release version and date of release. - -3. Create release in GitHub: - -- Select the correct target branch (e.g. `release/v1.0.x`). -- Choose a tag (e.g. `v1.0.3`). -- Write release notes. -- Check the `This is a pre-release` checkbox if needed (this applies for alpha, beta and release candidates). - -### Post-release procedure - -- Update [`CHANGELOG.md`](../../CHANGELOG.md) in `main` (remove from the `[Unreleased]` section any items that are part of the release).` -- Put back the `[Unreleased]` section in the release branch (e.g. `release/v1.0.x`) with clean sections for each of the types of changelog entries, so that entries will be added for the PRs that are backported for the next release. -- Update [version matrix](../../RELEASES.md#version-matrix) in `RELEASES.md`: add the new release and remove any tags that might not be recommended anymore. - -Additionally, for the first point release of a new major or minor release branch: - -- Update the table of supported release lines (and End of Life dates) in [`RELEASES.md`](../../RELEASES.md): add the new release line and remove any release lines that might have become discontinued. -- Update the [list of supported release lines in README.md](../../RELEASES.md#releases), if necessary. -- Update the [e2e compatibility test matrices](https://github.com/cosmos/ibc-go/tree/main/.github/compatibility-test-matrices): add the tag for the new release and remove any tags that might not be recommended anymore. -- Update the manual [e2e `simd`](https://github.com/cosmos/ibc-go/blob/main/.github/workflows/e2e-manual-simd.yaml) test workflow: - - Remove any tags that might not be recommended anymore. - -- Bump ibc-go version in [cosmos/interchain-accounts-demo repository](https://github.com/cosmos/interchain-accounts-demo) and create a tag. -- [ ] Update docs site: - - [ ] If the release is occurring on the main branch, on the latest version, then run `npm run docusaurus docs:version vX.Y.Z` in the `docs/` directory. (where `X.Y.Z` is the new version number) - - [ ] If the release is occurring on an older release branch, then make a PR to the main branch called `docs: new release vX.Y.Z` doing the following: - - [ ] Update the content of the docs found in `docs/versioned_docs/version-vx.y.z` if needed. (where `x.y.z` is the previous version number) - - [ ] Update the version number of the older release branch by changing the version number of the older release branch in: - - [ ] In `docs/versions.json`. - - [ ] Rename `docs/versioned_sidebars/version-vx.y.z-sidebars.json` - - [ ] Rename `docs/versioned_docs/version-vx.y.z` -- After changes to docs site are deployed, check [ibc.cosmos.network](https://ibc.cosmos.network) is updated. -- Open issue in [SDK tutorials repo](https://github.com/cosmos/sdk-tutorials) to update tutorials to the released version of ibc-go. - -See [this PR](https://github.com/cosmos/ibc-go/pull/2919) for an example of the involved changes. diff --git a/docs/docs/00-intro.md b/docs/docs/00-intro.md deleted file mode 100644 index 1e1c6a89f96..00000000000 --- a/docs/docs/00-intro.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -slug: / -sidebar_position: 0 ---- - -# IBC-Go Documentation - -Welcome to the documentation for IBC-Go, the Golang implementation of the Inter-Blockchain Communication Protocol! Looking for information on ibc-rs? [Click here to go to the ibc-rs github repo](https://github.com/cosmos/ibc-rs). - -The Inter-Blockchain Communication protocol (IBC) is an end-to-end, connection-oriented, stateful protocol for reliable, ordered, and authenticated communication between heterogeneous blockchains arranged in an unknown and dynamic topology. - -IBC is a protocol that allows blockchains to talk to each other. Chains that speak IBC can share arbitrary data, enabling the industry’s most feature-rich cross-chain interactions. IBC is secure and permissionless. - -The protocol realizes this interoperability by specifying a set of data structures, abstractions, and semantics that can be implemented by any distributed ledger that satisfies a small set of requirements. - -IBC can be used to build a wide range of cross-chain applications that include token transfers, atomic swaps, multi-chain smart contracts (with or without mutually comprehensible VMs), and data and code sharding of various kinds. diff --git a/docs/docs/01-ibc/01-overview.md b/docs/docs/01-ibc/01-overview.md deleted file mode 100644 index ccae6fc27be..00000000000 --- a/docs/docs/01-ibc/01-overview.md +++ /dev/null @@ -1,297 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /ibc/overview ---- - - -# Overview - -:::note Synopsis -Learn about IBC, its components, and IBC use cases. -::: - -## What is the Interblockchain Communication Protocol (IBC)? - -This document serves as a guide for developers who want to write their own Inter-Blockchain -Communication protocol (IBC) applications for custom use cases. - -> IBC applications must be written as self-contained modules. - -Due to the modular design of the IBC protocol, IBC -application developers do not need to be concerned with the low-level details of clients, -connections, and proof verification. - -This brief explanation of the lower levels of the -stack gives application developers a broad understanding of the IBC -protocol. Abstraction layer details for channels and ports are most relevant for application developers and describe how to define custom packets and `IBCModule` callbacks. - -The requirements to have your module interact over IBC are: - -- Bind to a port or ports. -- Define your packet data. -- Use the default acknowledgment struct provided by core IBC or optionally define a custom acknowledgment struct. -- Standardize an encoding of the packet data. -- Implement the `IBCModule` interface. - -Read on for a detailed explanation of how to write a self-contained IBC application module. - -## Components Overview - -### [Clients](https://github.com/cosmos/ibc-go/blob/main/modules/core/02-client) - -IBC clients are on-chain light clients. Each light client is identified by a unique client-id. -IBC clients track the consensus states of other blockchains, along with the proof spec necessary to -properly verify proofs against the client's consensus state. A client can be associated with any number -of connections to the counterparty chain. The client identifier is auto generated using the client type -and the global client counter appended in the format: `{client-type}-{N}`. - -A `ClientState` should contain chain specific and light client specific information necessary for verifying updates -and upgrades to the IBC client. The `ClientState` may contain information such as chain-id, latest height, proof specs, -unbonding periods or the status of the light client. The `ClientState` should not contain information that -is specific to a given block at a certain height, this is the function of the `ConsensusState`. Each `ConsensusState` -should be associated with a unique block and should be referenced using a height. IBC clients are given a -client identifier prefixed store to store their associated client state and consensus states along with -any metadata associated with the consensus states. Consensus states are stored using their associated height. - -The supported IBC clients are: - -- [Solo Machine light client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/06-solomachine): Devices such as phones, browsers, or laptops. -- [Tendermint light client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/07-tendermint): The default for Cosmos SDK-based chains. -- [Localhost (loopback) client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/09-localhost): Useful for -testing, simulation, and relaying packets to modules on the same application. - -### IBC Client Heights - -IBC Client Heights are represented by the struct: - -```go -type Height struct { - RevisionNumber uint64 - RevisionHeight uint64 -} -``` - -The `RevisionNumber` represents the revision of the chain that the height is representing. -A revision typically represents a continuous, monotonically increasing range of block-heights. -The `RevisionHeight` represents the height of the chain within the given revision. - -On any reset of the `RevisionHeight`—for example, when hard-forking a Tendermint chain— -the `RevisionNumber` will get incremented. This allows IBC clients to distinguish between a -block-height `n` of a previous revision of the chain (at revision `p`) and block-height `n` of the current -revision of the chain (at revision `e`). - -`Height`s that share the same revision number can be compared by simply comparing their respective `RevisionHeight`s. -`Height`s that do not share the same revision number will only be compared using their respective `RevisionNumber`s. -Thus a height `h` with revision number `e+1` will always be greater than a height `g` with revision number `e`, -**REGARDLESS** of the difference in revision heights. - -Ex: - -```go -Height{RevisionNumber: 3, RevisionHeight: 0} > Height{RevisionNumber: 2, RevisionHeight: 100000000000} -``` - -When a Tendermint chain is running a particular revision, relayers can simply submit headers and proofs with the revision number -given by the chain's `chainID`, and the revision height given by the Tendermint block height. When a chain updates using a hard-fork -and resets its block-height, it is responsible for updating its `chainID` to increment the revision number. -IBC Tendermint clients then verifies the revision number against their `chainID` and treat the `RevisionHeight` as the Tendermint block-height. - -Tendermint chains wishing to use revisions to maintain persistent IBC connections even across height-resetting upgrades must format their `chainID`s -in the following manner: `{chainID}-{revision_number}`. On any height-resetting upgrade, the `chainID` **MUST** be updated with a higher revision number -than the previous value. - -Ex: - -- Before upgrade `chainID`: `gaiamainnet-3` -- After upgrade `chainID`: `gaiamainnet-4` - -Clients that do not require revisions, such as the solo-machine client, simply hardcode `0` into the revision number whenever they -need to return an IBC height when implementing IBC interfaces and use the `RevisionHeight` exclusively. - -Other client-types can implement their own logic to verify the IBC heights that relayers provide in their `Update`, `Misbehavior`, and -`Verify` functions respectively. - -The IBC interfaces expect an `ibcexported.Height` interface, however all clients must use the concrete implementation provided in -`02-client/types` and reproduced above. - -### [Connections](https://github.com/cosmos/ibc-go/blob/main/modules/core/03-connection) - -Connections encapsulate two `ConnectionEnd` objects on two separate blockchains. Each -`ConnectionEnd` is associated with a client of the other blockchain (for example, the counterparty blockchain). -The connection handshake is responsible for verifying that the light clients on each chain are -correct for their respective counterparties. Connections, once established, are responsible for -facilitating all cross-chain verifications of IBC state. A connection can be associated with any -number of channels. - -### [Proofs](https://github.com/cosmos/ibc-go/blob/main/modules/core/23-commitment) and [Paths](https://github.com/cosmos/ibc-go/blob/main/modules/core/24-host) - -In IBC, blockchains do not directly pass messages to each other over the network. Instead, to -communicate, a blockchain commits some state to a specifically defined path that is reserved for a -specific message type and a specific counterparty. For example, for storing a specific connectionEnd as part -of a handshake or a packet intended to be relayed to a module on the counterparty chain. A relayer -process monitors for updates to these paths and relays messages by submitting the data stored -under the path and a proof to the counterparty chain. - -Proofs are passed from core IBC to light-clients as bytes. It is up to light client implementation to interpret these bytes appropriately. - -- The paths that all IBC implementations must use for committing IBC messages is defined in -[ICS-24 Host State Machine Requirements](https://github.com/cosmos/ics/tree/master/spec/core/ics-024-host-requirements). -- The proof format that all implementations must be able to produce and verify is defined in [ICS-23 Proofs](https://github.com/cosmos/ics23) implementation. - -### [Capabilities](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/advanced/10-ocap.md) - -IBC is intended to work in execution environments where modules do not necessarily trust each -other. Thus, IBC must authenticate module actions on ports and channels so that only modules with the -appropriate permissions can use them. - -This module authentication is accomplished using a [dynamic -capability store](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-003-dynamic-capability-store.md). Upon binding to a port or -creating a channel for a module, IBC returns a dynamic capability that the module must claim in -order to use that port or channel. The dynamic capability module prevents other modules from using that port or channel since -they do not own the appropriate capability. - -While this background information is useful, IBC modules do not need to interact at all with -these lower-level abstractions. The relevant abstraction layer for IBC application developers is -that of channels and ports. IBC applications must be written as self-contained **modules**. - -A module on one blockchain can communicate with other modules on other blockchains by sending, -receiving, and acknowledging packets through channels that are uniquely identified by the -`(channelID, portID)` tuple. - -A useful analogy is to consider IBC modules as internet applications on -a computer. A channel can then be conceptualized as an IP connection, with the IBC portID being -analogous to an IP port and the IBC channelID being analogous to an IP address. Thus, a single -instance of an IBC module can communicate on the same port with any number of other modules and -IBC correctly routes all packets to the relevant module using the (channelID, portID tuple). An -IBC module can also communicate with another IBC module over multiple ports, with each -`(portID<->portID)` packet stream being sent on a different unique channel. - -### [Ports](https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port) - -An IBC module can bind to any number of ports. Each port must be identified by a unique `portID`. -Since IBC is designed to be secure with mutually distrusted modules operating on the same ledger, -binding a port returns a dynamic object capability. In order to take action on a particular port -(for example, an open channel with its portID), a module must provide the dynamic object capability to the IBC -handler. This requirement prevents a malicious module from opening channels with ports it does not own. Thus, -IBC modules are responsible for claiming the capability that is returned on `BindPort`. - -### [Channels](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -An IBC channel can be established between two IBC ports. Currently, a port is exclusively owned by a -single module. IBC packets are sent over channels. Just as IP packets contain the destination IP -address and IP port, and the source IP address and source IP port, IBC packets contain -the destination portID and channelID, and the source portID and channelID. This packet structure enables IBC to -correctly route packets to the destination module while allowing modules receiving packets to -know the sender module. - -A channel can be `ORDERED`, where packets from a sending module must be processed by the -receiving module in the order they were sent. Or a channel can be `UNORDERED`, where packets -from a sending module are processed in the order they arrive (might be in a different order than they were sent). - -Modules can choose which channels they wish to communicate over with, thus IBC expects modules to -implement callbacks that are called during the channel handshake. These callbacks can do custom -channel initialization logic. If any callback returns an error, the channel handshake fails. Thus, by -returning errors on callbacks, modules can programmatically reject and accept channels. - -The channel handshake is a 4-step handshake. Briefly, if a given chain A wants to open a channel with -chain B using an already established connection: - -1. chain A sends a `ChanOpenInit` message to signal a channel initialization attempt with chain B. -2. chain B sends a `ChanOpenTry` message to try opening the channel on chain A. -3. chain A sends a `ChanOpenAck` message to mark its channel end status as open. -4. chain B sends a `ChanOpenConfirm` message to mark its channel end status as open. - -If all handshake steps are successful, the channel is opened on both sides. At each step in the handshake, the module -associated with the `ChannelEnd` executes its callback. So -on `ChanOpenInit`, the module on chain A executes its callback `OnChanOpenInit`. - -The channel identifier is auto derived in the format: `channel-{N}` where N is the next sequence to be used. - -Just as ports came with dynamic capabilities, channel initialization returns a dynamic capability -that the module **must** claim so that they can pass in a capability to authenticate channel actions -like sending packets. The channel capability is passed into the callback on the first parts of the -handshake; either `OnChanOpenInit` on the initializing chain or `OnChanOpenTry` on the other chain. - -#### Closing channels - -Closing a channel occurs in 2 handshake steps as defined in [ICS 04](https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics). - -`ChanCloseInit` closes a channel on the executing chain if the channel exists, it is not -already closed and the connection it exists upon is OPEN. Channels can only be closed by a -calling module or in the case of a packet timeout on an ORDERED channel. - -`ChanCloseConfirm` is a response to a counterparty channel executing `ChanCloseInit`. The channel -on the executing chain closes if the channel exists, the channel is not already closed, -the connection the channel exists upon is OPEN and the executing chain successfully verifies -that the counterparty channel has been closed. - -### [Packets](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -Modules communicate with each other by sending packets over IBC channels. All -IBC packets contain the destination `portID` and `channelID` along with the source `portID` and -`channelID`. This packet structure allows modules to know the sender module of a given packet. IBC packets -contain a sequence to optionally enforce ordering. - -IBC packets also contain a `TimeoutHeight` and a `TimeoutTimestamp` that determine the deadline before the receiving module must process a packet. - -Modules send custom application data to each other inside the `Data []byte` field of the IBC packet. -Thus, packet data is opaque to IBC handlers. It is incumbent on a sender module to encode -their application-specific packet information into the `Data` field of packets. The receiver -module must decode that `Data` back to the original application data. - -### [Receipts and Timeouts](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -Since IBC works over a distributed network and relies on potentially faulty relayers to relay messages between ledgers, -IBC must handle the case where a packet does not get sent to its destination in a timely manner or at all. Packets must -specify a non-zero value for timeout height (`TimeoutHeight`) or timeout timestamp (`TimeoutTimestamp` ) after which a packet can no longer be successfully received on the destination chain. - -- The `timeoutHeight` indicates a consensus height on the destination chain after which the packet is no longer be processed, and instead counts as having timed-out. -- The `timeoutTimestamp` indicates a timestamp on the destination chain after which the packet is no longer be processed, and instead counts as having timed-out. - -If the timeout passes without the packet being successfully received, the packet can no longer be -received on the destination chain. The sending module can timeout the packet and take appropriate actions. - -If the timeout is reached, then a proof of packet timeout can be submitted to the original chain. The original chain can then perform -application-specific logic to timeout the packet, perhaps by rolling back the packet send changes (refunding senders any locked funds, etc.). - -- In ORDERED channels, a timeout of a single packet in the channel causes the channel to close. - - - If packet sequence `n` times out, then a packet at sequence `k > n` cannot be received without violating the contract of ORDERED channels that packets are processed in the order that they are sent. - - Since ORDERED channels enforce this invariant, a proof that sequence `n` has not been received on the destination chain by the specified timeout of packet `n` is sufficient to timeout packet `n` and close the channel. - -- In UNORDERED channels, the application-specific timeout logic for that packet is applied and the channel is not closed. - - - Packets can be received in any order. - - - IBC writes a packet receipt for each sequence receives in the UNORDERED channel. This receipt does not contain information; it is simply a marker intended to signify that the UNORDERED channel has received a packet at the specified sequence. - - - To timeout a packet on an UNORDERED channel, a proof is required that a packet receipt **does not exist** for the packet's sequence by the specified timeout. - -For this reason, most modules should use UNORDERED channels as they require fewer liveness guarantees to function effectively for users of that channel. - -### [Acknowledgments](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -Modules can also choose to write application-specific acknowledgments upon processing a packet. Acknowledgments can be done: - -- Synchronously on `OnRecvPacket` if the module processes packets as soon as they are received from IBC module. -- Asynchronously if module processes packets at some later point after receiving the packet. - -This acknowledgment data is opaque to IBC much like the packet `Data` and is treated by IBC as a simple byte string `[]byte`. Receiver modules must encode their acknowledgment so that the sender module can decode it correctly. The encoding must be negotiated between the two parties during version negotiation in the channel handshake. - -The acknowledgment can encode whether the packet processing succeeded or failed, along with additional information that allows the sender module to take appropriate action. - -After the acknowledgment has been written by the receiving chain, a relayer relays the acknowledgment back to the original sender module. - -The original sender module then executes application-specific acknowledgment logic using the contents of the acknowledgment. - -- After an acknowledgement fails, packet-send changes can be rolled back (for example, refunding senders in ICS20). - -- After an acknowledgment is received successfully on the original sender on the chain, the corresponding packet commitment is deleted since it is no longer needed. - -## Further Readings and Specs - -If you want to learn more about IBC, check the following specifications: - -- [IBC specification overview](https://github.com/cosmos/ibc/blob/master/README.md) diff --git a/docs/docs/01-ibc/02-integration.md b/docs/docs/01-ibc/02-integration.md deleted file mode 100644 index ed67606f399..00000000000 --- a/docs/docs/01-ibc/02-integration.md +++ /dev/null @@ -1,230 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 2 -slug: /ibc/integration ---- - -# Integration - -:::note Synopsis -Learn how to integrate IBC to your application and send data packets to other chains. -::: - -This document outlines the required steps to integrate and configure the [IBC -module](https://github.com/cosmos/ibc-go/tree/main/modules/core) to your Cosmos SDK application and -send fungible token transfers to other chains. - -## Integrating the IBC module - -Integrating the IBC module to your SDK-based application is straighforward. The general changes can be summarized in the following steps: - -- Add required modules to the `module.BasicManager` -- Define additional `Keeper` fields for the new modules on the `App` type -- Add the module's `StoreKey`s and initialize their `Keeper`s -- Set up corresponding routers and routes for the `ibc` module -- Add the modules to the module `Manager` -- Add modules to `Begin/EndBlockers` and `InitGenesis` -- Update the module `SimulationManager` to enable simulations - -### Module `BasicManager` and `ModuleAccount` permissions - -The first step is to add the following modules to the `BasicManager`: `x/capability`, `x/ibc`, -and `x/ibc-transfer`. After that, we need to grant `Minter` and `Burner` permissions to -the `ibc-transfer` `ModuleAccount` to mint and burn relayed tokens. - -### Integrating light clients - -> Note that from v7 onwards, all light clients have to be explicitly registered in a chain's app.go and follow the steps listed below. -> This is in contrast to earlier versions of ibc-go when `07-tendermint` and `06-solomachine` were added out of the box. - -All light clients must be registered with `module.BasicManager` in a chain's app.go file. - -The following code example shows how to register the existing `ibctm.AppModuleBasic{}` light client implementation. - -```go -import ( - ... - // highlight-next-line -+ ibctm "github.com/cosmos/ibc-go/v6/modules/light-clients/07-tendermint" - ... -) - -// app.go -var ( - ModuleBasics = module.NewBasicManager( - // ... - capability.AppModuleBasic{}, - ibc.AppModuleBasic{}, - transfer.AppModuleBasic{}, // i.e ibc-transfer module - - // register light clients on IBC - // highlight-next-line -+ ibctm.AppModuleBasic{}, - ) - - // module account permissions - maccPerms = map[string][]string{ - // other module accounts permissions - // ... - ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, - } -) -``` - -### Application fields - -Then, we need to register the `Keepers` as follows: - -```go title="app.go" -type App struct { - // baseapp, keys and subspaces definitions - - // other keepers - // ... - IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly - TransferKeeper ibctransferkeeper.Keeper // for cross-chain fungible token transfers - - // make scoped keepers public for test purposes - ScopedIBCKeeper capabilitykeeper.ScopedKeeper - ScopedTransferKeeper capabilitykeeper.ScopedKeeper - - /// ... - /// module and simulation manager definitions -} -``` - -### Configure the `Keepers` - -During initialization, besides initializing the IBC `Keepers` (for the `x/ibc`, and -`x/ibc-transfer` modules), we need to grant specific capabilities through the capability module -`ScopedKeepers` so that we can authenticate the object-capability permissions for each of the IBC -channels. - -```go -func NewApp(...args) *App { - // define codecs and baseapp - - // add capability keeper and ScopeToModule for ibc module - app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey]) - - // grant capabilities for the ibc and ibc-transfer modules - scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibcexported.ModuleName) - scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) - - // ... other modules keepers - - // Create IBC Keeper - app.IBCKeeper = ibckeeper.NewKeeper( - appCodec, keys[ibcexported.StoreKey], app.GetSubspace(ibcexported.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper, - ) - - // Create Transfer Keepers - app.TransferKeeper = ibctransferkeeper.NewKeeper( - appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName), - app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, app.BankKeeper, scopedTransferKeeper, - ) - transferModule := transfer.NewAppModule(app.TransferKeeper) - - // .. continues -} -``` - -### Register `Routers` - -IBC needs to know which module is bound to which port so that it can route packets to the -appropriate module and call the appropriate callbacks. The port to module name mapping is handled by -IBC's port `Keeper`. However, the mapping from module name to the relevant callbacks is accomplished -by the port -[`Router`](https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port/types/router.go) on the -IBC module. - -Adding the module routes allows the IBC handler to call the appropriate callback when processing a -channel handshake or a packet. - -Currently, a `Router` is static so it must be initialized and set correctly on app initialization. -Once the `Router` has been set, no new routes can be added. - -```go title="app.go" -func NewApp(...args) *App { - // .. continuation from above - - // Create static IBC router, add ibc-tranfer module route, then set and seal it - ibcRouter := port.NewRouter() - ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule) - // Setting Router will finalize all routes by sealing router - // No more routes can be added - app.IBCKeeper.SetRouter(ibcRouter) - - // .. continues -``` - -### Module Managers - -In order to use IBC, we need to add the new modules to the module `Manager` and to the `SimulationManager` in case your application supports [simulations](https://github.com/cosmos/cosmos-sdk/blob/main/docs/build/building-modules/14-simulator.md). - -```go title="app.go" -func NewApp(...args) *App { - // .. continuation from above - - app.mm = module.NewManager( - // other modules - // ... - capability.NewAppModule(appCodec, *app.CapabilityKeeper), - ibc.NewAppModule(app.IBCKeeper), - transferModule, - ) - - // ... - - app.sm = module.NewSimulationManager( - // other modules - // ... - capability.NewAppModule(appCodec, *app.CapabilityKeeper), - ibc.NewAppModule(app.IBCKeeper), - transferModule, - ) - - // .. continues -``` - -### Application ABCI Ordering - -One addition from IBC is the concept of `HistoricalEntries` which are stored on the staking module. -Each entry contains the historical information for the `Header` and `ValidatorSet` of this chain which is stored -at each height during the `BeginBlock` call. The historical info is required to introspect the -past historical info at any given height in order to verify the light client `ConsensusState` during the -connection handhake. - -```go title="app.go" -func NewApp(...args) *App { - // .. continuation from above - - // add staking and ibc modules to BeginBlockers - app.mm.SetOrderBeginBlockers( - // other modules ... - stakingtypes.ModuleName, ibcexported.ModuleName, - ) - - // ... - - // 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. - app.mm.SetOrderInitGenesis( - capabilitytypes.ModuleName, - // other modules ... - ibcexported.ModuleName, ibctransfertypes.ModuleName, - ) - - // .. continues -``` - -:::warning -**IMPORTANT**: The capability module **must** be declared first in `SetOrderInitGenesis` -::: - -That's it! You have now wired up the IBC module and are now able to send fungible tokens across -different chains. If you want to have a broader view of the changes take a look into the SDK's -[`SimApp`](https://github.com/cosmos/ibc-go/blob/main/testing/simapp/app.go). diff --git a/docs/docs/01-ibc/03-apps/01-apps.md b/docs/docs/01-ibc/03-apps/01-apps.md deleted file mode 100644 index a80747c7642..00000000000 --- a/docs/docs/01-ibc/03-apps/01-apps.md +++ /dev/null @@ -1,494 +0,0 @@ ---- -title: IBC Applications -sidebar_label: IBC Applications -sidebar_position: 1 -slug: /ibc/apps/apps ---- - -# IBC Applications - -Learn how to configure your application to use IBC and send data packets to other chains. {synopsis} - -This document serves as a guide for developers who want to write their own Inter-blockchain -Communication Protocol (IBC) applications for custom use cases. - -Due to the modular design of the IBC protocol, IBC -application developers do not need to concern themselves with the low-level details of clients, -connections, and proof verification. Nevertheless a brief explanation of the lower levels of the -stack is given so that application developers may have a high-level understanding of the IBC -protocol. Then the document goes into detail on the abstraction layer most relevant for application -developers (channels and ports), and describes how to define your own custom packets, and -`IBCModule` callbacks. - -To have your module interact over IBC you must: bind to a port(s), define your own packet data and acknowledgement structs as well as how to encode/decode them, and implement the -`IBCModule` interface. Below is a more detailed explanation of how to write an IBC application -module correctly. - -:::note - -## Pre-requisites Readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: - -## Create a custom IBC application module - -### Implement `IBCModule` Interface and callbacks - -The Cosmos SDK expects all IBC modules to implement the [`IBCModule` -interface](https://github.com/cosmos/ibc-go/tree/main/modules/core/05-port/types/module.go). This -interface contains all of the callbacks IBC expects modules to implement. This section will describe -the callbacks that are called during channel handshake execution. - -Here are the channel handshake callbacks that modules are expected to implement: - -```go -// Called by IBC Handler on MsgOpenInit -func (k Keeper) OnChanOpenInit(ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) error { - // OpenInit must claim the channelCapability that IBC passes into the callback - if err := k.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return err - } - - // ... do custom initialization logic - - // Use above arguments to determine if we want to abort handshake - // Examples: Abort if order == UNORDERED, - // Abort if version is unsupported - err := checkArguments(args) - return err -} - -// Called by IBC Handler on MsgOpenTry -OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (string, error) { - // OpenTry must claim the channelCapability that IBC passes into the callback - if err := k.scopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return err - } - - // ... do custom initialization logic - - // Use above arguments to determine if we want to abort handshake - if err := checkArguments(args); err != nil { - return err - } - - // Construct application version - // IBC applications must return the appropriate application version - // This can be a simple string or it can be a complex version constructed - // from the counterpartyVersion and other arguments. - // The version returned will be the channel version used for both channel ends. - appVersion := negotiateAppVersion(counterpartyVersion, args) - - return appVersion, nil -} - -// Called by IBC Handler on MsgOpenAck -OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyVersion string, -) error { - // ... do custom initialization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} - -// Called by IBC Handler on MsgOpenConfirm -OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // ... do custom initialization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} -``` - -The channel closing handshake will also invoke module callbacks that can return errors to abort the -closing handshake. Closing a channel is a 2-step handshake, the initiating chain calls -`ChanCloseInit` and the finalizing chain calls `ChanCloseConfirm`. - -```go -// Called by IBC Handler on MsgCloseInit -OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - // ... do custom finalization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} - -// Called by IBC Handler on MsgCloseConfirm -OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // ... do custom finalization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} -``` - -#### Channel Handshake Version Negotiation - -Application modules are expected to verify versioning used during the channel handshake procedure. - -- `ChanOpenInit` callback should verify that the `MsgChanOpenInit.Version` is valid -- `ChanOpenTry` callback should construct the application version used for both channel ends. If no application version can be constructed, it must return an error. -- `ChanOpenAck` callback should verify that the `MsgChanOpenAck.CounterpartyVersion` is valid and supported. - -IBC expects application modules to perform application version negotiation in `OnChanOpenTry`. The negotiated version -must be returned to core IBC. If the version cannot be negotiated, an error should be returned. - -Versions must be strings but can implement any versioning structure. If your application plans to -have linear releases then semantic versioning is recommended. If your application plans to release -various features in between major releases then it is advised to use the same versioning scheme -as IBC. This versioning scheme specifies a version identifier and compatible feature set with -that identifier. Valid version selection includes selecting a compatible version identifier with -a subset of features supported by your application for that version. The struct is used for this -scheme can be found in `03-connection/types`. - -Since the version type is a string, applications have the ability to do simple version verification -via string matching or they can use the already impelemented versioning system and pass the proto -encoded version into each handhshake call as necessary. - -ICS20 currently implements basic string matching with a single supported version. - -### Bind Ports - -Currently, ports must be bound on app initialization. A module may bind to ports in `InitGenesis` -like so: - -```go -func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, state types.GenesisState) { - // ... other initialization logic - - // Only try to bind to port if it is not already bound, since we may already own - // port capability from capability InitGenesis - if !hasCapability(ctx, state.PortID) { - // module binds to desired ports on InitChain - // and claims returned capabilities - cap1 := keeper.IBCPortKeeper.BindPort(ctx, port1) - cap2 := keeper.IBCPortKeeper.BindPort(ctx, port2) - cap3 := keeper.IBCPortKeeper.BindPort(ctx, port3) - - // NOTE: The module's scoped capability keeper must be private - keeper.scopedKeeper.ClaimCapability(cap1) - keeper.scopedKeeper.ClaimCapability(cap2) - keeper.scopedKeeper.ClaimCapability(cap3) - } - - // ... more initialization logic -} -``` - -### Custom Packets - -Modules connected by a channel must agree on what application data they are sending over the -channel, as well as how they will encode/decode it. This process is not specified by IBC as it is up -to each application module to determine how to implement this agreement. However, for most -applications this will happen as a version negotiation during the channel handshake. While more -complex version negotiation is possible to implement inside the channel opening handshake, a very -simple version negotation is implemented in the [ibc-transfer module](https://github.com/cosmos/ibc-go/tree/main/modules/apps/transfer/module.go). - -Thus, a module must define its a custom packet data structure, along with a well-defined way to -encode and decode it to and from `[]byte`. - -```go -// Custom packet data defined in application module -type CustomPacketData struct { - // Custom fields ... -} - -EncodePacketData(packetData CustomPacketData) []byte { - // encode packetData to bytes -} - -DecodePacketData(encoded []byte) (CustomPacketData) { - // decode from bytes to packet data -} -``` - -Then a module must encode its packet data before sending it through IBC. - -```go -// retrieve the dynamic capability for this channel -channelCap := scopedKeeper.GetCapability(ctx, channelCapName) -// Sending custom application packet data -data := EncodePacketData(customPacketData) -packet.Data = data -// Send packet to IBC, authenticating with channelCap -sequence, err := IBCChannelKeeper.SendPacket( - ctx, - channelCap, - sourcePort, - sourceChannel, - timeoutHeight, - timeoutTimestamp, - data, -) -``` - -A module receiving a packet must decode the `PacketData` into a structure it expects so that it can -act on it. - -```go -// Receiving custom application packet data (in OnRecvPacket) -packetData := DecodePacketData(packet.Data) -// handle received custom packet data -``` - -#### Packet Flow Handling - -Just as IBC expected modules to implement callbacks for channel handshakes, IBC also expects modules -to implement callbacks for handling the packet flow through a channel. - -Once a module A and module B are connected to each other, relayers can start relaying packets and -acknowledgements back and forth on the channel. - -![IBC packet flow diagram](https://media.githubusercontent.com/media/cosmos/ibc/old/spec/ics-004-channel-and-packet-semantics/channel-state-machine.png) - -Briefly, a successful packet flow works as follows: - -1. module A sends a packet through the IBC module -2. the packet is received by module B -3. if module B writes an acknowledgement of the packet then module A will process the - acknowledgement -4. if the packet is not successfully received before the timeout, then module A processes the - packet's timeout. - -##### Sending Packets - -Modules do not send packets through callbacks, since the modules initiate the action of sending -packets to the IBC module, as opposed to other parts of the packet flow where msgs sent to the IBC -module must trigger execution on the port-bound module through the use of callbacks. Thus, to send a -packet a module simply needs to call `SendPacket` on the `IBCChannelKeeper`. - -```go -// retrieve the dynamic capability for this channel -channelCap := scopedKeeper.GetCapability(ctx, channelCapName) -// Sending custom application packet data -data := EncodePacketData(customPacketData) -// Send packet to IBC, authenticating with channelCap -sequence, err := IBCChannelKeeper.SendPacket( - ctx, - channelCap, - sourcePort, - sourceChannel, - timeoutHeight, - timeoutTimestamp, - data, -) -``` - -::: warning -In order to prevent modules from sending packets on channels they do not own, IBC expects -modules to pass in the correct channel capability for the packet's source channel. -::: - -##### Receiving Packets - -To handle receiving packets, the module must implement the `OnRecvPacket` callback. This gets -invoked by the IBC module after the packet has been proved valid and correctly processed by the IBC -keepers. Thus, the `OnRecvPacket` callback only needs to worry about making the appropriate state -changes given the packet data without worrying about whether the packet is valid or not. - -Modules may return to the IBC handler an acknowledgement which implements the Acknowledgement interface. -The IBC handler will then commit this acknowledgement of the packet so that a relayer may relay the -acknowledgement back to the sender module. - -The state changes that occurred during this callback will only be written if: - -- the acknowledgement was successful as indicated by the `Success()` function of the acknowledgement -- if the acknowledgement returned is nil indicating that an asynchronous process is occurring - -NOTE: Applications which process asynchronous acknowledgements must handle reverting state changes -when appropriate. Any state changes that occurred during the `OnRecvPacket` callback will be written -for asynchronous acknowledgements. - -```go -OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, -) ibcexported.Acknowledgement { - // Decode the packet data - packetData := DecodePacketData(packet.Data) - - // do application state changes based on packet data and return the acknowledgement - // NOTE: The acknowledgement will indicate to the IBC handler if the application - // state changes should be written via the `Success()` function. Application state - // changes are only written if the acknowledgement is successful or the acknowledgement - // returned is nil indicating that an asynchronous acknowledgement will occur. - ack := processPacket(ctx, packet, packetData) - - return ack -} -``` - -The Acknowledgement interface: - -```go -// Acknowledgement defines the interface used to return -// acknowledgements in the OnRecvPacket callback. -type Acknowledgement interface { - Success() bool - Acknowledgement() []byte -} -``` - -### Acknowledgements - -Modules may commit an acknowledgement upon receiving and processing a packet in the case of synchronous packet processing. -In the case where a packet is processed at some later point after the packet has been received (asynchronous execution), the acknowledgement -will be written once the packet has been processed by the application which may be well after the packet receipt. - -NOTE: Most blockchain modules will want to use the synchronous execution model in which the module processes and writes the acknowledgement -for a packet as soon as it has been received from the IBC module. - -This acknowledgement can then be relayed back to the original sender chain, which can take action -depending on the contents of the acknowledgement. - -Just as packet data was opaque to IBC, acknowledgements are similarly opaque. Modules must pass and -receive acknowledegments with the IBC modules as byte strings. - -Thus, modules must agree on how to encode/decode acknowledgements. The process of creating an -acknowledgement struct along with encoding and decoding it, is very similar to the packet data -example above. [ICS 04](https://github.com/cosmos/ibc/blob/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope) -specifies a recommended format for acknowledgements. This acknowledgement type can be imported from -[channel types](https://github.com/cosmos/ibc-go/tree/main/modules/core/04-channel/types). - -While modules may choose arbitrary acknowledgement structs, a default acknowledgement types is provided by IBC [here](https://github.com/cosmos/ibc-go/blob/main/proto/ibc/core/channel/v1/channel.proto): - -```proto -// Acknowledgement is the recommended acknowledgement format to be used by -// app-specific protocols. -// NOTE: The field numbers 21 and 22 were explicitly chosen to avoid accidental -// conflicts with other protobuf message formats used for acknowledgements. -// The first byte of any message with this format will be the non-ASCII values -// `0xaa` (result) or `0xb2` (error). Implemented as defined by ICS: -// https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope -message Acknowledgement { - // response contains either a result or an error and must be non-empty - oneof response { - bytes result = 21; - string error = 22; - } -} -``` - -#### Acknowledging Packets - -After a module writes an acknowledgement, a relayer can relay back the acknowledgement to the sender module. The sender module can -then process the acknowledgement using the `OnAcknowledgementPacket` callback. The contents of the -acknowledgement is entirely upto the modules on the channel (just like the packet data); however, it -may often contain information on whether the packet was successfully processed along -with some additional data that could be useful for remediation if the packet processing failed. - -Since the modules are responsible for agreeing on an encoding/decoding standard for packet data and -acknowledgements, IBC will pass in the acknowledgements as `[]byte` to this callback. The callback -is responsible for decoding the acknowledgement and processing it. - -```go -OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, -) (*sdk.Result, error) { - // Decode acknowledgement - ack := DecodeAcknowledgement(acknowledgement) - - // process ack - res, err := processAck(ack) - return res, err -} -``` - -#### Timeout Packets - -If the timeout for a packet is reached before the packet is successfully received or the -counterparty channel end is closed before the packet is successfully received, then the receiving -chain can no longer process it. Thus, the sending chain must process the timeout using -`OnTimeoutPacket` to handle this situation. Again the IBC module will verify that the timeout is -indeed valid, so our module only needs to implement the state machine logic for what to do once a -timeout is reached and the packet can no longer be received. - -```go -OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, -) (*sdk.Result, error) { - // do custom timeout logic -} -``` - -### Routing - -As mentioned above, modules must implement the IBC module interface (which contains both channel -handshake callbacks and packet handling callbacks). The concrete implementation of this interface -must be registered with the module name as a route on the IBC `Router`. - -```go -// app.go -func NewApp(...args) *App { -// ... - -// Create static IBC router, add module routes, then set and seal it -ibcRouter := port.NewRouter() - -ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule) -// Note: moduleCallbacks must implement IBCModule interface -ibcRouter.AddRoute(moduleName, moduleCallbacks) - -// Setting Router will finalize all routes by sealing router -// No more routes can be added -app.IBCKeeper.SetRouter(ibcRouter) -``` - -## Working Example - -For a real working example of an IBC application, you can look through the `ibc-transfer` module -which implements everything discussed above. - -Here are the useful parts of the module to look at: - -[Binding to transfer -port](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/genesis.go) - -[Sending transfer -packets](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/relay.go) - -[Implementing IBC -callbacks](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/ibc_module.go) diff --git a/docs/docs/01-ibc/03-apps/02-ibcmodule.md b/docs/docs/01-ibc/03-apps/02-ibcmodule.md deleted file mode 100644 index 5d5f499e7b7..00000000000 --- a/docs/docs/01-ibc/03-apps/02-ibcmodule.md +++ /dev/null @@ -1,379 +0,0 @@ ---- -title: Implement IBCModule interface and callbacks -sidebar_label: Implement IBCModule interface and callbacks -sidebar_position: 2 -slug: /ibc/apps/ibcmodule ---- - -# Implement `IBCModule` interface and callbacks - -:::note Synopsis -Learn how to implement the `IBCModule` interface and all of the callbacks it requires. -::: - -The Cosmos SDK expects all IBC modules to implement the [`IBCModule` -interface](https://github.com/cosmos/ibc-go/tree/main/modules/core/05-port/types/module.go). This interface contains all of the callbacks IBC expects modules to implement. They include callbacks related to channel handshake, closing and packet callbacks (`OnRecvPacket`, `OnAcknowledgementPacket` and `OnTimeoutPacket`). - -```go -// IBCModule implements the ICS26 interface for given the keeper. -// The implementation of the IBCModule interface could for example be in a file called ibc_module.go, -// but ultimately file structure is up to the developer -type IBCModule struct { - keeper keeper.Keeper -} -``` - -Additionally, in the `module.go` file, add the following line: - -```go -var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} - // Add this line - _ porttypes.IBCModule = IBCModule{} -) -``` - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: - -## Channel handshake callbacks - -This section will describe the callbacks that are called during channel handshake execution. Among other things, it will claim channel capabilities passed on from core IBC. For a refresher on capabilities, check [the Overview section](../01-overview.md#capabilities). - -Here are the channel handshake callbacks that modules are expected to implement: - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `checkArguments` and `negotiateAppVersion` functions. - -```go -// Called by IBC Handler on MsgOpenInit -func (im IBCModule) OnChanOpenInit(ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) (string, error) { - // ... do custom initialization logic - - // Use above arguments to determine if we want to abort handshake - // Examples: - // - Abort if order == UNORDERED, - // - Abort if version is unsupported - if err := checkArguments(args); err != nil { - return "", err - } - - // OpenInit must claim the channelCapability that IBC passes into the callback - if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return "", err - } - - return version, nil -} - -// Called by IBC Handler on MsgOpenTry -func (im IBCModule) OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (string, error) { - // ... do custom initialization logic - - // Use above arguments to determine if we want to abort handshake - if err := checkArguments(args); err != nil { - return "", err - } - - // OpenTry must claim the channelCapability that IBC passes into the callback - if err := im.keeper.scopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return err - } - - // Construct application version - // IBC applications must return the appropriate application version - // This can be a simple string or it can be a complex version constructed - // from the counterpartyVersion and other arguments. - // The version returned will be the channel version used for both channel ends. - appVersion := negotiateAppVersion(counterpartyVersion, args) - - return appVersion, nil -} - -// Called by IBC Handler on MsgOpenAck -func (im IBCModule) OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyVersion string, -) error { - if counterpartyVersion != types.Version { - return sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: %s, expected %s", counterpartyVersion, types.Version) - } - - // do custom logic - - return nil -} - -// Called by IBC Handler on MsgOpenConfirm -func (im IBCModule) OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // do custom logic - - return nil -} -``` - -The channel closing handshake will also invoke module callbacks that can return errors to abort the closing handshake. Closing a channel is a 2-step handshake, the initiating chain calls `ChanCloseInit` and the finalizing chain calls `ChanCloseConfirm`. - -```go -// Called by IBC Handler on MsgCloseInit -func (im IBCModule) OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - // ... do custom finalization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} - -// Called by IBC Handler on MsgCloseConfirm -func (im IBCModule) OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // ... do custom finalization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} -``` - -### Channel handshake version negotiation - -Application modules are expected to verify versioning used during the channel handshake procedure. - -- `OnChanOpenInit` will verify that the relayer-chosen parameters - are valid and perform any custom `INIT` logic. - It may return an error if the chosen parameters are invalid - in which case the handshake is aborted. - If the provided version string is non-empty, `OnChanOpenInit` should return - the version string if valid or an error if the provided version is invalid. - **If the version string is empty, `OnChanOpenInit` is expected to - return a default version string representing the version(s) - it supports.** - If there is no default version string for the application, - it should return an error if the provided version is an empty string. -- `OnChanOpenTry` will verify the relayer-chosen parameters along with the - counterparty-chosen version string and perform custom `TRY` logic. - If the relayer-chosen parameters - are invalid, the callback must return an error to abort the handshake. - If the counterparty-chosen version is not compatible with this module's - supported versions, the callback must return an error to abort the handshake. - If the versions are compatible, the try callback must select the final version - string and return it to core IBC. - `OnChanOpenTry` may also perform custom initialization logic. -- `OnChanOpenAck` will error if the counterparty selected version string - is invalid and abort the handshake. It may also perform custom ACK logic. - -Versions must be strings but can implement any versioning structure. If your application plans to -have linear releases then semantic versioning is recommended. If your application plans to release -various features in between major releases then it is advised to use the same versioning scheme -as IBC. This versioning scheme specifies a version identifier and compatible feature set with -that identifier. Valid version selection includes selecting a compatible version identifier with -a subset of features supported by your application for that version. The struct used for this -scheme can be found in [03-connection/types](https://github.com/cosmos/ibc-go/blob/main/modules/core/03-connection/types/version.go#L16). - -Since the version type is a string, applications have the ability to do simple version verification -via string matching or they can use the already impelemented versioning system and pass the proto -encoded version into each handhshake call as necessary. - -ICS20 currently implements basic string matching with a single supported version. - -## Packet callbacks - -Just as IBC expects modules to implement callbacks for channel handshakes, it also expects modules to implement callbacks for handling the packet flow through a channel, as defined in the `IBCModule` interface. - -Once a module A and module B are connected to each other, relayers can start relaying packets and acknowledgements back and forth on the channel. - -![IBC packet flow diagram](./images/packet_flow.png) - -Briefly, a successful packet flow works as follows: - -1. Module A sends a packet through the IBC module -2. The packet is received by module B -3. If module B writes an acknowledgement of the packet then module A will process the acknowledgement -4. If the packet is not successfully received before the timeout, then module A processes the packet's timeout. - -### Sending packets - -Modules **do not send packets through callbacks**, since the modules initiate the action of sending packets to the IBC module, as opposed to other parts of the packet flow where messages sent to the IBC -module must trigger execution on the port-bound module through the use of callbacks. Thus, to send a packet a module simply needs to call `SendPacket` on the `IBCChannelKeeper`. - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `EncodePacketData(customPacketData)` function. - -```go -// retrieve the dynamic capability for this channel -channelCap := scopedKeeper.GetCapability(ctx, channelCapName) -// Sending custom application packet data -data := EncodePacketData(customPacketData) -// Send packet to IBC, authenticating with channelCap -sequence, err := IBCChannelKeeper.SendPacket( - ctx, - channelCap, - sourcePort, - sourceChannel, - timeoutHeight, - timeoutTimestamp, - data, -) -``` - -:::warning -In order to prevent modules from sending packets on channels they do not own, IBC expects -modules to pass in the correct channel capability for the packet's source channel. -::: - -### Receiving packets - -To handle receiving packets, the module must implement the `OnRecvPacket` callback. This gets -invoked by the IBC module after the packet has been proved valid and correctly processed by the IBC -keepers. Thus, the `OnRecvPacket` callback only needs to worry about making the appropriate state -changes given the packet data without worrying about whether the packet is valid or not. - -Modules may return to the IBC handler an acknowledgement which implements the `Acknowledgement` interface. -The IBC handler will then commit this acknowledgement of the packet so that a relayer may relay the -acknowledgement back to the sender module. - -The state changes that occurred during this callback will only be written if: - -- the acknowledgement was successful as indicated by the `Success()` function of the acknowledgement -- if the acknowledgement returned is nil indicating that an asynchronous process is occurring - -NOTE: Applications which process asynchronous acknowledgements must handle reverting state changes -when appropriate. Any state changes that occurred during the `OnRecvPacket` callback will be written -for asynchronous acknowledgements. - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `DecodePacketData(packet.Data)` function. - -```go -func (im IBCModule) OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, -) ibcexported.Acknowledgement { - // Decode the packet data - packetData := DecodePacketData(packet.Data) - - // do application state changes based on packet data and return the acknowledgement - // NOTE: The acknowledgement will indicate to the IBC handler if the application - // state changes should be written via the `Success()` function. Application state - // changes are only written if the acknowledgement is successful or the acknowledgement - // returned is nil indicating that an asynchronous acknowledgement will occur. - ack := processPacket(ctx, packet, packetData) - - return ack -} -``` - -Reminder, the `Acknowledgement` interface: - -```go -// Acknowledgement defines the interface used to return -// acknowledgements in the OnRecvPacket callback. -type Acknowledgement interface { - Success() bool - Acknowledgement() []byte -} -``` - -### Acknowledging packets - -After a module writes an acknowledgement, a relayer can relay back the acknowledgement to the sender module. The sender module can -then process the acknowledgement using the `OnAcknowledgementPacket` callback. The contents of the -acknowledgement is entirely up to the modules on the channel (just like the packet data); however, it -may often contain information on whether the packet was successfully processed along -with some additional data that could be useful for remediation if the packet processing failed. - -Since the modules are responsible for agreeing on an encoding/decoding standard for packet data and -acknowledgements, IBC will pass in the acknowledgements as `[]byte` to this callback. The callback -is responsible for decoding the acknowledgement and processing it. - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `DecodeAcknowledgement(acknowledgments)` and `processAck(ack)` functions. - -```go -func (im IBCModule) OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, -) (*sdk.Result, error) { - // Decode acknowledgement - ack := DecodeAcknowledgement(acknowledgement) - - // process ack - res, err := processAck(ack) - return res, err -} -``` - -### Timeout packets - -If the timeout for a packet is reached before the packet is successfully received or the -counterparty channel end is closed before the packet is successfully received, then the receiving -chain can no longer process it. Thus, the sending chain must process the timeout using -`OnTimeoutPacket` to handle this situation. Again the IBC module will verify that the timeout is -indeed valid, so our module only needs to implement the state machine logic for what to do once a -timeout is reached and the packet can no longer be received. - -```go -func (im IBCModule) OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, -) (*sdk.Result, error) { - // do custom timeout logic -} -``` - -### Optional interfaces - -The following interface are optional and MAY be implemented by an IBCModule. - -#### PacketDataUnmarshaler - -The `PacketDataUnmarshaler` interface is defined as follows: - -```go -// PacketDataUnmarshaler defines an optional interface which allows a middleware to -// request the packet data to be unmarshaled by the base application. -type PacketDataUnmarshaler interface { - // UnmarshalPacketData unmarshals the packet data into a concrete type - UnmarshalPacketData([]byte) (interface{}, error) -} -``` - -The implementation of `UnmarshalPacketData` should unmarshal the bytes into the packet data type defined for an IBC stack. -The base application of an IBC stack should unmarshal the bytes into its packet data type, while a middleware may simply defer the call to the underlying application. - -This interface allows middlewares to unmarshal a packet data in order to make use of interfaces the packet data type implements. -For example, the callbacks middleware makes use of this function to access packet data types which implement the `PacketData` and `PacketDataProvider` interfaces. diff --git a/docs/docs/01-ibc/03-apps/03-bindports.md b/docs/docs/01-ibc/03-apps/03-bindports.md deleted file mode 100644 index 4bd85d29bc5..00000000000 --- a/docs/docs/01-ibc/03-apps/03-bindports.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -title: Bind ports -sidebar_label: Bind ports -sidebar_position: 3 -slug: /ibc/apps/bindports ---- - -# Bind ports - -:::note Synopsis -Learn what changes to make to bind modules to their ports on initialization. -::: - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: -Currently, ports must be bound on app initialization. In order to bind modules to their respective ports on initialization, the following needs to be implemented: - -> Note that `portID` does not refer to a certain numerical ID, like `localhost:8080` with a `portID` 8080. Rather it refers to the application module the port binds. For IBC Modules built with the Cosmos SDK, it defaults to the module's name and for Cosmwasm contracts it defaults to the contract address. - -1. Add port ID to the `GenesisState` proto definition: - -```protobuf -message GenesisState { - string port_id = 1; - // other fields -} -``` - -1. Add port ID as a key to the module store: - -```go -// x//types/keys.go -const ( - // ModuleName defines the IBC Module name - ModuleName = "moduleName" - - // Version defines the current version the IBC - // module supports - Version = "moduleVersion-1" - - // PortID is the default port id that module binds to - PortID = "portID" - - // ... -) -``` - -1. Add port ID to `x//types/genesis.go`: - -```go -// in x//types/genesis.go - -// DefaultGenesisState returns a GenesisState with "transfer" as the default PortID. -func DefaultGenesisState() *GenesisState { - return &GenesisState{ - PortId: PortID, - // additional k-v fields - } -} - -// Validate performs basic genesis state validation returning an error upon any -// failure. -func (gs GenesisState) Validate() error { - if err := host.PortIdentifierValidator(gs.PortId); err != nil { - return err - } - //addtional validations - - return gs.Params.Validate() -} -``` - -1. Bind to port(s) in the module keeper's `InitGenesis`: - -```go -// InitGenesis initializes the ibc-module state and binds to PortID. -func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) { - k.SetPort(ctx, state.PortId) - - // ... - - // Only try to bind to port if it is not already bound, since we may already own - // port capability from capability InitGenesis - if !k.hasCapability(ctx, state.PortId) { - // transfer module binds to the transfer port on InitChain - // and claims the returned capability - err := k.BindPort(ctx, state.PortId) - if err != nil { - panic(fmt.Sprintf("could not claim port capability: %v", err)) - } - } - - // ... -} -``` - -With: - -```go -// IsBound checks if the module is already bound to the desired port -func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { - _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) - return ok -} - -// BindPort defines a wrapper function for the port Keeper's function in -// order to expose it to module's InitGenesis function -func (k Keeper) BindPort(ctx sdk.Context, portID string) error { - cap := k.portKeeper.BindPort(ctx, portID) - return k.ClaimCapability(ctx, cap, host.PortPath(portID)) -} -``` - -The module binds to the desired port(s) and returns the capabilities. - -In the above we find reference to keeper methods that wrap other keeper functionality, in the next section the keeper methods that need to be implemented will be defined. diff --git a/docs/docs/01-ibc/03-apps/04-keeper.md b/docs/docs/01-ibc/03-apps/04-keeper.md deleted file mode 100644 index 8e0040e09fc..00000000000 --- a/docs/docs/01-ibc/03-apps/04-keeper.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: Keeper -sidebar_label: Keeper -sidebar_position: 4 -slug: /ibc/apps/keeper ---- - -# Keeper - -:::note Synopsis -Learn how to implement the IBC Module keeper. -::: - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: -In the previous sections, on channel handshake callbacks and port binding in `InitGenesis`, a reference was made to keeper methods that need to be implemented when creating a custom IBC module. Below is an overview of how to define an IBC module's keeper. - -> Note that some code has been left out for clarity, to get a full code overview, please refer to [the transfer module's keeper in the ibc-go repo](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/keeper.go). - -```go -// Keeper defines the IBC app module keeper -type Keeper struct { - storeKey sdk.StoreKey - cdc codec.BinaryCodec - paramSpace paramtypes.Subspace - - channelKeeper types.ChannelKeeper - portKeeper types.PortKeeper - scopedKeeper capabilitykeeper.ScopedKeeper - - // ... additional according to custom logic -} - -// NewKeeper creates a new IBC app module Keeper instance -func NewKeeper( - // args -) Keeper { - // ... - - return Keeper{ - cdc: cdc, - storeKey: key, - paramSpace: paramSpace, - - channelKeeper: channelKeeper, - portKeeper: portKeeper, - scopedKeeper: scopedKeeper, - - // ... additional according to custom logic - } -} - -// hasCapability checks if the IBC app module owns the port capability for the desired port -func (k Keeper) hasCapability(ctx sdk.Context, portID string) bool { - _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) - return ok -} - -// BindPort defines a wrapper function for the port Keeper's function in -// order to expose it to module's InitGenesis function -func (k Keeper) BindPort(ctx sdk.Context, portID string) error { - cap := k.portKeeper.BindPort(ctx, portID) - return k.ClaimCapability(ctx, cap, host.PortPath(portID)) -} - -// GetPort returns the portID for the IBC app module. Used in ExportGenesis -func (k Keeper) GetPort(ctx sdk.Context) string { - store := ctx.KVStore(k.storeKey) - return string(store.Get(types.PortKey)) -} - -// SetPort sets the portID for the IBC app module. Used in InitGenesis -func (k Keeper) SetPort(ctx sdk.Context, portID string) { - store := ctx.KVStore(k.storeKey) - store.Set(types.PortKey, []byte(portID)) -} - -// AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function -func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool { - return k.scopedKeeper.AuthenticateCapability(ctx, cap, name) -} - -// ClaimCapability allows the IBC app module to claim a capability that core IBC -// passes to it -func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { - return k.scopedKeeper.ClaimCapability(ctx, cap, name) -} - -// ... additional according to custom logic -``` diff --git a/docs/docs/01-ibc/03-apps/05-packets_acks.md b/docs/docs/01-ibc/03-apps/05-packets_acks.md deleted file mode 100644 index 9f7f76614ac..00000000000 --- a/docs/docs/01-ibc/03-apps/05-packets_acks.md +++ /dev/null @@ -1,166 +0,0 @@ ---- -title: Define packets and acks -sidebar_label: Define packets and acks -sidebar_position: 5 -slug: /ibc/apps/packets_acks ---- - -# Define packets and acks - -:::note Synopsis -Learn how to define custom packet and acknowledgement structs and how to encode and decode them. -::: - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: - -## Custom packets - -Modules connected by a channel must agree on what application data they are sending over the -channel, as well as how they will encode/decode it. This process is not specified by IBC as it is up -to each application module to determine how to implement this agreement. However, for most -applications this will happen as a version negotiation during the channel handshake. While more -complex version negotiation is possible to implement inside the channel opening handshake, a very -simple version negotation is implemented in the [ibc-transfer module](https://github.com/cosmos/ibc-go/tree/main/modules/apps/transfer/module.go). - -Thus, a module must define its custom packet data structure, along with a well-defined way to -encode and decode it to and from `[]byte`. - -```go -// Custom packet data defined in application module -type CustomPacketData struct { - // Custom fields ... -} - -EncodePacketData(packetData CustomPacketData) []byte { - // encode packetData to bytes -} - -DecodePacketData(encoded []byte) (CustomPacketData) { - // decode from bytes to packet data -} -``` - -> Note that the `CustomPacketData` struct is defined in the proto definition and then compiled by the protobuf compiler. - -Then a module must encode its packet data before sending it through IBC. - -```go -// retrieve the dynamic capability for this channel -channelCap := scopedKeeper.GetCapability(ctx, channelCapName) -// Sending custom application packet data -data := EncodePacketData(customPacketData) -// Send packet to IBC, authenticating with channelCap -sequence, err := IBCChannelKeeper.SendPacket( - ctx, - channelCap, - sourcePort, - sourceChannel, - timeoutHeight, - timeoutTimestamp, - data, -) -``` - -A module receiving a packet must decode the `PacketData` into a structure it expects so that it can -act on it. - -```go -// Receiving custom application packet data (in OnRecvPacket) -packetData := DecodePacketData(packet.Data) -// handle received custom packet data -``` - -### Optional interfaces - -The following interfaces are optional and MAY be implemented by a custom packet type. -They allow middlewares such as callbacks to access information stored within the packet data. - -#### PacketData interface - -The `PacketData` interface is defined as follows: - -```go -// PacketData defines an optional interface which an application's packet data structure may implement. -type PacketData interface { - // GetPacketSender returns the sender address of the packet data. - // If the packet sender is unknown or undefined, an empty string should be returned. - GetPacketSender(sourcePortID string) string -} -``` - -The implementation of `GetPacketSender` should return the sender of the packet data. -If the packet sender is unknown or undefined, an empty string should be returned. - -This interface is intended to give IBC middlewares access to the packet sender of a packet data type. - -#### PacketDataProvider interface - -The `PacketDataProvider` interface is defined as follows: - -```go -// PacketDataProvider defines an optional interfaces for retrieving custom packet data stored on behalf of another application. -// An existing problem in the IBC middleware design is the inability for a middleware to define its own packet data type and insert packet sender provided information. -// A short term solution was introduced into several application's packet data to utilize a memo field to carry this information on behalf of another application. -// This interfaces standardizes that behaviour. Upon realization of the ability for middleware's to define their own packet data types, this interface will be deprecated and removed with time. -type PacketDataProvider interface { - // GetCustomPacketData returns the packet data held on behalf of another application. - // The name the information is stored under should be provided as the key. - // If no custom packet data exists for the key, nil should be returned. - GetCustomPacketData(key string) interface{} -} -``` - -The implementation of `GetCustomPacketData` should return packet data held on behalf of another application (if present and supported). -If this functionality is not supported, it should return nil. Otherwise it should return the packet data associated with the provided key. - -This interface gives IBC applications access to the packet data information embedded into the base packet data type. -Within transfer and interchain accounts, the embedded packet data is stored within the Memo field. - -Once all IBC applications within an IBC stack are capable of creating/maintaining their own packet data type's, this interface function will be deprecated and removed. - -## Acknowledgements - -Modules may commit an acknowledgement upon receiving and processing a packet in the case of synchronous packet processing. -In the case where a packet is processed at some later point after the packet has been received (asynchronous execution), the acknowledgement -will be written once the packet has been processed by the application which may be well after the packet receipt. - -NOTE: Most blockchain modules will want to use the synchronous execution model in which the module processes and writes the acknowledgement -for a packet as soon as it has been received from the IBC module. - -This acknowledgement can then be relayed back to the original sender chain, which can take action -depending on the contents of the acknowledgement. - -Just as packet data was opaque to IBC, acknowledgements are similarly opaque. Modules must pass and -receive acknowledegments with the IBC modules as byte strings. - -Thus, modules must agree on how to encode/decode acknowledgements. The process of creating an -acknowledgement struct along with encoding and decoding it, is very similar to the packet data -example above. [ICS 04](https://github.com/cosmos/ibc/blob/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope) -specifies a recommended format for acknowledgements. This acknowledgement type can be imported from -[channel types](https://github.com/cosmos/ibc-go/tree/main/modules/core/04-channel/types). - -While modules may choose arbitrary acknowledgement structs, a default acknowledgement types is provided by IBC [here](https://github.com/cosmos/ibc-go/blob/main/proto/ibc/core/channel/v1/channel.proto): - -```protobuf -// Acknowledgement is the recommended acknowledgement format to be used by -// app-specific protocols. -// NOTE: The field numbers 21 and 22 were explicitly chosen to avoid accidental -// conflicts with other protobuf message formats used for acknowledgements. -// The first byte of any message with this format will be the non-ASCII values -// `0xaa` (result) or `0xb2` (error). Implemented as defined by ICS: -// https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope -message Acknowledgement { - // response contains either a result or an error and must be non-empty - oneof response { - bytes result = 21; - string error = 22; - } -} -``` diff --git a/docs/docs/01-ibc/03-apps/06-routing.md b/docs/docs/01-ibc/03-apps/06-routing.md deleted file mode 100644 index 666fb1af11b..00000000000 --- a/docs/docs/01-ibc/03-apps/06-routing.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Routing -sidebar_label: Routing -sidebar_position: 6 -slug: /ibc/apps/routing ---- - -# Routing - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: -:::note Synopsis -Learn how to hook a route to the IBC router for the custom IBC module. -::: - -As mentioned above, modules must implement the `IBCModule` interface (which contains both channel -handshake callbacks and packet handling callbacks). The concrete implementation of this interface -must be registered with the module name as a route on the IBC `Router`. - -```go -// app.go -func NewApp(...args) *App { - // ... - - // Create static IBC router, add module routes, then set and seal it - ibcRouter := port.NewRouter() - - ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule) - // Note: moduleCallbacks must implement IBCModule interface - ibcRouter.AddRoute(moduleName, moduleCallbacks) - - // Setting Router will finalize all routes by sealing router - // No more routes can be added - app.IBCKeeper.SetRouter(ibcRouter) - - // ... -} -``` diff --git a/docs/docs/01-ibc/03-apps/_category_.json b/docs/docs/01-ibc/03-apps/_category_.json deleted file mode 100644 index 4561a95b84c..00000000000 --- a/docs/docs/01-ibc/03-apps/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Applications", - "position": 3, - "link": null -} \ No newline at end of file diff --git a/docs/docs/01-ibc/03-apps/images/packet_flow.png b/docs/docs/01-ibc/03-apps/images/packet_flow.png deleted file mode 100644 index db2d1d314b8..00000000000 Binary files a/docs/docs/01-ibc/03-apps/images/packet_flow.png and /dev/null differ diff --git a/docs/docs/01-ibc/04-middleware/01-overview.md b/docs/docs/01-ibc/04-middleware/01-overview.md deleted file mode 100644 index 24a27689755..00000000000 --- a/docs/docs/01-ibc/04-middleware/01-overview.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: IBC middleware -sidebar_label: IBC middleware -sidebar_position: 1 -slug: /ibc/middleware/overview ---- - -# IBC middleware - -:::note Synopsis -Learn how to write your own custom middleware to wrap an IBC application, and understand how to hook different middleware to IBC base applications to form different IBC application stacks -::: - -This documentation serves as a guide for middleware developers who want to write their own middleware and for chain developers who want to use IBC middleware on their chains. - -After going through the overview they can consult respectively: - -- [documentation on developing custom middleware](02-develop.md) -- [documentation on integrating middleware into a stack on a chain](03-integration.md) - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC Integration](../02-integration.md) -- [IBC Application Developer Guide](../03-apps/01-apps.md) - -::: - -## Why middleware? - -IBC applications are designed to be self-contained modules that implement their own application-specific logic through a set of interfaces with the core IBC handlers. These core IBC handlers, in turn, are designed to enforce the correctness properties of IBC (transport, authentication, ordering) while delegating all application-specific handling to the IBC application modules. **However, there are cases where some functionality may be desired by many applications, yet not appropriate to place in core IBC.** - -Middleware allows developers to define the extensions as separate modules that can wrap over the base application. This middleware can thus perform its own custom logic, and pass data into the application so that it may run its logic without being aware of the middleware's existence. This allows both the application and the middleware to implement its own isolated logic while still being able to run as part of a single packet flow. - -## Definitions - -`Middleware`: A self-contained module that sits between core IBC and an underlying IBC application during packet execution. All messages between core IBC and underlying application must flow through middleware, which may perform its own custom logic. - -`Underlying Application`: An underlying application is the application that is directly connected to the middleware in question. This underlying application may itself be middleware that is chained to a base application. - -`Base Application`: A base application is an IBC application that does not contain any middleware. It may be nested by 0 or multiple middleware to form an application stack. - -`Application Stack (or stack)`: A stack is the complete set of application logic (middleware(s) + base application) that gets connected to core IBC. A stack may be just a base application, or it may be a series of middlewares that nest a base application. - -The diagram below gives an overview of a middleware stack consisting of two middleware (one stateless, the other stateful). - -![middleware-stack.png](./images/middleware-stack.png) - -Keep in mind that: - -- **The order of the middleware matters** (more on how to correctly define your stack in the code will follow in the [integration section](03-integration.md)). -- Depending on the type of message, it will either be passed on from the base application up the middleware stack to core IBC or down the stack in the reverse situation (handshake and packet callbacks). -- IBC middleware will wrap over an underlying IBC application and sits between core IBC and the application. It has complete control in modifying any message coming from IBC to the application, and any message coming from the application to core IBC. **Middleware must be completely trusted by chain developers who wish to integrate them**, as this gives them complete flexibility in modifying the application(s) they wrap. diff --git a/docs/docs/01-ibc/04-middleware/02-develop.md b/docs/docs/01-ibc/04-middleware/02-develop.md deleted file mode 100644 index aff2a14b076..00000000000 --- a/docs/docs/01-ibc/04-middleware/02-develop.md +++ /dev/null @@ -1,519 +0,0 @@ ---- -title: Create a custom IBC middleware -sidebar_label: Create a custom IBC middleware -sidebar_position: 2 -slug: /ibc/middleware/develop ---- - - -# Create a custom IBC middleware - -IBC middleware will wrap over an underlying IBC application (a base application or downstream middleware) and sits between core IBC and the base application. - -The interfaces a middleware must implement are found [here](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/05-port/types/module.go). - -```go -// Middleware implements the ICS26 Module interface -type Middleware interface { - IBCModule // middleware has acccess to an underlying application which may be wrapped by more middleware - ICS4Wrapper // middleware has access to ICS4Wrapper which may be core IBC Channel Handler or a higher-level middleware that wraps this middleware. -} -``` - -An `IBCMiddleware` struct implementing the `Middleware` interface, can be defined with its constructor as follows: - -```go -// @ x/module_name/ibc_middleware.go - -// IBCMiddleware implements the ICS26 callbacks and ICS4Wrapper for the fee middleware given the -// fee keeper and the underlying application. -type IBCMiddleware struct { - app porttypes.IBCModule - keeper keeper.Keeper -} - -// NewIBCMiddleware creates a new IBCMiddlware given the keeper and underlying application -func NewIBCMiddleware(app porttypes.IBCModule, k keeper.Keeper) IBCMiddleware { - return IBCMiddleware{ - app: app, - keeper: k, - } -} -``` - -## Implement `IBCModule` interface - -`IBCMiddleware` is a struct that implements the [ICS-26 `IBCModule` interface (`porttypes.IBCModule`)](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/05-port/types/module.go#L14-L107). It is recommended to separate these callbacks into a separate file `ibc_middleware.go`. - -> Note how this is analogous to implementing the same interfaces for IBC applications that act as base applications. - -As will be mentioned in the [integration section](03-integration.md), this struct should be different than the struct that implements `AppModule` in case the middleware maintains its own internal state and processes separate SDK messages. - -The middleware must have access to the underlying application, and be called before it during all ICS-26 callbacks. It may execute custom logic during these callbacks, and then call the underlying application's callback. - -> Middleware **may** choose not to call the underlying application's callback at all. Though these should generally be limited to error cases. - -The `IBCModule` interface consists of the channel handshake callbacks and packet callbacks. Most of the custom logic will be performed in the packet callbacks, in the case of the channel handshake callbacks, introducing the middleware requires consideration to the version negotiation and passing of capabilities. - -### Channel handshake callbacks - -#### Version negotiation - -In the case where the IBC middleware expects to speak to a compatible IBC middleware on the counterparty chain, they must use the channel handshake to negotiate the middleware version without interfering in the version negotiation of the underlying application. - -Middleware accomplishes this by formatting the version in a JSON-encoded string containing the middleware version and the application version. The application version may as well be a JSON-encoded string, possibly including further middleware and app versions, if the application stack consists of multiple milddlewares wrapping a base application. The format of the version is specified in ICS-30 as the following: - -```json -{ - "": "", - "app_version": "" -} -``` - -The `` key in the JSON struct should be replaced by the actual name of the key for the corresponding middleware (e.g. `fee_version`). - -During the handshake callbacks, the middleware can unmarshal the version string and retrieve the middleware and application versions. It can do its negotiation logic on ``, and pass the `` to the underlying application. - -> **NOTE**: Middleware that does not need to negotiate with a counterparty middleware on the remote stack will not implement the version unmarshalling and negotiation, and will simply perform its own custom logic on the callbacks without relying on the counterparty behaving similarly. - -#### `OnChanOpenInit` - -```go -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) { - if version != "" { - // try to unmarshal JSON-encoded version string and pass - // the app-specific version to app callback. - // otherwise, pass version directly to app callback. - metadata, err := Unmarshal(version) - if err != nil { - // Since it is valid for fee version to not be specified, - // the above middleware version may be for another middleware. - // Pass the entire version string onto the underlying application. - return im.app.OnChanOpenInit( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - version, - ) - } - else { - metadata = { - // set middleware version to default value - MiddlewareVersion: defaultMiddlewareVersion, - // allow application to return its default version - AppVersion: "", - } - } - } - - doCustomLogic() - - // if the version string is empty, OnChanOpenInit is expected to return - // a default version string representing the version(s) it supports - appVersion, err := im.app.OnChanOpenInit( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - metadata.AppVersion, // note we only pass app version here - ) - if err != nil { - // Since it is valid for fee version to not be specified, - // the above middleware version may be for another middleware. - // Pass the entire version string onto the underlying application. - return im.app.OnChanOpenInit( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - version, - ) - } - else { - metadata = { - // set middleware version to default value - MiddlewareVersion: defaultMiddlewareVersion, - // allow application to return its default version - AppVersion: "", - } - } - - doCustomLogic() - - // if the version string is empty, OnChanOpenInit is expected to return - // a default version string representing the version(s) it supports - appVersion, err := im.app.OnChanOpenInit( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - metadata.AppVersion, // note we only pass app version here - ) - if err != nil { - return "", err - } - - version := constructVersion(metadata.MiddlewareVersion, appVersion) - - return version, nil -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/apps/29-fee/ibc_middleware.go#L36-L83) an example implementation of this callback for the ICS-29 Fee Middleware module. - -#### `OnChanOpenTry` - -```go -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) { - // try to unmarshal JSON-encoded version string and pass - // the app-specific version to app callback. - // otherwise, pass version directly to app callback. - cpMetadata, err := Unmarshal(counterpartyVersion) - if err != nil { - return app.OnChanOpenTry( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - counterpartyVersion, - ) - } - - doCustomLogic() - - // Call the underlying application's OnChanOpenTry callback. - // The try callback must select the final app-specific version string and return it. - appVersion, err := app.OnChanOpenTry( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - cpMetadata.AppVersion, // note we only pass counterparty app version here - ) - if err != nil { - return "", err - } - - // negotiate final middleware version - middlewareVersion := negotiateMiddlewareVersion(cpMetadata.MiddlewareVersion) - version := constructVersion(middlewareVersion, appVersion) - - return version, nil -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/apps/29-fee/ibc_middleware.go#L88-L125) an example implementation of this callback for the ICS-29 Fee Middleware module. - -#### `OnChanOpenAck` - -```go -func (im IBCMiddleware) OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyChannelID string, - counterpartyVersion string, -) error { - // try to unmarshal JSON-encoded version string and pass - // the app-specific version to app callback. - // otherwise, pass version directly to app callback. - cpMetadata, err = UnmarshalJSON(counterpartyVersion) - if err != nil { - return app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) - } - - if !isCompatible(cpMetadata.MiddlewareVersion) { - return error - } - doCustomLogic() - - // call the underlying application's OnChanOpenTry callback - return app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, cpMetadata.AppVersion) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/apps/29-fee/ibc_middleware.go#L128-L153)) an example implementation of this callback for the ICS-29 Fee Middleware module. - -#### `OnChanOpenConfirm` - -```go -func OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - doCustomLogic() - - return app.OnChanOpenConfirm(ctx, portID, channelID) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/apps/29-fee/ibc_middleware.go#L156-L163) an example implementation of this callback for the ICS-29 Fee Middleware module. - -#### `OnChanCloseInit` - -```go -func OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - doCustomLogic() - - return app.OnChanCloseInit(ctx, portID, channelID) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/apps/29-fee/ibc_middleware.go#L166-L188) an example implementation of this callback for the ICS-29 Fee Middleware module. - -#### `OnChanCloseConfirm` - -```go -func OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - doCustomLogic() - - return app.OnChanCloseConfirm(ctx, portID, channelID) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/apps/29-fee/ibc_middleware.go#L191-L213) an example implementation of this callback for the ICS-29 Fee Middleware module. - -#### Capabilities - -The middleware should simply pass the capability in the callback arguments along to the underlying application so that it may be claimed by the base application. The base application will then pass the capability up the stack in order to authenticate an outgoing packet/acknowledgement, which you can check in the [`ICS4Wrapper` section](02-develop.md#ics-4-wrappers). - -In the case where the middleware wishes to send a packet or acknowledgment without the involvement of the underlying application, it should be given access to the same `scopedKeeper` as the base application so that it can retrieve the capabilities by itself. - -### Packet callbacks - -The packet callbacks just like the handshake callbacks wrap the application's packet callbacks. The packet callbacks are where the middleware performs most of its custom logic. The middleware may read the packet flow data and perform some additional packet handling, or it may modify the incoming data before it reaches the underlying application. This enables a wide degree of usecases, as a simple base application like token-transfer can be transformed for a variety of usecases by combining it with custom middleware. - -#### `OnRecvPacket` - -```go -func (im IBCMiddleware) OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) ibcexported.Acknowledgement { - doCustomLogic(packet) - - ack := app.OnRecvPacket(ctx, packet, relayer) - - doCustomLogic(ack) // middleware may modify outgoing ack - - return ack -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/apps/29-fee/ibc_middleware.go#L217-L238) an example implementation of this callback for the ICS-29 Fee Middleware module. - -#### `OnAcknowledgementPacket` - -```go -func (im IBCMiddleware) OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - relayer sdk.AccAddress, -) error { - doCustomLogic(packet, ack) - - return app.OnAcknowledgementPacket(ctx, packet, ack, relayer) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/apps/29-fee/ibc_middleware.go#L242-L293) an example implementation of this callback for the ICS-29 Fee Middleware module. - -#### `OnTimeoutPacket` - -```go -func (im IBCMiddleware) OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) error { - doCustomLogic(packet) - - return app.OnTimeoutPacket(ctx, packet, relayer) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/apps/29-fee/ibc_middleware.go#L297-L335) an example implementation of this callback for the ICS-29 Fee Middleware module. - -## ICS-04 wrappers - -Middleware must also wrap ICS-04 so that any communication from the application to the `channelKeeper` goes through the middleware first. Similar to the packet callbacks, the middleware may modify outgoing acknowledgements and packets in any way it wishes. - -To ensure optimal generalisability, the `ICS4Wrapper` abstraction serves to abstract away whether a middleware is the topmost middleware (and thus directly caling into the ICS-04 `channelKeeper`) or itself being wrapped by another middleware. - -Remember that middleware can be stateful or stateless. When defining the stateful middleware's keeper, the `ics4Wrapper` field is included. Then the appropriate keeper can be passed when instantiating the middleware's keeper in `app.go` - -```go -type Keeper struct { - storeKey storetypes.StoreKey - cdc codec.BinaryCodec - - ics4Wrapper porttypes.ICS4Wrapper - channelKeeper types.ChannelKeeper - portKeeper types.PortKeeper - ... -} -``` - -For stateless middleware, the `ics4Wrapper` can be passed on directly without having to instantiate a keeper struct for the middleware. - -[The interface](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/05-port/types/module.go#L110-L133) looks as follows: - -```go -// This is implemented by ICS4 and all middleware that are wrapping base application. -// The base application will call `sendPacket` or `writeAcknowledgement` of the middleware directly above them -// which will call the next middleware until it reaches the core IBC handler. -type ICS4Wrapper interface { - SendPacket( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - data []byte, - ) (sequence uint64, err error) - - WriteAcknowledgement( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - packet exported.PacketI, - ack exported.Acknowledgement, - ) error - - GetAppVersion( - ctx sdk.Context, - portID, - channelID string, - ) (string, bool) -} -``` - -:warning: In the following paragraphs, the methods are presented in pseudo code which has been kept general, not stating whether the middleware is stateful or stateless. Remember that when the middleware is stateful, `ics4Wrapper` can be accessed through the keeper. - -Check out the references provided for an actual implementation to clarify, where the `ics4Wrapper` methods in `ibc_middleware.go` simply call the equivalent keeper methods where the actual logic resides. - -### `SendPacket` - -```go -func SendPacket( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - appData []byte, -) (uint64, error) { - // middleware may modify data - data = doCustomLogic(appData) - - return ics4Wrapper.SendPacket( - ctx, - chanCap, - sourcePort, - sourceChannel, - timeoutHeight, - timeoutTimestamp, - data, - ) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/apps/29-fee/keeper/relay.go#L17-L27) an example implementation of this function for the ICS-29 Fee Middleware module. - -### `WriteAcknowledgement` - -```go -// only called for async acks -func WriteAcknowledgement( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - packet exported.PacketI, - ack exported.Acknowledgement, -) error { - // middleware may modify acknowledgement - ack_bytes = doCustomLogic(ack) - - return ics4Wrapper.WriteAcknowledgement(packet, ack_bytes) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/apps/29-fee/keeper/relay.go#L31-L55) an example implementation of this function for the ICS-29 Fee Middleware module. - -### `GetAppVersion` - -```go -// middleware must return the underlying application version -func GetAppVersion( - ctx sdk.Context, - portID, - channelID string, -) (string, bool) { - version, found := ics4Wrapper.GetAppVersion(ctx, portID, channelID) - if !found { - return "", false - } - - if !MiddlewareEnabled { - return version, true - } - - // unwrap channel version - metadata, err := Unmarshal(version) - if err != nil { - panic(fmt.Errof("unable to unmarshal version: %w", err)) - } - - return metadata.AppVersion, true -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/apps/29-fee/keeper/relay.go#L58-L74) an example implementation of this function for the ICS-29 Fee Middleware module. diff --git a/docs/docs/01-ibc/04-middleware/03-integration.md b/docs/docs/01-ibc/04-middleware/03-integration.md deleted file mode 100644 index f049555e544..00000000000 --- a/docs/docs/01-ibc/04-middleware/03-integration.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -title: Integrating IBC middleware into a chain -sidebar_label: Integrating IBC middleware into a chain -sidebar_position: 3 -slug: /ibc/middleware/integration ---- - - -# Integrating IBC middleware into a chain - -Learn how to integrate IBC middleware(s) with a base application to your chain. The following document only applies for Cosmos SDK chains. - -If the middleware is maintaining its own state and/or processing SDK messages, then it should create and register its SDK module with the module manager in `app.go`. - -All middleware must be connected to the IBC router and wrap over an underlying base IBC application. An IBC application may be wrapped by many layers of middleware, only the top layer middleware should be hooked to the IBC router, with all underlying middlewares and application getting wrapped by it. - -The order of middleware **matters**, function calls from IBC to the application travel from top-level middleware to the bottom middleware and then to the application. Function calls from the application to IBC goes through the bottom middleware in order to the top middleware and then to core IBC handlers. Thus the same set of middleware put in different orders may produce different effects. - -## Example integration - -```go -// app.go pseudocode - -// middleware 1 and middleware 3 are stateful middleware, -// perhaps implementing separate sdk.Msg and Handlers -mw1Keeper := mw1.NewKeeper(storeKey1, ..., ics4Wrapper: channelKeeper, ...) // in stack 1 & 3 -// middleware 2 is stateless -mw3Keeper1 := mw3.NewKeeper(storeKey3,..., ics4Wrapper: mw1Keeper, ...) // in stack 1 -mw3Keeper2 := mw3.NewKeeper(storeKey3,..., ics4Wrapper: channelKeeper, ...) // in stack 2 - -// Only create App Module **once** and register in app module -// if the module maintains independent state and/or processes sdk.Msgs -app.moduleManager = module.NewManager( - ... - mw1.NewAppModule(mw1Keeper), - mw3.NewAppModule(mw3Keeper1), - mw3.NewAppModule(mw3Keeper2), - transfer.NewAppModule(transferKeeper), - custom.NewAppModule(customKeeper) -) - -scopedKeeperTransfer := capabilityKeeper.NewScopedKeeper("transfer") -scopedKeeperCustom1 := capabilityKeeper.NewScopedKeeper("custom1") -scopedKeeperCustom2 := capabilityKeeper.NewScopedKeeper("custom2") - -// NOTE: IBC Modules may be initialized any number of times provided they use a separate -// scopedKeeper and underlying port. - -customKeeper1 := custom.NewKeeper(..., scopedKeeperCustom1, ...) -customKeeper2 := custom.NewKeeper(..., scopedKeeperCustom2, ...) - -// initialize base IBC applications -// if you want to create two different stacks with the same base application, -// they must be given different scopedKeepers and assigned different ports. -transferIBCModule := transfer.NewIBCModule(transferKeeper) -customIBCModule1 := custom.NewIBCModule(customKeeper1, "portCustom1") -customIBCModule2 := custom.NewIBCModule(customKeeper2, "portCustom2") - -// create IBC stacks by combining middleware with base application -// NOTE: since middleware2 is stateless it does not require a Keeper -// stack 1 contains mw1 -> mw3 -> transfer -stack1 := mw1.NewIBCMiddleware(mw3.NewIBCMiddleware(transferIBCModule, mw3Keeper1), mw1Keeper) -// stack 2 contains mw3 -> mw2 -> custom1 -stack2 := mw3.NewIBCMiddleware(mw2.NewIBCMiddleware(customIBCModule1), mw3Keeper2) -// stack 3 contains mw2 -> mw1 -> custom2 -stack3 := mw2.NewIBCMiddleware(mw1.NewIBCMiddleware(customIBCModule2, mw1Keeper)) - -// associate each stack with the moduleName provided by the underlying scopedKeeper -ibcRouter := porttypes.NewRouter() -ibcRouter.AddRoute("transfer", stack1) -ibcRouter.AddRoute("custom1", stack2) -ibcRouter.AddRoute("custom2", stack3) -app.IBCKeeper.SetRouter(ibcRouter) -``` diff --git a/docs/docs/01-ibc/04-middleware/_category_.json b/docs/docs/01-ibc/04-middleware/_category_.json deleted file mode 100644 index 6596fe16c13..00000000000 --- a/docs/docs/01-ibc/04-middleware/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Middleware", - "position": 4, - "link": null -} \ No newline at end of file diff --git a/docs/docs/01-ibc/04-middleware/images/middleware-stack.png b/docs/docs/01-ibc/04-middleware/images/middleware-stack.png deleted file mode 100644 index 1d54f808170..00000000000 Binary files a/docs/docs/01-ibc/04-middleware/images/middleware-stack.png and /dev/null differ diff --git a/docs/docs/01-ibc/05-upgrades/00-intro.md b/docs/docs/01-ibc/05-upgrades/00-intro.md deleted file mode 100644 index 386a0ebfe73..00000000000 --- a/docs/docs/01-ibc/05-upgrades/00-intro.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: Upgrading IBC Chains Overview -sidebar_label: Overview -sidebar_position: 0 -slug: /ibc/upgrades/intro ---- - -# Upgrading IBC Chains Overview - -This directory contains information on how to upgrade an IBC chain without breaking counterparty clients and connections. - -IBC-connnected chains must be able to upgrade without breaking connections to other chains. Otherwise there would be a massive disincentive towards upgrading and disrupting high-value IBC connections, thus preventing chains in the IBC ecosystem from evolving and improving. Many chain upgrades may be irrelevant to IBC, however some upgrades could potentially break counterparty clients if not handled correctly. Thus, any IBC chain that wishes to perform a IBC-client-breaking upgrade must perform an IBC upgrade in order to allow counterparty clients to securely upgrade to the new light client. - -1. The [quick-guide](./01-quick-guide.md) describes how IBC-connected chains can perform client-breaking upgrades and how relayers can securely upgrade counterparty clients using the SDK. -2. The [developer-guide](./02-developer-guide.md) is a guide for developers intending to develop IBC client implementations with upgrade functionality. diff --git a/docs/docs/01-ibc/05-upgrades/01-quick-guide.md b/docs/docs/01-ibc/05-upgrades/01-quick-guide.md deleted file mode 100644 index a1a0b766e60..00000000000 --- a/docs/docs/01-ibc/05-upgrades/01-quick-guide.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: How to Upgrade IBC Chains and their Clients -sidebar_label: How to Upgrade IBC Chains and their Clients -sidebar_position: 1 -slug: /ibc/upgrades/quick-guide ---- - - -# How to Upgrade IBC Chains and their Clients - -:::note Synopsis -Learn how to upgrade your chain and counterparty clients. -::: - -The information in this doc for upgrading chains is relevant to SDK chains. However, the guide for counterparty clients is relevant to any Tendermint client that enables upgrades. - -## IBC Client Breaking Upgrades - -IBC-connected chains must perform an IBC upgrade if their upgrade will break counterparty IBC clients. The current IBC protocol supports upgrading tendermint chains for a specific subset of IBC-client-breaking upgrades. Here is the exhaustive list of IBC client-breaking upgrades and whether the IBC protocol currently supports such upgrades. - -IBC currently does **NOT** support unplanned upgrades. All of the following upgrades must be planned and committed to in advance by the upgrading chain, in order for counterparty clients to maintain their connections securely. - -Note: Since upgrades are only implemented for Tendermint clients, this doc only discusses upgrades on Tendermint chains that would break counterparty IBC Tendermint Clients. - -1. Changing the Chain-ID: **Supported** -2. Changing the UnbondingPeriod: **Partially Supported**, chains may increase the unbonding period with no issues. However, decreasing the unbonding period may irreversibly break some counterparty clients. Thus, it is **not recommended** that chains reduce the unbonding period. -3. Changing the height (resetting to 0): **Supported**, so long as chains remember to increment the revision number in their chain-id. -4. Changing the ProofSpecs: **Supported**, this should be changed if the proof structure needed to verify IBC proofs is changed across the upgrade. Ex: Switching from an IAVL store, to a SimpleTree Store -5. Changing the UpgradePath: **Supported**, this might involve changing the key under which upgraded clients and consensus states are stored in the upgrade store, or even migrating the upgrade store itself. -6. Migrating the IBC store: **Unsupported**, as the IBC store location is negotiated by the connection. -7. Upgrading to a backwards compatible version of IBC: Supported -8. Upgrading to a non-backwards compatible version of IBC: **Unsupported**, as IBC version is negotiated on connection handshake. -9. Changing the Tendermint LightClient algorithm: **Partially Supported**. Changes to the light client algorithm that do not change the ClientState or ConsensusState struct may be supported, provided that the counterparty is also upgraded to support the new light client algorithm. Changes that require updating the ClientState and ConsensusState structs themselves are theoretically possible by providing a path to translate an older ClientState struct into the new ClientState struct; however this is not currently implemented. - -## Step-by-Step Upgrade Process for SDK chains - -If the IBC-connected chain is conducting an upgrade that will break counterparty clients, it must ensure that the upgrade is first supported by IBC using the list above and then execute the upgrade process described below in order to prevent counterparty clients from breaking. - -1. Create a governance proposal with the [`MsgIBCSoftwareUpgrade`](https://buf.build/cosmos/ibc/docs/main:ibc.core.client.v1#ibc.core.client.v1.MsgIBCSoftwareUpgrade) message which contains an `UpgradePlan` and a new IBC `ClientState` in the `UpgradedClientState` field. Note that the `UpgradePlan` must specify an upgrade height **only** (no upgrade time), and the `ClientState` should only include the fields common to all valid clients (chain-specified parameters) and zero out any client-customizable fields (such as `TrustingPeriod`). -2. Vote on and pass the governance proposal. - -Upon passing the governance proposal, the upgrade module will commit the `UpgradedClient` under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedClient`. On the block right before the upgrade height, the upgrade module will also commit an initial consensus state for the next chain under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedConsState`. - -Once the chain reaches the upgrade height and halts, a relayer can upgrade the counterparty clients to the last block of the old chain. They can then submit the proofs of the `UpgradedClient` and `UpgradedConsensusState` against this last block and upgrade the counterparty client. - -## Step-by-Step Upgrade Process for Relayers Upgrading Counterparty Clients - -Once the upgrading chain has committed to upgrading, relayers must wait till the chain halts at the upgrade height before upgrading counterparty clients. This is because chains may reschedule or cancel upgrade plans before they occur. Thus, relayers must wait till the chain reaches the upgrade height and halts before they can be sure the upgrade will take place. - -Thus, the upgrade process for relayers trying to upgrade the counterparty clients is as follows: - -1. Wait for the upgrading chain to reach the upgrade height and halt -2. Query a full node for the proofs of `UpgradedClient` and `UpgradedConsensusState` at the last height of the old chain. -3. Update the counterparty client to the last height of the old chain using the `UpdateClient` msg. -4. Submit an `UpgradeClient` msg to the counterparty chain with the `UpgradedClient`, `UpgradedConsensusState` and their respective proofs. -5. Submit an `UpdateClient` msg to the counterparty chain with a header from the new upgraded chain. - -The Tendermint client on the counterparty chain will verify that the upgrading chain did indeed commit to the upgraded client and upgraded consensus state at the upgrade height (since the upgrade height is included in the key). If the proofs are verified against the upgrade height, then the client will upgrade to the new client while retaining all of its client-customized fields. Thus, it will retain its old TrustingPeriod, TrustLevel, MaxClockDrift, etc; while adopting the new chain-specified fields such as UnbondingPeriod, ChainId, UpgradePath, etc. Note, this can lead to an invalid client since the old client-chosen fields may no longer be valid given the new chain-chosen fields. Upgrading chains should try to avoid these situations by not altering parameters that can break old clients. For an example, see the UnbondingPeriod example in the supported upgrades section. - -The upgraded consensus state will serve purely as a basis of trust for future `UpdateClientMsgs` and will not contain a consensus root to perform proof verification against. Thus, relayers must submit an `UpdateClientMsg` with a header from the new chain so that the connection can be used for proof verification again. diff --git a/docs/docs/01-ibc/05-upgrades/02-developer-guide.md b/docs/docs/01-ibc/05-upgrades/02-developer-guide.md deleted file mode 100644 index 1f33e9d0ad2..00000000000 --- a/docs/docs/01-ibc/05-upgrades/02-developer-guide.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: IBC Client Developer Guide to Upgrades -sidebar_label: IBC Client Developer Guide to Upgrades -sidebar_position: 2 -slug: /ibc/upgrades/developer-guide ---- - -# IBC Client Developer Guide to Upgrades - -:::note Synopsis -Learn how to implement upgrade functionality for your custom IBC client. -::: - -Please see the section [Handling upgrades](../../03-light-clients/01-developer-guide/05-upgrades.md) from the light client developer guide for more information. diff --git a/docs/docs/01-ibc/05-upgrades/03-genesis-restart.md b/docs/docs/01-ibc/05-upgrades/03-genesis-restart.md deleted file mode 100644 index 3a15141d41d..00000000000 --- a/docs/docs/01-ibc/05-upgrades/03-genesis-restart.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: Genesis Restart Upgrades -sidebar_label: Genesis Restart Upgrades -sidebar_position: 3 -slug: /ibc/upgrades/genesis-restart ---- - - -# Genesis Restart Upgrades - -:::note Synopsis -Learn how to upgrade your chain and counterparty clients using genesis restarts. -::: - -**NOTE**: Regular genesis restarts are currently unsupported by relayers! - -## IBC Client Breaking Upgrades - -IBC client breaking upgrades are possible using genesis restarts. -It is highly recommended to use the in-place migrations instead of a genesis restart. -Genesis restarts should be used sparingly and as backup plans. - -Genesis restarts still require the usage of an IBC upgrade proposal in order to correctly upgrade counterparty clients. - -### Step-by-Step Upgrade Process for SDK Chains - -If the IBC-connected chain is conducting an upgrade that will break counterparty clients, it must ensure that the upgrade is first supported by IBC using the [IBC Client Breaking Upgrade List](./01-quick-guide.md#ibc-client-breaking-upgrades) and then execute the upgrade process described below in order to prevent counterparty clients from breaking. - -1. Create a governance proposal with the [`MsgIBCSoftwareUpgrade`](https://buf.build/cosmos/ibc/docs/main:ibc.core.client.v1#ibc.core.client.v1.MsgIBCSoftwareUpgrade) which contains an `UpgradePlan` and a new IBC `ClientState` in the `UpgradedClientState` field. Note that the `UpgradePlan` must specify an upgrade height **only** (no upgrade time), and the `ClientState` should only include the fields common to all valid clients and zero out any client-customizable fields (such as `TrustingPeriod`). -2. Vote on and pass the governance proposal. -3. Halt the node after successful upgrade. -4. Export the genesis file. -5. Swap to the new binary. -6. Run migrations on the genesis file. -7. Remove the upgrade plan set by the governance proposal from the genesis file. This may be done by migrations. -8. Change desired chain-specific fields (chain id, unbonding period, etc). This may be done by migrations. -8. Reset the node's data. -9. Start the chain. - -Upon passing the governance proposal, the upgrade module will commit the `UpgradedClient` under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedClient`. On the block right before the upgrade height, the upgrade module will also commit an initial consensus state for the next chain under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedConsState`. - -Once the chain reaches the upgrade height and halts, a relayer can upgrade the counterparty clients to the last block of the old chain. They can then submit the proofs of the `UpgradedClient` and `UpgradedConsensusState` against this last block and upgrade the counterparty client. - -### Step-by-Step Upgrade Process for Relayers Upgrading Counterparty Clients - -These steps are identical to the regular [IBC client breaking upgrade process](./01-quick-guide.md#step-by-step-upgrade-process-for-relayers-upgrading-counterparty-clients). - -## Non-IBC Client Breaking Upgrades - -While ibc-go supports genesis restarts which do not break IBC clients, relayers do not support this upgrade path. -Here is a tracking issue on [Hermes](https://github.com/informalsystems/ibc-rs/issues/1152). -Please do not attempt a regular genesis restarts unless you have a tool to update counterparty clients correctly. diff --git a/docs/docs/01-ibc/05-upgrades/_category_.json b/docs/docs/01-ibc/05-upgrades/_category_.json deleted file mode 100644 index 46eea8924ec..00000000000 --- a/docs/docs/01-ibc/05-upgrades/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Upgrades", - "position": 5, - "link": { "type": "doc", "id": "intro" } -} diff --git a/docs/docs/01-ibc/06-proposals.md b/docs/docs/01-ibc/06-proposals.md deleted file mode 100644 index 13b27fbd364..00000000000 --- a/docs/docs/01-ibc/06-proposals.md +++ /dev/null @@ -1,118 +0,0 @@ ---- -title: Governance Proposals -sidebar_label: Governance Proposals -sidebar_position: 6 -slug: /ibc/proposals ---- - -# Governance Proposals - -In uncommon situations, a highly valued client may become frozen due to uncontrollable -circumstances. A highly valued client might have hundreds of channels being actively used. -Some of those channels might have a significant amount of locked tokens used for ICS 20. - -If the one third of the validator set of the chain the client represents decides to collude, -they can sign off on two valid but conflicting headers each signed by the other one third -of the honest validator set. The light client can now be updated with two valid, but conflicting -headers at the same height. The light client cannot know which header is trustworthy and therefore -evidence of such misbehaviour is likely to be submitted resulting in a frozen light client. - -Frozen light clients cannot be updated under any circumstance except via a governance proposal. -Since a quorum of validators can sign arbitrary state roots which may not be valid executions -of the state machine, a governance proposal has been added to ease the complexity of unfreezing -or updating clients which have become "stuck". Without this mechanism, validator sets would need -to construct a state root to unfreeze the client. Unfreezing clients, re-enables all of the channels -built upon that client. This may result in recovery of otherwise lost funds. - -Tendermint light clients may become expired if the trusting period has passed since their -last update. This may occur if relayers stop submitting headers to update the clients. - -An unplanned upgrade by the counterparty chain may also result in expired clients. If the counterparty -chain undergoes an unplanned upgrade, there may be no commitment to that upgrade signed by the validator -set before the chain ID changes. In this situation, the validator set of the last valid update for the -light client is never expected to produce another valid header since the chain ID has changed, which will -ultimately lead the on-chain light client to become expired. - -In the case that a highly valued light client is frozen, expired, or rendered non-updateable, a -governance proposal may be submitted to update this client, known as the subject client. The -proposal includes the client identifier for the subject and the client identifier for a substitute -client. Light client implementations may implement custom updating logic, but in most cases, -the subject will be updated to the latest consensus state of the substitute client, if the proposal passes. -The substitute client is used as a "stand in" while the subject is on trial. It is best practice to create -a substitute client *after* the subject has become frozen to avoid the substitute from also becoming frozen. -An active substitute client allows headers to be submitted during the voting period to prevent accidental expiry -once the proposal passes. - -*note* two of these parameters: `AllowUpdateAfterExpiry` and `AllowUpdateAfterMisbehavior` have been deprecated, and will both be set to `false` upon upgrades even if they were previously set to `true`. These parameters will no longer play a role in restricting a client upgrade. Please see ADR026 for more details. - -# How to recover an expired client with a governance proposal - -See also the relevant documentation: [ADR-026, IBC client recovery mechanisms](/architecture/adr-026-ibc-client-recovery-mechanisms) - -> **Who is this information for?** -> Although technically anyone can submit the governance proposal to recover an expired client, often it will be **relayer operators** (at least coordinating the submission). - -## Preconditions - -- There exists an active client (with a known client identifier) for the same counterparty chain as the expired client. -- The governance deposit. - -## Steps - -### Step 1 - -Check if the client is attached to the expected `chain_id`. For example, for an expired Tendermint client representing the Akash chain the client state looks like this on querying the client state: - -```text -{ - client_id: 07-tendermint-146 - client_state: - '@type': /ibc.lightclients.tendermint.v1.ClientState - allow_update_after_expiry: true - allow_update_after_misbehaviour: true - chain_id: akashnet-2 -} -``` - -The client is attached to the expected Akash `chain_id`. Note that although the parameters (`allow_update_after_expiry` and `allow_update_after_misbehaviour`) exist to signal intent, these parameters have been deprecated and will not enforce any checks on the revival of client. See ADR-026 for more context on this deprecation. - -### Step 2 - -Anyone can submit the governance proposal to recover the client by executing the following via CLI. -If the chain is on an ibc-go version older than v8, please see the [relevant documentation](https://ibc.cosmos.network/v7/ibc/proposals). - -- From ibc-go v8 onwards - - ```shell - tx gov submit-proposal [path-to-proposal-json] - ``` - - where `proposal.json` contains: - - ```json - { - "messages": [ - { - "@type": "/ibc.core.client.v1.MsgRecoverClient", - "subject_client_id": "", - "substitute_client_id": "", - "signer": "" - } - ], - "metadata": "", - "deposit": "10stake" - "title": "My proposal", - "summary": "A short summary of my proposal", - "expedited": false - } - ``` - -The `` identifier is the proposed client to be updated. This client must be either frozen or expired. - -The `` represents a substitute client. It carries all the state for the client which may be updated. It must have identical client and chain parameters to the client which may be updated (except for latest height, frozen height, and chain ID). It should be continually updated during the voting period. - -After this, all that remains is deciding who funds the governance deposit and ensuring the governance proposal passes. If it does, the client on trial will be updated to the latest state of the substitute. - -## Important considerations - -Please note that if the counterparty client is also expired, that client will also need to update. This process updates only one client. diff --git a/docs/docs/01-ibc/07-relayer.md b/docs/docs/01-ibc/07-relayer.md deleted file mode 100644 index f40e9e671a3..00000000000 --- a/docs/docs/01-ibc/07-relayer.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: Relayer -sidebar_label: Relayer -sidebar_position: 7 -slug: /ibc/relayer ---- - -# Relayer - -:::note - -## Pre-requisite readings - -- [IBC Overview](01-overview.md) -- [Events](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/advanced/08-events.md) - -::: - -## Events - -Events are emitted for every transaction processed by the base application to indicate the execution -of some logic clients may want to be aware of. This is extremely useful when relaying IBC packets. -Any message that uses IBC will emit events for the corresponding TAO logic executed as defined in -the [IBC events document](/events/events). - -In the SDK, it can be assumed that for every message there is an event emitted with the type `message`, -attribute key `action`, and an attribute value representing the type of message sent -(`channel_open_init` would be the attribute value for `MsgChannelOpenInit`). If a relayer queries -for transaction events, it can split message events using this event Type/Attribute Key pair. - -The Event Type `message` with the Attribute Key `module` may be emitted multiple times for a single -message due to application callbacks. It can be assumed that any TAO logic executed will result in -a module event emission with the attribute value `ibc_` (02-client emits `ibc_client`). - -### Subscribing with Tendermint - -Calling the Tendermint RPC method `Subscribe` via [Tendermint's Websocket](https://docs.tendermint.com/main/rpc/) will return events using -Tendermint's internal representation of them. Instead of receiving back a list of events as they -were emitted, Tendermint will return the type `map[string][]string` which maps a string in the -form `.` to `attribute_value`. This causes extraction of the event -ordering to be non-trivial, but still possible. - -A relayer should use the `message.action` key to extract the number of messages in the transaction -and the type of IBC transactions sent. For every IBC transaction within the string array for -`message.action`, the necessary information should be extracted from the other event fields. If -`send_packet` appears at index 2 in the value for `message.action`, a relayer will need to use the -value at index 2 of the key `send_packet.packet_sequence`. This process should be repeated for each -piece of information needed to relay a packet. - -## Example Implementations - -- [Golang Relayer](https://github.com/cosmos/relayer) -- [Hermes](https://github.com/informalsystems/ibc-rs/tree/master/crates/relayer) diff --git a/docs/docs/01-ibc/08-proto-docs.md b/docs/docs/01-ibc/08-proto-docs.md deleted file mode 100644 index e1e87fb2845..00000000000 --- a/docs/docs/01-ibc/08-proto-docs.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Protobuf Documentation -sidebar_label: Protobuf Documentation -sidebar_position: 8 -slug: /ibc/proto-docs ---- - - -# Protobuf documentation - -See [ibc-go Buf Protobuf documentation](https://buf.build/cosmos/ibc/docs/main). diff --git a/docs/docs/01-ibc/09-roadmap.md b/docs/docs/01-ibc/09-roadmap.md deleted file mode 100644 index a4e1836d273..00000000000 --- a/docs/docs/01-ibc/09-roadmap.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: Roadmap -sidebar_label: Roadmap -sidebar_position: 9 -slug: /ibc/roadmap ---- - -# Roadmap ibc-go - -*Lastest update: September 12th, 2023* - -This document endeavours to inform the wider IBC community about plans and priorities for work on ibc-go by the team at Interchain GmbH. It is intended to broadly inform all users of ibc-go, including developers and operators of IBC, relayer, chain and wallet applications. - -This roadmap should be read as a high-level guide, rather than a commitment to schedules and deliverables. The degree of specificity is inversely proportional to the timeline. We will update this document periodically to reflect the status and plans. For the latest expected release timelines, please check [here](https://github.com/cosmos/ibc-go/wiki/Release-timeline). - -## v8.0.0 - -Follow the progress with the [milestone](https://github.com/cosmos/ibc-go/milestone/38). - -This release main addtions are: - -- Upgrade to Cosmos SDK v0.50. -- [Migration of gov proposals from v1beta1 to v1](https://github.com/cosmos/ibc-go/issues/1282). -- [Migration of params to be self managed](https://github.com/cosmos/ibc-go/issues/2010). - -## 08-wasm/v0.1.0 - -Follow the progress with the [milestone](https://github.com/cosmos/ibc-go/milestone/40). - -The first release of this new module will add support for Wasm light clients. The first Wasm client developed on top of ibc-go/v7 02-client refactor and stored as Wasm bytecode will be the GRANDPA light client used for Cosmos x Substrate IBC connections. This feature will be used also for a NEAR light client in the future. - -This feature has been developed by Composable and Strangelove. - -## v9.0.0 - -### Channel upgradability - -Channel upgradability will allow chains to renegotiate an existing channel to take advantage of new features without having to create a new channel, thus preserving all existing packet state processed on the channel. This feature will enable, for example, the adoption on existing channels of features like [path unwinding](https://github.com/cosmos/ibc/discussions/824) or fee middleware. - -Follow the progress with the [alpha milestone](https://github.com/cosmos/ibc-go/milestone/29) or the [project board](https://github.com/orgs/cosmos/projects/7/views/17). - ---- - -This roadmap is also available as a [project board](https://github.com/orgs/cosmos/projects/7/views/25). - -For the latest expected release timelines, please check [here](https://github.com/cosmos/ibc-go/wiki/Release-timeline). - -For the latest information on the progress of the work or the decisions made that might influence the roadmap, please follow the [Annoucements](https://github.com/cosmos/ibc-go/discussions/categories/announcements) category in the Discussions tab of the repository. - ---- - -**Note**: release version numbers may be subject to change. diff --git a/docs/docs/01-ibc/10-troubleshooting.md b/docs/docs/01-ibc/10-troubleshooting.md deleted file mode 100644 index 0504a993b17..00000000000 --- a/docs/docs/01-ibc/10-troubleshooting.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: Troubleshooting -sidebar_label: Troubleshooting -sidebar_position: 10 -slug: /ibc/troubleshooting ---- - -# Troubleshooting - -## Unauthorized client states - -If it is being reported that a client state is unauthorized, this is due to the client type not being present -in the [`AllowedClients`](https://github.com/cosmos/ibc-go/blob/v6.0.0/modules/core/02-client/types/client.pb.go#L345) array. - -Unless the client type is present in this array, all usage of clients of this type will be prevented. diff --git a/docs/docs/01-ibc/11-capability-module.md b/docs/docs/01-ibc/11-capability-module.md deleted file mode 100644 index d8bd27108ce..00000000000 --- a/docs/docs/01-ibc/11-capability-module.md +++ /dev/null @@ -1,139 +0,0 @@ ---- -title: Capability Module -sidebar_label: Capability Module -sidebar_position: 11 -slug: /ibc/capability-module ---- - -# Capability Module - -## Overview - -`modules/capability` is an implementation of a Cosmos SDK module, per [ADR 003](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-003-dynamic-capability-store.md), that allows for provisioning, tracking, and authenticating multi-owner capabilities at runtime. - -The keeper maintains two states: persistent and ephemeral in-memory. The persistent -store maintains a globally unique auto-incrementing index and a mapping from -capability index to a set of capability owners that are defined as a module and -capability name tuple. The in-memory ephemeral state keeps track of the actual -capabilities, represented as addresses in local memory, with both forward and reverse indexes. -The forward index maps module name and capability tuples to the capability name. The -reverse index maps between the module and capability name and the capability itself. - -The keeper allows the creation of "scoped" sub-keepers which are tied to a particular -module by name. Scoped keepers must be created at application initialization and -passed to modules, which can then use them to claim capabilities they receive and -retrieve capabilities which they own by name, in addition to creating new capabilities -& authenticating capabilities passed by other modules. A scoped keeper cannot escape its scope, -so a module cannot interfere with or inspect capabilities owned by other modules. - -The keeper provides no other core functionality that can be found in other modules -like queriers, REST and CLI handlers, and genesis state. - -## Initialization - -During application initialization, the keeper must be instantiated with a persistent -store key and an in-memory store key. - -```go -type App struct { - // ... - - capabilityKeeper *capability.Keeper -} - -func NewApp(...) *App { - // ... - - app.capabilityKeeper = capabilitykeeper.NewKeeper(codec, persistentStoreKey, memStoreKey) -} -``` - -After the keeper is created, it can be used to create scoped sub-keepers which -are passed to other modules that can create, authenticate, and claim capabilities. -After all the necessary scoped keepers are created and the state is loaded, the -main capability keeper must be sealed to prevent further scoped keepers from -being created. - -```go -func NewApp(...) *App { - // ... - - // Creating a scoped keeper - scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName) - - // Seal the capability keeper to prevent any further modules from creating scoped - // sub-keepers. - app.capabilityKeeper.Seal() - - return app -} -``` - -## Contents - -- [`modules/capability`](#capability-module) - - [Overview](#overview) - - [Initialization](#initialization) - - [Contents](#contents) - - [Concepts](#concepts) - - [Capabilities](#capabilities) - - [Stores](#stores) - - [State](#state) - - [Persisted KV store](#persisted-kv-store) - - [In-memory KV store](#in-memory-kv-store) - -## Concepts - -### Capabilities - -Capabilities are multi-owner. A scoped keeper can create a capability via `NewCapability` -which creates a new unique, unforgeable object-capability reference. The newly -created capability is automatically persisted; the calling module need not call -`ClaimCapability`. Calling `NewCapability` will create the capability with the -calling module and name as a tuple to be treated the capabilities first owner. - -Capabilities can be claimed by other modules which add them as owners. `ClaimCapability` -allows a module to claim a capability key which it has received from another -module so that future `GetCapability` calls will succeed. `ClaimCapability` MUST -be called if a module which receives a capability wishes to access it by name in -the future. Again, capabilities are multi-owner, so if multiple modules have a -single Capability reference, they will all own it. If a module receives a capability -from another module but does not call `ClaimCapability`, it may use it in the executing -transaction but will not be able to access it afterwards. - -`AuthenticateCapability` can be called by any module to check that a capability -does in fact correspond to a particular name (the name can be un-trusted user input) -with which the calling module previously associated it. - -`GetCapability` allows a module to fetch a capability which it has previously -claimed by name. The module is not allowed to retrieve capabilities which it does -not own. - -### Stores - -- MemStore -- KeyStore - -## State - -### Persisted KV store - -1. Global unique capability index -2. Capability owners - -Indexes: - -- Unique index: `[]byte("index") -> []byte(currentGlobalIndex)` -- Capability Index: `[]byte("capability_index") | []byte(index) -> ProtocolBuffer(CapabilityOwners)` - -### In-memory KV store - -1. Initialized flag -2. Mapping between the module and capability tuple and the capability name -3. Mapping between the module and capability name and its index - -Indexes: - -- Initialized flag: `[]byte("mem_initialized")` -- RevCapabilityKey: `[]byte(moduleName + "/rev/" + capabilityName) -> []byte(index)` -- FwdCapabilityKey: `[]byte(moduleName + "/fwd/" + capabilityPointerAddress) -> []byte(capabilityName)` diff --git a/docs/docs/01-ibc/_category_.json b/docs/docs/01-ibc/_category_.json deleted file mode 100644 index 066f3af93b1..00000000000 --- a/docs/docs/01-ibc/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Using IBC-Go", - "position": 1, - "link": null -} \ No newline at end of file diff --git a/docs/docs/02-apps/01-transfer/01-overview.md b/docs/docs/02-apps/01-transfer/01-overview.md deleted file mode 100644 index 7e257d1e805..00000000000 --- a/docs/docs/02-apps/01-transfer/01-overview.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /apps/transfer/overview ---- - -# Overview - -:::note Synopsis -Learn about what the token Transfer module is -::: - -## What is the Transfer module? - -Transfer is the Cosmos SDK implementation of the [ICS-20](https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer) protocol, which enables cross-chain fungible token transfers. - -## Concepts - -### Acknowledgements - -ICS20 uses the recommended acknowledgement format as specified by [ICS 04](https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope). - -A successful receive of a transfer packet will result in a Result Acknowledgement being written -with the value `[]byte{byte(1)}` in the `Response` field. - -An unsuccessful receive of a transfer packet will result in an Error Acknowledgement being written -with the error message in the `Response` field. - -### Denomination trace - -The denomination trace corresponds to the information that allows a token to be traced back to its -origin chain. It contains a sequence of port and channel identifiers ordered from the most recent to -the oldest in the timeline of transfers. - -This information is included on the token denomination field in the form of a hash to prevent an -unbounded denomination length. For example, the token `transfer/channelToA/uatom` will be displayed -as `ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2`. - -Each send to any chain other than the one it was previously received from is a movement forwards in -the token's timeline. This causes trace to be added to the token's history and the destination port -and destination channel to be prefixed to the denomination. In these instances the sender chain is -acting as the "source zone". When the token is sent back to the chain it previously received from, the -prefix is removed. This is a backwards movement in the token's timeline and the sender chain is -acting as the "sink zone". - -It is strongly recommended to read the full details of [ADR 001: Coin Source Tracing](/architecture/adr-001-coin-source-tracing) to understand the implications and context of the IBC token representations. - -## UX suggestions for clients - -For clients (wallets, exchanges, applications, block explorers, etc) that want to display the source of the token, it is recommended to use the following alternatives for each of the cases below: - -### Direct connection - -If the denomination trace contains a single identifier prefix pair (as in the example above), then -the easiest way to retrieve the chain and light client identifier is to map the trace information -directly. In summary, this requires querying the channel from the denomination trace identifiers, -and then the counterparty client state using the counterparty port and channel identifiers from the -retrieved channel. - -A general pseudo algorithm would look like the following: - -1. Query the full denomination trace. -2. Query the channel with the `portID/channelID` pair, which corresponds to the first destination of the - token. -3. Query the client state using the identifiers pair. Note that this query will return a `"Not -Found"` response if the current chain is not connected to this channel. -4. Retrieve the client identifier or chain identifier from the client state (eg: on - Tendermint clients) and store it locally. - -Using the gRPC gateway client service the steps above would be, with a given IBC token `ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2` stored on `chainB`: - -1. `GET /ibc/apps/transfer/v1/denom_traces/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2` -> `{"path": "transfer/channelToA", "base_denom": "uatom"}` -2. `GET /ibc/apps/transfer/v1/channels/channelToA/ports/transfer/client_state"` -> `{"client_id": "clientA", "chain-id": "chainA", ...}` -3. `GET /ibc/apps/transfer/v1/channels/channelToA/ports/transfer"` -> `{"channel_id": "channelToA", port_id": "transfer", counterparty: {"channel_id": "channelToB", port_id": "transfer"}, ...}` -4. `GET /ibc/apps/transfer/v1/channels/channelToB/ports/transfer/client_state" -> {"client_id": "clientB", "chain-id": "chainB", ...}` - -Then, the token transfer chain path for the `uatom` denomination would be: `chainA` -> `chainB`. - -### Multiple hops - -The multiple channel hops case applies when the token has passed through multiple chains between the original source and final destination chains. - -The IBC protocol doesn't know the topology of the overall network (i.e connections between chains and identifier names between them). For this reason, in the multiple hops case, a particular chain in the timeline of the individual transfers can't query the chain and client identifiers of the other chains. - -Take for example the following sequence of transfers `A -> B -> C` for an IBC token, with a final prefix path (trace info) of `transfer/channelChainC/transfer/channelChainB`. What the paragraph above means is that even in the case that chain `C` is directly connected to chain `A`, querying the port and channel identifiers that chain `B` uses to connect to chain `A` (eg: `transfer/channelChainA`) can be completely different from the one that chain `C` uses to connect to chain `A` (eg: `transfer/channelToChainA`). - -Thus the proposed solution for clients that the IBC team recommends are the following: - -- **Connect to all chains**: Connecting to all the chains in the timeline would allow clients to - perform the queries outlined in the [direct connection](#direct-connection) section to each - relevant chain. By repeatedly following the port and channel denomination trace transfer timeline, - clients should always be able to find all the relevant identifiers. This comes at the tradeoff - that the client must connect to nodes on each of the chains in order to perform the queries. -- **Relayer as a Service (RaaS)**: A longer term solution is to use/create a relayer service that - could map the denomination trace to the chain path timeline for each token (i.e `origin chain -> -chain #1 -> ... -> chain #(n-1) -> final chain`). These services could provide merkle proofs in - order to allow clients to optionally verify the path timeline correctness for themselves by - running light clients. If the proofs are not verified, they should be considered as trusted third - parties services. Additionally, client would be advised in the future to use RaaS that support the - largest number of connections between chains in the ecosystem. Unfortunately, none of the existing - public relayers (in [Golang](https://github.com/cosmos/relayer) and - [Rust](https://github.com/informalsystems/ibc-rs)), provide this service to clients. - -:::tip -The only viable alternative for clients (at the time of writing) to tokens with multiple connection hops, is to connect to all chains directly and perform relevant queries to each of them in the sequence. -::: - -## Locked funds - -In some [exceptional cases](/architecture/adr-026-ibc-client-recovery-mechanisms#exceptional-cases), a client state associated with a given channel cannot be updated. This causes that funds from fungible tokens in that channel will be permanently locked and thus can no longer be transferred. - -To mitigate this, a client update governance proposal can be submitted to update the frozen client -with a new valid header. Once the proposal passes the client state will be unfrozen and the funds -from the associated channels will then be unlocked. This mechanism only applies to clients that -allow updates via governance, such as Tendermint clients. - -In addition to this, it's important to mention that a token must be sent back along the exact route -that it took originally in order to return it to its original form on the source chain (eg: the -Cosmos Hub for the `uatom`). Sending a token back to the same chain across a different channel will -**not** move the token back across its timeline. If a channel in the chain history closes before the -token can be sent back across that channel, then the token will not be returnable to its original -form. - -## Security considerations - -For safety, no other module must be capable of minting tokens with the `ibc/` prefix. The IBC -transfer module needs a subset of the denomination space that only it can create tokens in. diff --git a/docs/docs/02-apps/01-transfer/02-state.md b/docs/docs/02-apps/01-transfer/02-state.md deleted file mode 100644 index 916e99b46c3..00000000000 --- a/docs/docs/02-apps/01-transfer/02-state.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: State -sidebar_label: State -sidebar_position: 2 -slug: /apps/transfer/state ---- - -# State - -The IBC transfer application module keeps state of the port to which the module is binded and the denomination trace information as outlined in [ADR 001](/architecture/adr-001-coin-source-tracing). - -- `Port`: `0x01 -> ProtocolBuffer(string)` -- `DenomTrace`: `0x02 | []bytes(traceHash) -> ProtocolBuffer(DenomTrace)` diff --git a/docs/docs/02-apps/01-transfer/03-state-transitions.md b/docs/docs/02-apps/01-transfer/03-state-transitions.md deleted file mode 100644 index 7c73b8da21c..00000000000 --- a/docs/docs/02-apps/01-transfer/03-state-transitions.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: State Transitions -sidebar_label: State Transitions -sidebar_position: 3 -slug: /apps/transfer/state-transitions ---- - -# State transitions - -## Send fungible tokens - -A successful fungible token send has two state transitions depending if the transfer is a movement forward or backwards in the token's timeline: - -1. Sender chain is the source chain, *i.e* a transfer to any chain other than the one it was previously received from is a movement forwards in the token's timeline. This results in the following state transitions: - - - The coins are transferred to an escrow address (i.e locked) on the sender chain. - - The coins are transferred to the receiving chain through IBC TAO logic. - -2. Sender chain is the sink chain, *i.e* the token is sent back to the chain it previously received from. This is a backwards movement in the token's timeline. This results in the following state transitions: - - - The coins (vouchers) are burned on the sender chain. - - The coins are transferred to the receiving chain through IBC TAO logic. - -## Receive fungible tokens - -A successful fungible token receive has two state transitions depending if the transfer is a movement forward or backwards in the token's timeline: - -1. Receiver chain is the source chain. This is a backwards movement in the token's timeline. This results in the following state transitions: - - - The leftmost port and channel identifier pair is removed from the token denomination prefix. - - The tokens are unescrowed and sent to the receiving address. - -2. Receiver chain is the sink chain. This is a movement forwards in the token's timeline. This results in the following state transitions: - - - Token vouchers are minted by prefixing the destination port and channel identifiers to the trace information. - - The receiving chain stores the new trace information in the store (if not set already). - - The vouchers are sent to the receiving address. diff --git a/docs/docs/02-apps/01-transfer/04-messages.md b/docs/docs/02-apps/01-transfer/04-messages.md deleted file mode 100644 index 483384a09fe..00000000000 --- a/docs/docs/02-apps/01-transfer/04-messages.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: Messages -sidebar_label: Messages -sidebar_position: 4 -slug: /apps/transfer/messages ---- - -# Messages - -## `MsgTransfer` - -A fungible token cross chain transfer is achieved by using the `MsgTransfer`: - -```go -type MsgTransfer struct { - SourcePort string - SourceChannel string - Token sdk.Coin - Sender string - Receiver string - TimeoutHeight ibcexported.Height - TimeoutTimestamp uint64 - Memo string -} -``` - -This message is expected to fail if: - -- `SourcePort` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). -- `SourceChannel` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -- `Token` is invalid (denom is invalid or amount is negative) - - `Token.Amount` is not positive. - - `Token.Denom` is not a valid IBC denomination as per [ADR 001 - Coin Source Tracing](/architecture/adr-001-coin-source-tracing). -- `Sender` is empty. -- `Receiver` is empty. -- `TimeoutHeight` and `TimeoutTimestamp` are both zero. - -This message will send a fungible token to the counterparty chain represented by the counterparty Channel End connected to the Channel End with the identifiers `SourcePort` and `SourceChannel`. - -The denomination provided for transfer should correspond to the same denomination represented on this chain. The prefixes will be added as necessary upon by the receiving chain. - -### Memo - -The memo field was added to allow applications and users to attach metadata to transfer packets. The field is optional and may be left empty. When it is used to attach metadata for a particular middleware, the memo field should be represented as a json object where different middlewares use different json keys. - -For example, the following memo field is used by the [callbacks middleware](../../04-middleware/02-callbacks/01-overview.md) to attach a source callback to a transfer packet: - -```jsonc -{ - "src_callback": { - "address": "callbackAddressString", - // optional - "gas_limit": "userDefinedGasLimitString", - } -} -``` - -You can find more information about other applications that use the memo field in the [chain registry](https://github.com/cosmos/chain-registry/blob/master/_memo_keys/ICS20_memo_keys.json). diff --git a/docs/docs/02-apps/01-transfer/05-events.md b/docs/docs/02-apps/01-transfer/05-events.md deleted file mode 100644 index 888b26a959a..00000000000 --- a/docs/docs/02-apps/01-transfer/05-events.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Events -sidebar_label: Events -sidebar_position: 5 -slug: /apps/transfer/events ---- - - -# Events - -## `MsgTransfer` - -| Type | Attribute Key | Attribute Value | -|--------------|---------------|-----------------| -| ibc_transfer | sender | {sender} | -| ibc_transfer | receiver | {receiver} | -| message | action | transfer | -| message | module | transfer | - -## `OnRecvPacket` callback - -| Type | Attribute Key | Attribute Value | -|-----------------------|---------------|-----------------| -| fungible_token_packet | module | transfer | -| fungible_token_packet | sender | {sender} | -| fungible_token_packet | receiver | {receiver} | -| fungible_token_packet | denom | {denom} | -| fungible_token_packet | amount | {amount} | -| fungible_token_packet | success | {ackSuccess} | -| fungible_token_packet | memo | {memo} | -| denomination_trace | trace_hash | {hex_hash} | - -## `OnAcknowledgePacket` callback - -| Type | Attribute Key | Attribute Value | -|-----------------------|-----------------|-------------------| -| fungible_token_packet | module | transfer | -| fungible_token_packet | sender | {sender} | -| fungible_token_packet | receiver | {receiver} | -| fungible_token_packet | denom | {denom} | -| fungible_token_packet | amount | {amount} | -| fungible_token_packet | memo | {memo} | -| fungible_token_packet | acknowledgement | {ack.String()} | -| fungible_token_packet | success | error | {ack.Response} | - -## `OnTimeoutPacket` callback - -| Type | Attribute Key | Attribute Value | -|-----------------------|-----------------|-----------------| -| fungible_token_packet | module | transfer | -| fungible_token_packet | refund_receiver | {receiver} | -| fungible_token_packet | denom | {denom} | -| fungible_token_packet | amount | {amount} | -| fungible_token_packet | memo | {memo} | diff --git a/docs/docs/02-apps/01-transfer/06-metrics.md b/docs/docs/02-apps/01-transfer/06-metrics.md deleted file mode 100644 index 104e5b4d3bc..00000000000 --- a/docs/docs/02-apps/01-transfer/06-metrics.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: Metrics -sidebar_label: Metrics -sidebar_position: 6 -slug: /apps/transfer/metrics ---- - - -# Metrics - -The IBC transfer application module exposes the following set of [metrics](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/advanced/09-telemetry.md). - -| Metric | Description | Unit | Type | -|:--------------------------------|:------------------------------------------------------------------------------------------|:----------------|:--------| -| `tx_msg_ibc_transfer` | The total amount of tokens transferred via IBC in a `MsgTransfer` (source or sink chain) | token | gauge | -| `ibc_transfer_packet_receive` | The total amount of tokens received in a `FungibleTokenPacketData` (source or sink chain) | token | gauge | -| `ibc_transfer_send` | Total number of IBC transfers sent from a chain (source or sink) | transfer | counter | -| `ibc_transfer_receive` | Total number of IBC transfers received to a chain (source or sink) | transfer | counter | diff --git a/docs/docs/02-apps/01-transfer/07-params.md b/docs/docs/02-apps/01-transfer/07-params.md deleted file mode 100644 index 365fc21c3e3..00000000000 --- a/docs/docs/02-apps/01-transfer/07-params.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -title: Params -sidebar_label: Params -sidebar_position: 7 -slug: /apps/transfer/params ---- - - -# Parameters - -The IBC transfer application module contains the following parameters: - -| Name | Type | Default Value | -| ---------------- | ---- | ------------- | -| `SendEnabled` | bool | `true` | -| `ReceiveEnabled` | bool | `true` | - -The IBC transfer module stores its parameters in its keeper with the prefix of `0x03`. - -## `SendEnabled` - -The `SendEnabled` parameter controls send cross-chain transfer capabilities for all fungible tokens. - -To prevent a single token from being transferred from the chain, set the `SendEnabled` parameter to `true` and then, depending on the Cosmos SDK version, do one of the following: - -- For Cosmos SDK v0.46.x or earlier, set the bank module's [`SendEnabled` parameter](https://github.com/cosmos/cosmos-sdk/blob/release/v0.46.x/x/bank/spec/05_params.md#sendenabled) for the denomination to `false`. -- For Cosmos SDK versions above v0.46.x, set the bank module's `SendEnabled` entry for the denomination to `false` using `MsgSetSendEnabled` as a governance proposal. - -::: warning -Doing so will prevent the token from being transferred between any accounts in the blockchain. -::: - -## `ReceiveEnabled` - -The transfers enabled parameter controls receive cross-chain transfer capabilities for all fungible tokens. - -To prevent a single token from being transferred to the chain, set the `ReceiveEnabled` parameter to `true` and then, depending on the Cosmos SDK version, do one of the following: - -- For Cosmos SDK v0.46.x or earlier, set the bank module's [`SendEnabled` parameter](https://github.com/cosmos/cosmos-sdk/blob/release/v0.46.x/x/bank/spec/05_params.md#sendenabled) for the denomination to `false`. -- For Cosmos SDK versions above v0.46.x, set the bank module's `SendEnabled` entry for the denomination to `false` using `MsgSetSendEnabled` as a governance proposal. - -::: warning -Doing so will prevent the token from being transferred between any accounts in the blockchain. -::: - -## Queries - -Current parameter values can be queried via a query message. - - - -```protobuf -// proto/ibc/applications/transfer/v1/query.proto - -// QueryParamsRequest is the request type for the Query/Params RPC method. -message QueryParamsRequest {} - -// QueryParamsResponse is the response type for the Query/Params RPC method. -message QueryParamsResponse { - // params defines the parameters of the module. - Params params = 1; -} -``` - -To execute the query in `simd`, you use the following command: - -```bash -simd query ibc-transfer params -``` - -## Changing Parameters - -To change the parameter values, you must make a governance proposal that executes the `MsgUpdateParams` message. - - - -```protobuf -// proto/ibc/applications/transfer/v1/tx.proto - -// MsgUpdateParams is the Msg/UpdateParams request type. -message MsgUpdateParams { - // signer address (it may be the the address that controls the module, which defaults to x/gov unless overwritten). - string signer = 1; - - // params defines the transfer parameters to update. - // - // NOTE: All parameters must be supplied. - Params params = 2 [(gogoproto.nullable) = false]; -} - -// MsgUpdateParamsResponse defines the response structure for executing a -// MsgUpdateParams message. -message MsgUpdateParamsResponse {} -``` diff --git a/docs/docs/02-apps/01-transfer/08-authorizations.md b/docs/docs/02-apps/01-transfer/08-authorizations.md deleted file mode 100644 index 2bd4920f945..00000000000 --- a/docs/docs/02-apps/01-transfer/08-authorizations.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: Authorizations -sidebar_label: Authorizations -sidebar_position: 8 -slug: /apps/transfer/authorizations ---- -# `TransferAuthorization` - -`TransferAuthorization` implements the `Authorization` interface for `ibc.applications.transfer.v1.MsgTransfer`. It allows a granter to grant a grantee the privilege to submit `MsgTransfer` on its behalf. Please see the [Cosmos SDK docs](https://docs.cosmos.network/v0.47/modules/authz) for more details on granting privileges via the `x/authz` module. - -More specifically, the granter allows the grantee to transfer funds that belong to the granter over a specified channel. - -For the specified channel, the granter must be able to specify a spend limit of a specific denomination they wish to allow the grantee to be able to transfer. - -The granter may be able to specify the list of addresses that they allow to receive funds. If empty, then all addresses are allowed. - -It takes: - -- a `SourcePort` and a `SourceChannel` which together comprise the unique transfer channel identifier over which authorized funds can be transferred. - -- a `SpendLimit` that specifies the maximum amount of tokens the grantee can transfer. The `SpendLimit` is updated as the tokens are transfered, unless the sentinel value of the maximum value for a 256-bit unsigned integer (i.e. 2^256 - 1) is used for the amount, in which case the `SpendLimit` will not be updated (please be aware that using this sentinel value will grant the grantee the privilege to transfer **all** the tokens of a given denomination available at the granter's account). The helper function `UnboundedSpendLimit` in the `types` package of the `transfer` module provides the sentinel value that can be used. This `SpendLimit` may also be updated to increase or decrease the limit as the granter wishes. - -- an `AllowList` list that specifies the list of addresses that are allowed to receive funds. If this list is empty, then all addresses are allowed to receive funds from the `TransferAuthorization`. - -Setting a `TransferAuthorization` is expected to fail if: - -- the spend limit is nil -- the denomination of the spend limit is an invalid coin type -- the source port ID is invalid -- the source channel ID is invalid -- there are duplicate entries in the `AllowList` - -Below is the `TransferAuthorization` message: - -```go -func NewTransferAuthorization(allocations ...Allocation) *TransferAuthorization { - return &TransferAuthorization{ - Allocations: allocations, - } -} - -type Allocation struct { - // the port on which the packet will be sent - SourcePort string - // the channel by which the packet will be sent - SourceChannel string - // spend limitation on the channel - SpendLimit sdk.Coins - // allow list of receivers, an empty allow list permits any receiver address - AllowList []string -} - -``` diff --git a/docs/docs/02-apps/01-transfer/09-client.md b/docs/docs/02-apps/01-transfer/09-client.md deleted file mode 100644 index 64ec2bd6ad1..00000000000 --- a/docs/docs/02-apps/01-transfer/09-client.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: Client -sidebar_label: Client -sidebar_position: 9 -slug: /apps/transfer/client ---- - -# Client - -## CLI - -A user can query and interact with the `transfer` module using the CLI. Use the `--help` flag to discover the available commands: - -### Query - -The `query` commands allow users to query `transfer` state. - -```shell -simd query ibc-transfer --help -``` - -#### `total-escrow` - -The `total-escrow` command allows users to query the total amount in escrow for a particular coin denomination regardless of the transfer channel from where the coins were sent out. - -```shell -simd query ibc-transfer total-escrow [denom] [flags] -``` - -Example: - -```shell -simd query ibc-transfer total-escrow samoleans -``` - -Example Output: - -```shell -amount: "100" -``` - -## gRPC - -A user can query the `transfer` module using gRPC endpoints. - -### `TotalEscrowForDenom` - -The `TotalEscrowForDenom` endpoint allows users to query the total amount in escrow for a particular coin denomination regardless of the transfer channel from where the coins were sent out. - -```shell -ibc.applications.transfer.v1.Query/TotalEscrowForDenom -``` - -Example: - -```shell -grpcurl -plaintext \ - -d '{"denom":"samoleans"}' \ - localhost:9090 \ - ibc.applications.transfer.v1.Query/TotalEscrowForDenom -``` - -Example output: - -```shell -{ - "amount": "100" -} -``` diff --git a/docs/docs/02-apps/01-transfer/_category_.json b/docs/docs/02-apps/01-transfer/_category_.json deleted file mode 100644 index d643a498cdf..00000000000 --- a/docs/docs/02-apps/01-transfer/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Transfer", - "position": 1, - "link": null -} \ No newline at end of file diff --git a/docs/docs/02-apps/02-interchain-accounts/01-overview.md b/docs/docs/02-apps/02-interchain-accounts/01-overview.md deleted file mode 100644 index e8edada979f..00000000000 --- a/docs/docs/02-apps/02-interchain-accounts/01-overview.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /apps/interchain-accounts/overview ---- - - -# Overview - -:::note Synopsis -Learn about what the Interchain Accounts module is -::: - -## What is the Interchain Accounts module? - -Interchain Accounts is the Cosmos SDK implementation of the ICS-27 protocol, which enables cross-chain account management built upon IBC. - -- How does an interchain account differ from a regular account? - -Regular accounts use a private key to sign transactions. Interchain Accounts are instead controlled programmatically by counterparty chains via IBC packets. - -## Concepts - -`Host Chain`: The chain where the interchain account is registered. The host chain listens for IBC packets from a controller chain which should contain instructions (e.g. Cosmos SDK messages) for which the interchain account will execute. - -`Controller Chain`: The chain registering and controlling an account on a host chain. The controller chain sends IBC packets to the host chain to control the account. - -`Interchain Account`: An account on a host chain created using the ICS-27 protocol. An interchain account has all the capabilities of a normal account. However, rather than signing transactions with a private key, a controller chain will send IBC packets to the host chain which signals what transactions the interchain account should execute. - -`Authentication Module`: A custom application module on the controller chain that uses the Interchain Accounts module to build custom logic for the creation & management of interchain accounts. It can be either an IBC application module using the [legacy API](10-legacy/03-keeper-api.md), or a regular Cosmos SDK application module sending messages to the controller submodule's `MsgServer` (this is the recommended approach from ibc-go v6 if access to packet callbacks is not needed). Please note that the legacy API will eventually be removed and IBC applications will not be able to use them in later releases. - -## SDK security model - -SDK modules on a chain are assumed to be trustworthy. For example, there are no checks to prevent an untrustworthy module from accessing the bank keeper. - -The implementation of ICS-27 in ibc-go uses this assumption in its security considerations. - -The implementation assumes other IBC application modules will not bind to ports within the ICS-27 namespace. diff --git a/docs/docs/02-apps/02-interchain-accounts/02-development.md b/docs/docs/02-apps/02-interchain-accounts/02-development.md deleted file mode 100644 index eb2aaa1f90a..00000000000 --- a/docs/docs/02-apps/02-interchain-accounts/02-development.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: Development Use Cases -sidebar_label: Development Use Cases -sidebar_position: 2 -slug: /apps/interchain-accounts/development ---- - - -# Development use cases - -The initial version of Interchain Accounts allowed for the controller submodule to be extended by providing it with an underlying application which would handle all packet callbacks. -That functionality is now being deprecated in favor of alternative approaches. -This document will outline potential use cases and redirect each use case to the appropriate documentation. - -## Custom authentication - -Interchain accounts may be associated with alternative types of authentication relative to the traditional public/private key signing. -If you wish to develop or use Interchain Accounts with a custom authentication module and do not need to execute custom logic on the packet callbacks, we recommend you use ibc-go v6 or greater and that your custom authentication module interacts with the controller submodule via the [`MsgServer`](05-messages.md). - -If you wish to consume and execute custom logic in the packet callbacks, then please read the section [Packet callbacks](#packet-callbacks) below. - -## Redirection to a smart contract - -It may be desirable to allow smart contracts to control an interchain account. -To faciliate such an action, the controller submodule may be provided an underlying application which redirects to smart contract callers. -An improved design has been suggested in [ADR 008](https://github.com/cosmos/ibc-go/pull/1976) which performs this action via middleware. - -Implementors of this use case are recommended to follow the ADR 008 approach. -The underlying application may continue to be used as a short term solution for ADR 008 and the [legacy API](03-auth-modules.md#registerinterchainaccount) should continue to be utilized in such situations. - -## Packet callbacks - -If a developer requires access to packet callbacks for their use case, then they have the following options: - -1. Write a smart contract which is connected via an ADR 008 or equivalent IBC application (recommended). -2. Use the controller's underlying application to implement packet callback logic. - -In the first case, the smart contract should use the [`MsgServer`](05-messages.md). - -In the second case, the underlying application should use the [legacy API](10-legacy/03-keeper-api.md). diff --git a/docs/docs/02-apps/02-interchain-accounts/03-auth-modules.md b/docs/docs/02-apps/02-interchain-accounts/03-auth-modules.md deleted file mode 100644 index 31231952208..00000000000 --- a/docs/docs/02-apps/02-interchain-accounts/03-auth-modules.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: Authentication Modules -sidebar_label: Authentication Modules -sidebar_position: 3 -slug: /apps/interchain-accounts/auth-modules ---- - - -# Building an authentication module - -:::note Synopsis -Authentication modules enable application developers to perform custom logic when interacting with the Interchain Accounts controller sumbmodule's `MsgServer`. -::: - -The controller submodule is used for account registration and packet sending. It executes only logic required of all controllers of interchain accounts. The type of authentication used to manage the interchain accounts remains unspecified. There may exist many different types of authentication which are desirable for different use cases. Thus the purpose of the authentication module is to wrap the controller submodule with custom authentication logic. - -In ibc-go, authentication modules can communicate with the controller submodule by passing messages through `baseapp`'s `MsgServiceRouter`. To implement an authentication module, the `IBCModule` interface need not be fulfilled; it is only required to fulfill Cosmos SDK's `AppModuleBasic` interface, just like any regular Cosmos SDK application module. - -The authentication module must: - -- Authenticate interchain account owners. -- Track the associated interchain account address for an owner. -- Send packets on behalf of an owner (after authentication). - -## Integration into `app.go` file - -To integrate the authentication module into your chain, please follow the steps outlined in [`app.go` integration](04-integration.md#example-integration). diff --git a/docs/docs/02-apps/02-interchain-accounts/04-integration.md b/docs/docs/02-apps/02-interchain-accounts/04-integration.md deleted file mode 100644 index 974e7f978df..00000000000 --- a/docs/docs/02-apps/02-interchain-accounts/04-integration.md +++ /dev/null @@ -1,199 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 4 -slug: /apps/interchain-accounts/integration ---- - - -# Integration - -:::note Synopsis -Learn how to integrate Interchain Accounts host and controller functionality to your chain. The following document only applies for Cosmos SDK chains. -::: - -The Interchain Accounts module contains two submodules. Each submodule has its own IBC application. The Interchain Accounts module should be registered as an `AppModule` in the same way all SDK modules are registered on a chain, but each submodule should create its own `IBCModule` as necessary. A route should be added to the IBC router for each submodule which will be used. - -Chains who wish to support ICS-27 may elect to act as a host chain, a controller chain or both. Disabling host or controller functionality may be done statically by excluding the host or controller submodule entirely from the `app.go` file or it may be done dynamically by taking advantage of the on-chain parameters which enable or disable the host or controller submodules. - -Interchain Account authentication modules (both custom or generic, such as the `x/gov`, `x/group` or `x/auth` Cosmos SDK modules) can send messages to the controller submodule's [`MsgServer`](05-messages.md) to register interchain accounts and send packets to the interchain account. To accomplish this, the authentication module needs to be composed with `baseapp`'s `MsgServiceRouter`. - -![ica-v6.png](./images/ica-v6.png) - -## Example integration - -```go -// app.go - -// Register the AppModule for the Interchain Accounts module and the authentication module -// Note: No `icaauth` exists, this must be substituted with an actual Interchain Accounts authentication module -ModuleBasics = module.NewBasicManager( - ... - ica.AppModuleBasic{}, - icaauth.AppModuleBasic{}, - ... -) - -... - -// Add module account permissions for the Interchain Accounts module -// Only necessary for host chain functionality -// Each Interchain Account created on the host chain is derived from the module account created -maccPerms = map[string][]string{ - ... - icatypes.ModuleName: nil, -} - -... - -// Add Interchain Accounts Keepers for each submodule used and the authentication module -// If a submodule is being statically disabled, the associated Keeper does not need to be added. -type App struct { - ... - - ICAControllerKeeper icacontrollerkeeper.Keeper - ICAHostKeeper icahostkeeper.Keeper - ICAAuthKeeper icaauthkeeper.Keeper - - ... -} - -... - -// Create store keys for each submodule Keeper and the authentication module -keys := sdk.NewKVStoreKeys( - ... - icacontrollertypes.StoreKey, - icahosttypes.StoreKey, - icaauthtypes.StoreKey, - ... -) - -... - -// Create the scoped keepers for each submodule keeper and authentication keeper -scopedICAControllerKeeper := app.CapabilityKeeper.ScopeToModule(icacontrollertypes.SubModuleName) -scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icahosttypes.SubModuleName) -scopedICAAuthKeeper := app.CapabilityKeeper.ScopeToModule(icaauthtypes.ModuleName) - -... - -// Create the Keeper for each submodule -app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( - appCodec, keys[icacontrollertypes.StoreKey], app.GetSubspace(icacontrollertypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - scopedICAControllerKeeper, app.MsgServiceRouter(), -) -app.ICAHostKeeper = icahostkeeper.NewKeeper( - appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), -) - -// Create Interchain Accounts AppModule -icaModule := ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper) - -// Create your Interchain Accounts authentication module -app.ICAAuthKeeper = icaauthkeeper.NewKeeper(appCodec, keys[icaauthtypes.StoreKey], app.MsgServiceRouter()) - -// ICA auth AppModule -icaAuthModule := icaauth.NewAppModule(appCodec, app.ICAAuthKeeper) - -// Create controller IBC application stack and host IBC module as desired -icaControllerStack := icacontroller.NewIBCMiddleware(nil, app.ICAControllerKeeper) -icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - -// Register host and authentication routes -ibcRouter. - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icahosttypes.SubModuleName, icaHostIBCModule) -... - -// Register Interchain Accounts and authentication module AppModule's -app.moduleManager = module.NewManager( - ... - icaModule, - icaAuthModule, -) - -... - -// Add Interchain Accounts to begin blocker logic -app.moduleManager.SetOrderBeginBlockers( - ... - icatypes.ModuleName, - ... -) - -// Add Interchain Accounts to end blocker logic -app.moduleManager.SetOrderEndBlockers( - ... - icatypes.ModuleName, - ... -) - -// Add Interchain Accounts module InitGenesis logic -app.moduleManager.SetOrderInitGenesis( - ... - icatypes.ModuleName, - ... -) - -// initParamsKeeper init params keeper and its subspaces -func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) paramskeeper.Keeper { - ... - paramsKeeper.Subspace(icahosttypes.SubModuleName) - paramsKeeper.Subspace(icacontrollertypes.SubModuleName) - ... -} -``` - -If no custom athentication module is needed and a generic Cosmos SDK authentication module can be used, then from the sample integration code above all references to `ICAAuthKeeper` and `icaAuthModule` can be removed. That's it, the following code would not be needed: - -```go -// Create your Interchain Accounts authentication module -app.ICAAuthKeeper = icaauthkeeper.NewKeeper(appCodec, keys[icaauthtypes.StoreKey], app.MsgServiceRouter()) - -// ICA auth AppModule -icaAuthModule := icaauth.NewAppModule(appCodec, app.ICAAuthKeeper) -``` - -### Using submodules exclusively - -As described above, the Interchain Accounts application module is structured to support the ability of exclusively enabling controller or host functionality. -This can be achieved by simply omitting either controller or host `Keeper` from the Interchain Accounts `NewAppModule` constructor function, and mounting only the desired submodule via the `IBCRouter`. -Alternatively, submodules can be enabled and disabled dynamically using [on-chain parameters](06-parameters.md). - -The following snippets show basic examples of statically disabling submodules using `app.go`. - -#### Disabling controller chain functionality - -```go -// Create Interchain Accounts AppModule omitting the controller keeper -icaModule := ica.NewAppModule(nil, &app.ICAHostKeeper) - -// Create host IBC Module -icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - -// Register host route -ibcRouter.AddRoute(icahosttypes.SubModuleName, icaHostIBCModule) -``` - -#### Disabling host chain functionality - -```go -// Create Interchain Accounts AppModule omitting the host keeper -icaModule := ica.NewAppModule(&app.ICAControllerKeeper, nil) - - -// Optionally instantiate your custom authentication module if needed, or not otherwise -... - -// Create controller IBC application stack -icaControllerStack := icacontroller.NewIBCMiddleware(nil, app.ICAControllerKeeper) - -// Register controller route -ibcRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) -``` diff --git a/docs/docs/02-apps/02-interchain-accounts/05-messages.md b/docs/docs/02-apps/02-interchain-accounts/05-messages.md deleted file mode 100644 index 119c740e03e..00000000000 --- a/docs/docs/02-apps/02-interchain-accounts/05-messages.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: Messages -sidebar_label: Messages -sidebar_position: 5 -slug: /apps/interchain-accounts/messages ---- - - -# Messages - -## `MsgRegisterInterchainAccount` - -An Interchain Accounts channel handshake can be initated using `MsgRegisterInterchainAccount`: - -```go -type MsgRegisterInterchainAccount struct { - Owner string - ConnectionID string - Version string -} -``` - -This message is expected to fail if: - -- `Owner` is an empty string. -- `ConnectionID` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). - -This message will construct a new `MsgChannelOpenInit` on chain and route it to the core IBC message server to initiate the opening step of the channel handshake. - -The controller submodule will generate a new port identifier and claim the associated port capability. The caller is expected to provide an appropriate application version string. For example, this may be an ICS-27 JSON encoded [`Metadata`](https://github.com/cosmos/ibc-go/blob/v6.0.0/proto/ibc/applications/interchain_accounts/v1/metadata.proto#L11) type or an ICS-29 JSON encoded [`Metadata`](https://github.com/cosmos/ibc-go/blob/v6.0.0/proto/ibc/applications/fee/v1/metadata.proto#L11) type with a nested application version. -If the `Version` string is omitted, the controller submodule will construct a default version string in the `OnChanOpenInit` handshake callback. - -```go -type MsgRegisterInterchainAccountResponse struct { - ChannelID string - PortId string -} -``` - -The `ChannelID` and `PortID` are returned in the message response. - -## `MsgSendTx` - -An Interchain Accounts transaction can be executed on a remote host chain by sending a `MsgSendTx` from the corresponding controller chain: - -```go -type MsgSendTx struct { - Owner string - ConnectionID string - PacketData InterchainAccountPacketData - RelativeTimeout uint64 -} -``` - -This message is expected to fail if: - -- `Owner` is an empty string. -- `ConnectionID` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -- `PacketData` contains an `UNSPECIFIED` type enum, the length of `Data` bytes is zero or the `Memo` field exceeds 256 characters in length. -- `RelativeTimeout` is zero. - -This message will create a new IBC packet with the provided `PacketData` and send it via the channel associated with the `Owner` and `ConnectionID`. -The `PacketData` is expected to contain a list of serialized `[]sdk.Msg` in the form of `CosmosTx`. Please note the signer field of each `sdk.Msg` must be the interchain account address. -When the packet is relayed to the host chain, the `PacketData` is unmarshalled and the messages are authenticated and executed. - -```go -type MsgSendTxResponse struct { - Sequence uint64 -} -``` - -The packet `Sequence` is returned in the message response. - -## Atomicity - -As the Interchain Accounts module supports the execution of multiple transactions using the Cosmos SDK `Msg` interface, it provides the same atomicity guarantees as Cosmos SDK-based applications, leveraging the [`CacheMultiStore`](https://docs.cosmos.network/main/learn/advanced/store#cachemultistore) architecture provided by the [`Context`](https://docs.cosmos.network/main/learn/advanced/context.html) type. - -This provides atomic execution of transactions when using Interchain Accounts, where state changes are only committed if all `Msg`s succeed. diff --git a/docs/docs/02-apps/02-interchain-accounts/06-parameters.md b/docs/docs/02-apps/02-interchain-accounts/06-parameters.md deleted file mode 100644 index 5ab4fdd8478..00000000000 --- a/docs/docs/02-apps/02-interchain-accounts/06-parameters.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -title: Parameters -sidebar_label: Parameters -sidebar_position: 6 -slug: /apps/interchain-accounts/parameters ---- - - -# Parameters - -The Interchain Accounts module contains the following on-chain parameters, logically separated for each distinct submodule: - -## Controller Submodule Parameters - -| Name | Type | Default Value | -|------------------------|------|---------------| -| `ControllerEnabled` | bool | `true` | - -### ControllerEnabled - -The `ControllerEnabled` parameter controls a chains ability to service ICS-27 controller specific logic. This includes the sending of Interchain Accounts packet data as well as the following ICS-26 callback handlers: - -- `OnChanOpenInit` -- `OnChanOpenAck` -- `OnChanCloseConfirm` -- `OnAcknowledgementPacket` -- `OnTimeoutPacket` - -## Host Submodule Parameters - -| Name | Type | Default Value | -|------------------------|----------|---------------| -| `HostEnabled` | bool | `true` | -| `AllowMessages` | []string | `["*"]` | - -### HostEnabled - -The `HostEnabled` parameter controls a chains ability to service ICS-27 host specific logic. This includes the following ICS-26 callback handlers: - -- `OnChanOpenTry` -- `OnChanOpenConfirm` -- `OnChanCloseConfirm` -- `OnRecvPacket` - -### AllowMessages - -The `AllowMessages` parameter provides the ability for a chain to limit the types of messages or transactions that hosted interchain accounts are authorized to execute by defining an allowlist using the Protobuf message type URL format. - -For example, a Cosmos SDK-based chain that elects to provide hosted Interchain Accounts with the ability of governance voting and staking delegations will define its parameters as follows: - -```json -"params": { - "host_enabled": true, - "allow_messages": ["/cosmos.staking.v1beta1.MsgDelegate", "/cosmos.gov.v1beta1.MsgVote"] -} -``` - -There is also a special wildcard `"*"` value which allows any type of message to be executed by the interchain account. This must be the only value in the `allow_messages` array. - -```json -"params": { - "host_enabled": true, - "allow_messages": ["*"] -} -``` diff --git a/docs/docs/02-apps/02-interchain-accounts/07-tx-encoding.md b/docs/docs/02-apps/02-interchain-accounts/07-tx-encoding.md deleted file mode 100644 index 5be03af2f8e..00000000000 --- a/docs/docs/02-apps/02-interchain-accounts/07-tx-encoding.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: Transaction Encoding -sidebar_label: Transaction Encoding -sidebar_position: 7 -slug: /apps/interchain-accounts/tx-encoding ---- - -# Transaction Encoding - -When orchestrating an interchain account transaction, which comprises multiple `sdk.Msg` objects represented as `Any` types, the transactions must be encoded as bytes within [`InterchainAccountPacketData`](https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/interchain_accounts/v1/packet.proto#L21-L26). - -```protobuf -// InterchainAccountPacketData is comprised of a raw transaction, type of transaction and optional memo field. -message InterchainAccountPacketData { - Type type = 1; - bytes data = 2; - string memo = 3; -} -``` - -The `data` field must be encoded as a [`CosmosTx`](https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/interchain_accounts/v1/packet.proto#L28-L31). - -```protobuf -// CosmosTx contains a list of sdk.Msg's. It should be used when sending transactions to an SDK host chain. -message CosmosTx { - repeated google.protobuf.Any messages = 1; -} -``` - -The encoding method for `CosmosTx` is determined during the channel handshake process. If the channel version [metadata's `encoding` field](https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/interchain_accounts/v1/metadata.proto#L22) is marked as `proto3`, then `CosmosTx` undergoes protobuf encoding. Conversely, if the field is set to `proto3json`, then [proto3 json](https://protobuf.dev/programming-guides/proto3/#json) encoding takes place, which generates a JSON representation of the protobuf message. - -## Protobuf Encoding - -Protobuf encoding serves as the standard encoding process for `CosmosTx`. This occurs if the channel handshake initiates with an empty channel version metadata or if the `encoding` field explicitly denotes `proto3`. In Golang, the protobuf encoding procedure utilizes the `proto.Marshal` function. Every protobuf autogenerated Golang type comes equipped with a `Marshal` method that can be employed to encode the message. - -## (Protobuf) JSON Encoding - -The proto3 JSON encoding presents an alternative encoding technique for `CosmosTx`. It is selected if the channel handshake begins with the channel version metadata `encoding` field labeled as `proto3json`. In Golang, the Proto3 canonical encoding in JSON is implemented by the `"github.com/cosmos/gogoproto/jsonpb"` package. Within Cosmos SDK, the `ProtoCodec` structure implements the `JSONCodec` interface, leveraging the `jsonpb` package. This method generates a JSON format as follows: - -```json -{ - "messages": [ - { - "@type": "/cosmos.bank.v1beta1.MsgSend", - "from_address": "cosmos1...", - "to_address": "cosmos1...", - "amount": [ - { - "denom": "uatom", - "amount": "1000000" - } - ] - } - ] -} -``` - -Here, the `"messages"` array is populated with transactions. Each transaction is represented as a JSON object with the `@type` field denoting the transaction type and the remaining fields representing the transaction's attributes. diff --git a/docs/docs/02-apps/02-interchain-accounts/08-client.md b/docs/docs/02-apps/02-interchain-accounts/08-client.md deleted file mode 100644 index c7c50d09d82..00000000000 --- a/docs/docs/02-apps/02-interchain-accounts/08-client.md +++ /dev/null @@ -1,183 +0,0 @@ ---- -title: Client -sidebar_label: Client -sidebar_position: 8 -slug: /apps/interchain-accounts/client ---- - -# Client - -## CLI - -A user can query and interact with the Interchain Accounts module using the CLI. Use the `--help` flag to discover the available commands: - -```shell -simd query interchain-accounts --help -``` - -> Please not that this section does not document all the available commands, but only the ones that deserved extra documentation that was not possible to fit in the command line documentation. - -### Controller - -A user can query and interact with the controller submodule. - -#### Query - -The `query` commands allow users to query the controller submodule. - -```shell -simd query interchain-accounts controller --help -``` - -#### Transactions - -The `tx` commands allow users to interact with the controller submodule. - -```shell -simd tx interchain-accounts controller --help -``` - -#### `send-tx` - -The `send-tx` command allows users to send a transaction on the provided connection to be executed using an interchain account on the host chain. - -```shell -simd tx interchain-accounts controller send-tx [connection-id] [path/to/packet_msg.json] -``` - -Example: - -```shell -simd tx interchain-accounts controller send-tx connection-0 packet-data.json --from cosmos1.. -``` - -See below for example contents of `packet-data.json`. The CLI handler will unmarshal the following into `InterchainAccountPacketData` appropriately. - -```json -{ - "type":"TYPE_EXECUTE_TX", - "data":"CqIBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEoEBCkFjb3Ntb3MxNWNjc2hobXAwZ3N4MjlxcHFxNmc0em1sdG5udmdteXU5dWV1YWRoOXkybmM1emowc3psczVndGRkehItY29zbW9zMTBoOXN0YzV2Nm50Z2V5Z2Y1eGY5NDVuanFxNWgzMnI1M3VxdXZ3Gg0KBXN0YWtlEgQxMDAw", - "memo":"" -} -``` - -Note the `data` field is a base64 encoded byte string as per the tx encoding agreed upon during the channel handshake. - -A helper CLI is provided in the host submodule which can be used to generate the packet data JSON using the counterparty chain's binary. See the [`generate-packet-data` command](#generate-packet-data) for an example. - -### Host - -A user can query and interact with the host submodule. - -#### Query - -The `query` commands allow users to query the host submodule. - -```shell -simd query interchain-accounts host --help -``` - -#### Transactions - -The `tx` commands allow users to interact with the controller submodule. - -```shell -simd tx interchain-accounts host --help -``` - -##### `generate-packet-data` - -The `generate-packet-data` command allows users to generate protobuf or proto3 JSON encoded interchain accounts packet data for input message(s). The packet data can then be used with the controller submodule's [`send-tx` command](#send-tx). The `--encoding` flag can be uesd to specify the encoding format (value must be either `proto3` or `proto3json`); if not specified, the default will be `proto3`. The `--memo` flag can be used to include a memo string in the interchain accounts packet data. - -```shell -simd tx interchain-accounts host generate-packet-data [message] -``` - -Example: - -```shell -simd tx interchain-accounts host generate-packet-data '[{ - "@type":"/cosmos.bank.v1beta1.MsgSend", - "from_address":"cosmos15ccshhmp0gsx29qpqq6g4zmltnnvgmyu9ueuadh9y2nc5zj0szls5gtddz", - "to_address":"cosmos10h9stc5v6ntgeygf5xf945njqq5h32r53uquvw", - "amount": [ - { - "denom": "stake", - "amount": "1000" - } - ] -}]' --memo memo -``` - -The command accepts a single `sdk.Msg` or a list of `sdk.Msg`s that will be encoded into the outputs `data` field. - -Example output: - -```json -{ - "type":"TYPE_EXECUTE_TX", - "data":"CqIBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEoEBCkFjb3Ntb3MxNWNjc2hobXAwZ3N4MjlxcHFxNmc0em1sdG5udmdteXU5dWV1YWRoOXkybmM1emowc3psczVndGRkehItY29zbW9zMTBoOXN0YzV2Nm50Z2V5Z2Y1eGY5NDVuanFxNWgzMnI1M3VxdXZ3Gg0KBXN0YWtlEgQxMDAw", - "memo":"memo" -} -``` - -## gRPC - -A user can query the interchain account module using gRPC endpoints. - -### Controller - -A user can query the controller submodule using gRPC endpoints. - -#### `InterchainAccount` - -The `InterchainAccount` endpoint allows users to query the controller submodule for the interchain account address for a given owner on a particular connection. - -```shell -ibc.applications.interchain_accounts.controller.v1.Query/InterchainAccount -``` - -Example: - -```shell -grpcurl -plaintext \ - -d '{"owner":"cosmos1..","connection_id":"connection-0"}' \ - localhost:9090 \ - ibc.applications.interchain_accounts.controller.v1.Query/InterchainAccount -``` - -#### `Params` - -The `Params` endpoint users to query the current controller submodule parameters. - -```shell -ibc.applications.interchain_accounts.controller.v1.Query/Params -``` - -Example: - -```shell -grpcurl -plaintext \ - localhost:9090 \ - ibc.applications.interchain_accounts.controller.v1.Query/Params -``` - -### Host - -A user can query the host submodule using gRPC endpoints. - -#### `Params` - -The `Params` endpoint users to query the current host submodule parameters. - -```shell -ibc.applications.interchain_accounts.host.v1.Query/Params -``` - -Example: - -```shell -grpcurl -plaintext \ - localhost:9090 \ - ibc.applications.interchain_accounts.host.v1.Query/Params -``` diff --git a/docs/docs/02-apps/02-interchain-accounts/09-active-channels.md b/docs/docs/02-apps/02-interchain-accounts/09-active-channels.md deleted file mode 100644 index 2aedeb8a42f..00000000000 --- a/docs/docs/02-apps/02-interchain-accounts/09-active-channels.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Active Channels -sidebar_label: Active Channels -sidebar_position: 9 -slug: /apps/interchain-accounts/active-channels ---- - -# Understanding Active Channels - -The Interchain Accounts module uses [ORDERED channels](https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#ordering) to maintain the order of transactions when sending packets from a controller to a host chain. A limitation when using ORDERED channels is that when a packet times out the channel will be closed. - -In the case of a channel closing, a controller chain needs to be able to regain access to the interchain account registered on this channel. `Active Channels` enable this functionality. - -When an Interchain Account is registered using `MsgRegisterInterchainAccount`, a new channel is created on a particular port. During the `OnChanOpenAck` and `OnChanOpenConfirm` steps (on controller & host chain respectively) the `Active Channel` for this interchain account is stored in state. - -It is possible to create a new channel using the same controller chain portID if the previously set `Active Channel` is now in a `CLOSED` state. This channel creation can be initialized programatically by sending a new `MsgChannelOpenInit` message like so: - -```go -msg := channeltypes.NewMsgChannelOpenInit(portID, string(versionBytes), channeltypes.ORDERED, []string{connectionID}, icatypes.HostPortID, authtypes.NewModuleAddress(icatypes.ModuleName).String()) -handler := keeper.msgRouter.Handler(msg) -res, err := handler(ctx, msg) -if err != nil { - return err -} -``` - -Alternatively, any relayer operator may initiate a new channel handshake for this interchain account once the previously set `Active Channel` is in a `CLOSED` state. This is done by initiating the channel handshake on the controller chain using the same portID associated with the interchain account in question. - -It is important to note that once a channel has been opened for a given interchain account, new channels can not be opened for this account until the currently set `Active Channel` is set to `CLOSED`. - -## Future improvements - -Future versions of the ICS-27 protocol and the Interchain Accounts module will likely use a new channel type that provides ordering of packets without the channel closing in the event of a packet timing out, thus removing the need for `Active Channels` entirely. -The following is a list of issues which will provide the infrastructure to make this possible: - -- [IBC Channel Upgrades](https://github.com/cosmos/ibc-go/issues/1599) -- [Implement ORDERED_ALLOW_TIMEOUT logic in 04-channel](https://github.com/cosmos/ibc-go/issues/1661) -- [Add ORDERED_ALLOW_TIMEOUT as supported ordering in 03-connection](https://github.com/cosmos/ibc-go/issues/1662) -- [Allow ICA channels to be opened as ORDERED_ALLOW_TIMEOUT](https://github.com/cosmos/ibc-go/issues/1663) diff --git a/docs/docs/02-apps/02-interchain-accounts/10-legacy/01-auth-modules.md b/docs/docs/02-apps/02-interchain-accounts/10-legacy/01-auth-modules.md deleted file mode 100644 index 70cc36b8a69..00000000000 --- a/docs/docs/02-apps/02-interchain-accounts/10-legacy/01-auth-modules.md +++ /dev/null @@ -1,274 +0,0 @@ ---- -title: Authentication Modules -sidebar_label: Authentication Modules -sidebar_position: 1 -slug: /apps/interchain-accounts/legacy/auth-modules ---- - - -# Building an authentication module - -## Deprecation Notice - -**This document is deprecated and will be removed in future releases**. - -:::note Synopsis -Authentication modules play the role of the `Base Application` as described in [ICS-30 IBC Middleware](https://github.com/cosmos/ibc/tree/master/spec/app/ics-030-middleware), and enable application developers to perform custom logic when working with the Interchain Accounts controller API. -::: - -The controller submodule is used for account registration and packet sending. It executes only logic required of all controllers of interchain accounts. The type of authentication used to manage the interchain accounts remains unspecified. There may exist many different types of authentication which are desirable for different use cases. Thus the purpose of the authentication module is to wrap the controller submodule with custom authentication logic. - -In ibc-go, authentication modules are connected to the controller chain via a middleware stack. The controller submodule is implemented as [middleware](https://github.com/cosmos/ibc/tree/master/spec/app/ics-030-middleware) and the authentication module is connected to the controller submodule as the base application of the middleware stack. To implement an authentication module, the `IBCModule` interface must be fulfilled. By implementing the controller submodule as middleware, any amount of authentication modules can be created and connected to the controller submodule without writing redundant code. - -The authentication module must: - -- Authenticate interchain account owners. -- Track the associated interchain account address for an owner. -- Send packets on behalf of an owner (after authentication). - -> Please note that since ibc-go v6 the channel capability is claimed by the controller submodule and therefore it is not required for authentication modules to claim the capability in the `OnChanOpenInit` callback. When the authentication module sends packets on the channel created for the associated interchain account it can pass a `nil` capability to the legacy function `SendTx` of the controller keeper (see section [`SendTx`](03-keeper-api.md#sendtx) for more information). - -## `IBCModule` implementation - -The following `IBCModule` callbacks must be implemented with appropriate custom logic: - -```go -// OnChanOpenInit implements the IBCModule interface -func (im IBCModule) OnChanOpenInit( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) (string, error) { - // since ibc-go v6 the authentication module *must not* claim the channel capability on OnChanOpenInit - - // perform custom logic - - return version, nil -} - -// OnChanOpenAck implements the IBCModule interface -func (im IBCModule) OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyVersion string, -) error { - // perform custom logic - - return nil -} - -// OnChanCloseConfirm implements the IBCModule interface -func (im IBCModule) OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // perform custom logic - - return nil -} - -// OnAcknowledgementPacket implements the IBCModule interface -func (im IBCModule) OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - relayer sdk.AccAddress, -) error { - // perform custom logic - - return nil -} - -// OnTimeoutPacket implements the IBCModule interface. -func (im IBCModule) OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) error { - // perform custom logic - - return nil -} -``` - -The following functions must be defined to fulfill the `IBCModule` interface, but they will never be called by the controller submodule so they may error or panic. That is because in Interchain Accounts, the channel handshake is always initiated on the controller chain and packets are always sent to the host chain and never to the controller chain. - -```go -// OnChanOpenTry implements the IBCModule interface -func (im IBCModule) OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (string, error) { - panic("UNIMPLEMENTED") -} - -// OnChanOpenConfirm implements the IBCModule interface -func (im IBCModule) OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - panic("UNIMPLEMENTED") -} - -// OnChanCloseInit implements the IBCModule interface -func (im IBCModule) OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - panic("UNIMPLEMENTED") -} - -// OnRecvPacket implements the IBCModule interface. A successful acknowledgement -// is returned if the packet data is succesfully decoded and the receive application -// logic returns without error. -func (im IBCModule) OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) ibcexported.Acknowledgement { - panic("UNIMPLEMENTED") -} -``` - -## `OnAcknowledgementPacket` - -Controller chains will be able to access the acknowledgement written into the host chain state once a relayer relays the acknowledgement. -The acknowledgement bytes contain either the response of the execution of the message(s) on the host chain or an error. They will be passed to the auth module via the `OnAcknowledgementPacket` callback. Auth modules are expected to know how to decode the acknowledgement. - -If the controller chain is connected to a host chain using the host module on ibc-go, it may interpret the acknowledgement bytes as follows: - -Begin by unmarshaling the acknowledgement into `sdk.TxMsgData`: - -```go -var ack channeltypes.Acknowledgement -if err := channeltypes.SubModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { - return err -} - -txMsgData := &sdk.TxMsgData{} -if err := proto.Unmarshal(ack.GetResult(), txMsgData); err != nil { - return err -} -``` - -If the `txMsgData.Data` field is non nil, the host chain is using SDK version <= v0.45. -The auth module should interpret the `txMsgData.Data` as follows: - -```go -switch len(txMsgData.Data) { -case 0: - // see documentation below for SDK 0.46.x or greater -default: - for _, msgData := range txMsgData.Data { - if err := handler(msgData); err != nil { - return err - } - } -... -} -``` - -A handler will be needed to interpret what actions to perform based on the message type sent. -A router could be used, or more simply a switch statement. - -```go -func handler(msgData sdk.MsgData) error { -switch msgData.MsgType { -case sdk.MsgTypeURL(&banktypes.MsgSend{}): - msgResponse := &banktypes.MsgSendResponse{} - if err := proto.Unmarshal(msgData.Data, msgResponse}; err != nil { - return err - } - - handleBankSendMsg(msgResponse) - -case sdk.MsgTypeURL(&stakingtypes.MsgDelegate{}): - msgResponse := &stakingtypes.MsgDelegateResponse{} - if err := proto.Unmarshal(msgData.Data, msgResponse}; err != nil { - return err - } - - handleStakingDelegateMsg(msgResponse) - -case sdk.MsgTypeURL(&transfertypes.MsgTransfer{}): - msgResponse := &transfertypes.MsgTransferResponse{} - if err := proto.Unmarshal(msgData.Data, msgResponse}; err != nil { - return err - } - - handleIBCTransferMsg(msgResponse) - -default: - return -} -``` - -If the `txMsgData.Data` is empty, the host chain is using SDK version > v0.45. -The auth module should interpret the `txMsgData.Responses` as follows: - -```go -... -// switch statement from above -case 0: - for _, any := range txMsgData.MsgResponses { - if err := handleAny(any); err != nil { - return err - } - } -} -``` - -A handler will be needed to interpret what actions to perform based on the type URL of the Any. -A router could be used, or more simply a switch statement. -It may be possible to deduplicate logic between `handler` and `handleAny`. - -```go -func handleAny(any *codectypes.Any) error { -switch any.TypeURL { -case banktypes.MsgSend: - msgResponse, err := unpackBankMsgSendResponse(any) - if err != nil { - return err - } - - handleBankSendMsg(msgResponse) - -case stakingtypes.MsgDelegate: - msgResponse, err := unpackStakingDelegateResponse(any) - if err != nil { - return err - } - - handleStakingDelegateMsg(msgResponse) - - case transfertypes.MsgTransfer: - msgResponse, err := unpackIBCTransferMsgResponse(any) - if err != nil { - return err - } - - handleIBCTransferMsg(msgResponse) - -default: - return -} -``` - -## Integration into `app.go` file - -To integrate the authentication module into your chain, please follow the steps outlined in [`app.go` integration](02-integration.md#example-integration). diff --git a/docs/docs/02-apps/02-interchain-accounts/10-legacy/02-integration.md b/docs/docs/02-apps/02-interchain-accounts/10-legacy/02-integration.md deleted file mode 100644 index 90a645aaabd..00000000000 --- a/docs/docs/02-apps/02-interchain-accounts/10-legacy/02-integration.md +++ /dev/null @@ -1,201 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 2 -slug: /apps/interchain-accounts/legacy/integration ---- - - -# Integration - -## Deprecation Notice - -**This document is deprecated and will be removed in future releases**. - -:::note Synopsis -Learn how to integrate Interchain Accounts host and controller functionality to your chain. The following document only applies for Cosmos SDK chains. -::: - -The Interchain Accounts module contains two submodules. Each submodule has its own IBC application. The Interchain Accounts module should be registered as an `AppModule` in the same way all SDK modules are registered on a chain, but each submodule should create its own `IBCModule` as necessary. A route should be added to the IBC router for each submodule which will be used. - -Chains who wish to support ICS-27 may elect to act as a host chain, a controller chain or both. Disabling host or controller functionality may be done statically by excluding the host or controller module entirely from the `app.go` file or it may be done dynamically by taking advantage of the on-chain parameters which enable or disable the host or controller submodules. - -Interchain Account authentication modules are the base application of a middleware stack. The controller submodule is the middleware in this stack. - -![ica-pre-v6.png](./images/ica-pre-v6.png) - -> Please note that since ibc-go v6 the channel capability is claimed by the controller submodule and therefore it is not required for authentication modules to claim the capability in the `OnChanOpenInit` callback. Therefore the custom authentication module does not need a scoped keeper anymore. - -## Example integration - -```go -// app.go - -// Register the AppModule for the Interchain Accounts module and the authentication module -// Note: No `icaauth` exists, this must be substituted with an actual Interchain Accounts authentication module -ModuleBasics = module.NewBasicManager( - ... - ica.AppModuleBasic{}, - icaauth.AppModuleBasic{}, - ... -) - -... - -// Add module account permissions for the Interchain Accounts module -// Only necessary for host chain functionality -// Each Interchain Account created on the host chain is derived from the module account created -maccPerms = map[string][]string{ - ... - icatypes.ModuleName: nil, -} - -... - -// Add Interchain Accounts Keepers for each submodule used and the authentication module -// If a submodule is being statically disabled, the associated Keeper does not need to be added. -type App struct { - ... - - ICAControllerKeeper icacontrollerkeeper.Keeper - ICAHostKeeper icahostkeeper.Keeper - ICAAuthKeeper icaauthkeeper.Keeper - - ... -} - -... - -// Create store keys for each submodule Keeper and the authentication module -keys := sdk.NewKVStoreKeys( - ... - icacontrollertypes.StoreKey, - icahosttypes.StoreKey, - icaauthtypes.StoreKey, - ... -) - -... - -// Create the scoped keepers for each submodule keeper and authentication keeper -scopedICAControllerKeeper := app.CapabilityKeeper.ScopeToModule(icacontrollertypes.SubModuleName) -scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icahosttypes.SubModuleName) - -... - -// Create the Keeper for each submodule -app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( - appCodec, keys[icacontrollertypes.StoreKey], app.GetSubspace(icacontrollertypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - scopedICAControllerKeeper, app.MsgServiceRouter(), -) -app.ICAHostKeeper = icahostkeeper.NewKeeper( - appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), -) - -// Create Interchain Accounts AppModule -icaModule := ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper) - -// Create your Interchain Accounts authentication module -app.ICAAuthKeeper = icaauthkeeper.NewKeeper(appCodec, keys[icaauthtypes.StoreKey], app.ICAControllerKeeper) - -// ICA auth AppModule -icaAuthModule := icaauth.NewAppModule(appCodec, app.ICAAuthKeeper) - -// ICA auth IBC Module -icaAuthIBCModule := icaauth.NewIBCModule(app.ICAAuthKeeper) - -// Create controller IBC application stack and host IBC module as desired -icaControllerStack := icacontroller.NewIBCMiddleware(icaAuthIBCModule, app.ICAControllerKeeper) -icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - -// Register host and authentication routes -ibcRouter. - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icahosttypes.SubModuleName, icaHostIBCModule). - AddRoute(icaauthtypes.ModuleName, icaControllerStack) // Note, the authentication module is routed to the top level of the middleware stack - -... - -// Register Interchain Accounts and authentication module AppModule's -app.moduleManager = module.NewManager( - ... - icaModule, - icaAuthModule, -) - -... - -// Add fee middleware to begin blocker logic -app.moduleManager.SetOrderBeginBlockers( - ... - icatypes.ModuleName, - ... -) - -// Add fee middleware to end blocker logic -app.moduleManager.SetOrderEndBlockers( - ... - icatypes.ModuleName, - ... -) - -// Add Interchain Accounts module InitGenesis logic -app.moduleManager.SetOrderInitGenesis( - ... - icatypes.ModuleName, - ... -) - -// initParamsKeeper init params keeper and its subspaces -func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) paramskeeper.Keeper { - ... - paramsKeeper.Subspace(icahosttypes.SubModuleName) - paramsKeeper.Subspace(icacontrollertypes.SubModuleName) - ... -``` - -## Using submodules exclusively - -As described above, the Interchain Accounts application module is structured to support the ability of exclusively enabling controller or host functionality. -This can be achieved by simply omitting either controller or host `Keeper` from the Interchain Accounts `NewAppModule` constructor function, and mounting only the desired submodule via the `IBCRouter`. -Alternatively, submodules can be enabled and disabled dynamically using [on-chain parameters](../06-parameters.md). - -The following snippets show basic examples of statically disabling submodules using `app.go`. - -### Disabling controller chain functionality - -```go -// Create Interchain Accounts AppModule omitting the controller keeper -icaModule := ica.NewAppModule(nil, &app.ICAHostKeeper) - -// Create host IBC Module -icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - -// Register host route -ibcRouter.AddRoute(icahosttypes.SubModuleName, icaHostIBCModule) -``` - -### Disabling host chain functionality - -```go -// Create Interchain Accounts AppModule omitting the host keeper -icaModule := ica.NewAppModule(&app.ICAControllerKeeper, nil) - -// Create your Interchain Accounts authentication module, setting up the Keeper, AppModule and IBCModule appropriately -app.ICAAuthKeeper = icaauthkeeper.NewKeeper(appCodec, keys[icaauthtypes.StoreKey], app.ICAControllerKeeper) -icaAuthModule := icaauth.NewAppModule(appCodec, app.ICAAuthKeeper) -icaAuthIBCModule := icaauth.NewIBCModule(app.ICAAuthKeeper) - -// Create controller IBC application stack -icaControllerStack := icacontroller.NewIBCMiddleware(icaAuthIBCModule, app.ICAControllerKeeper) - -// Register controller and authentication routes -ibcRouter. - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icaauthtypes.ModuleName, icaControllerStack) // Note, the authentication module is routed to the top level of the middleware stack -``` diff --git a/docs/docs/02-apps/02-interchain-accounts/10-legacy/03-keeper-api.md b/docs/docs/02-apps/02-interchain-accounts/10-legacy/03-keeper-api.md deleted file mode 100644 index 252c7eaf7ff..00000000000 --- a/docs/docs/02-apps/02-interchain-accounts/10-legacy/03-keeper-api.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -title: Keeper API -sidebar_label: Keeper API -sidebar_position: 3 -slug: /apps/interchain-accounts/legacy/keeper-api ---- - - -# Keeper API - -## Deprecation Notice - -**This document is deprecated and will be removed in future releases**. - -The controller submodule keeper exposes two legacy functions that allow respectively for custom authentication modules to register interchain accounts and send packets to the interchain account. - -## `RegisterInterchainAccount` - -The authentication module can begin registering interchain accounts by calling `RegisterInterchainAccount`: - -```go -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, connectionID, owner.String(), version); err != nil { - return err -} - -return nil -``` - -The `version` argument is used to support ICS-29 fee middleware for relayer incentivization of ICS-27 packets. Consumers of the `RegisterInterchainAccount` are expected to build the appropriate JSON encoded version string themselves and pass it accordingly. If an empty string is passed in the `version` argument, then the version will be initialized to a default value in the `OnChanOpenInit` callback of the controller's handler, so that channel handshake can proceed. - -The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, controllerConnectionID, owner.String(), string(appVersion)); err != nil { - return err -} -``` - -Similarly, if the application stack is configured to route through ICS-29 fee middleware and a fee enabled channel is desired, construct the appropriate ICS-29 `Metadata` type: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -feeMetadata := feetypes.Metadata{ - AppVersion: string(appVersion), - FeeVersion: feetypes.Version, -} - -feeEnabledVersion, err := feetypes.ModuleCdc.MarshalJSON(&feeMetadata) -if err != nil { - return err -} - -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, controllerConnectionID, owner.String(), string(feeEnabledVersion)); err != nil { - return err -} -``` - -## `SendTx` - -The authentication module can attempt to send a packet by calling `SendTx`: - -```go -// Authenticate owner -// perform custom logic - -// Construct controller portID based on interchain account owner address -portID, err := icatypes.NewControllerPortID(owner.String()) -if err != nil { - return err -} - -// Obtain data to be sent to the host chain. -// In this example, the owner of the interchain account would like to send a bank MsgSend to the host chain. -// The appropriate serialization function should be called. The host chain must be able to deserialize the transaction. -// If the host chain is using the ibc-go host module, `SerializeCosmosTx` should be used. -msg := &banktypes.MsgSend{FromAddress: fromAddr, ToAddress: toAddr, Amount: amt} -data, err := icatypes.SerializeCosmosTx(keeper.cdc, []proto.Message{msg}) -if err != nil { - return err -} - -// Construct packet data -packetData := icatypes.InterchainAccountPacketData{ - Type: icatypes.EXECUTE_TX, - Data: data, -} - -// Obtain timeout timestamp -// An appropriate timeout timestamp must be determined based on the usage of the interchain account. -// If the packet times out, the channel will be closed requiring a new channel to be created. -timeoutTimestamp := obtainTimeoutTimestamp() - -// Send the interchain accounts packet, returning the packet sequence -// A nil channel capability can be passed, since the controller submodule (and not the authentication module) -// claims the channel capability since ibc-go v6. -seq, err = keeper.icaControllerKeeper.SendTx(ctx, nil, portID, packetData, timeoutTimestamp) -``` - -The data within an `InterchainAccountPacketData` must be serialized using a format supported by the host chain. -If the host chain is using the ibc-go host chain submodule, `SerializeCosmosTx` should be used. If the `InterchainAccountPacketData.Data` is serialized using a format not supported by the host chain, the packet will not be successfully received. diff --git a/docs/docs/02-apps/02-interchain-accounts/10-legacy/_category_.json b/docs/docs/02-apps/02-interchain-accounts/10-legacy/_category_.json deleted file mode 100644 index 70500795bf8..00000000000 --- a/docs/docs/02-apps/02-interchain-accounts/10-legacy/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Legacy", - "position": 10, - "link": null -} diff --git a/docs/docs/02-apps/02-interchain-accounts/10-legacy/images/ica-pre-v6.png b/docs/docs/02-apps/02-interchain-accounts/10-legacy/images/ica-pre-v6.png deleted file mode 100644 index acd00d1294b..00000000000 Binary files a/docs/docs/02-apps/02-interchain-accounts/10-legacy/images/ica-pre-v6.png and /dev/null differ diff --git a/docs/docs/02-apps/02-interchain-accounts/_category_.json b/docs/docs/02-apps/02-interchain-accounts/_category_.json deleted file mode 100644 index 5ac86ce8ff6..00000000000 --- a/docs/docs/02-apps/02-interchain-accounts/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Interchain Accounts", - "position": 2, - "link": null -} \ No newline at end of file diff --git a/docs/docs/02-apps/02-interchain-accounts/images/ica-v6.png b/docs/docs/02-apps/02-interchain-accounts/images/ica-v6.png deleted file mode 100644 index 0ffa707c981..00000000000 Binary files a/docs/docs/02-apps/02-interchain-accounts/images/ica-v6.png and /dev/null differ diff --git a/docs/docs/02-apps/_category_.json b/docs/docs/02-apps/_category_.json deleted file mode 100644 index fa5fbf0ac9a..00000000000 --- a/docs/docs/02-apps/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "IBC Application Modules", - "position": 2, - "link": null -} \ No newline at end of file diff --git a/docs/docs/03-light-clients/01-developer-guide/01-overview.md b/docs/docs/03-light-clients/01-developer-guide/01-overview.md deleted file mode 100644 index eeef65a7be7..00000000000 --- a/docs/docs/03-light-clients/01-developer-guide/01-overview.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /ibc/light-clients/overview ---- - -# Overview - -:::note Synopsis -Learn how to build IBC light client modules and fulfill the interfaces required to integrate with core IBC. -::: - -:::note - -## Pre-requisite readings - -- [IBC Overview](../../01-ibc/01-overview.md) -- [IBC Transport, Authentication, and Ordering Layer - Clients](https://tutorials.cosmos.network/academy/3-ibc/4-clients.html) -- [ICS-002 Client Semantics](https://github.com/cosmos/ibc/tree/main/spec/core/ics-002-client-semantics) - -::: - -IBC uses light clients in order to provide trust-minimized interoperability between sovereign blockchains. Light clients operate under a strict set of rules which provide security guarantees for state updates and facilitate the ability to verify the state of a remote blockchain using merkle proofs. - -The following aims to provide a high level IBC light client module developer guide. Access to IBC light clients are gated by the core IBC `MsgServer` which utilizes the abstractions set by the `02-client` submodule to call into a light client module. A light client module developer is only required to implement a set interfaces as defined in the `modules/core/exported` package of ibc-go. - -A light client module developer should be concerned with three main interfaces: - -- [`ClientState`](#clientstate) encapsulates the light client implementation and its semantics. -- [`ConsensusState`](#consensusstate) tracks consensus data used for verification of client updates, misbehaviour detection and proof verification of counterparty state. -- [`ClientMessage`](#clientmessage) used for submitting block headers for client updates and submission of misbehaviour evidence using conflicting headers. - -Throughout this guide the `07-tendermint` light client module may be referred to as a reference example. - -## Concepts and vocabulary - -### `ClientState` - -`ClientState` is a term used to define the data structure which encapsulates opaque light client state. The `ClientState` contains all the information needed to verify a `ClientMessage` and perform membership and non-membership proof verification of counterparty state. This includes properties that refer to the remote state machine, the light client type and the specific light client instance. - -For example: - -- Constraints used for client updates. -- Constraints used for misbehaviour detection. -- Constraints used for state verification. -- Constraints used for client upgrades. - -The `ClientState` type maintained within the light client module *must* implement the [`ClientState`](https://github.com/cosmos/ibc-go/tree/02-client-refactor-beta1/modules/core/exported/client.go#L36) interface defined in `core/modules/exported/client.go`. -The methods which make up this interface are detailed at a more granular level in the [ClientState section of this guide](02-client-state.md). - -Please refer to the `07-tendermint` light client module's [`ClientState` definition](https://github.com/cosmos/ibc-go/tree/02-client-refactor-beta1/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L18) containing information such as chain ID, status, latest height, unbonding period and proof specifications. - -### `ConsensusState` - -`ConsensusState` is a term used to define the data structure which encapsulates consensus data at a particular point in time, i.e. a unique height or sequence number of a state machine. There must exist a single trusted `ConsensusState` for each height. `ConsensusState` generally contains a trusted root, validator set information and timestamp. - -For example, the `ConsensusState` of the `07-tendermint` light client module defines a trusted root which is used by the `ClientState` to perform verification of membership and non-membership commitment proofs, as well as the next validator set hash used for verifying headers can be trusted in client updates. - -The `ConsensusState` type maintained within the light client module *must* implement the [`ConsensusState`](https://github.com/cosmos/ibc-go/tree/02-client-refactor-beta1/modules/core/exported/client.go#L134) interface defined in `modules/core/exported/client.go`. -The methods which make up this interface are detailed at a more granular level in the [`ConsensusState` section of this guide](03-consensus-state.md). - -### `Height` - -`Height` defines a monotonically increasing sequence number which provides ordering of consensus state data persisted through client updates. -IBC light client module developers are expected to use the [concrete type](https://github.com/cosmos/ibc-go/tree/02-client-refactor-beta1/proto/ibc/core/client/v1/client.proto#L89) provided by the `02-client` submodule. This implements the expectations required by the [`Height`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go#L156) interface defined in `modules/core/exported/client.go`. - -### `ClientMessage` - -`ClientMessage` refers to the interface type [`ClientMessage`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go#L147) used for performing updates to a `ClientState` stored on chain. -This may be any concrete type which produces a change in state to the IBC client when verified. - -The following are considered as valid update scenarios: - -- A block header which when verified inserts a new `ConsensusState` at a unique height. -- A batch of block headers which when verified inserts `N` `ConsensusState` instances for `N` unique heights. -- Evidence of misbehaviour provided by two conflicting block headers. - -Learn more in the [Handling update and misbehaviour](04-updates-and-misbehaviour.md) section. diff --git a/docs/docs/03-light-clients/01-developer-guide/02-client-state.md b/docs/docs/03-light-clients/01-developer-guide/02-client-state.md deleted file mode 100644 index cceb32637fd..00000000000 --- a/docs/docs/03-light-clients/01-developer-guide/02-client-state.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -title: Client State interface -sidebar_label: Client State interface -sidebar_position: 2 -slug: /ibc/light-clients/client-state ---- - - -# Implementing the `ClientState` interface - -Learn how to implement the [`ClientState`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go#L36) interface. This list of methods described here does not include all methods of the interface. Some methods are explained in detail in the relevant sections of the guide. - -## `ClientType` method - -`ClientType` should return a unique string identifier of the light client. This will be used when generating a client identifier. -The format is created as follows: `ClientType-{N}` where `{N}` is the unique global nonce associated with a specific client. - -## `GetLatestHeight` method - -`GetLatestHeight` should return the latest block height that the client state represents. - -## `Validate` method - -`Validate` should validate every client state field and should return an error if any value is invalid. The light client -implementer is in charge of determining which checks are required. See the [Tendermint light client implementation](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/client_state.go#L111) as a reference. - -## `Status` method - -`Status` must return the status of the client. - -- An `Active` status indicates that clients are allowed to process packets. -- A `Frozen` status indicates that misbehaviour was detected in the counterparty chain and the client is not allowed to be used. -- An `Expired` status indicates that a client is not allowed to be used because it was not updated for longer than the trusting period. -- An `Unknown` status indicates that there was an error in determining the status of a client. - -All possible `Status` types can be found [here](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go#L22-L32). - -This field is returned in the response of the gRPC [`ibc.core.client.v1.Query/ClientStatus`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/02-client/types/query.pb.go#L665) endpoint. - -## `ZeroCustomFields` method - -`ZeroCustomFields` should return a copy of the light client with all client customizable fields with their zero value. It should not mutate the fields of the light client. -This method is used when [scheduling upgrades](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/02-client/keeper/proposal.go#L82). Upgrades are used to upgrade chain specific fields. -In the tendermint case, this may be the chain ID or the unbonding period. -For more information about client upgrades see the [Handling upgrades](05-upgrades.md) section. - -## `GetTimestampAtHeight` method - -`GetTimestampAtHeight` must return the timestamp for the consensus state associated with the provided height. -This value is used to facilitate timeouts by checking the packet timeout timestamp against the returned value. - -## `Initialize` method - -Clients must validate the initial consensus state, and set the initial client state and consensus state in the provided client store. -Clients may also store any necessary client-specific metadata. - -`Initialize` is called when a [client is created](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/02-client/keeper/client.go#L30). - -## `VerifyMembership` method - -`VerifyMembership` must verify the existence of a value at a given commitment path at the specified height. For more information about membership proofs -see the [Existence and non-existence proofs section](06-proofs.md). - -## `VerifyNonMembership` method - -`VerifyNonMembership` must verify the absence of a value at a given commitment path at a specified height. For more information about non-membership proofs -see the [Existence and non-existence proofs section](06-proofs.md). - -## `VerifyClientMessage` method - -`VerifyClientMessage` must verify a `ClientMessage`. A `ClientMessage` could be a `Header`, `Misbehaviour`, or batch update. -It must handle each type of `ClientMessage` appropriately. Calls to `CheckForMisbehaviour`, `UpdateState`, and `UpdateStateOnMisbehaviour` -will assume that the content of the `ClientMessage` has been verified and can be trusted. An error should be returned -if the ClientMessage fails to verify. - -## `CheckForMisbehaviour` method - -Checks for evidence of a misbehaviour in `Header` or `Misbehaviour` type. It assumes the `ClientMessage` -has already been verified. diff --git a/docs/docs/03-light-clients/01-developer-guide/03-consensus-state.md b/docs/docs/03-light-clients/01-developer-guide/03-consensus-state.md deleted file mode 100644 index b9e03083e6f..00000000000 --- a/docs/docs/03-light-clients/01-developer-guide/03-consensus-state.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: Consensus State interface -sidebar_label: Consensus State interface -sidebar_position: 3 -slug: /ibc/light-clients/consensus-state ---- - - -# Implementing the `ConsensusState` interface - -A `ConsensusState` is the snapshot of the counterparty chain, that an IBC client uses to verify proofs (e.g. a block). - -The further development of multiple types of IBC light clients and the difficulties presented by this generalization problem (see [ADR-006](https://github.com/cosmos/ibc-go/blob/main/docs/architecture/adr-006-02-client-refactor.md) for more information about this historical context) led to the design decision of each client keeping track of and set its own `ClientState` and `ConsensusState`, as well as the simplification of client `ConsensusState` updates through the generalized `ClientMessage` interface. - -The below [`ConsensusState`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go#L133) interface is a generalized interface for the types of information a `ConsensusState` could contain. For a reference `ConsensusState` implementation, please see the [Tendermint light client `ConsensusState`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/consensus_state.go). - -## `ClientType` method - -This is the type of client consensus. It should be the same as the `ClientType` return value for the [corresponding `ClientState` implementation](02-client-state.md). - -## `GetTimestamp` method - -`GetTimestamp` should return the timestamp (in nanoseconds) of the consensus state snapshot. - -## `ValidateBasic` method - -`ValidateBasic` should validate every consensus state field and should return an error if any value is invalid. The light client implementer is in charge of determining which checks are required. diff --git a/docs/docs/03-light-clients/01-developer-guide/04-updates-and-misbehaviour.md b/docs/docs/03-light-clients/01-developer-guide/04-updates-and-misbehaviour.md deleted file mode 100644 index 776c442baed..00000000000 --- a/docs/docs/03-light-clients/01-developer-guide/04-updates-and-misbehaviour.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -title: Handling Updates and Misbehaviour -sidebar_label: Handling Updates and Misbehaviour -sidebar_position: 4 -slug: /ibc/light-clients/updates-and-misbehaviour ---- - - -# Handling `ClientMessage`s: updates and misbehaviour - -As mentioned before in the documentation about [implementing the `ConsensusState` interface](03-consensus-state.md), [`ClientMessage`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go#L147) is an interface used to update an IBC client. This update may be performed by: - -- a single header -- a batch of headers -- evidence of misbehaviour, -- or any type which when verified produces a change to the consensus state of the IBC client. - -This interface has been purposefully kept generic in order to give the maximum amount of flexibility to the light client implementer. - -## Implementing the `ClientMessage` interface - -Find the `ClientMessage`interface in `modules/core/exported`: - -```go -type ClientMessage interface { - proto.Message - - ClientType() string - ValidateBasic() error -} -``` - -The `ClientMessage` will be passed to the client to be used in [`UpdateClient`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/02-client/keeper/client.go#L48), which retrieves the `ClientState` by client ID (available in `MsgUpdateClient`). This `ClientState` implements the [`ClientState` interface](02-client-state.md) for its specific consenus type (e.g. Tendermint). - -`UpdateClient` will then handle a number of cases including misbehaviour and/or updating the consensus state, utilizing the specific methods defined in the relevant `ClientState`. - -```go -VerifyClientMessage(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg ClientMessage) error -CheckForMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg ClientMessage) bool -UpdateStateOnMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg ClientMessage) -UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg ClientMessage) []Height -``` - -## Handling updates and misbehaviour - -The functions for handling updates to a light client and evidence of misbehaviour are all found in the [`ClientState`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go#L36) interface, and will be discussed below. - -> It is important to note that `Misbehaviour` in this particular context is referring to misbehaviour on the chain level intended to fool the light client. This will be defined by each light client. - -## `VerifyClientMessage` - -`VerifyClientMessage` must verify a `ClientMessage`. A `ClientMessage` could be a `Header`, `Misbehaviour`, or batch update. To understand how to implement a `ClientMessage`, please refer to the [Implementing the `ClientMessage` interface](#implementing-the-clientmessage-interface) section. - -It must handle each type of `ClientMessage` appropriately. Calls to `CheckForMisbehaviour`, `UpdateState`, and `UpdateStateOnMisbehaviour` will assume that the content of the `ClientMessage` has been verified and can be trusted. An error should be returned if the `ClientMessage` fails to verify. - -For an example of a `VerifyClientMessage` implementation, please check the [Tendermint light client](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/update.go#L20). - -## `CheckForMisbehaviour` - -Checks for evidence of a misbehaviour in `Header` or `Misbehaviour` type. It assumes the `ClientMessage` has already been verified. - -For an example of a `CheckForMisbehaviour` implementation, please check the [Tendermint light client](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/misbehaviour_handle.go#L19). - -> The Tendermint light client [defines `Misbehaviour`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/misbehaviour.go) as two different types of situations: a situation where two conflicting `Header`s with the same height have been submitted to update a client's `ConsensusState` within the same trusting period, or that the two conflicting `Header`s have been submitted at different heights but the consensus states are not in the correct monotonic time ordering (BFT time violation). More explicitly, updating to a new height must have a timestamp greater than the previous consensus state, or, if inserting a consensus at a past height, then time must be less than those heights which come after and greater than heights which come before. - -## `UpdateStateOnMisbehaviour` - -`UpdateStateOnMisbehaviour` should perform appropriate state changes on a client state given that misbehaviour has been detected and verified. This method should only be called when misbehaviour is detected, as it does not perform any misbehaviour checks. Notably, it should freeze the client so that calling the `Status` function on the associated client state no longer returns `Active`. - -For an example of a `UpdateStateOnMisbehaviour` implementation, please check the [Tendermint light client](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/update.go#L199). - -## `UpdateState` - -`UpdateState` updates and stores as necessary any associated information for an IBC client, such as the `ClientState` and corresponding `ConsensusState`. It should perform a no-op on duplicate updates. - -It assumes the `ClientMessage` has already been verified. - -For an example of a `UpdateState` implementation, please check the [Tendermint light client](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/update.go#L131). - -## Putting it all together - -The `02-client` `Keeper` module in ibc-go offers a reference as to how these functions will be used to [update the client](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/02-client/keeper/client.go#L48). - -```go -if err := clientState.VerifyClientMessage(clientMessage); err != nil { - return err -} - -foundMisbehaviour := clientState.CheckForMisbehaviour(clientMessage) -if foundMisbehaviour { - clientState.UpdateStateOnMisbehaviour(clientMessage) - // emit misbehaviour event - return -} - -clientState.UpdateState(clientMessage) // expects no-op on duplicate header -// emit update event -return diff --git a/docs/docs/03-light-clients/01-developer-guide/05-upgrades.md b/docs/docs/03-light-clients/01-developer-guide/05-upgrades.md deleted file mode 100644 index a6fc3858c3d..00000000000 --- a/docs/docs/03-light-clients/01-developer-guide/05-upgrades.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Handling Upgrades -sidebar_label: Handling Upgrades -sidebar_position: 5 -slug: /ibc/light-clients/upgrades ---- - - -# Handling upgrades - -It is vital that high-value IBC clients can upgrade along with their underlying chains to avoid disruption to the IBC ecosystem. Thus, IBC client developers will want to implement upgrade functionality to enable clients to maintain connections and channels even across chain upgrades. - -## Implementing `VerifyUpgradeAndUpdateState` - -The IBC protocol allows client implementations to provide a path to upgrading clients given the upgraded `ClientState`, upgraded `ConsensusState` and proofs for each. This path is provided in the `VerifyUpgradeAndUpdateState` method: - -```go -// NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last height committed by the current revision. Clients are responsible for ensuring that the planned last height of the current revision is somehow encoded in the proof verification process. -// This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty may be cancelled or modified before the last planned height. -// If the upgrade is verified, the upgraded client and consensus states must be set in the client store. -func (cs ClientState) VerifyUpgradeAndUpdateState( - ctx sdk.Context, - cdc codec.BinaryCodec, - store sdk.KVStore, - newClient ClientState, - newConsState ConsensusState, - proofUpgradeClient, - proofUpgradeConsState []byte, -) error -``` - -> Please refer to the [Tendermint light client implementation](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/upgrade.go#L27) as an example for implementation. - -It is important to note that light clients **must** handle all management of client and consensus states including the setting of updated `ClientState` and `ConsensusState` in the client store. This can include verifying that the submitted upgraded `ClientState` is of a valid `ClientState` type, that the height of the upgraded client is not greater than the height of the current client (in order to preserve BFT monotonic time), or that certain parameters which should not be changed have not been altered in the upgraded `ClientState`. - -Developers must ensure that the `MsgUpgradeClient` does not pass until the last height of the old chain has been committed, and after the chain upgrades, the `MsgUpgradeClient` should pass once and only once on all counterparty clients. - -### Upgrade path - -Clients should have **prior knowledge of the merkle path** that the upgraded client and upgraded consensus states will use. The height at which the upgrade has occurred should also be encoded in the proof. -> The Tendermint client implementation accomplishes this by including an `UpgradePath` in the `ClientState` itself, which is used along with the upgrade height to construct the merkle path under which the client state and consensus state are committed. - -## Chain specific vs client specific client parameters - -Developers should maintain the distinction between client parameters that are uniform across every valid light client of a chain (chain-chosen parameters), and client parameters that are customizable by each individual client (client-chosen parameters); since this distinction is necessary to implement the `ZeroCustomFields` method in the [`ClientState` interface](02-client-state.md): - -```go -// Utility function that zeroes out any client customizable fields in client state -// Ledger enforced fields are maintained while all custom fields are zero values -// Used to verify upgrades -func (cs ClientState) ZeroCustomFields() ClientState -``` - -Developers must ensure that the new client adopts all of the new client parameters that must be uniform across every valid light client of a chain (chain-chosen parameters), while maintaining the client parameters that are customizable by each individual client (client-chosen parameters) from the previous version of the client. `ZeroCustomFields` is a useful utility function to ensure only chain specific fields are updated during upgrades. - -## Security - -Upgrades must adhere to the IBC Security Model. IBC does not rely on the assumption of honest relayers for correctness. Thus users should not have to rely on relayers to maintain client correctness and security (though honest relayers must exist to maintain relayer liveness). While relayers may choose any set of client parameters while creating a new `ClientState`, this still holds under the security model since users can always choose a relayer-created client that suits their security and correctness needs or create a client with their desired parameters if no such client exists. - -However, when upgrading an existing client, one must keep in mind that there are already many users who depend on this client's particular parameters. **We cannot give the upgrading relayer free choice over these parameters once they have already been chosen. This would violate the security model** since users who rely on the client would have to rely on the upgrading relayer to maintain the same level of security. - -Thus, developers must make sure that their upgrade mechanism allows clients to upgrade the chain-specified parameters whenever a chain upgrade changes these parameters (examples in the Tendermint client include `UnbondingPeriod`, `TrustingPeriod`, `ChainID`, `UpgradePath`, etc), while ensuring that the relayer submitting the `MsgUpgradeClient` cannot alter the client-chosen parameters that the users are relying upon (examples in Tendermint client include `TrustLevel`, `MaxClockDrift`, etc). The previous paragraph discusses how `ZeroCustomFields` helps achieve this. - -### Document potential client parameter conflicts during upgrades - -Counterparty clients can upgrade securely by using all of the chain-chosen parameters from the chain-committed `UpgradedClient` and preserving all of the old client-chosen parameters. This enables chains to securely upgrade without relying on an honest relayer, however it can in some cases lead to an invalid final `ClientState` if the new chain-chosen parameters clash with the old client-chosen parameter. This can happen in the Tendermint client case if the upgrading chain lowers the `UnbondingPeriod` (chain-chosen) to a duration below that of a counterparty client's `TrustingPeriod` (client-chosen). Such cases should be clearly documented by developers, so that chains know which upgrades should be avoided to prevent this problem. The final upgraded client should also be validated in `VerifyUpgradeAndUpdateState` before returning to ensure that the client does not upgrade to an invalid `ClientState`. diff --git a/docs/docs/03-light-clients/01-developer-guide/06-proofs.md b/docs/docs/03-light-clients/01-developer-guide/06-proofs.md deleted file mode 100644 index 636e2b70e80..00000000000 --- a/docs/docs/03-light-clients/01-developer-guide/06-proofs.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Existence/Non-Existence Proofs -sidebar_label: Existence/Non-Existence Proofs -sidebar_position: 6 -slug: /ibc/light-clients/proofs ---- - - -# Existence and non-existence proofs - -IBC uses merkle proofs in order to verify the state of a remote counterparty state machine given a trusted root, and [ICS-23](https://github.com/cosmos/ics23/tree/master/go) is a general approach for verifying merkle trees which is used in ibc-go. - -Currently, all Cosmos SDK modules contain their own stores, which maintain the state of the application module in an IAVL (immutable AVL) binary merkle tree format. Specifically with regard to IBC, core IBC maintains its own IAVL store, and IBC apps (e.g. transfer) maintain their own dedicated stores. The Cosmos SDK multistore therefore creates a simple merkle tree of all of these IAVL trees, and from each of these individual IAVL tree root hashes it derives a root hash for the application state tree as a whole (the `AppHash`). - -For the purposes of ibc-go, there are two types of proofs which are important: existence and non-existence proofs, terms which have been used interchangeably with membership and non-membership proofs. For the purposes of this guide, we will stick with "existence" and "non-existence". - -## Existence proofs - -Existence proofs are used in IBC transactions which involve verification of counterparty state for transactions which will result in the writing of provable state. For example, this includes verification of IBC store state for handshakes and packets. - -Put simply, existence proofs prove that a particular key and value exists in the tree. Under the hood, an IBC existence proof comprises of two proofs: an IAVL proof that the key exists in IBC store/IBC root hash, and a proof that the IBC root hash exists in the multistore root hash. - -## Non-existence proofs - -Non-existence proofs verify the absence of data stored within counterparty state and are used to prove that a key does NOT exist in state. As stated above, these types of proofs can be used to timeout packets by proving that the counterparty has not written a packet receipt into the store, meaning that a token transfer has NOT successfully occurred. - -Some trees (e.g. SMT) may have a sentinel empty child for non-existent keys. In this case, the ICS-23 proof spec should include this `EmptyChild` so that ICS-23 handles the non-existence proof correctly. - -In some cases, there is a necessity to "mock" non-existence proofs if the counterparty does not have ability to prove absence. Since the verification method is designed to give complete control to client implementations, clients can support chains that do not provide absence proofs by verifying the existence of a non-empty sentinel `ABSENCE` value. In these special cases, the proof provided will be an ICS-23 `Existence` proof, and the client will verify that the `ABSENCE` value is stored under the given path for the given height. - -## State verification methods: `VerifyMembership` and `VerifyNonMembership` - -The state verification functions for all IBC data types have been consolidated into two generic methods, `VerifyMembership` and `VerifyNonMembership`. - -From the [`ClientState` interface definition](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go#L68-L91), we find: - -```go -VerifyMembership( - ctx sdk.Context, - clientStore sdk.KVStore, - cdc codec.BinaryCodec, - height Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - proof []byte, - path Path, - value []byte, -) error - -// VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. -// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). -VerifyNonMembership( - ctx sdk.Context, - clientStore sdk.KVStore, - cdc codec.BinaryCodec, - height Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - proof []byte, - path Path, -) error -``` - -Both are expected to be provided with a standardised key path, `exported.Path`, as defined in [ICS-24 host requirements](https://github.com/cosmos/ibc/tree/main/spec/core/ics-024-host-requirements). Membership verification requires callers to provide the value marshalled as `[]byte`. Delay period values should be zero for non-packet processing verification. A zero proof height is now allowed by core IBC and may be passed into `VerifyMembership` and `VerifyNonMembership`. Light clients are responsible for returning an error if a zero proof height is invalid behaviour. - -Please refer to the [ICS-23 implementation](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/23-commitment/types/merkle.go#L131-L205) for a concrete example. diff --git a/docs/docs/03-light-clients/01-developer-guide/07-proposals.md b/docs/docs/03-light-clients/01-developer-guide/07-proposals.md deleted file mode 100644 index a5af1b4c705..00000000000 --- a/docs/docs/03-light-clients/01-developer-guide/07-proposals.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: Handling Proposals -sidebar_label: Handling Proposals -sidebar_position: 7 -slug: /ibc/light-clients/proposals ---- - - -# Handling proposals - -It is possible to update the client with the state of the substitute client through a governance proposal. [This type of governance proposal](https://ibc.cosmos.network/main/ibc/proposals.html) is typically used to recover an expired or frozen client, as it can recover the entire state and therefore all existing channels built on top of the client. `CheckSubstituteAndUpdateState` should be implemented to handle the proposal. - -## Implementing `CheckSubstituteAndUpdateState` - -In the [`ClientState`interface](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go), we find: - -```go -// CheckSubstituteAndUpdateState must verify that the provided substitute may be used to update the subject client. -// The light client must set the updated client and consensus states within the clientStore for the subject client. -CheckSubstituteAndUpdateState( - ctx sdk.Context, - cdc codec.BinaryCodec, - subjectClientStore, - substituteClientStore sdk.KVStore, - substituteClient ClientState, -) error -``` - -Prior to updating, this function must verify that: - -- the substitute client is the same type as the subject client. For a reference implementation, please see the [Tendermint light client](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/proposal_handle.go#L32). -- the provided substitute may be used to update the subject client. This may mean that certain parameters must remain unaltered. For example, a [valid substitute Tendermint light client](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/proposal_handle.go#L84) must NOT change the chain ID, trust level, max clock drift, unbonding period, proof specs or upgrade path. Please note that `AllowUpdateAfterMisbehaviour` and `AllowUpdateAfterExpiry` have been deprecated (see ADR 026 for more information). - -After these checks are performed, the function must [set the updated client and consensus states](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/proposal_handle.go#L77) within the client store for the subject client. - -Please refer to the [Tendermint light client implementation](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/proposal_handle.go#L27) for reference. diff --git a/docs/docs/03-light-clients/01-developer-guide/08-genesis.md b/docs/docs/03-light-clients/01-developer-guide/08-genesis.md deleted file mode 100644 index 5c7c611e729..00000000000 --- a/docs/docs/03-light-clients/01-developer-guide/08-genesis.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Handling Genesis -sidebar_label: Handling Genesis -sidebar_position: 8 -slug: /ibc/light-clients/genesis ---- - -# Genesis metadata - -:::note Synopsis -Learn how to implement the `ExportMetadata` interface -::: - -:::note - -## Pre-requisite readings - -- [Cosmos SDK module genesis](https://docs.cosmos.network/v0.47/building-modules/genesis) - -::: - -`ClientState` instances are provided their own isolated and namespaced client store upon initialisation. `ClientState` implementations may choose to store any amount of arbitrary metadata in order to verify counterparty consensus state and perform light client updates correctly. - -The `ExportMetadata` method of the [`ClientState` interface](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go#L47) provides light client modules with the ability to persist metadata in genesis exports. - -```go -ExportMetadata(clientStore sdk.KVStore) []GenesisMetadata -``` - -`ExportMetadata` is provided the client store and returns an array of `GenesisMetadata`. For maximum flexibility, `GenesisMetadata` is defined as a simple interface containing two distinct `Key` and `Value` accessor methods. - -```go -type GenesisMetadata interface { - // return store key that contains metadata without clientID-prefix - GetKey() []byte - // returns metadata value - GetValue() []byte -} -``` - -This allows `ClientState` instances to retrieve and export any number of key-value pairs which are maintained within the store in their raw `[]byte` form. - -When a chain is started with a `genesis.json` file which contains `ClientState` metadata (for example, when performing manual upgrades using an exported `genesis.json`) the `02-client` submodule of core IBC will handle setting the key-value pairs within their respective client stores. [See `02-client` `InitGenesis`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/02-client/genesis.go#L18-L22). - -Please refer to the [Tendermint light client implementation](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/genesis.go#L12) for an example. diff --git a/docs/docs/03-light-clients/01-developer-guide/09-setup.md b/docs/docs/03-light-clients/01-developer-guide/09-setup.md deleted file mode 100644 index f3bba760ec2..00000000000 --- a/docs/docs/03-light-clients/01-developer-guide/09-setup.md +++ /dev/null @@ -1,133 +0,0 @@ ---- -title: Setup -sidebar_label: Setup -sidebar_position: 9 -slug: /ibc/light-clients/setup ---- - - -# Setup - -:::note Synopsis -Learn how to configure light client modules and create clients using core IBC and the `02-client` submodule. -::: - -A last step to finish the development of the light client, is to implement the `AppModuleBasic` interface to allow it to be added to the chain's `app.go` alongside other light client types the chain enables. - -Finally, a succinct rundown is given of the remaining steps to make the light client operational, getting the light client type passed through governance and creating the clients. - -## Configuring a light client module - -An IBC light client module must implement the [`AppModuleBasic`](https://github.com/cosmos/cosmos-sdk/blob/main/types/module/module.go#L50) interface in order to register its concrete types against the core IBC interfaces defined in `modules/core/exported`. This is accomplished via the `RegisterInterfaces` method which provides the light client module with the opportunity to register codec types using the chain's `InterfaceRegistry`. Please refer to the [`07-tendermint` codec registration](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/codec.go#L11). - -The `AppModuleBasic` interface may also be leveraged to install custom CLI handlers for light client module users. Light client modules can safely no-op for interface methods which it does not wish to implement. - -Please refer to the [core IBC documentation](../../01-ibc/02-integration.md#integrating-light-clients) for how to configure additional light client modules alongside `07-tendermint` in `app.go`. - -See below for an example of the `07-tendermint` implementation of `AppModuleBasic`. - -```go -var _ module.AppModuleBasic = AppModuleBasic{} - -// AppModuleBasic defines the basic application module used by the tendermint light client. -// Only the RegisterInterfaces function needs to be implemented. All other function perform -// a no-op. -type AppModuleBasic struct{} - -// Name returns the tendermint module name. -func (AppModuleBasic) Name() string { - return ModuleName -} - -// RegisterLegacyAminoCodec performs a no-op. The Tendermint client does not support amino. -func (AppModuleBasic) RegisterLegacyAminoCodec(*codec.LegacyAmino) {} - -// RegisterInterfaces registers module concrete types into protobuf Any. This allows core IBC -// to unmarshal tendermint light client types. -func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { - RegisterInterfaces(registry) -} - -// DefaultGenesis performs a no-op. Genesis is not supported for the tendermint light client. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { - return nil -} - -// ValidateGenesis performs a no-op. Genesis is not supported for the tendermint light cilent. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { - return nil -} - -// RegisterGRPCGatewayRoutes performs a no-op. -func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) {} - -// GetTxCmd performs a no-op. Please see the 02-client cli commands. -func (AppModuleBasic) GetTxCmd() *cobra.Command { - return nil -} - -// GetQueryCmd performs a no-op. Please see the 02-client cli commands. -func (AppModuleBasic) GetQueryCmd() *cobra.Command { - return nil -} -``` - -## Creating clients - -A client is created by executing a new `MsgCreateClient` transaction composed with a valid `ClientState` and initial `ConsensusState` encoded as protobuf `Any`s. -Generally, this is performed by an off-chain process known as an [IBC relayer](https://github.com/cosmos/ibc/tree/main/spec/relayer/ics-018-relayer-algorithms) however, this is not a strict requirement. - -See below for a list of IBC relayer implementations: - -- [cosmos/relayer](https://github.com/cosmos/relayer) -- [informalsystems/hermes](https://github.com/informalsystems/hermes) -- [confio/ts-relayer](https://github.com/confio/ts-relayer) - -Stateless checks are performed within the [`ValidateBasic`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/02-client/types/msgs.go#L48) method of `MsgCreateClient`. - -```protobuf -// MsgCreateClient defines a message to create an IBC client -message MsgCreateClient { - option (gogoproto.goproto_getters) = false; - - // light client state - google.protobuf.Any client_state = 1 [(gogoproto.moretags) = "yaml:\"client_state\""]; - // consensus state associated with the client that corresponds to a given - // height. - google.protobuf.Any consensus_state = 2 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; - // signer address - string signer = 3; -} -``` - -Leveraging protobuf `Any` encoding allows core IBC to [unpack](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/keeper/msg_server.go#L28-L36) both the `ClientState` and `ConsensusState` into their respective interface types registered previously using the light client module's `RegisterInterfaces` method. - -Within the `02-client` submodule, the [`ClientState` is then initialized](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/02-client/keeper/client.go#L30-L32) with its own isolated key-value store, namespaced using a unique client identifier. - -In order to successfully create an IBC client using a new client type, it [must be supported](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/02-client/keeper/client.go#L19-L25). Light client support in IBC is gated by on-chain governance. The allow list may be updated by submitting a new governance proposal to update the `02-client` parameter `AllowedClients`. - -See below for example: - -```shell -%s tx gov submit-proposal --from -``` - -where `proposal.json` contains: - -```json -{ - "title": "IBC Clients Param Change", - "summary": "Update allowed clients", - "messages": [ - { - "@type": "/ibc.core.client.v1.MsgUpdateParams", - "signer": "cosmos1...", // The gov module account address - "params": { - "allowed_clients": ["06-solomachine", "07-tendermint", "0x-new-client"] - } - } - ], - "metadata": "AQ==", - "deposit": "100stake" -} -``` diff --git a/docs/docs/03-light-clients/01-developer-guide/_category_.json b/docs/docs/03-light-clients/01-developer-guide/_category_.json deleted file mode 100644 index 9be9c3c3a08..00000000000 --- a/docs/docs/03-light-clients/01-developer-guide/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Developer Guide", - "position": 1, - "link": null -} \ No newline at end of file diff --git a/docs/docs/03-light-clients/01-developer-guide/wasm/audits/Ethan Frey - Wasm Client Review.pdf b/docs/docs/03-light-clients/01-developer-guide/wasm/audits/Ethan Frey - Wasm Client Review.pdf deleted file mode 100644 index 12300a49b3f..00000000000 Binary files a/docs/docs/03-light-clients/01-developer-guide/wasm/audits/Ethan Frey - Wasm Client Review.pdf and /dev/null differ diff --git a/docs/docs/03-light-clients/01-developer-guide/wasm/audits/Halborn audit report.pdf b/docs/docs/03-light-clients/01-developer-guide/wasm/audits/Halborn audit report.pdf deleted file mode 100644 index df97d6f4a07..00000000000 Binary files a/docs/docs/03-light-clients/01-developer-guide/wasm/audits/Halborn audit report.pdf and /dev/null differ diff --git a/docs/docs/03-light-clients/02-localhost/01-overview.md b/docs/docs/03-light-clients/02-localhost/01-overview.md deleted file mode 100644 index d32ccb01684..00000000000 --- a/docs/docs/03-light-clients/02-localhost/01-overview.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /ibc/light-clients/localhost/overview ---- - - -# `09-localhost` - -## Overview - -:::note Synopsis -Learn about the 09-localhost light client module. -::: - -The 09-localhost light client module implements a localhost loopback client with the ability to send and receive IBC packets to and from the same state machine. - -### Context - -In a multichain environment, application developers will be used to developing cross-chain applications through IBC. From their point of view, whether or not they are interacting with multiple modules on the same chain or on different chains should not matter. The localhost client module enables a unified interface to interact with different applications on a single chain, using the familiar IBC application layer semantics. - -### Implementation - -There exists a [single sentinel `ClientState`](03-client-state.md) instance with the client identifier `09-localhost`. - -To supplement this, a [sentinel `ConnectionEnd` is stored in core IBC](04-connection.md) state with the connection identifier `connection-localhost`. This enables IBC applications to create channels directly on top of the sentinel connection which leverage the 09-localhost loopback functionality. - -[State verification](05-state-verification.md) for channel state in handshakes or processing packets is reduced in complexity, the `09-localhost` client can simply compare bytes stored under the standardized key paths. - -### Localhost vs *regular* client - -The localhost client aims to provide a unified approach to interacting with applications on a single chain, as the IBC application layer provides for cross-chain interactions. To achieve this unified interface though, there are a number of differences under the hood compared to a 'regular' IBC client (excluding `06-solomachine` and `09-localhost` itself). - -The table below lists some important differences: - -| | Regular client | Localhost | -| -------------------------------------------- | --------------------------------------------------------------------------- | --------- | -| Number of clients | Many instances of a client *type* corresponding to different counterparties | A single sentinel client with the client identifier `09-localhost`| -| Client creation | Relayer (permissionless) | `ClientState` is instantiated in the `InitGenesis` handler of the 02-client submodule in core IBC | -| Client updates | Relayer submits headers using `MsgUpdateClient` | Latest height is updated periodically through the ABCI [`BeginBlock`](https://docs.cosmos.network/v0.47/building-modules/beginblock-endblock) interface of the 02-client submodule in core IBC | -| Number of connections | Many connections, 1 (or more) per client | A single sentinel connection with the connection identifier `connection-localhost` | -| Connection creation | Connection handshake, provided underlying client | Sentinel `ConnectionEnd` is created and set in store in the `InitGenesis` handler of the 03-connection submodule in core IBC | -| Counterparty | Underlying client, representing another chain | Client with identifier `09-localhost` in same chain | -| `VerifyMembership` and `VerifyNonMembership` | Performs proof verification using consensus state roots | Performs state verification using key-value lookups in the core IBC store | -| Integration | Expected to register codec types using the `AppModuleBasic` interface | Registers codec types within the core IBC module | diff --git a/docs/docs/03-light-clients/02-localhost/02-integration.md b/docs/docs/03-light-clients/02-localhost/02-integration.md deleted file mode 100644 index 01f77fce67e..00000000000 --- a/docs/docs/03-light-clients/02-localhost/02-integration.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 2 -slug: /ibc/light-clients/localhost/integration ---- - - -# Integration - -The 09-localhost light client module registers codec types within the core IBC module. This differs from other light client module implementations which are expected to register codec types using the `AppModuleBasic` interface. - -The localhost client is added to the 02-client submodule param [`allowed_clients`](https://github.com/cosmos/ibc-go/blob/v7.0.0/proto/ibc/core/client/v1/client.proto#L102) by default in ibc-go. - -```go -var ( - // DefaultAllowedClients are the default clients for the AllowedClients parameter. - DefaultAllowedClients = []string{exported.Solomachine, exported.Tendermint, exported.Localhost} -) -``` diff --git a/docs/docs/03-light-clients/02-localhost/03-client-state.md b/docs/docs/03-light-clients/02-localhost/03-client-state.md deleted file mode 100644 index 5f0a990412e..00000000000 --- a/docs/docs/03-light-clients/02-localhost/03-client-state.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: ClientState -sidebar_label: ClientState -sidebar_position: 3 -slug: /ibc/light-clients/localhost/client-state ---- - - -# `ClientState` - -The 09-localhost `ClientState` maintains a single field used to track the latest sequence of the state machine i.e. the height of the blockchain. - -```go -type ClientState struct { - // the latest height of the blockchain - LatestHeight clienttypes.Height -} -``` - -The 09-localhost `ClientState` is instantiated in the `InitGenesis` handler of the 02-client submodule in core IBC. -It calls `CreateLocalhostClient`, declaring a new `ClientState` and initializing it with its own client prefixed store. - -```go -func (k Keeper) CreateLocalhostClient(ctx sdk.Context) error { - var clientState localhost.ClientState - return clientState.Initialize(ctx, k.cdc, k.ClientStore(ctx, exported.LocalhostClientID), nil) -} -``` - -It is possible to disable the localhost client by removing the `09-localhost` entry from the `allowed_clients` list through governance. - -## Client updates - -The latest height is updated periodically through the ABCI [`BeginBlock`](https://docs.cosmos.network/v0.47/building-modules/beginblock-endblock) interface of the 02-client submodule in core IBC. - -[See `BeginBlocker` in abci.go.](https://github.com/cosmos/ibc-go/blob/09-localhost/modules/core/02-client/abci.go#L12) - -```go -func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { - // ... - - if clientState, found := k.GetClientState(ctx, exported.Localhost); found { - if k.GetClientStatus(ctx, clientState, exported.Localhost) == exported.Active { - k.UpdateLocalhostClient(ctx, clientState) - } - } -} -``` - -The above calls into the the 09-localhost `UpdateState` method of the `ClientState` . -It retrieves the current block height from the application context and sets the `LatestHeight` of the 09-localhost client. - -```go -func (cs ClientState) UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg exported.ClientMessage) []exported.Height { - height := clienttypes.GetSelfHeight(ctx) - cs.LatestHeight = height - - clientStore.Set(host.ClientStateKey(), clienttypes.MustMarshalClientState(cdc, &cs)) - - return []exported.Height{height} -} -``` - -Note that the 09-localhost `ClientState` is not updated through the 02-client interface leveraged by conventional IBC light clients. diff --git a/docs/docs/03-light-clients/02-localhost/04-connection.md b/docs/docs/03-light-clients/02-localhost/04-connection.md deleted file mode 100644 index 160c814d229..00000000000 --- a/docs/docs/03-light-clients/02-localhost/04-connection.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: Connection -sidebar_label: Connection -sidebar_position: 4 -slug: /ibc/light-clients/localhost/connection ---- - - -# Localhost connections - -The 09-localhost light client module integrates with core IBC through a single sentinel localhost connection. -The sentinel `ConnectionEnd` is stored by default in the core IBC store. - -This enables channel handshakes to be initiated out of the box by supplying the localhost connection identifier (`connection-localhost`) in the `connectionHops` parameter of `MsgChannelOpenInit`. - -The `ConnectionEnd` is created and set in store via the `InitGenesis` handler of the 03-connection submodule in core IBC. -The `ConnectionEnd` and its `Counterparty` both reference the `09-localhost` client identifier, and share the localhost connection identifier `connection-localhost`. - -```go -// CreateSentinelLocalhostConnection creates and sets the sentinel localhost connection end in the IBC store. -func (k Keeper) CreateSentinelLocalhostConnection(ctx sdk.Context) { - counterparty := types.NewCounterparty(exported.LocalhostClientID, exported.LocalhostConnectionID, commitmenttypes.NewMerklePrefix(k.GetCommitmentPrefix().Bytes())) - connectionEnd := types.NewConnectionEnd(types.OPEN, exported.LocalhostClientID, counterparty, types.GetCompatibleVersions(), 0) - - k.SetConnection(ctx, exported.LocalhostConnectionID, connectionEnd) -} -``` - -Note that connection handshakes are disallowed when using the `09-localhost` client type. diff --git a/docs/docs/03-light-clients/02-localhost/05-state-verification.md b/docs/docs/03-light-clients/02-localhost/05-state-verification.md deleted file mode 100644 index ddf4f03de10..00000000000 --- a/docs/docs/03-light-clients/02-localhost/05-state-verification.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: State Verification -sidebar_label: State Verification -sidebar_position: 5 -slug: /ibc/light-clients/localhost/state-verification ---- - - -# State verification - -The localhost client handles state verification through the `ClientState` interface methods `VerifyMembership` and `VerifyNonMembership` by performing read-only operations directly on the core IBC store. - -When verifying channel state in handshakes or processing packets the `09-localhost` client can simply compare bytes stored under the standardized key paths defined by [ICS-24](https://github.com/cosmos/ibc/tree/main/spec/core/ics-024-host-requirements). - -For existence proofs via `VerifyMembership` the 09-localhost client will retrieve the value stored under the provided key path and compare it against the value provided by the caller. In contrast, non-existence proofs via `VerifyNonMembership` assert the absence of a value at the provided key path. - -Relayers are expected to provide a sentinel proof when sending IBC messages. Submission of nil or empty proofs is disallowed in core IBC messaging. -The 09-localhost light client module defines a `SentinelProof` as a single byte. Localhost client state verification will fail if the sentinel proof value is not provided. - -```go -var SentinelProof = []byte{0x01} -``` diff --git a/docs/docs/03-light-clients/02-localhost/_category_.json b/docs/docs/03-light-clients/02-localhost/_category_.json deleted file mode 100644 index 0dc062d29e6..00000000000 --- a/docs/docs/03-light-clients/02-localhost/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Localhost", - "position": 2, - "link": null -} \ No newline at end of file diff --git a/docs/docs/03-light-clients/03-solomachine/01-solomachine.md b/docs/docs/03-light-clients/03-solomachine/01-solomachine.md deleted file mode 100644 index 394e5ec6efb..00000000000 --- a/docs/docs/03-light-clients/03-solomachine/01-solomachine.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: Solomachine -sidebar_label: Solomachine -sidebar_position: 1 -slug: /ibc/light-clients/solomachine/solomachine ---- - - -# `solomachine` - -## Abstract - -This paper defines the implementation of the ICS06 protocol on the Cosmos SDK. For the general -specification please refer to the [ICS06 Specification](https://github.com/cosmos/ibc/tree/master/spec/client/ics-006-solo-machine-client). - -This implementation of a solo machine light client supports single and multi-signature public -keys. The client is capable of handling public key updates by header and governance proposals. -The light client is capable of processing client misbehaviour. Proofs of the counterparty state -are generated by the solo machine client by signing over the desired state with a certain sequence, -diversifier, and timestamp. - -## Contents - -1. **[Concepts](02-concepts.md)** -2. **[State](03-state.md)** -3. **[State Transitions](04-state_transitions.md)** diff --git a/docs/docs/03-light-clients/03-solomachine/02-concepts.md b/docs/docs/03-light-clients/03-solomachine/02-concepts.md deleted file mode 100644 index 270dab232a6..00000000000 --- a/docs/docs/03-light-clients/03-solomachine/02-concepts.md +++ /dev/null @@ -1,168 +0,0 @@ ---- -title: Concepts -sidebar_label: Concepts -sidebar_position: 2 -slug: /ibc/light-clients/solomachine/concepts ---- - - -# Concepts - -## Client State - -The `ClientState` for a solo machine light client stores the latest sequence, the frozen sequence, -the latest consensus state, and client flag indicating if the client should be allowed to be updated -after a governance proposal. - -If the client is not frozen then the frozen sequence is 0. - -## Consensus State - -The consensus states stores the public key, diversifier, and timestamp of the solo machine light client. - -The diversifier is used to prevent accidental misbehaviour if the same public key is used across -different chains with the same client identifier. It should be unique to the chain the light client -is used on. - -## Public Key - -The public key can be a single public key or a multi-signature public key. The public key type used -must fulfill the tendermint public key interface (this will become the SDK public key interface in the -near future). The public key must be registered on the application codec otherwise encoding/decoding -errors will arise. The public key stored in the consensus state is represented as a protobuf `Any`. -This allows for flexibility in what other public key types can be supported in the future. - -## Counterparty Verification - -The solo machine light client can verify counterparty client state, consensus state, connection state, -channel state, packet commitments, packet acknowledgements, packet receipt absence, -and the next sequence receive. At the end of each successful verification call the light -client sequence number will be incremented. - -Successful verification requires the current public key to sign over the proof. - -## Proofs - -A solo machine proof should verify that the solomachine public key signed -over some specified data. The format for generating marshaled proofs for -the SDK's implementation of solo machine is as follows: - -1. Construct the data using the associated protobuf definition and marshal it. - -For example: - -```go -data := &ClientStateData{ - Path: []byte(path.String()), - ClientState: protoAny, -} - -dataBz, err := cdc.Marshal(data) -``` - -The helper functions `...DataBytes()` in [proof.go](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/06-solomachine/proof.go) handle this -functionality. - -2. Construct the `SignBytes` and marshal it. - -For example: - -```go -signBytes := &SignBytes{ - Sequence: sequence, - Timestamp: timestamp, - Diversifier: diversifier, - DataType: CLIENT, - Data: dataBz, -} - -signBz, err := cdc.Marshal(signBytes) -``` - -The helper functions `...SignBytes()` in [proof.go](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/06-solomachine/proof.go) handle this functionality. -The `DataType` field is used to disambiguate what type of data was signed to prevent potential -proto encoding overlap. - -3. Sign the sign bytes. Embed the signatures into either `SingleSignatureData` or `MultiSignatureData`. -Convert the `SignatureData` to proto and marshal it. - -For example: - -```go -sig, err := key.Sign(signBz) -sigData := &signing.SingleSignatureData{ - Signature: sig, -} - -protoSigData := signing.SignatureDataToProto(sigData) -bz, err := cdc.Marshal(protoSigData) -``` - -4. Construct a `TimestampedSignatureData` and marshal it. The marshaled result can be passed in -as the proof parameter to the verification functions. - -For example: - -```go -timestampedSignatureData := &solomachine.TimestampedSignatureData{ - SignatureData: sigData, - Timestamp: solomachine.Time, -} - -proof, err := cdc.Marshal(timestampedSignatureData) -``` - -NOTE: At the end of this process, the sequence associated with the key needs to be updated. -The sequence must be incremented each time proof is generated. - -## Updates By Header - -An update by a header will only succeed if: - -- the header provided is parseable to solo machine header -- the header sequence matches the current sequence -- the header timestamp is greater than or equal to the consensus state timestamp -- the currently registered public key generated the proof - -If the update is successful: - -- the public key is updated -- the diversifier is updated -- the timestamp is updated -- the sequence is incremented by 1 -- the new consensus state is set in the client state - -## Updates By Proposal - -An update by a governance proposal will only succeed if: - -- the substitute provided is parseable to solo machine client state -- the new consensus state public key does not equal the current consensus state public key - -If the update is successful: - -- the subject client state is updated to the substitute client state -- the subject consensus state is updated to the substitute consensus state -- the client is unfrozen (if it was previously frozen) - -NOTE: Previously, `AllowUpdateAfterProposal` was used to signal the update/recovery options for the solo machine client. However, this has now been deprecated because a code migration can overwrite the client and consensus states regardless of the value of this parameter. If governance would vote to overwrite a client or consensus state, it is likely that governance would also be willing to perform a code migration to do the same. - -## Misbehaviour - -Misbehaviour handling will only succeed if: - -- the misbehaviour provided is parseable to solo machine misbehaviour -- the client is not already frozen -- the current public key signed over two unique data messages at the same sequence and diversifier. - -If the misbehaviour is successfully processed: - -- the client is frozen by setting the frozen sequence to the misbehaviour sequence - -NOTE: Misbehaviour processing is data processing order dependent. A misbehaving solo machine -could update to a new public key to prevent being frozen before misbehaviour is submitted. - -## Upgrades - -Upgrades to solo machine light clients are not supported since an entirely different type of -public key can be set using normal client updates. diff --git a/docs/docs/03-light-clients/03-solomachine/03-state.md b/docs/docs/03-light-clients/03-solomachine/03-state.md deleted file mode 100644 index 90d017473c3..00000000000 --- a/docs/docs/03-light-clients/03-solomachine/03-state.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: State -sidebar_label: State -sidebar_position: 3 -slug: /ibc/light-clients/solomachine/state ---- - - -# State - -The solo machine light client will only store consensus states for each update by a header -or a governance proposal. The latest client state is also maintained in the store. diff --git a/docs/docs/03-light-clients/03-solomachine/04-state_transitions.md b/docs/docs/03-light-clients/03-solomachine/04-state_transitions.md deleted file mode 100644 index 22a456fcc0e..00000000000 --- a/docs/docs/03-light-clients/03-solomachine/04-state_transitions.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: State Transitions -sidebar_label: State Transitions -sidebar_position: 4 -slug: /ibc/light-clients/solomachine/state_transitions ---- - - -# State Transitions - -## Client State Verification Functions - -Successful state verification by a solo machine light client will result in: - -- the sequence being incremented by 1. - -## Update By Header - -A successful update of a solo machine light client by a header will result in: - -- the public key being updated to the new public key provided by the header. -- the diversifier being updated to the new diviersifier provided by the header. -- the timestamp being updated to the new timestamp provided by the header. -- the sequence being incremented by 1 -- the consensus state being updated (consensus state stores the public key, diversifier, and timestamp) - -## Update By Governance Proposal - -A successful update of a solo machine light client by a governance proposal will result in: - -- the client state being updated to the substitute client state -- the consensus state being updated to the substitute consensus state (consensus state stores the public key, diversifier, and timestamp) -- the frozen sequence being set to zero (client is unfrozen if it was previously frozen). - -## Upgrade - -Client udgrades are not supported for the solo machine light client. No state transition occurs. - -## Misbehaviour - -Successful misbehaviour processing of a solo machine light client will result in: - -- the frozen sequence being set to the sequence the misbehaviour occurred at diff --git a/docs/docs/03-light-clients/03-solomachine/_category_.json b/docs/docs/03-light-clients/03-solomachine/_category_.json deleted file mode 100644 index de0a6927408..00000000000 --- a/docs/docs/03-light-clients/03-solomachine/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Solomachine", - "position": 3, - "link": null -} \ No newline at end of file diff --git a/docs/docs/03-light-clients/04-wasm/01-overview.md b/docs/docs/03-light-clients/04-wasm/01-overview.md deleted file mode 100644 index 3214ca775d3..00000000000 --- a/docs/docs/03-light-clients/04-wasm/01-overview.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /ibc/light-clients/wasm/overview ---- - -# `08-wasm` - -## Overview - -Learn about the `08-wasm` light client proxy module. {synopsis} - -### Context - -Traditionally, light clients used by ibc-go have been implemented only in Go, and since ibc-go v7 (with the release of the 02-client refactor), they are [first-class Cosmos SDK modules](../../../architecture/adr-010-light-clients-as-sdk-modules.md). This means that updating existing light client implementations or adding support for new light clients is a multi-step, time-consuming process involving on-chain governance: it is necessary to modify the codebase of ibc-go (if the light client is part of its codebase), re-build chains' binaries, pass a governance proposal and have validators upgrade their nodes. - -### Motivation - -To break the limitation of being able to write light client implementations only in Go, the `08-wasm` adds support to run light clients written in a Wasm-compilable language. The light client byte code implements the entry points of a [CosmWasm](https://docs.cosmwasm.com/docs/) smart contract, and runs inside a Wasm VM. The `08-wasm` module exposes a proxy light client interface that routes incoming messages to the appropriate handler function, inside the Wasm VM, for execution. - -Adding a new light client to a chain is just as simple as submitting a governance proposal with the message that stores the byte code of the light client contract. No coordinated upgrade is needed. When the governance proposal passes and the message is executed, the contract is ready to be instantiated upon receiving a relayer-submitted `MsgCreateClient`. The process of creating a Wasm light client is the same as with a regular light client implemented in Go. - -### Use cases - -- Development of light clients for non-Cosmos ecosystem chains: state machines in other ecosystems are, in many cases, implemented in Rust, and thus there are probably libraries used in their light client implementations for which there is no equivalent in Go. This makes the development of a light client in Go very difficult, but relatively simple to do it in Rust. Therefore, writing a CosmWasm smart contract in Rust that implements the light client algorithm becomes a lower effort. diff --git a/docs/docs/03-light-clients/04-wasm/02-concepts.md b/docs/docs/03-light-clients/04-wasm/02-concepts.md deleted file mode 100644 index 49c1c548975..00000000000 --- a/docs/docs/03-light-clients/04-wasm/02-concepts.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -title: Concepts -sidebar_label: Concepts -sidebar_position: 2 -slug: /ibc/light-clients/wasm/concepts ---- - -# Concepts - -Learn about the differences between a proxy light client and a Wasm light client. {synopsis} - -## Proxy light client - -The `08-wasm` module is not a regular light client in the same sense as, for example, the 07-tendermint light client. `08-wasm` is instead a *proxy* light client module, and this means that the module acts a proxy to the actual implementations of light clients. The module will act as a wrapper for the actual light clients uploaded as Wasm byte code and will delegate all operations to them (i.e. `08-wasm` just passes through the requests to the Wasm light clients). Still, the `08-wasm` module implements all the required interfaces necessary to integrate with core IBC, so that 02-client can call into it as it would for any other light client module. These interfaces are `ClientState`, `ConsensusState` and `ClientMessage`, and we will describe them in the context of `08-wasm` in the following sections. For more information about this set of interfaces, please read section [Overview of the light client module developer guide](../01-developer-guide/01-overview.md#overview). - -### `ClientState` - -The `08-wasm`'s `ClientState` data structure contains three fields: - -- `Data` contains the bytes of the Protobuf-encoded client state of the underlying light client implemented as a Wasm contract. For example, if the Wasm light client contract implements the GRANDPA light client algorithm, then `Data` will contain the bytes for a [GRANDPA client state](https://github.com/ComposableFi/composable-ibc/blob/02ce69e2843e7986febdcf795f69a757ce569272/light-clients/ics10-grandpa/src/proto/grandpa.proto#L35-L60). -- `CodeHash` is the sha256 hash of the Wasm contract's byte code. This hash is used as an identifier to call the right contract. -- `LatestHeight` is the latest height of the counterparty state machine (i.e. the height of the blockchain), whose consensus state the light client tracks. - -```go -type ClientState struct { - // bytes encoding the client state of the underlying - // light client implemented as a Wasm contract - Data []byte - // sha256 hash of Wasm contract byte code - CodeHash []byte - // latest height of the counterparty ledger - LatestHeight types.Height -} -``` - -See section [`ClientState` of the light client module developer guide](../01-developer-guide/01-overview.md#clientstate) for more information about the `ClientState` interface. - -### `ConsensusState` - -The `08-wasm`'s `ConsensusState` data structure maintains one field: - -- `Data` contains the bytes of the Protobuf-encoded consensus state of the underlying light client implemented as a Wasm contract. For example, if the Wasm light client contract implements the GRANDPA light client algorithm, then `Data` will contain the bytes for a [GRANDPA consensus state](https://github.com/ComposableFi/composable-ibc/blob/02ce69e2843e7986febdcf795f69a757ce569272/light-clients/ics10-grandpa/src/proto/grandpa.proto#L87-L94). - -```go -type ConsensusState struct { - // bytes encoding the consensus state of the underlying light client - // implemented as a Wasm contract. - Data []byte -} -``` - -See section [`ConsensusState` of the light client module developer guide](../01-developer-guide/01-overview.md#consensusstate) for more information about the `ConsensusState` interface. - -### `ClientMessage` - -`ClientMessage` is used for performing updates to a `ClientState` stored on chain. The `08-wasm`'s `ClientMessage` data structure maintains one field: - -- `Data` contains the bytes of the Protobuf-encoded header(s) or misbehaviour for the underlying light client implemented as a Wasm contract. For example, if the Wasm light client contract implements the GRANDPA light client algorithm, then `Data` will contain the bytes of either [header](https://github.com/ComposableFi/composable-ibc/blob/02ce69e2843e7986febdcf795f69a757ce569272/light-clients/ics10-grandpa/src/proto/grandpa.proto#L96-L104) or [misbehaviour](https://github.com/ComposableFi/composable-ibc/blob/02ce69e2843e7986febdcf795f69a757ce569272/light-clients/ics10-grandpa/src/proto/grandpa.proto#L106-L112) for a GRANDPA light client. - -```go -type ClientMessage struct { - // bytes encoding the header(s) or misbehaviour for the underlying light client - // implemented as a Wasm contract. - Data []byte -} -``` - -See section [`ClientMessage` of the light client module developer guide](../01-developer-guide/01-overview.md#clientmessage) for more information about the `ClientMessage` interface. - -## Wasm light client - -The actual light client can be implemented in any language that compiles to Wasm and implements the interfaces of a [CosmWasm](https://docs.cosmwasm.com/docs/) contract. Even though in theory other languages could be used, in practice (at least for the time being) the most suitable language to use would be Rust, since there is already good support for it for developing CosmWasm smart contracts. - -At the moment of writing there are two contracts available: one for [Tendermint](https://github.com/ComposableFi/composable-ibc/tree/master/light-clients/ics07-tendermint-cw) and one [GRANDPA](https://github.com/ComposableFi/composable-ibc/tree/master/light-clients/ics10-grandpa-cw) (which is being used in production in [Composable Finance's Centauri bridge](https://github.com/ComposableFi/composable-ibc)). And there are others in development (e.g. for Near). diff --git a/docs/docs/03-light-clients/04-wasm/03-integration.md b/docs/docs/03-light-clients/04-wasm/03-integration.md deleted file mode 100644 index 2ed9b4d301d..00000000000 --- a/docs/docs/03-light-clients/04-wasm/03-integration.md +++ /dev/null @@ -1,280 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 3 -slug: /ibc/light-clients/wasm/integration ---- - -# Integration - -Learn how to integrate the `08-wasm` module in a chain binary and about the recommended approaches depending on whether the [`x/wasm` module](https://github.com/CosmWasm/wasmd/tree/main/x/wasm) is already used in the chain. The following document only applies for Cosmos SDK chains. {synopsis} - -## `app.go` setup - -The sample code below shows the relevant integration points in `app.go` required to setup the `08-wasm` module in a chain binary. Since `08-wasm` is a light client module itself, please check out as well the section [Integrating light clients](../../01-ibc/02-integration.md#integrating-light-clients) for more information: - -```go -// app.go -import ( - ... - "github.com/cosmos/cosmos-sdk/runtime" - - cmtos "github.com/cometbft/cometbft/libs/os" - - wasm "github.com/cosmos/ibc-go/modules/light-clients/08-wasm" - wasmkeeper "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper" - wasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" - ... -) - -... - -// Register the AppModule for the 08-wasm module -ModuleBasics = module.NewBasicManager( - ... - wasm.AppModuleBasic{}, - ... -) - -// Add 08-wasm Keeper -type SimApp struct { - ... - WasmClientKeeper wasmkeeper.Keeper - ... -} - -func NewSimApp( - logger log.Logger, - db dbm.DB, - traceStore io.Writer, - loadLatest bool, - appOpts servertypes.AppOptions, - baseAppOptions ...func(*baseapp.BaseApp), -) *SimApp { - ... - keys := sdk.NewKVStoreKeys( - ... - wasmtypes.StoreKey, - ) - - // Instantiate 08-wasm's keeper - // This sample code uses a constructor function that - // accepts a pointer to an existing instance of Wasm VM. - // This is the recommended approach when the chain - // also uses `x/wasm`, and then the Wasm VM instance - // can be shared. - // This sample code uses also an implementation of the - // wasmvm.Querier interface (querier). If nil is passed - // instead, then a default querier will be used that - // returns an error for all query types. - // See the section below for more information. - app.WasmClientKeeper = wasmkeeper.NewKeeperWithVM( - appCodec, - runtime.NewKVStoreService(keys[wasmtypes.StoreKey]), - app.IBCKeeper.ClientKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), - wasmVM, - querier, - ) - app.ModuleManager = module.NewManager( - // SDK app modules - ... - wasm.NewAppModule(app.WasmClientKeeper), - ) - app.ModuleManager.SetOrderBeginBlockers( - ... - wasmtypes.ModuleName, - ... - ) - app.ModuleManager.SetOrderEndBlockers( - ... - wasmtypes.ModuleName, - ... - ) - genesisModuleOrder := []string{ - ... - wasmtypes.ModuleName, - ... - } - app.ModuleManager.SetOrderInitGenesis(genesisModuleOrder...) - app.ModuleManager.SetOrderExportGenesis(genesisModuleOrder...) - ... - - // initialize BaseApp - app.SetInitChainer(app.InitChainer) - ... - - // must be before Loading version - if manager := app.SnapshotManager(); manager != nil { - err := manager.RegisterExtensions( - wasmkeeper.NewWasmSnapshotter(app.CommitMultiStore(), &app.WasmClientKeeper), - ) - if err != nil { - panic(fmt.Errorf("failed to register snapshot extension: %s", err)) - } - } - ... - - if loadLatest { - ... - - ctx := app.BaseApp.NewUncachedContext(true, cmtproto.Header{}) - - // Initialize pinned codes in wasmvm as they are not persisted there - if err := wasmkeeper.InitializePinnedCodes(ctx); err != nil { - cmtos.Exit(fmt.Sprintf("failed initialize pinned codes %s", err)) - } - } -} -``` - -## Keeper instantiation - -When it comes to instantiating `08-wasm`'s keeper there are two recommended ways of doing it. Choosing one or the other will depend on whether the chain already integrates [`x/wasm`](https://github.com/CosmWasm/wasmd/tree/main/x/wasm) or not. Both available constructor functions accept a querier parameter that should implement the [`Querier` interface of `wasmvm`](https://github.com/CosmWasm/wasmvm/blob/v2.0.0/types/queries.go#L37). If `nil` is provided, then a default querier implementation is used that returns error for any query type. - -### If `x/wasm` is present - -If the chain where the module is integrated uses `x/wasm` then we recommend that both `08-wasm` and `x/wasm` share the same Wasm VM instance. Having two separate Wasm VM instances is still possible, but care should be taken to make sure that both instances do not share the directory when the VM stores blobs and various caches, otherwise unexpected behaviour is likely to happen (from `x/wasm` v0.51 and `08-wasm` v0.2.0.0+ibc-go-v8.2-wasmvm-v2.0 this will be forbidden anyway, since wasmvm v2.0.0 and above will not allow two different Wasm VM instances to shared the same data folder). - -In order to share the Wasm VM instance please follow the guideline below. Please note that this requires `x/wasm` v0.41 or above. - -- Instantiate the Wasm VM in `app.go` with the parameters of your choice. -- [Create an `Option` with this Wasm VM instance](https://github.com/CosmWasm/wasmd/blob/db93d7b6c7bb6f4a340d74b96a02cec885729b59/x/wasm/keeper/options.go#L21-L25). -- Add the option created in the previous step to a slice and [pass it to the `x/wasm NewKeeper` constructor function](https://github.com/CosmWasm/wasmd/blob/db93d7b6c7bb6f4a340d74b96a02cec885729b59/x/wasm/keeper/keeper_cgo.go#L36). -- Pass the pointer to the Wasm VM instance to `08-wasm` [NewKeeperWithVM constructor function](https://github.com/cosmos/ibc-go/blob/c95c22f45cb217d27aca2665af9ac60b0d2f3a0c/modules/light-clients/08-wasm/keeper/keeper.go#L33-L38). - -The code to set this up would look something like this: - -```go -// app.go -import ( - ... - "github.com/cosmos/cosmos-sdk/runtime" - - wasmvm "github.com/CosmWasm/wasmvm/v2" - wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" - ... -) - -... - -// instantiate the Wasm VM with the chosen parameters -wasmer, err := wasmvm.NewVM( - dataDir, - availableCapabilities, - contractMemoryLimit, - contractDebugMode, - memoryCacheSize, -) -if err != nil { - panic(err) -} - -// create an Option slice (or append to an existing one) -// with the option to use a custom Wasm VM instance -wasmOpts = []wasmkeeper.Option{ - wasmkeeper.WithWasmEngine(wasmer), -} - -// the keeper will use the provided Wasm VM instance, -// instead of instantiating a new one -app.WasmKeeper = wasmkeeper.NewKeeper( - appCodec, - keys[wasmtypes.StoreKey], - app.AccountKeeper, - app.BankKeeper, - app.StakingKeeper, - distrkeeper.NewQuerier(app.DistrKeeper), - app.IBCFeeKeeper, // ISC4 Wrapper: fee IBC middleware - app.IBCKeeper.ChannelKeeper, - &app.IBCKeeper.PortKeeper, - scopedWasmKeeper, - app.TransferKeeper, - app.MsgServiceRouter(), - app.GRPCQueryRouter(), - wasmDir, - wasmConfig, - availableCapabilities, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), - wasmOpts..., -) - -// This sample code uses also an implementation of the -// wasmvm.Querier interface (querier). If nil is passed -// instead, then a default querier will be used that -// returns an error for all query types. -app.WasmClientKeeper = wasmkeeper.NewKeeperWithVM( - appCodec, - runtime.NewKVStoreService(keys[wasmtypes.StoreKey]), - app.IBCKeeper.ClientKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), - wasmer, // pass the Wasm VM instance to `08-wasm` keeper constructor - querier, -) -... -``` - -### If `x/wasm` is not present - -If the chain does not use [`x/wasm`](https://github.com/CosmWasm/wasmd/tree/main/x/wasm), even though it is still possible to use the method above from the previous section -(e.g. instantiating a Wasm VM in app.go an pass it to 08-wasm's [`NewKeeperWithVM` constructor function](https://github.com/cosmos/ibc-go/blob/c95c22f45cb217d27aca2665af9ac60b0d2f3a0c/modules/light-clients/08-wasm/keeper/keeper.go#L33-L38), since there would be no need in this case to share the Wasm VM instance with another module, you can use the [`NewKeeperWithConfig`` constructor function](https://github.com/cosmos/ibc-go/blob/c95c22f45cb217d27aca2665af9ac60b0d2f3a0c/modules/light-clients/08-wasm/keeper/keeper.go#L52-L57) and provide the Wasm VM configuration parameters of your choice instead. A Wasm VM instance will be created in`NewKeeperWithConfig`. The parameters that can set are: - -- `DataDir` is the [directory for Wasm blobs and various caches](https://github.com/CosmWasm/wasmvm/blob/v2.0.0/lib.go#L25). As an example, in `wasmd` this is set to the [`wasm` folder under the home directory](https://github.com/CosmWasm/wasmd/blob/36416def20effe47fb77f29f5ba35a003970fdba/app/app.go#L578). In the code snippet below we set this field to the `ibc_08-wasm_client_data` folder under the home directory. -- `SupportedCapabilities` is a [list of capabilities supported by the chain](https://github.com/CosmWasm/wasmvm/blob/v2.0.0/lib.go#L26). [`wasmd` sets this to all the available capabilities](https://github.com/CosmWasm/wasmd/blob/36416def20effe47fb77f29f5ba35a003970fdba/app/app.go#L586), but 08-wasm only requires `iterator`. -- `MemoryCacheSize` sets [the size in MiB of an in-memory cache for e.g. module caching](https://github.com/CosmWasm/wasmvm/blob/v2.0.0/lib.go#L29C16-L29C104). It is not consensus-critical and should be defined on a per-node basis, often in the range 100 to 1000 MB. [`wasmd` reads this value of](https://github.com/CosmWasm/wasmd/blob/36416def20effe47fb77f29f5ba35a003970fdba/app/app.go#L579). Default value is 256. -- `ContractDebugMode` is a [flag to enable/disable printing debug logs from the contract to STDOUT](https://github.com/CosmWasm/wasmvm/blob/v2.0.0/lib.go#L28). This should be false in production environments. Default value is false. - -Another configuration parameter of the Wasm VM is the contract memory limit (in MiB), which is [set to 32](https://github.com/cosmos/ibc-go/blob/c95c22f45cb217d27aca2665af9ac60b0d2f3a0c/modules/light-clients/08-wasm/types/config.go#L5), [following the example of `wasmd`](https://github.com/CosmWasm/wasmd/blob/36416def20effe47fb77f29f5ba35a003970fdba/x/wasm/keeper/keeper.go#L32-L34). This parameter is not configurable by users of `08-wasm`. - -The following sample code shows how the keeper would be constructed using this method: - -```go -// app.go -import ( - ... - "github.com/cosmos/cosmos-sdk/runtime" - - wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" - wasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" - ... -) -... - -// homePath is the path to the directory where the data -// directory for Wasm blobs and caches will be created -wasmConfig := ibcwasmtypes.WasmConfig{ - DataDir: filepath.Join(homePath, "ibc_08-wasm_client_data"), - SupportedCapabilities: []string{"iterator"}, - ContractDebugMode: false, -} -app.WasmClientKeeper = wasmkeeper.NewKeeperWithConfig( - appCodec, - runtime.NewKVStoreService(keys[wasmtypes.StoreKey]), - app.IBCKeeper.ClientKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), - wasmConfig, - querier -) -``` - -Check out also the [`WasmConfig` type definition](https://github.com/cosmos/ibc-go/blob/c95c22f45cb217d27aca2665af9ac60b0d2f3a0c/modules/light-clients/08-wasm/types/config.go#L7-L20) for more information on each of the configurable parameters. Some parameters allow node-level configurations. There is additionally the function [`DefaultWasmConfig`](https://github.com/cosmos/ibc-go/blob/6d8cee53a72524b7cf396d65f6c19fed45803321/modules/light-clients/08-wasm/types/config.go#L30) available that returns a configuration with the default values. - -## Updating `AllowedClients` - -In order to use the `08-wasm` module chains must update the [`AllowedClients` parameter in the 02-client submodule](https://github.com/cosmos/ibc-go/blob/main/proto/ibc/core/client/v1/client.proto#L103) of core IBC. This can be configured directly in the application upgrade handler with the sample code below: - -```go -params := clientKeeper.GetParams(ctx) -params.AllowedClients = append(params.AllowedClients, exported.Wasm) -clientKeeper.SetParams(ctx, params) -``` - -Or alternatively the parameter can be updated via a governance proposal (see at the bottom of section [`Creating clients`](../01-developer-guide/09-setup.md#creating-clients) for an example of how to do this). - -## Adding snapshot support - -In order to use the `08-wasm` module chains are required to register the `WasmSnapshotter` extension in the snapshot manager. This snapshotter takes care of persisting the external state, in the form of contract code, of the Wasm VM instance to disk when the chain is snapshotted. [This code](https://github.com/cosmos/ibc-go/blob/2bd29c08fd1fe50b461fc33a25735aa792dc896e/modules/light-clients/08-wasm/testing/simapp/app.go#L768-L776) should be placed in `NewSimApp` function in `app.go`: - -## Pin byte codes at start - -Wasm byte codes should be pinned to the WasmVM cache on every application start, therefore [this code](https://github.com/cosmos/ibc-go/blob/0ed221f687ffce75984bc57402fd678e07aa6cc5/modules/light-clients/08-wasm/testing/simapp/app.go#L821-L826) should be placed in `NewSimApp` function in `app.go`. diff --git a/docs/docs/03-light-clients/04-wasm/04-messages.md b/docs/docs/03-light-clients/04-wasm/04-messages.md deleted file mode 100644 index 911b54cae70..00000000000 --- a/docs/docs/03-light-clients/04-wasm/04-messages.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -title: Messages -sidebar_label: Messages -sidebar_position: 4 -slug: /ibc/light-clients/wasm/messages ---- - -# Messages - -## `MsgStoreCode` - -Uploading the Wasm light client contract to the Wasm VM storage is achieved by means of `MsgStoreCode`: - -```go -type MsgStoreCode struct { - // signer address - Signer string - // wasm byte code of light client contract. It can be raw or gzip compressed - WasmByteCode []byte -} -``` - -This message is expected to fail if: - -- `Signer` is an invalid Bech32 address, or it does not match the designated authority address. -- `WasmByteCode` is empty or it exceeds the maximum size, currently set to 3MB. - -Only light client contracts stored using `MsgStoreCode` are allowed to be instantiated. An attempt to create a light client from contracts uploaded via other means (e.g. through `x/wasm` if the module shares the same Wasm VM instance with 08-wasm) will fail. Due to the idempotent nature of the Wasm VM's `StoreCode` function, it is possible to store the same byte code multiple times. - -When execution of `MsgStoreCode` succeeds, the code hash of the contract (i.e. the sha256 hash of the contract's byte code) is stored in an allow list. When a relayer submits [`MsgCreateClient`](https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/core/client/v1/tx.proto#L25-L37) with 08-wasm's `ClientState`, the client state includes the code hash of the Wasm byte code that should be called. Then 02-client calls [08-wasm's implementation of `Initialize` function](https://github.com/cosmos/ibc-go/blob/v7.2.0/modules/core/02-client/keeper/client.go#L34) (which is an interface function part of `ClientState`), and it will check that the code hash in the client state matches one of the code hashes in the allow list. If a match is found, the light client is initialized; otherwise, the transaction is aborted. - -## `MsgMigrateContract` - -Migrating a contract to a new Wasm byte code is achieved by means of `MsgMigrateContract`: - -```go -type MsgMigrateContract struct { - // signer address - Signer string - // the client id of the contract - ClientId string - // the SHA-256 hash of the new wasm byte code for the contract - CodeHash []byte - // the json-encoded migrate msg to be passed to the contract on migration - Msg []byte -} -``` - -This message is expected to fail if: - -- `Signer` is an invalid Bech32 address, or it does not match the designated authority address. -- `ClientId` is not a valid identifier prefixed by `08-wasm`. -- `CodeHash` is not exactly 32 bytes long or it is not found in the list of allowed code hashes (a new code hash is added to the list when executing `MsgStoreCode`), or it matches the current code hash of the contract. - -When a Wasm light client contract is migrated to a new Wasm byte code the code hash for the contract will be updated with the new code hash. - -## `MsgRemoveCodeHash` - -Removing a code hash from the list of allowed code hashes is achieved by means of `MsgRemoveCodeHash`: - -```go -type MsgRemoveCodeHash struct { - // signer address - Signer string - // code hash to be removed from the store - CodeHash []byte -} -``` - -This message is expected to fail if: - -- `Signer` is an invalid Bech32 address, or it does not match the designated authority address. -- `CodeHash` is not exactly 32 bytes long or it is not found in the list of allowed code hashes (a new code hash is added to the list when executing `MsgStoreCode`). - -When a code hash is removed from the list of allowed code hashes, then the corresponding Wasm byte code will not be available for instantiation in [08-wasm's implementation of `Initialize` function](https://github.com/cosmos/ibc-go/blob/v7.2.0/modules/core/02-client/keeper/client.go#L34). diff --git a/docs/docs/03-light-clients/04-wasm/05-governance.md b/docs/docs/03-light-clients/04-wasm/05-governance.md deleted file mode 100644 index dd59809b7cc..00000000000 --- a/docs/docs/03-light-clients/04-wasm/05-governance.md +++ /dev/null @@ -1,126 +0,0 @@ ---- -title: Governance -sidebar_label: Governance -sidebar_position: 5 -slug: /ibc/light-clients/wasm/governance ---- - -# Governance - -Learn how to upload Wasm light client byte code on a chain, and how to migrate an existing Wasm light client contract. {synopsis} - -## Setting an authority - -Both the storage of Wasm light client byte code as well as the migration of an existing Wasm light client contract are permissioned (i.e. only allowed to an authority such as governance). The designated authority is specified when instantiating `08-wasm`'s keeper: both [`NewKeeperWithVM`](https://github.com/cosmos/ibc-go/blob/c95c22f45cb217d27aca2665af9ac60b0d2f3a0c/modules/light-clients/08-wasm/keeper/keeper.go#L33-L38) and [`NewKeeperWithConfig`](https://github.com/cosmos/ibc-go/blob/c95c22f45cb217d27aca2665af9ac60b0d2f3a0c/modules/light-clients/08-wasm/keeper/keeper.go#L52-L57) constructor functions accept an `authority` argument that must be the address of the authorized actor. For example, in `app.go`, when instantiating the keeper, you can pass the address of the governance module: - -```go -// app.go -import ( - ... - "github.com/cosmos/cosmos-sdk/runtime" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - - wasmkeeper "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper" - wasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" - ... -) - -// app.go -app.WasmClientKeeper = wasmkeeper.NewKeeperWithVM( - appCodec, - runtime.NewKVStoreService(keys[wasmtypes.StoreKey]), - app.IBCKeeper.ClientKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), // authority - wasmVM, - querier, -) -``` - -## Storing new Wasm light client byte code - - If governance is the allowed authority, the governance v1 proposal that needs to be submitted to upload a new light client contract should contain the message [`MsgStoreCode`](https://github.com/cosmos/ibc-go/blob/f822b4fa7932a657420aba219c563e06c4465221/proto/ibc/lightclients/wasm/v1/tx.proto#L16-L23) with the base64-encoded byte code of the Wasm contract. Use the following CLI command and JSON as an example: - -```shell -simd tx gov submit-proposal --from -``` - -where `proposal.json` contains: - -```json -{ - "title": "Upload IBC Wasm light client", - "summary": "Upload wasm client", - "messages": [ - { - "@type": "/ibc.lightclients.wasm.v1.MsgStoreCode", - "signer": "cosmos1...", // the authority address (e.g. the gov module account address) - "wasm_byte_code": "YWJ...PUB+" // standard base64 encoding of the Wasm contract byte code - } - ], - "metadata": "AQ==", - "deposit": "100stake" -} -``` - -To learn more about the `submit-proposal` CLI command, please check out [the relevant section in Cosmos SDK documentation](https://docs.cosmos.network/main/modules/gov#submit-proposal). - -Alternatively, the process of submitting the proposal may be simpler if you use the CLI command `store-code`. This CLI command accepts as argument the file of the Wasm light client contract and takes care of constructing the proposal message with `MsgStoreCode` and broadcasting it. See section [`store-code`](./08-client.md#store-code) for more information. - -## Migrating an existing Wasm light client contract - -If governance is the allowed authority, the governance v1 proposal that needs to be submitted to migrate an existing new Wasm light client contract should contain the message [`MsgMigrateContract`](https://github.com/cosmos/ibc-go/blob/729cb090951b1e996427b2258cf72c49787b885a/proto/ibc/lightclients/wasm/v1/tx.proto#L51-L63) with the code hash of the Wasm byte code to migrate to. Use the following CLI command and JSON as an example: - -```shell -simd tx gov submit-proposal --from -``` - -where `proposal.json` contains: - -```json -{ - "title": "Migrate IBC Wasm light client", - "summary": "Migrate wasm client", - "messages": [ - { - "@type": "/ibc.lightclients.wasm.v1.MsgMigrateContract", - "signer": "cosmos1...", // the authority address (e.g. the gov module account address) - "client_id": "08-wasm-1", // client identifier of the Wasm light client contract that will be migrated - "new_code_hash": "a8ad...4dc0", // SHA-256 hash of the Wasm byte code to migrate to, previously stored with MsgStoreCode - "msg": "{}" // JSON-encoded message to be passed to the contract on migration - } - ], - "metadata": "AQ==", - "deposit": "100stake" -} -``` - -To learn more about the `submit-proposal` CLI command, please check out [the relevant section in Cosmos SDK documentation](https://docs.cosmos.network/main/modules/gov#submit-proposal). - -## Removing an existing code hash - -If governance is the allowed authority, the governance v1 proposal that needs to be submitted to remove a specific code hash from the -list of allowed code hashes should contain the message [`MsgRemoveCodeHash`](https://github.com/cosmos/ibc-go/blob/729cb090951b1e996427b2258cf72c49787b885a/proto/ibc/lightclients/wasm/v1/tx.proto#L38-L46) with the code hash (of a corresponding Wasm byte code). Use the following CLI command and JSON as an example: - -```shell -simd tx gov submit-proposal --from -``` - -where `proposal.json` contains: - -```json -{ - "title": "Remove code hash of Wasm light client byte code", - "summary": "Remove code hash", - "messages": [ - { - "@type": "/ibc.lightclients.wasm.v1.MsgRemoveCodeHash", - "signer": "cosmos1...", // the authority address (e.g. the gov module account address) - "code_hash": "a8ad...4dc0", // SHA-256 hash of the Wasm byte code that should be removed from the list of allowed code hashes - } - ], - "metadata": "AQ==", - "deposit": "100stake" -} -``` - -To learn more about the `submit-proposal` CLI command, please check out [the relevant section in Cosmos SDK documentation](https://docs.cosmos.network/main/modules/gov#submit-proposal). diff --git a/docs/docs/03-light-clients/04-wasm/06-events.md b/docs/docs/03-light-clients/04-wasm/06-events.md deleted file mode 100644 index 58277f3f2ee..00000000000 --- a/docs/docs/03-light-clients/04-wasm/06-events.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: Events -sidebar_label: Events -sidebar_position: 6 -slug: /ibc/light-clients/wasm/events ---- - -# Events - -The `08-wasm` module emits the following events: - -## `MsgStoreCode` - -| Type | Attribute Key | Attribute Value | -|------------------|----------------|------------------------| -| store_wasm_code | wasm_code_hash | {hex.Encode(codeHash)} | -| message | module | 08-wasm | - -## `MsgMigrateContract` - -| Type | Attribute Key | Attribute Value | -|------------------|----------------|---------------------------| -| migrate_contract | client_id | {clientId} | -| migrate_contract | wasm_code_hash | {hex.Encode(codeHash)} | -| migrate_contract | new_code_hash | {hex.Encode(newCodeHash)} | -| message | module | 08-wasm | diff --git a/docs/docs/03-light-clients/04-wasm/07-contracts.md b/docs/docs/03-light-clients/04-wasm/07-contracts.md deleted file mode 100644 index 9bfa6ce7ab8..00000000000 --- a/docs/docs/03-light-clients/04-wasm/07-contracts.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -title: Contracts -sidebar_label: Contracts -sidebar_position: 7 -slug: /ibc/light-clients/wasm/contracts ---- - -# Contracts - -Learn about the expected behaviour of Wasm light client contracts and the between with `08-wasm`. {synopsis} - -## API - -The `08-wasm` light client proxy performs calls to the Wasm light client via the Wasm VM. The calls require as input JSON-encoded payload messages that fall in the three categories described in the next sections. - -## `InstantiateMessage` - -This is the message sent to the contract's `instantiate` entry point. It contains the bytes of the protobuf-encoded client and consensus states of the underlying light client, both provided in [`MsgCreateClient`](https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/core/client/v1/tx.proto#L25-L37). Please note that the bytes contained within the JSON message are represented as base64-encoded strings. - -```go -type InstantiateMessage struct { - ClientState []byte `json:"client_state"` - ConsensusState []byte `json:"consensus_state"` - Checksum []byte `json:"checksum" -} -``` - -The Wasm light client contract is expected to store the client and consensus state in the corresponding keys of the client-prefixed store. - -## `QueryMsg` - -`QueryMsg` acts as a discriminated union type that is used to encode the messages that are sent to the contract's `query` entry point. Only one of the fields of the type should be set at a time, so that the other fields are omitted in the encoded JSON and the payload can be correctly translated to the corresponding element of the enumeration in Rust. - -```go -type QueryMsg struct { - Status *StatusMsg `json:"status,omitempty"` - ExportMetadata *ExportMetadataMsg `json:"export_metadata,omitempty"` - TimestampAtHeight *TimestampAtHeightMsg `json:"timestamp_at_height,omitempty"` - VerifyClientMessage *VerifyClientMessageMsg `json:"verify_client_message,omitempty"` - CheckForMisbehaviour *CheckForMisbehaviourMsg `json:"check_for_misbehaviour,omitempty"` -} -``` - -```rust -#[cw_serde] -pub enum QueryMsg { - Status(StatusMsg), - ExportMetadata(ExportMetadataMsg), - TimestampAtHeight(TimestampAtHeightMsg), - VerifyClientMessage(VerifyClientMessageRaw), - CheckForMisbehaviour(CheckForMisbehaviourMsgRaw), -} -``` - -To learn what it is expected from the Wasm light client contract when processing each message, please read the corresponsing section of the [Light client developer guide](../01-developer-guide/01-overview.md): - -- For `StatusMsg`, see the section [`Status` method](../01-developer-guide/02-client-state.md#status-method). -- For `ExportMetadataMsg`, see the section [Genesis metadata](../01-developer-guide/08-genesis.md#genesis-metadata). -- For `TimestampAtHeightMsg`, see the section [`GetTimestampAtHeight` method](../01-developer-guide/02-client-state.md#gettimestampatheight-method). -- For `VerifyClientMessageMsg`, see the section [`VerifyClientMessage`](../01-developer-guide/04-updates-and-misbehaviour.md#verifyclientmessage). -- For `CheckForMisbehaviourMsg`, see the section [`CheckForMisbehaviour` method](../01-developer-guide/02-client-state.md#checkformisbehaviour-method). - -## `SudoMsg` - -`SudoMsg` acts as a discriminated union type that is used to encode the messages that are sent to the contract's `sudo` entry point. Only one of the fields of the type should be set at a time, so that the other fields are omitted in the encoded JSON and the payload can be correctly translated to the corresponding element of the enumeration in Rust. - -The `sudo` entry point is able to perform state-changing writes in the client-prefixed store. - -```go -type SudoMsg struct { - UpdateState *UpdateStateMsg `json:"update_state,omitempty"` - UpdateStateOnMisbehaviour *UpdateStateOnMisbehaviourMsg `json:"update_state_on_misbehaviour,omitempty"` - VerifyUpgradeAndUpdateState *VerifyUpgradeAndUpdateStateMsg `json:"verify_upgrade_and_update_state,omitempty"` - VerifyMembership *VerifyMembershipMsg `json:"verify_membership,omitempty"` - VerifyNonMembership *VerifyNonMembershipMsg `json:"verify_non_membership,omitempty"` - MigrateClientStore *MigrateClientStoreMsg `json:"migrate_client_store,omitempty"` -} -``` - -```rust -#[cw_serde] -pub enum SudoMsg { - UpdateState(UpdateStateMsgRaw), - UpdateStateOnMisbehaviour(UpdateStateOnMisbehaviourMsgRaw), - VerifyUpgradeAndUpdateState(VerifyUpgradeAndUpdateStateMsgRaw), - VerifyMembership(VerifyMembershipMsgRaw), - VerifyNonMembership(VerifyNonMembershipMsgRaw), - MigrateClientStore(MigrateClientStoreMsgRaw), -} -``` - -To learn what it is expected from the Wasm light client contract when processing each message, please read the corresponsing section of the [Light client developer guide](../01-developer-guide/01-overview.md): - -- For `UpdateStateMsg`, see the section [`UpdateState`](../01-developer-guide/04-updates-and-misbehaviour.md#updatestate). -- For `UpdateStateOnMisbehaviourMsg`, see the section [`UpdateStateOnMisbehaviour`](../01-developer-guide/04-updates-and-misbehaviour.md#updatestateonmisbehaviour). -- For `VerifyUpgradeAndUpdateStateMsg`, see the section [`GetTimestampAtHeight` method](../01-developer-guide/05-upgrades.md#implementing-verifyupgradeandupdatestate). -- For `VerifyMembershipMsg`, see the section [`VerifyMembership` method](../01-developer-guide/02-client-state.md#verifymembership-method). -- For `VerifyNonMembershipMsg`, see the section [`VerifyNonMembership` method](../01-developer-guide/02-client-state.md#verifynonmembership-method). -- For `MigrateClientStoreMsg`, see the section [Implementing `CheckSubstituteAndUpdateState`](../01-developer-guide/07-proposals.md#implementing-checksubstituteandupdatestate). - -### Migration - -The `08-wasm` proxy light client exposes the `MigrateContract` RPC endpoint that can be used to migrate a given Wasm light client contract (specified by the client identifier) to a new Wasm byte code (specified by the hash of the byte code). The expected use case for this RPC endpoint is to enable contracts to migrate to new byte code in case the current byte code is found to have a bug or vulnerability. The Wasm byte code that contracts are migrated have to be uploaded beforehand using `MsgStoreCode` and must implement the `migrate` entry point. See section[`MsgMigrateContract`](./04-messages.md#msgmigratecontract) for information about the request messsage for this RPC endpoint. - -## Expected behaviour - -The `08-wasm` proxy light client modules expects the following behaviour from the Wasm light client contracts when executing messages that perform state-changing writes: - -- The contract must not delete the client state from the store. -- The contract must not change the client state to a client state of another type. -- The contract must not change the code hash in the client state. - -Any violation of these rules will result in an error returned from `08-wasm` that will abort the transaction. diff --git a/docs/docs/03-light-clients/04-wasm/08-client.md b/docs/docs/03-light-clients/04-wasm/08-client.md deleted file mode 100644 index 0cb4170e329..00000000000 --- a/docs/docs/03-light-clients/04-wasm/08-client.md +++ /dev/null @@ -1,151 +0,0 @@ ---- -title: Client -sidebar_label: Client -sidebar_position: 7 -slug: /ibc/light-clients/wasm/client ---- - -# Client - -## CLI - -A user can query and interact with the `08-wasm` module using the CLI. Use the `--help` flag to discover the available commands: - -### Transactions - -The `tx` commands allow users to interact with the `08-wasm` submodule. - -```shell -simd tx ibc-wasm --help -``` - -#### `store-code` - -The `store-code` command allows users to submit a governance proposal with a `MsgStoreCode` to store the byte code of a Wasm light client contract. - -```shell -simd tx ibc-wasm store-code [path/to/wasm-file] [flags] -``` - -`path/to/wasm-file` is the path to the `.wasm` or `.wasm.gz` file. - -#### `migrate-contract` - -The `migrate-contract` command allows users to broadcast a transaction with a `MsgMigrateContract` to migrate the contract for a given light client to a new byte code denoted by the given checksum. - -```shell -simd tx ibc-wasm migrate-contract [client-id] [checksum] [migrate-msg] -``` - -The migrate message must not be emptied and is expected to be a JSON-encoded string. - -### Query - -The `query` commands allow users to query `08-wasm` state. - -```shell -simd query ibc-wasm --help -``` - -#### `code-hashes` - -The `code-hashes` command allows users to query the list of code hashes of Wasm light client contracts stored in the Wasm VM via the `MsgStoreCode`. The code hashes are hex-encoded. - -```shell -simd query ibc-wasm code-hashes [flags] -``` - -Example: - -```shell -simd query ibc-wasm code-hashes -``` - -Example Output: - -```shell -code_hashes: -- c64f75091a6195b036f472cd8c9f19a56780b9eac3c3de7ced0ec2e29e985b64 -pagination: - next_key: null - total: "1" -``` - -#### `code` - -The `code` command allows users to query the Wasm byte code of a light client contract given the provided input code hash. - -```shell -./simd q ibc-wasm code -``` - -Example: - -```shell -simd query ibc-wasm code c64f75091a6195b036f472cd8c9f19a56780b9eac3c3de7ced0ec2e29e985b64 -``` - -Example Output: - -```shell -code: AGFzb...AqBBE= -``` - -## gRPC - -A user can query the `08-wasm` module using gRPC endpoints. - -### `CodeHashes` - -The `CodeHashes` endpoint allows users to query the list of code hashes of Wasm light client contracts stored in the Wasm VM via the `MsgStoreCode`. - -```shell -ibc.lightclients.wasm.v1.Query/CodeHashes -``` - -Example: - -```shell -grpcurl -plaintext \ - -d '{}' \ - localhost:9090 \ - ibc.lightclients.wasm.v1.Query/CodeHashes -``` - -Example output: - -```shell -{ - "codeIds": [ - "c64f75091a6195b036f472cd8c9f19a56780b9eac3c3de7ced0ec2e29e985b64" - ], - "pagination": { - "total": "1" - } -} -``` - -### `Code` - -The `Code` endpoint allows users to query the Wasm byte code of a light client contract given the provided input code hash. - -```shell -ibc.lightclients.wasm.v1.Query/Code -``` - -Example: - -```shell -grpcurl -plaintext \ - -d '{"code_hash":"c64f75091a6195b036f472cd8c9f19a56780b9eac3c3de7ced0ec2e29e985b64"}' \ - localhost:9090 \ - ibc.lightclients.wasm.v1.Query/Code -``` - -Example output: - -```shell -{ - "code": AGFzb...AqBBE= -} -``` diff --git a/docs/docs/03-light-clients/04-wasm/09-migrations.md b/docs/docs/03-light-clients/04-wasm/09-migrations.md deleted file mode 100644 index ff4800e74ec..00000000000 --- a/docs/docs/03-light-clients/04-wasm/09-migrations.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -title: Migrations -sidebar_label: Migrations -sidebar_position: 9 -slug: /ibc/light-clients/wasm/migrations ---- - -# Migrations - -This guide provides instructions for migrating 08-wasm versions. - -## From ibc-go v7.3.x to ibc-go v8.0.x - -### Chains - -In the 08-wasm versions compatible with ibc-go v7.3.x and above from the v7 release line, the checksums of the uploaded Wasm bytecodes are all stored under a single key. From ibc-go v8.0.x the checksums are stored using [`collections.KeySet`](https://docs.cosmos.network/v0.50/build/packages/collections#keyset), whose full functionality became available in Cosmos SDK v0.50. There is therefore an [automatic migration handler](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/module.go#L115-L118) configured in the 08-wasm module to migrate the stored checksums to `collections.KeySet`. - -## From v0.1.0+ibc-go-v8.0-wasmvm-v1.5 to v0.2.0-ibc-go-v8.2-wasmvm-v2.0 - -The `WasmEngine` interface has been updated to reflect changes in the function signatures of Wasm VM: - -```diff -type WasmEngine interface { -- StoreCode(code wasmvm.WasmCode) (wasmvm.Checksum, error) -+ StoreCode(code wasmvm.WasmCode, gasLimit uint64) (wasmvmtypes.Checksum, uint64, error) - - StoreCodeUnchecked(code wasmvm.WasmCode) (wasmvm.Checksum, error) - - Instantiate( - checksum wasmvm.Checksum, - env wasmvmtypes.Env, - info wasmvmtypes.MessageInfo, - initMsg []byte, - store wasmvm.KVStore, - goapi wasmvm.GoAPI, - querier wasmvm.Querier, - gasMeter wasmvm.GasMeter, - gasLimit uint64, - deserCost wasmvmtypes.UFraction, -- ) (*wasmvmtypes.Response, uint64, error) -+ ) (*wasmvmtypes.ContractResult, uint64, error) - - Query( - checksum wasmvm.Checksum, - env wasmvmtypes.Env, - queryMsg []byte, - store wasmvm.KVStore, - goapi wasmvm.GoAPI, - querier wasmvm.Querier, - gasMeter wasmvm.GasMeter, - gasLimit uint64, - deserCost wasmvmtypes.UFraction, -- ) ([]byte, uint64, error) -+ ) (*wasmvmtypes.QueryResult, uint64, error) - - Migrate( - checksum wasmvm.Checksum, - env wasmvmtypes.Env, - migrateMsg []byte, - store wasmvm.KVStore, - goapi wasmvm.GoAPI, - querier wasmvm.Querier, - gasMeter wasmvm.GasMeter, - gasLimit uint64, - deserCost wasmvmtypes.UFraction, -- ) (*wasmvmtypes.Response, uint64, error) -+ ) (*wasmvmtypes.ContractResult, uint64, error) - - Sudo( - checksum wasmvm.Checksum, - env wasmvmtypes.Env, - sudoMsg []byte, - store wasmvm.KVStore, - goapi wasmvm.GoAPI, - querier wasmvm.Querier, - gasMeter wasmvm.GasMeter, - gasLimit uint64, - deserCost wasmvmtypes.UFraction, -- ) (*wasmvmtypes.Response, uint64, error) -+ ) (*wasmvmtypes.ContractResult, uint64, error) - - GetCode(checksum wasmvm.Checksum) (wasmvm.WasmCode, error) - - Pin(checksum wasmvm.Checksum) error - - Unpin(checksum wasmvm.Checksum) error -} -``` - -Similar changes were required in the functions of `MockWasmEngine` interface. - -### Chains - -The `SupportedCapabilities` field of `WasmConfig` is now of type `[]string`: - -```diff -type WasmConfig struct { - DataDir string -- SupportedCapabilities string -+ SupportedCapabilities []string - ContractDebugMode bool -} -``` diff --git a/docs/docs/03-light-clients/04-wasm/_category_.json b/docs/docs/03-light-clients/04-wasm/_category_.json deleted file mode 100644 index 6dc3d24d11a..00000000000 --- a/docs/docs/03-light-clients/04-wasm/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Wasm", - "position": 4, - "link": null -} \ No newline at end of file diff --git a/docs/docs/03-light-clients/_category_.json b/docs/docs/03-light-clients/_category_.json deleted file mode 100644 index 8e1f221f353..00000000000 --- a/docs/docs/03-light-clients/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "IBC Light Clients", - "position": 3, - "link": null -} \ No newline at end of file diff --git a/docs/docs/04-middleware/01-ics29-fee/01-overview.md b/docs/docs/04-middleware/01-ics29-fee/01-overview.md deleted file mode 100644 index 7a34adec74e..00000000000 --- a/docs/docs/04-middleware/01-ics29-fee/01-overview.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /middleware/ics29-fee/overview ---- - -# Overview - -:::note Synopsis -Learn about what the Fee Middleware module is, and how to build custom modules that utilize the Fee Middleware functionality -::: - -## What is the Fee Middleware module? - -IBC does not depend on relayer operators for transaction verification. However, the relayer infrastructure ensures liveness of the Interchain network — operators listen for packets sent through channels opened between chains, and perform the vital service of ferrying these packets (and proof of the transaction on the sending chain/receipt on the receiving chain) to the clients on each side of the channel. - -Though relaying is permissionless and completely decentralized and accessible, it does come with operational costs. Running full nodes to query transaction proofs and paying for transaction fees associated with IBC packets are two of the primary cost burdens which have driven the overall discussion on **a general, in-protocol incentivization mechanism for relayers**. - -Initially, a [simple proposal](https://github.com/cosmos/ibc/pull/577/files) was created to incentivize relaying on ICS20 token transfers on the destination chain. However, the proposal was specific to ICS20 token transfers and would have to be reimplemented in this format on every other IBC application module. - -After much discussion, the proposal was expanded to a [general incentivisation design](https://github.com/cosmos/ibc/tree/master/spec/app/ics-029-fee-payment) that can be adopted by any ICS application protocol as [middleware](../../01-ibc/04-middleware/02-develop.md). - -## Concepts - -ICS29 fee payments in this middleware design are built on the assumption that sender chains are the source of incentives — the chain on which packets are incentivized is the chain that distributes fees to relayer operators. However, as part of the IBC packet flow, messages have to be submitted on both sender and destination chains. This introduces the requirement of a mapping of relayer operator's addresses on both chains. - -To achieve the stated requirements, the **fee middleware module has two main groups of functionality**: - -- Registering of relayer addresses associated with each party involved in relaying the packet on the source chain. This registration process can be automated on start up of relayer infrastructure and happens only once, not every packet flow. - - This is described in the [Fee distribution section](04-fee-distribution.md). - -- Escrowing fees by any party which will be paid out to each rightful party on completion of the packet lifecycle. - - This is described in the [Fee messages section](03-msgs.md). - -We complete the introduction by giving a list of definitions of relevant terminolgy. - -`Forward relayer`: The relayer that submits the `MsgRecvPacket` message for a given packet (on the destination chain). - -`Reverse relayer`: The relayer that submits the `MsgAcknowledgement` message for a given packet (on the source chain). - -`Timeout relayer`: The relayer that submits the `MsgTimeout` or `MsgTimeoutOnClose` messages for a given packet (on the source chain). - -`Payee`: The account address on the source chain to be paid on completion of the packet lifecycle. The packet lifecycle on the source chain completes with the receipt of a `MsgTimeout`/`MsgTimeoutOnClose` or a `MsgAcknowledgement`. - -`Counterparty payee`: The account address to be paid on completion of the packet lifecycle on the destination chain. The package lifecycle on the destination chain completes with a successful `MsgRecvPacket`. - -`Refund address`: The address of the account paying for the incentivization of packet relaying. The account is refunded timeout fees upon successful acknowledgement. In the event of a packet timeout, both acknowledgement and receive fees are refunded. - -## Known Limitations - -The first version of fee payments middleware will only support incentivisation of new channels, however, channel upgradeability will enable incentivisation of all existing channels. diff --git a/docs/docs/04-middleware/01-ics29-fee/02-integration.md b/docs/docs/04-middleware/01-ics29-fee/02-integration.md deleted file mode 100644 index 343e09fb11e..00000000000 --- a/docs/docs/04-middleware/01-ics29-fee/02-integration.md +++ /dev/null @@ -1,177 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 2 -slug: /middleware/ics29-fee/integration ---- - -# Integration - -:::note Synopsis -Learn how to configure the Fee Middleware module with IBC applications. The following document is intended for developers building on top of the Cosmos SDK and only applies for Cosmos SDK chains. -::: - -:::note - -## Pre-requisite Readings - -- [IBC middleware development](../../01-ibc/04-middleware/02-develop.md) -- [IBC middleware integration](../../01-ibc/04-middleware/03-integration.md) - -::: - -The Fee Middleware module, as the name suggests, plays the role of an IBC middleware and as such must be configured by chain developers to route and handle IBC messages correctly. -For Cosmos SDK chains this setup is done via the `app/app.go` file, where modules are constructed and configured in order to bootstrap the blockchain application. - -## Example integration of the Fee Middleware module - -```go -// app.go - -// Register the AppModule for the fee middleware module -ModuleBasics = module.NewBasicManager( - ... - ibcfee.AppModuleBasic{}, - ... -) - -... - -// Add module account permissions for the fee middleware module -maccPerms = map[string][]string{ - ... - ibcfeetypes.ModuleName: nil, -} - -... - -// Add fee middleware Keeper -type App struct { - ... - - IBCFeeKeeper ibcfeekeeper.Keeper - - ... -} - -... - -// Create store keys -keys := sdk.NewKVStoreKeys( - ... - ibcfeetypes.StoreKey, - ... -) - -... - -app.IBCFeeKeeper = ibcfeekeeper.NewKeeper( - appCodec, keys[ibcfeetypes.StoreKey], - app.IBCKeeper.ChannelKeeper, // may be replaced with IBC middleware - app.IBCKeeper.ChannelKeeper, - &app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, -) - - -// See the section below for configuring an application stack with the fee middleware module - -... - -// Register fee middleware AppModule -app.moduleManager = module.NewManager( - ... - ibcfee.NewAppModule(app.IBCFeeKeeper), -) - -... - -// Add fee middleware to begin blocker logic -app.moduleManager.SetOrderBeginBlockers( - ... - ibcfeetypes.ModuleName, - ... -) - -// Add fee middleware to end blocker logic -app.moduleManager.SetOrderEndBlockers( - ... - ibcfeetypes.ModuleName, - ... -) - -// Add fee middleware to init genesis logic -app.moduleManager.SetOrderInitGenesis( - ... - ibcfeetypes.ModuleName, - ... -) -``` - -## Configuring an application stack with Fee Middleware - -As mentioned in [IBC middleware development](../../01-ibc/04-middleware/02-develop.md) an application stack may be composed of many or no middlewares that nest a base application. -These layers form the complete set of application logic that enable developers to build composable and flexible IBC application stacks. -For example, an application stack may be just a single base application like `transfer`, however, the same application stack composed with `29-fee` will nest the `transfer` base application -by wrapping it with the Fee Middleware module. - -### Transfer - -See below for an example of how to create an application stack using `transfer` and `29-fee`. -The following `transferStack` is configured in `app/app.go` and added to the IBC `Router`. -The in-line comments describe the execution flow of packets between the application stack and IBC core. - -```go -// Create Transfer Stack -// SendPacket, since it is originating from the application to core IBC: -// transferKeeper.SendPacket -> fee.SendPacket -> channel.SendPacket - -// RecvPacket, message that originates from core IBC and goes down to app, the flow is the other way -// channel.RecvPacket -> fee.OnRecvPacket -> transfer.OnRecvPacket - -// transfer stack contains (from top to bottom): -// - IBC Fee Middleware -// - Transfer - -// create IBC module from bottom to top of stack -var transferStack porttypes.IBCModule -transferStack = transfer.NewIBCModule(app.TransferKeeper) -transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) - -// Add transfer stack to IBC Router -ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) -``` - -### Interchain Accounts - -See below for an example of how to create an application stack using `27-interchain-accounts` and `29-fee`. -The following `icaControllerStack` and `icaHostStack` are configured in `app/app.go` and added to the IBC `Router` with the associated authentication module. -The in-line comments describe the execution flow of packets between the application stack and IBC core. - -```go -// Create Interchain Accounts Stack -// SendPacket, since it is originating from the application to core IBC: -// icaAuthModuleKeeper.SendTx -> icaController.SendPacket -> fee.SendPacket -> channel.SendPacket - -// initialize ICA module with mock module as the authentication module on the controller side -var icaControllerStack porttypes.IBCModule -icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp("", scopedICAMockKeeper)) -app.ICAAuthModule = icaControllerStack.(ibcmock.IBCModule) -icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) -icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) - -// RecvPacket, message that originates from core IBC and goes down to app, the flow is: -// channel.RecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket - -var icaHostStack porttypes.IBCModule -icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) -icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) - -// Add authentication module, controller and host to IBC router -ibcRouter. - // the ICA Controller middleware needs to be explicitly added to the IBC Router because the - // ICA controller module owns the port capability for ICA. The ICA authentication module - // owns the channel capability. - AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack) - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icahosttypes.SubModuleName, icaHostStack). -``` diff --git a/docs/docs/04-middleware/01-ics29-fee/03-msgs.md b/docs/docs/04-middleware/01-ics29-fee/03-msgs.md deleted file mode 100644 index 4496df29f98..00000000000 --- a/docs/docs/04-middleware/01-ics29-fee/03-msgs.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: Fee Messages -sidebar_label: Fee Messages -sidebar_position: 3 -slug: /middleware/ics29-fee/msgs ---- - -# Fee messages - -:::note Synopsis -Learn about the different ways to pay for fees, how the fees are paid out and what happens when not enough escrowed fees are available for payout -::: - -## Escrowing fees - -The fee middleware module exposes two different ways to pay fees for relaying IBC packets: - -### `MsgPayPacketFee` - -`MsgPayPacketFee` enables the escrowing of fees for a packet at the next sequence send and should be combined into one `MultiMsgTx` with the message that will be paid for. Note that the `Relayers` field has been set up to allow for an optional whitelist of relayers permitted to receive this fee, however, this feature has not yet been enabled at this time. - -```go -type MsgPayPacketFee struct{ - // fee encapsulates the recv, ack and timeout fees associated with an IBC packet - Fee Fee - // the source port unique identifier - SourcePortId string - // the source channel unique identifer - SourceChannelId string - // account address to refund fee if necessary - Signer string - // optional list of relayers permitted to the receive packet fee - Relayers []string -} -``` - -The `Fee` message contained in this synchronous fee payment method configures different fees which will be paid out for `MsgRecvPacket`, `MsgAcknowledgement`, and `MsgTimeout`/`MsgTimeoutOnClose`. - -```go -type Fee struct { - RecvFee types.Coins - AckFee types.Coins - TimeoutFee types.Coins -} -``` - -The diagram below shows the `MultiMsgTx` with the `MsgTransfer` coming from a token transfer message, along with `MsgPayPacketFee`. - -![msgpaypacket.png](./images/msgpaypacket.png) - -### `MsgPayPacketFeeAsync` - -`MsgPayPacketFeeAsync` enables the asynchronous escrowing of fees for a specified packet. Note that a packet can be 'topped up' multiple times with additional fees of any coin denomination by broadcasting multiple `MsgPayPacketFeeAsync` messages. - -```go -type MsgPayPacketFeeAsync struct { - // unique packet identifier comprised of the channel ID, port ID and sequence - PacketId channeltypes.PacketId - // the packet fee associated with a particular IBC packet - PacketFee PacketFee -} -``` - -where the `PacketFee` also specifies the `Fee` to be paid as well as the refund address for fees which are not paid out - -```go -type PacketFee struct { - Fee Fee - RefundAddress string - Relayers []string -} -``` - -The diagram below shows how multiple `MsgPayPacketFeeAsync` can be broadcasted asynchronously. Escrowing of the fee associated with a packet can be carried out by any party because ICS-29 does not dictate a particular fee payer. In fact, chains can choose to simply not expose this fee payment to end users at all and rely on a different module account or even the community pool as the source of relayer incentives. - -![paypacketfeeasync.png](./images/paypacketfeeasync.png) - -Please see our [wiki](https://github.com/cosmos/ibc-go/wiki/Fee-enabled-fungible-token-transfers) for example flows on how to use these messages to incentivise a token transfer channel using a CLI. - -## Paying out the escrowed fees - -Following diagram takes a look at the packet flow for an incentivized token transfer and investigates the several scenario's for paying out the escrowed fees. We assume that the relayers have registered their counterparty address, detailed in the [Fee distribution section](04-fee-distribution.md). - -![feeflow.png](./images/feeflow.png) - -- In the case of a successful transaction, `RecvFee` will be paid out to the designated counterparty payee address which has been registered on the receiver chain and sent back with the `MsgAcknowledgement`, `AckFee` will be paid out to the relayer address which has submitted the `MsgAcknowledgement` on the sending chain (or the registered payee in case one has been registered for the relayer address), and `TimeoutFee` will be reimbursed to the account which escrowed the fee. -- In case of a timeout transaction, `RecvFee` and `AckFee` will be reimbursed. The `TimeoutFee` will be paid to the `Timeout Relayer` (who submits the timeout message to the source chain). - -> Please note that fee payments are built on the assumption that sender chains are the source of incentives — the chain that sends the packets is the same chain where fee payments will occur -- please see the [Fee distribution section](04-fee-distribution.md) to understand the flow for registering payee and counterparty payee (fee receiving) addresses. - -## A locked fee middleware module - -The fee middleware module can become locked if the situation arises that the escrow account for the fees does not have sufficient funds to pay out the fees which have been escrowed for each packet. *This situation indicates a severe bug.* In this case, the fee module will be locked until manual intervention fixes the issue. - -> A locked fee module will simply skip fee logic and continue on to the underlying packet flow. A channel with a locked fee module will temporarily function as a fee disabled channel, and the locking of a fee module will not affect the continued flow of packets over the channel. diff --git a/docs/docs/04-middleware/01-ics29-fee/04-fee-distribution.md b/docs/docs/04-middleware/01-ics29-fee/04-fee-distribution.md deleted file mode 100644 index d66c067bdac..00000000000 --- a/docs/docs/04-middleware/01-ics29-fee/04-fee-distribution.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -title: Fee Distribution -sidebar_label: Fee Distribution -sidebar_position: 4 -slug: /middleware/ics29-fee/fee-distribution ---- - -# Fee distribution - -:::note Synopsis -Learn about payee registration for the distribution of packet fees. The following document is intended for relayer operators. -::: - -:::note - -## Pre-requisite readings - -- [Fee Middleware](01-overview.md) - -::: - -Packet fees are divided into 3 distinct amounts in order to compensate relayer operators for packet relaying on fee enabled IBC channels. - -- `RecvFee`: The sum of all packet receive fees distributed to a payee for successful execution of `MsgRecvPacket`. -- `AckFee`: The sum of all packet acknowledgement fees distributed to a payee for successful execution of `MsgAcknowledgement`. -- `TimeoutFee`: The sum of all packet timeout fees distributed to a payee for successful execution of `MsgTimeout`. - -## Register a counterparty payee address for forward relaying - -As mentioned in [ICS29 Concepts](01-overview.md#concepts), the forward relayer describes the actor who performs the submission of `MsgRecvPacket` on the destination chain. -Fee distribution for incentivized packet relays takes place on the packet source chain. - -> Relayer operators are expected to register a counterparty payee address, in order to be compensated accordingly with `RecvFee`s upon completion of a packet lifecycle. - -The counterparty payee address registered on the destination chain is encoded into the packet acknowledgement and communicated as such to the source chain for fee distribution. -**If a counterparty payee is not registered for the forward relayer on the destination chain, the escrowed fees will be refunded upon fee distribution.** - -### Relayer operator actions - -A transaction must be submitted **to the destination chain** including a `CounterpartyPayee` address of an account on the source chain. -The transaction must be signed by the `Relayer`. - -Note: If a module account address is used as the `CounterpartyPayee` but the module has been set as a blocked address in the `BankKeeper`, the refunding to the module account will fail. This is because many modules use invariants to compare internal tracking of module account balances against the actual balance of the account stored in the `BankKeeper`. If a token transfer to the module account occurs without going through this module and updating the account balance of the module on the `BankKeeper`, then invariants may break and unknown behaviour could occur depending on the module implementation. Therefore, if it is desirable to use a module account that is currently blocked, the module developers should be consulted to gauge to possibility of removing the module account from the blocked list. - -```go -type MsgRegisterCounterpartyPayee struct { - // unique port identifier - PortId string - // unique channel identifier - ChannelId string - // the relayer address - Relayer string - // the counterparty payee address - CounterpartyPayee string -} -``` - -> This message is expected to fail if: -> -> - `PortId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). -> - `ChannelId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -> - `Relayer` is an invalid address (see [Cosmos SDK Addresses](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/beginner/03-accounts.md#addresses)). -> - `CounterpartyPayee` is empty. - -See below for an example CLI command: - -```bash -simd tx ibc-fee register-counterparty-payee transfer channel-0 \ - cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh \ - osmo1v5y0tz01llxzf4c2afml8s3awue0ymju22wxx2 \ - --from cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh -``` - -## Register an alternative payee address for reverse and timeout relaying - -As mentioned in [ICS29 Concepts](01-overview.md#concepts), the reverse relayer describes the actor who performs the submission of `MsgAcknowledgement` on the source chain. -Similarly the timeout relayer describes the actor who performs the submission of `MsgTimeout` (or `MsgTimeoutOnClose`) on the source chain. - -> Relayer operators **may choose** to register an optional payee address, in order to be compensated accordingly with `AckFee`s and `TimeoutFee`s upon completion of a packet life cycle. - -If a payee is not registered for the reverse or timeout relayer on the source chain, then fee distribution assumes the default behaviour, where fees are paid out to the relayer account which delivers `MsgAcknowledgement` or `MsgTimeout`/`MsgTimeoutOnClose`. - -### Relayer operator actions - -A transaction must be submitted **to the source chain** including a `Payee` address of an account on the source chain. -The transaction must be signed by the `Relayer`. - -Note: If a module account address is used as the `Payee` it is recommended to [turn off invariant checks](https://github.com/cosmos/ibc-go/blob/v7.0.0/testing/simapp/app.go#L727) for that module. - -```go -type MsgRegisterPayee struct { - // unique port identifier - PortId string - // unique channel identifier - ChannelId string - // the relayer address - Relayer string - // the payee address - Payee string -} -``` - -> This message is expected to fail if: -> -> - `PortId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). -> - `ChannelId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -> - `Relayer` is an invalid address (see [Cosmos SDK Addresses](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/beginner/03-accounts.md#addresses)). -> - `Payee` is an invalid address (see [Cosmos SDK Addresses](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/beginner/03-accounts.md#addresses)). - -See below for an example CLI command: - -```bash -simd tx ibc-fee register-payee transfer channel-0 \ - cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh \ - cosmos153lf4zntqt33a4v0sm5cytrxyqn78q7kz8j8x5 \ - --from cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh -``` diff --git a/docs/docs/04-middleware/01-ics29-fee/05-events.md b/docs/docs/04-middleware/01-ics29-fee/05-events.md deleted file mode 100644 index 610130fa578..00000000000 --- a/docs/docs/04-middleware/01-ics29-fee/05-events.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: Events -sidebar_label: Events -sidebar_position: 5 -slug: /middleware/ics29-fee/events ---- - - -# Events - -:::note Synopsis -An overview of all events related to ICS-29 -::: - -## `MsgPayPacketFee`, `MsgPayPacketFeeAsync` - -| Type | Attribute Key | Attribute Value | -| ----------------------- | --------------- | --------------- | -| incentivized_ibc_packet | port_id | {portID} | -| incentivized_ibc_packet | channel_id | {channelID} | -| incentivized_ibc_packet | packet_sequence | {sequence} | -| incentivized_ibc_packet | recv_fee | {recvFee} | -| incentivized_ibc_packet | ack_fee | {ackFee} | -| incentivized_ibc_packet | timeout_fee | {timeoutFee} | -| message | module | fee-ibc | - -## `RegisterPayee` - -| Type | Attribute Key | Attribute Value | -| -------------- | ------------- | --------------- | -| register_payee | relayer | {relayer} | -| register_payee | payee | {payee} | -| register_payee | channel_id | {channelID} | -| message | module | fee-ibc | - -## `RegisterCounterpartyPayee` - -| Type | Attribute Key | Attribute Value | -| --------------------------- | ------------------ | ------------------- | -| register_counterparty_payee | relayer | {relayer} | -| register_counterparty_payee | counterparty_payee | {counterpartyPayee} | -| register_counterparty_payee | channel_id | {channelID} | -| message | module | fee-ibc | diff --git a/docs/docs/04-middleware/01-ics29-fee/06-end-users.md b/docs/docs/04-middleware/01-ics29-fee/06-end-users.md deleted file mode 100644 index f3985cc0358..00000000000 --- a/docs/docs/04-middleware/01-ics29-fee/06-end-users.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: End Users -sidebar_label: End Users -sidebar_position: 6 -slug: /middleware/ics29-fee/end-users ---- - -# For end users - -:::note Synopsis -Learn how to incentivize IBC packets using the ICS29 Fee Middleware module. -::: - -:::note - -## Pre-requisite readings - -- [Fee Middleware](01-overview.md) - -::: - -## Summary - -Different types of end users: - -- CLI users who want to manually incentivize IBC packets -- Client developers - -The Fee Middleware module allows end users to add a 'tip' to each IBC packet which will incentivize relayer operators to relay packets between chains. gRPC endpoints are exposed for client developers as well as a simple CLI for manually incentivizing IBC packets. - -## CLI Users - -For an in depth guide on how to use the ICS29 Fee Middleware module using the CLI please take a look at the [wiki](https://github.com/cosmos/ibc-go/wiki/Fee-enabled-fungible-token-transfers#asynchronous-incentivization-of-a-fungible-token-transfer) on the `ibc-go` repo. - -## Client developers - -Client developers can read more about the relevant ICS29 message types in the [Fee messages section](03-msgs.md). - -[CosmJS](https://github.com/cosmos/cosmjs) is a useful client library for signing and broadcasting Cosmos SDK messages. diff --git a/docs/docs/04-middleware/01-ics29-fee/_category_.json b/docs/docs/04-middleware/01-ics29-fee/_category_.json deleted file mode 100644 index ddca8d29da6..00000000000 --- a/docs/docs/04-middleware/01-ics29-fee/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Fee Middleware", - "position": 1, - "link": null -} \ No newline at end of file diff --git a/docs/docs/04-middleware/01-ics29-fee/images/feeflow.png b/docs/docs/04-middleware/01-ics29-fee/images/feeflow.png deleted file mode 100644 index ba02071f4d8..00000000000 Binary files a/docs/docs/04-middleware/01-ics29-fee/images/feeflow.png and /dev/null differ diff --git a/docs/docs/04-middleware/01-ics29-fee/images/msgpaypacket.png b/docs/docs/04-middleware/01-ics29-fee/images/msgpaypacket.png deleted file mode 100644 index 1bd5deb01fd..00000000000 Binary files a/docs/docs/04-middleware/01-ics29-fee/images/msgpaypacket.png and /dev/null differ diff --git a/docs/docs/04-middleware/01-ics29-fee/images/paypacketfeeasync.png b/docs/docs/04-middleware/01-ics29-fee/images/paypacketfeeasync.png deleted file mode 100644 index 27c486a6f82..00000000000 Binary files a/docs/docs/04-middleware/01-ics29-fee/images/paypacketfeeasync.png and /dev/null differ diff --git a/docs/docs/04-middleware/02-callbacks/01-overview.md b/docs/docs/04-middleware/02-callbacks/01-overview.md deleted file mode 100644 index 70eefc31e7d..00000000000 --- a/docs/docs/04-middleware/02-callbacks/01-overview.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /middleware/callbacks/overview ---- - -# Overview - -Learn about what the Callbacks Middleware is, and how to build custom modules that utilize the Callbacks Middleware functionality {synopsis} - -## What is the Callbacks Middleware? - -IBC was designed with callbacks between core IBC and IBC applications. IBC apps would send a packet to core IBC, and receive a callback on every step of that packet's lifecycle. This allows IBC applications to be built on top of core IBC, and to be able to execute custom logic on packet lifecycle events (e.g. unescrow tokens for ICS-20). - -This setup worked well for off-chain users interacting with IBC applications. However, we are now seeing the desire for secondary applications (e.g. smart contracts, modules) to call into IBC apps as part of their state machine logic and then do some actions on packet lifecycle events. - -The Callbacks Middleware allows for this functionality by allowing the packets of the underlying IBC applications to register callbacks to secondary applications for lifecycle events. These callbacks are then executed by the Callbacks Middleware when the corresponding packet lifecycle event occurs. - -After much discussion, the design was expanded to [an ADR](/architecture/adr-008-app-caller-cbs), and the Callbacks Middleware is an implementation of that ADR. - -## Concepts - -Callbacks Middleware was built with smart contracts in mind, but can be used by any secondary application that wants to allow IBC packets to call into it. Think of the Callbacks Middleware as a bridge between core IBC and a secondary application. - -We have the following definitions: - -- `Underlying IBC application`: The IBC application that is wrapped by the Callbacks Middleware. This is the IBC application that is actually sending and receiving packet lifecycle events from core IBC. For example, the transfer module, or the ICA controller submodule. -- `IBC Actor`: IBC Actor is an on-chain or off-chain entity that can initiate a packet on the underlying IBC application. For example, a smart contract, an off-chain user, or a module that sends a transfer packet are all IBC Actors. -- `Secondary application`: The application that is being called into by the Callbacks Middleware for packet lifecycle events. This is the application that is receiving the callback directly from the Callbacks Middleware module. For example, the `x/wasm` module. -- `Callback Actor`: The on-chain smart contract or module that is registered to receive callbacks from the secondary application. For example, a Wasm smart contract (gatekeeped by the `x/wasm` module). Note that the Callback Actor is not necessarily the same as the IBC Actor. For example, an off-chain user can initiate a packet on the underlying IBC application, but the Callback Actor could be a smart contract. The secondary application may want to check that the IBC Actor is allowed to call into the Callback Actor, for example, by checking that the IBC Actor is the same as the Callback Actor. -- `Callback Address`: Address of the Callback Actor. This is the address that the secondary application will call into when a packet lifecycle event occurs. For example, the address of the Wasm smart contract. -- `Maximum gas limit`: The maximum amount of gas that the Callbacks Middleware will allow the secondary application to use when it executes its custom logic. -- `User defined gas limit`: The amount of gas that the IBC Actor wants to allow the secondary application to use when it executes its custom logic. This is the gas limit that the IBC Actor specifies when it sends a packet to the underlying IBC application. This cannot be greater than the maximum gas limit. - -Think of the secondary application as a bridge between the Callbacks Middleware and the Callback Actor. The secondary application is responsible for executing the custom logic of the Callback Actor when a packet lifecycle event occurs. The secondary application is also responsible for checking that the IBC Actor is allowed to call into the Callback Actor. - -Note that it is possible that the IBC Actor, Secondary Application, and Callback Actor are all the same entity. In which case, the Callback Address should be the secondary application's module address. - -The following diagram shows how a typical `RecvPacket`, `AcknowledgementPacket`, and `TimeoutPacket` execution flow would look like: -![callbacks-middleware](./images/callbackflow.svg) - -And the following diagram shows how a typical `SendPacket` and `WriteAcknowledgement` execution flow would look like: -![callbacks-middleware](./images/ics4-callbackflow.svg) - -## Known Limitations - -- Callbacks are always executed after the underlying IBC application has executed its logic. -- Maximum gas limit is hardcoded manually during wiring. It requires a coordinated upgrade to change the maximum gas limit. -- The receive packet callback does not pass the relayer address to the secondary application. This is so that we can use the same callback for both synchronous and asynchronous acknowledgements. -- The receive packet callback does not pass IBC Actor's address, this is because the IBC Actor lives in the counterparty chain and cannot be trusted. diff --git a/docs/docs/04-middleware/02-callbacks/02-integration.md b/docs/docs/04-middleware/02-callbacks/02-integration.md deleted file mode 100644 index 83bb33a3e3a..00000000000 --- a/docs/docs/04-middleware/02-callbacks/02-integration.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 2 -slug: /middleware/callbacks/integration ---- - -# Integration - -Learn how to integrate the callbacks middleware with IBC applications. The following document is intended for developers building on top of the Cosmos SDK and only applies for Cosmos SDK chains. {synopsis} - -The callbacks middleware is a minimal and stateless implementation of the IBC middleware interface. It does not have a keeper, nor does it store any state. It simply routes IBC middleware messages to the appropriate callback function, which is implemented by the secondary application. Therefore, it doesn't need to be registered as a module, nor does it need to be added to the module manager. It only needs to be added to the IBC application stack. - -## Pre-requisite Readings - -- [IBC middleware development](../../01-ibc/04-middleware/02-develop.md) -- [IBC middleware integration](../../01-ibc/04-middleware/03-integration.md) - -The callbacks middleware, as the name suggests, plays the role of an IBC middleware and as such must be configured by chain developers to route and handle IBC messages correctly. -For Cosmos SDK chains this setup is done via the `app/app.go` file, where modules are constructed and configured in order to bootstrap the blockchain application. - -## Configuring an application stack with the callbacks middleware - -As mentioned in [IBC middleware development](../../01-ibc/04-middleware/02-develop.md) an application stack may be composed of many or no middlewares that nest a base application. -These layers form the complete set of application logic that enable developers to build composable and flexible IBC application stacks. -For example, an application stack may just be a single base application like `transfer`, however, the same application stack composed with `29-fee` and `callbacks` will nest the `transfer` base application twice by wrapping it with the Fee Middleware module and then callbacks middleware. - -The callbacks middleware also **requires** a secondary application that will receive the callbacks to implement the [`ContractKeeper`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/apps/callbacks/types/expected_keepers.go#L11-L83). Since the wasm module does not yet support the callbacks middleware, we will use the `mockContractKeeper` module in the examples below. You should replace this with a module that implements `ContractKeeper`. - -### Transfer - -See below for an example of how to create an application stack using `transfer`, `29-fee`, and `callbacks`. Feel free to omit the `29-fee` middleware if you do not want to use it. -The following `transferStack` is configured in `app/app.go` and added to the IBC `Router`. -The in-line comments describe the execution flow of packets between the application stack and IBC core. - -```go -// Create Transfer Stack -// SendPacket, since it is originating from the application to core IBC: -// transferKeeper.SendPacket -> callbacks.SendPacket -> fee.SendPacket -> channel.SendPacket - -// RecvPacket, message that originates from core IBC and goes down to app, the flow is the other way -// channel.RecvPacket -> callbacks.OnRecvPacket -> fee.OnRecvPacket -> transfer.OnRecvPacket - -// transfer stack contains (from top to bottom): -// - IBC Callbacks Middleware -// - IBC Fee Middleware -// - Transfer - -// create IBC module from bottom to top of stack -var transferStack porttypes.IBCModule -transferStack = transfer.NewIBCModule(app.TransferKeeper) -transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) -// maxCallbackGas is a hard-coded value that is passed to the callbacks middleware -transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCFeeKeeper, app.MockContractKeeper, maxCallbackGas) -// Since the callbacks middleware itself is an ics4wrapper, it needs to be passed to the transfer keeper -app.TransferKeeper.WithICS4Wrapper(transferStack.(porttypes.ICS4Wrapper)) - -// Add transfer stack to IBC Router -ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) -``` - -::: warning -The usage of `WithICS4Wrapper` after `transferStack`'s configuration is critical! It allows the callbacks middleware to do `SendPacket` callbacks and asynchronous `ReceivePacket` callbacks. You must do this regardless of whether you are using the `29-fee` middleware or not. -::: - -### Interchain Accounts Controller - -```go -// Create Interchain Accounts Stack -// SendPacket, since it is originating from the application to core IBC: -// icaControllerKeeper.SendTx -> callbacks.SendPacket -> fee.SendPacket -> channel.SendPacket - -var icaControllerStack porttypes.IBCModule -icaControllerStack = icacontroller.NewIBCMiddleware(nil, app.ICAControllerKeeper) -icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) -// maxCallbackGas is a hard-coded value that is passed to the callbacks middleware -icaControllerStack = ibccallbacks.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper, app.MockContractKeeper, maxCallbackGas) -// Since the callbacks middleware itself is an ics4wrapper, it needs to be passed to the ica controller keeper -app.ICAControllerKeeper.WithICS4Wrapper(icaControllerStack.(porttypes.ICS4Wrapper)) - -// RecvPacket, message that originates from core IBC and goes down to app, the flow is: -// channel.RecvPacket -> callbacks.OnRecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket - -var icaHostStack porttypes.IBCModule -icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) -icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) - -// Add ICA host and controller to IBC router ibcRouter. -AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). -AddRoute(icahosttypes.SubModuleName, icaHostStack). -``` - -::: warning -The usage of `WithICS4Wrapper` here is also critical! -::: diff --git a/docs/docs/04-middleware/02-callbacks/03-interfaces.md b/docs/docs/04-middleware/02-callbacks/03-interfaces.md deleted file mode 100644 index 0c05b1bb27b..00000000000 --- a/docs/docs/04-middleware/02-callbacks/03-interfaces.md +++ /dev/null @@ -1,151 +0,0 @@ ---- -title: Interfaces -sidebar_label: Interfaces -sidebar_position: 3 -slug: /middleware/callbacks/interfaces ---- - -# Interfaces - -The callbacks middleware requires certain interfaces to be implemented by the underlying IBC applications and the secondary application. If you're simply wiring up the callbacks middleware to an existing IBC application stack and a secondary application such as `icacontroller` and `x/wasm`, you can skip this section. - -## Interfaces for developing the Underlying IBC Application - -### `PacketDataUnmarshaler` - -```go -// PacketDataUnmarshaler defines an optional interface which allows a middleware to -// request the packet data to be unmarshaled by the base application. -type PacketDataUnmarshaler interface { - // UnmarshalPacketData unmarshals the packet data into a concrete type - UnmarshalPacketData([]byte) (interface{}, error) -} -``` - -The callbacks middleware **requires** the underlying ibc application to implement the [`PacketDataUnmarshaler`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/core/05-port/types/module.go#L142-L147) interface so that it can unmarshal the packet data bytes into the appropriate packet data type. This allows usage of interface functions implemented by the packet data type. The packet data type is expected to implement the `PacketDataProvider` interface (see section below), which is used to parse the callback data that is currently stored in the packet memo field for `transfer` and `ica` packets as a JSON string. See its implementation in the [`transfer`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/apps/transfer/ibc_module.go#L303-L313) and [`icacontroller`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/apps/27-interchain-accounts/controller/ibc_middleware.go#L258-L268) modules for reference. - -If the underlying application is a middleware itself, then it can implement this interface by simply passing the function call to its underlying application. See its implementation in the [`fee middleware`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/apps/29-fee/ibc_middleware.go#L368-L378) for reference. - -### `PacketDataProvider` - -```go -// PacketDataProvider defines an optional interfaces for retrieving custom packet data stored on behalf of another application. -// An existing problem in the IBC middleware design is the inability for a middleware to define its own packet data type and insert packet sender provided information. -// A short term solution was introduced into several application's packet data to utilize a memo field to carry this information on behalf of another application. -// This interfaces standardizes that behaviour. Upon realization of the ability for middleware's to define their own packet data types, this interface will be deprecated and removed with time. -type PacketDataProvider interface { - // GetCustomPacketData returns the packet data held on behalf of another application. - // The name the information is stored under should be provided as the key. - // If no custom packet data exists for the key, nil should be returned. - GetCustomPacketData(key string) interface{} -} -``` - -The callbacks middleware also **requires** the underlying ibc application's packet data type to implement the [`PacketDataProvider`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/core/exported/packet.go#L43-L52) interface. This interface is used to retrieve the callback data from the packet data (using the memo field in the case of `transfer` and `ica`). For example, see its implementation in the [`transfer`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/apps/transfer/types/packet.go#L85-L105) module. - -Since middlewares do not have packet types, they do not need to implement this interface. - -### `PacketData` - -```go -// PacketData defines an optional interface which an application's packet data structure may implement. -type PacketData interface { - // GetPacketSender returns the sender address of the packet data. - // If the packet sender is unknown or undefined, an empty string should be returned. - GetPacketSender(sourcePortID string) string -} -``` - -[`PacketData`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/core/exported/packet.go#L36-L41) is an optional interface that can be implemented by the underlying ibc application's packet data type. It is used to retrieve the packet sender address from the packet data. The callbacks middleware uses this interface to retrieve the packet sender address and pass it to the callback function during a source callback. If this interface is not implemented, then the callbacks middleware passes and empty string as the sender address. For example, see its implementation in the [`transfer`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/apps/transfer/types/packet.go#L74-L83) and [`ica`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/apps/27-interchain-accounts/types/packet.go#L78-L92) module. - -This interface was added so that secondary applications can retrieve the packet sender address to perform custom authorization logic if needed. - -Since middlewares do not have packet types, they do not need to implement this interface. - -## Interfaces for developing the Secondary Application - -### `ContractKeeper` - -The callbacks middleware requires the secondary application to implement the [`ContractKeeper`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/apps/callbacks/types/expected_keepers.go#L11-L83) interface. The contract keeper will be invoked at each step of the packet lifecycle. When a packet is sent, if callback information is provided, the contract keeper will be invoked via the `IBCSendPacketCallback`. This allows the contract keeper to prevent packet sends when callback information is provided, for example if the sender is unauthroized to perform callbacks on the given information. If the packet send is successful, the contract keeper on the destination (if present) will be invoked when a packet has been received and the acknowledgement is written, this will occur via `IBCReceivePacketCallback`. At the end of the packet lifecycle, when processing acknowledgements or timeouts, the source contract keeper will be invoked either via `IBCOnAcknowledgementPacket` or `IBCOnTimeoutPacket`. Once a packet has been sent, each step of the packet lifecycle can be processed given that a relayer sets the gas limit to be more than or equal to the required `CommitGasLimit`. State changes performed in the callback will only be committed upon successful execution. - -```go -// ContractKeeper defines the entry points exposed to the VM module which invokes a smart contract -type ContractKeeper interface { - // IBCSendPacketCallback is called in the source chain when a PacketSend is executed. The - // packetSenderAddress is determined by the underlying module, and may be empty if the sender is - // unknown or undefined. The contract is expected to handle the callback within the user defined - // gas limit, and handle any errors, or panics gracefully. - // This entry point is called with a cached context. If an error is returned, then the changes in - // this context will not be persisted, and the error will be propagated to the underlying IBC - // application, resulting in a packet send failure. - // - // Implementations are provided with the packetSenderAddress and MAY choose to use this to perform - // validation on the origin of a given packet. It is recommended to perform the same validation - // on all source chain callbacks (SendPacket, AcknowledgementPacket, TimeoutPacket). This - // defensively guards against exploits due to incorrectly wired SendPacket ordering in IBC stacks. - IBCSendPacketCallback( - cachedCtx sdk.Context, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - packetData []byte, - contractAddress, - packetSenderAddress string, - ) error - // IBCOnAcknowledgementPacketCallback is called in the source chain when a packet acknowledgement - // is received. The packetSenderAddress is determined by the underlying module, and may be empty if - // the sender is unknown or undefined. The contract is expected to handle the callback within the - // user defined gas limit, and handle any errors, or panics gracefully. - // This entry point is called with a cached context. If an error is returned, then the changes in - // this context will not be persisted, but the packet lifecycle will not be blocked. - // - // Implementations are provided with the packetSenderAddress and MAY choose to use this to perform - // validation on the origin of a given packet. It is recommended to perform the same validation - // on all source chain callbacks (SendPacket, AcknowledgementPacket, TimeoutPacket). This - // defensively guards against exploits due to incorrectly wired SendPacket ordering in IBC stacks. - IBCOnAcknowledgementPacketCallback( - cachedCtx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - relayer sdk.AccAddress, - contractAddress, - packetSenderAddress string, - ) error - // IBCOnTimeoutPacketCallback is called in the source chain when a packet is not received before - // the timeout height. The packetSenderAddress is determined by the underlying module, and may be - // empty if the sender is unknown or undefined. The contract is expected to handle the callback - // within the user defined gas limit, and handle any error, out of gas, or panics gracefully. - // This entry point is called with a cached context. If an error is returned, then the changes in - // this context will not be persisted, but the packet lifecycle will not be blocked. - // - // Implementations are provided with the packetSenderAddress and MAY choose to use this to perform - // validation on the origin of a given packet. It is recommended to perform the same validation - // on all source chain callbacks (SendPacket, AcknowledgementPacket, TimeoutPacket). This - // defensively guards against exploits due to incorrectly wired SendPacket ordering in IBC stacks. - IBCOnTimeoutPacketCallback( - cachedCtx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, - contractAddress, - packetSenderAddress string, - ) error - // IBCReceivePacketCallback is called in the destination chain when a packet acknowledgement is written. - // The contract is expected to handle the callback within the user defined gas limit, and handle any errors, - // out of gas, or panics gracefully. - // This entry point is called with a cached context. If an error is returned, then the changes in - // this context will not be persisted, but the packet lifecycle will not be blocked. - IBCReceivePacketCallback( - cachedCtx sdk.Context, - packet ibcexported.PacketI, - ack ibcexported.Acknowledgement, - contractAddress string, - ) error -} -``` - -These are the callback entry points exposed to the secondary application. The secondary application is expected to execute its custom logic within these entry points. The callbacks middleware will handle the execution of these callbacks and revert the state if needed. - -:::tip -Note that the source callback entry points are provided with the `packetSenderAddress` and MAY choose to use this to perform validation on the origin of a given packet. It is recommended to perform the same validation on all source chain callbacks (SendPacket, AcknowledgePacket, TimeoutPacket). This defensively guards against exploits due to incorrectly wired SendPacket ordering in IBC stacks. -::: diff --git a/docs/docs/04-middleware/02-callbacks/04-events.md b/docs/docs/04-middleware/02-callbacks/04-events.md deleted file mode 100644 index c7711100fb7..00000000000 --- a/docs/docs/04-middleware/02-callbacks/04-events.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Events -sidebar_label: Events -sidebar_position: 4 -slug: /middleware/callbacks/events ---- - -# Events - -An overview of all events related to the callbacks middleware. There are two types of events, `"ibc_src_callback"` and `"ibc_dest_callback"`. - -## Shared Attributes - -Both of these event types share the following attributes: - -| **Attribute Key** | **Attribute Values** | **Optional** | -|:-------------------------:|:---------------------------------------------------------------------------------------:|:------------------:| -| module | "ibccallbacks" | | -| callback_type | **One of**: "send_packet", "acknowledgement_packet", "timeout_packet", "receive_packet" | | -| callback_address | string | | -| callback_exec_gas_limit | string (parsed from uint64) | | -| callback_commit_gas_limit | string (parsed from uint64) | | -| packet_sequence | string (parsed from uint64) | | -| callback_result | **One of**: "success", "failure" | | -| callback_error | string (parsed from callback err) | Yes, if err != nil | - -## `ibc_src_callback` Attributes - -| **Attribute Key** | **Attribute Values** | -|:------------------:|:------------------------:| -| packet_src_port | string (sourcePortID) | -| packet_src_channel | string (sourceChannelID) | - -## `ibc_dest_callback` Attributes - -| **Attribute Key** | **Attribute Values** | -|:-------------------:|:------------------------:| -| packet_dest_port | string (destPortID) | -| packet_dest_channel | string (destChannelID) | diff --git a/docs/docs/04-middleware/02-callbacks/05-end-users.md b/docs/docs/04-middleware/02-callbacks/05-end-users.md deleted file mode 100644 index f2500ae3c05..00000000000 --- a/docs/docs/04-middleware/02-callbacks/05-end-users.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: End Users -sidebar_label: End Users -sidebar_position: 5 -slug: /middleware/callbacks/end-users ---- - -# Usage - -This section explains how to use the callbacks middleware from the perspective of an IBC Actor. Callbacks middleware provides two types of callbacks: - -- Source callbacks: - - `SendPacket` callback - - `OnAcknowledgementPacket` callback - - `OnTimeoutPacket` callback -- Destination callbacks: - - `ReceivePacket` callback - -For a given channel, the source callbacks are supported if the source chain has the callbacks middleware wired up in the channel's IBC stack. Similarly, the destination callbacks are supported if the destination chain has the callbacks middleware wired up in the channel's IBC stack. - -::: tip -Callbacks are always executed after the packet has been processed by the underlying IBC module. -::: - -::: warning -If the underlying application module is doing an asynchronous acknowledgement on packet receive (for example, if the [packet forward middleware](https://github.com/cosmos/ibc-apps/tree/main/middleware/packet-forward-middleware) is in the stack, and is being used by this packet), then the callbacks middleware will execute the `ReceivePacket` callback after the acknowledgement has been received. -::: - -## Source Callbacks - -Source callbacks are natively supported in the following ibc modules (if they are wrapped by the callbacks middleware): - -- `transfer` -- `icacontroller` - -To have your source callbacks be processed by the callbacks middleware, you must set the memo in the application's packet data to the following format: - -```jsonc -{ - "src_callback": { - "address": "callbackAddressString", - // optional - "gas_limit": "userDefinedGasLimitString", - } -} -``` - -## Destination Callbacks - -Destination callbacks are natively only supported in the transfer module. Note that wrapping icahost is not supported. This is because icahost should be able to execute an arbitrary transaction anyway, and can call contracts or modules directly. - -To have your destination callbacks processed by the callbacks middleware, you must set the memo in the application's packet data to the following format: - -```jsonc -{ - "dest_callback": { - "address": "callbackAddressString", - // optional - "gas_limit": "userDefinedGasLimitString", - } -} -``` - -Note that a packet can have both a source and destination callback. - -```jsonc -{ - "src_callback": { - "address": "callbackAddressString", - // optional - "gas_limit": "userDefinedGasLimitString", - }, - "dest_callback": { - "address": "callbackAddressString", - // optional - "gas_limit": "userDefinedGasLimitString", - } -} -``` - -# User Defined Gas Limit - -User defined gas limit was added for the following reasons: - -- To prevent callbacks from blocking packet lifecycle. -- To prevent relayers from being able to DOS the callback execution by sending a packet with a low amount of gas. - -::: tip -There is a chain wide parameter that sets the maximum gas limit that a user can set for a callback. This is to prevent a user from setting a gas limit that is too high for relayers. If the `"gas_limit"` is not set in the packet memo, then the maximum gas limit is used. -::: - -These goals are achieved by creating a minimum gas amount required for callback execution. If the relayer provides at least the minimum gas limit for the callback execution, then the packet lifecycle will not be blocked if the callback runs out of gas during execution, and the callback cannot be retried. If the relayer does not provided the minimum amount of gas and the callback executions runs out of gas, the entire tx is reverted and it may be executed again. - -::: tip -`SendPacket` callback is always reverted if the callback execution fails or returns an error for any reason. This is so that the packet is not sent if the callback execution fails. -::: diff --git a/docs/docs/04-middleware/02-callbacks/06-gas.md b/docs/docs/04-middleware/02-callbacks/06-gas.md deleted file mode 100644 index d9637c58344..00000000000 --- a/docs/docs/04-middleware/02-callbacks/06-gas.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: Gas Management -sidebar_label: Gas Management -sidebar_position: 6 -slug: /middleware/callbacks/gas ---- - -# Gas Management - -## Overview - -Executing arbitrary code on a chain can be arbitrarily expensive. In general, a callback may consume infinite gas (think of a callback that loops forever). This is problematic for a few reasons: - -- It can block the packet lifecycle. -- It can be used to consume all of the relayer's funds and gas. -- A relayer can DOS the callback execution by sending a packet with a low amount of gas. - -To prevent these, the callbacks middleware introduces two gas limits: a chain wide gas limit (`maxCallbackGas`) and a user defined gas limit. - -### Chain Wide Gas Limit - -Since the callbacks middleware does not have a keeper, it does not use a governance parameter to set the chain wide gas limit. Instead, the chain wide gas limit is passed in as a parameter to the callbacks middleware during initialization. - -```go -// app.go - -maxCallbackGas := uint64(1_000_000) - -var transferStack porttypes.IBCModule -transferStack = transfer.NewIBCModule(app.TransferKeeper) -transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) -transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCFeeKeeper, app.MockContractKeeper, maxCallbackGas) -// Since the callbacks middleware itself is an ics4wrapper, it needs to be passed to the transfer keeper -app.TransferKeeper.WithICS4Wrapper(transferStack.(porttypes.ICS4Wrapper)) - -// Add transfer stack to IBC Router -ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) -``` - -### User Defined Gas Limit - -The user defined gas limit is set by the IBC Actor during packet creation. The user defined gas limit is set in the packet memo. If the user defined gas limit is not set or if the user defined gas limit is greater than the chain wide gas limit, then the chain wide gas limit is used as the user defined gas limit. - -```jsonc -{ - "src_callback": { - "address": "callbackAddressString", - // optional - "gas_limit": "userDefinedGasLimitString", - }, - "dest_callback": { - "address": "callbackAddressString", - // optional - "gas_limit": "userDefinedGasLimitString", - } -} -``` - -## Gas Limit Enforcement - -During a callback execution, there are three types of gas limits that are enforced: - -- User defined gas limit -- Chain wide gas limit -- Context gas limit (amount of gas that the relayer has left for this execution) - -Chain wide gas limit is used as a maximum to the user defined gas limit as explained in the [previous section](#user-defined-gas-limit). It may also be used as a default value if no user gas limit is provided. Therefore, we can ignore the chain wide gas limit for the rest of this section and work with the minimum of the chain wide gas limit and user defined gas limit. This minimum is called the commit gas limit. - -The gas limit enforcement is done by executing the callback inside a cached context with a new gas meter. The gas meter is initialized with the minimum of the commit gas limit and the context gas limit. This minimum is called the execution gas limit. We say that retries are allowed if `context gas limit < commit gas limit`. Otherwise, we say that retries are not allowed. - -If the callback execution fails due to an out of gas error, then the middleware checks if retries are allowed. If retries are not allowed, then it recovers from the out of gas error, consumes execution gas limit from the original context, and continues with the packet life cycle. If retries are allowed, then it panics with an out of gas error to revert the entire tx. The packet can then be submitted again with a higher gas limit. The out of gas panic descriptor is shown below. - -```go -fmt.Sprintf("ibc %s callback out of gas; commitGasLimit: %d", callbackType, callbackData.CommitGasLimit)} -``` - -If the callback execution does not fail due to an out of gas error then the callbacks middleware does not block the packet life cycle regardless of whether retries are allowed or not. diff --git a/docs/docs/04-middleware/02-callbacks/_category_.json b/docs/docs/04-middleware/02-callbacks/_category_.json deleted file mode 100644 index 06ae30acec9..00000000000 --- a/docs/docs/04-middleware/02-callbacks/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Callbacks Middleware", - "position": 2, - "link": null -} diff --git a/docs/docs/04-middleware/02-callbacks/images/callbackflow.svg b/docs/docs/04-middleware/02-callbacks/images/callbackflow.svg deleted file mode 100644 index 2323889b7c9..00000000000 --- a/docs/docs/04-middleware/02-callbacks/images/callbackflow.svg +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/docs/04-middleware/02-callbacks/images/ics4-callbackflow.svg b/docs/docs/04-middleware/02-callbacks/images/ics4-callbackflow.svg deleted file mode 100644 index 032a83f7662..00000000000 --- a/docs/docs/04-middleware/02-callbacks/images/ics4-callbackflow.svg +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/docs/04-middleware/_category_.json b/docs/docs/04-middleware/_category_.json deleted file mode 100644 index 72f60663bf3..00000000000 --- a/docs/docs/04-middleware/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "IBC Middleware Modules", - "position": 4, - "link": null -} \ No newline at end of file diff --git a/docs/docs/05-migrations/01-support-denoms-with-slashes.md b/docs/docs/05-migrations/01-support-denoms-with-slashes.md deleted file mode 100644 index 99d08040903..00000000000 --- a/docs/docs/05-migrations/01-support-denoms-with-slashes.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -title: Support transfer of coins whose base denom contains slashes -sidebar_label: Support transfer of coins whose base denom contains slashes -sidebar_position: 1 -slug: /migrations/support-denoms-with-slashes ---- -# Migrating from not supporting base denoms with slashes to supporting base denoms with slashes - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -This document is necessary when chains are upgrading from a version that does not support base denoms with slashes (e.g. v3.0.0) to a version that does (e.g. v3.2.0). All versions of ibc-go smaller than v1.5.0 for the v1.x release line, v2.3.0 for the v2.x release line, and v3.1.0 for the v3.x release line do **NOT** support IBC token transfers of coins whose base denoms contain slashes. Therefore the in-place of genesis migration described in this document are required when upgrading. - -If a chain receives coins of a base denom with slashes before it upgrades to supporting it, the receive may pass however the trace information will be incorrect. - -E.g. If a base denom of `testcoin/testcoin/testcoin` is sent to a chain that does not support slashes in the base denom, the receive will be successful. However, the trace information stored on the receiving chain will be: `Trace: "transfer/{channel-id}/testcoin/testcoin", BaseDenom: "testcoin"`. - -This incorrect trace information must be corrected when the chain does upgrade to fully supporting denominations with slashes. - -To do so, chain binaries should include a migration script that will run when the chain upgrades from not supporting base denominations with slashes to supporting base denominations with slashes. - -## Chains - -### ICS20 - Transfer - -The transfer module will now support slashes in base denoms, so we must iterate over current traces to check if any of them are incorrectly formed and correct the trace information. - -### Upgrade Proposal - -```go -app.UpgradeKeeper.SetUpgradeHandler("MigrateTraces", - func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - // transfer module consensus version has been bumped to 2 - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) -``` - -This is only necessary if there are denom traces in the store with incorrect trace information from previously received coins that had a slash in the base denom. However, it is recommended that any chain upgrading to support base denominations with slashes runs this code for safety. - -For a more detailed sample, please check out the code changes in [this pull request](https://github.com/cosmos/ibc-go/pull/1680). - -### Genesis Migration - -If the chain chooses to add support for slashes in base denoms via genesis export, then the trace information must be corrected during genesis migration. - -The migration code required may look like: - -```go -func migrateGenesisSlashedDenomsUpgrade(appState genutiltypes.AppMap, clientCtx client.Context, genDoc *tmtypes.GenesisDoc) (genutiltypes.AppMap, error) { - if appState[ibctransfertypes.ModuleName] != nil { - transferGenState := &ibctransfertypes.GenesisState{} - clientCtx.Codec.MustUnmarshalJSON(appState[ibctransfertypes.ModuleName], transferGenState) - - substituteTraces := make([]ibctransfertypes.DenomTrace, len(transferGenState.DenomTraces)) - for i, dt := range transferGenState.DenomTraces { - // replace all previous traces with the latest trace if validation passes - // note most traces will have same value - newTrace := ibctransfertypes.ParseDenomTrace(dt.GetFullDenomPath()) - - if err := newTrace.Validate(); err != nil { - substituteTraces[i] = dt - } else { - substituteTraces[i] = newTrace - } - } - - transferGenState.DenomTraces = substituteTraces - - // delete old genesis state - delete(appState, ibctransfertypes.ModuleName) - - // set new ibc transfer genesis state - appState[ibctransfertypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(transferGenState) - } - - return appState, nil -} -``` - -For a more detailed sample, please check out the code changes in [this pull request](https://github.com/cosmos/ibc-go/pull/1528). diff --git a/docs/docs/05-migrations/02-sdk-to-v1.md b/docs/docs/05-migrations/02-sdk-to-v1.md deleted file mode 100644 index e24c0f62bb6..00000000000 --- a/docs/docs/05-migrations/02-sdk-to-v1.md +++ /dev/null @@ -1,195 +0,0 @@ ---- -title: SDK v0.43 to IBC-Go v1 -sidebar_label: SDK v0.43 to IBC-Go v1 -sidebar_position: 2 -slug: /migrations/sdk-to-v1 ---- - -# Migrating to ibc-go - -This file contains information on how to migrate from the IBC module contained in the SDK 0.41.x and 0.42.x lines to the IBC module in the ibc-go repository based on the 0.44 SDK version. - -## Import Changes - -The most obvious changes is import name changes. We need to change: - -- applications -> apps -- cosmos-sdk/x/ibc -> ibc-go - -On my GNU/Linux based machine I used the following commands, executed in order: - -```shell -grep -RiIl 'cosmos-sdk\/x\/ibc\/applications' | xargs sed -i 's/cosmos-sdk\/x\/ibc\/applications/ibc-go\/modules\/apps/g' -``` - -```shell -grep -RiIl 'cosmos-sdk\/x\/ibc' | xargs sed -i 's/cosmos-sdk\/x\/ibc/ibc-go\/modules/g' -``` - -ref: [explanation of the above commands](https://www.internalpointers.com/post/linux-find-and-replace-text-multiple-files) - -Executing these commands out of order will cause issues. - -Feel free to use your own method for modifying import names. - -NOTE: Updating to the `v0.44.0` SDK release and then running `go mod tidy` will cause a downgrade to `v0.42.0` in order to support the old IBC import paths. -Update the import paths before running `go mod tidy`. - -## Chain Upgrades - -Chains may choose to upgrade via an upgrade proposal or genesis upgrades. Both in-place store migrations and genesis migrations are supported. - -**WARNING**: Please read at least the quick guide for [IBC client upgrades](../01-ibc/05-upgrades/01-quick-guide.md) before upgrading your chain. It is highly recommended you do not change the chain-ID during an upgrade, otherwise you must follow the IBC client upgrade instructions. - -Both in-place store migrations and genesis migrations will: - -- migrate the solo machine client state from v1 to v2 protobuf definitions -- prune all solo machine consensus states -- prune all expired tendermint consensus states - -Chains must set a new connection parameter during either in place store migrations or genesis migration. The new parameter, max expected block time, is used to enforce packet processing delays on the receiving end of an IBC packet flow. Checkout the [docs](https://github.com/cosmos/ibc-go/blob/release/v1.0.x/docs/ibc/proto-docs.md#params-2) for more information. - -### In-Place Store Migrations - -The new chain binary will need to run migrations in the upgrade handler. The fromVM (previous module version) for the IBC module should be 1. This will allow migrations to be run for IBC updating the version from 1 to 2. - -Ex: - -```go -app.UpgradeKeeper.SetUpgradeHandler("my-upgrade-proposal", - func(ctx sdk.Context, _ upgradetypes.Plan, _ module.VersionMap) (module.VersionMap, error) { - // set max expected block time parameter. Replace the default with your expected value - // https://github.com/cosmos/ibc-go/blob/release/v1.0.x/docs/ibc/proto-docs.md#params-2 - app.IBCKeeper.ConnectionKeeper.SetParams(ctx, ibcconnectiontypes.DefaultParams()) - - fromVM := map[string]uint64{ - ... // other modules - "ibc": 1, - ... - } - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) - -``` - -### Genesis Migrations - -To perform genesis migrations, the following code must be added to your existing migration code. - -```go -// add imports as necessary -import ( - ibcv100 "github.com/cosmos/ibc-go/modules/core/legacy/v100" - ibchost "github.com/cosmos/ibc-go/modules/core/24-host" -) - -... - -// add in migrate cmd function -// expectedTimePerBlock is a new connection parameter -// https://github.com/cosmos/ibc-go/blob/release/v1.0.x/docs/ibc/proto-docs.md#params-2 -newGenState, err = ibcv100.MigrateGenesis(newGenState, clientCtx, *genDoc, expectedTimePerBlock) -if err != nil { - return err -} -``` - -**NOTE:** The genesis chain-id, time and height MUST be updated before migrating IBC, otherwise the tendermint consensus state will not be pruned. - -## IBC Keeper Changes - -The IBC Keeper now takes in the Upgrade Keeper. Please add the chains' Upgrade Keeper after the Staking Keeper: - -```diff -// Create IBC Keeper -app.IBCKeeper = ibckeeper.NewKeeper( -- appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, scopedIBCKeeper, -+ appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper, -) -``` - -## Proposals - -### UpdateClientProposal - -The `UpdateClient` has been modified to take in two client-identifiers and one initial height. Please see the [documentation](../01-ibc/06-proposals.md) for more information. - -### UpgradeProposal - -A new IBC proposal type has been added, `UpgradeProposal`. This handles an IBC (breaking) Upgrade. -The previous `UpgradedClientState` field in an Upgrade `Plan` has been deprecated in favor of this new proposal type. - -### Proposal Handler Registration - -The `ClientUpdateProposalHandler` has been renamed to `ClientProposalHandler`. -It handles both `UpdateClientProposal`s and `UpgradeProposal`s. - -Add this import: - -```diff -+ ibcclienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" -``` - -Please ensure the governance module adds the correct route: - -```diff -- AddRoute(ibchost.RouterKey, ibcclient.NewClientUpdateProposalHandler(app.IBCKeeper.ClientKeeper)) -+ AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)) -``` - -NOTE: Simapp registration was incorrect in the 0.41.x releases. The `UpdateClient` proposal handler should be registered with the router key belonging to `ibc-go/core/02-client/types` -as shown in the diffs above. - -### Proposal CLI Registration - -Please ensure both proposal type CLI commands are registered on the governance module by adding the following arguments to `gov.NewAppModuleBasic()`: - -Add the following import: - -```diff -+ ibcclientclient "github.com/cosmos/ibc-go/modules/core/02-client/client" -``` - -Register the cli commands: - -```diff -gov.NewAppModuleBasic( - paramsclient.ProposalHandler, distrclient.ProposalHandler, upgradeclient.ProposalHandler, upgradeclient.CancelProposalHandler, -+ ibcclientclient.UpdateClientProposalHandler, ibcclientclient.UpgradeProposalHandler, -), -``` - -REST routes are not supported for these proposals. - -## Proto file changes - -The gRPC querier service endpoints have changed slightly. The previous files used `v1beta1` gRPC route, this has been updated to `v1`. - -The solo machine has replaced the FrozenSequence uint64 field with a IsFrozen boolean field. The package has been bumped from `v1` to `v2` - -## IBC callback changes - -### OnRecvPacket - -Application developers need to update their `OnRecvPacket` callback logic. - -The `OnRecvPacket` callback has been modified to only return the acknowledgement. The acknowledgement returned must implement the `Acknowledgement` interface. The acknowledgement should indicate if it represents a successful processing of a packet by returning true on `Success()` and false in all other cases. A return value of false on `Success()` will result in all state changes which occurred in the callback being discarded. More information can be found in the [documentation](../01-ibc/03-apps/01-apps.md#receiving-packets). - -The `OnRecvPacket`, `OnAcknowledgementPacket`, and `OnTimeoutPacket` callbacks are now passed the `sdk.AccAddress` of the relayer who relayed the IBC packet. Applications may use or ignore this information. - -## IBC Event changes - -The `packet_data` attribute has been deprecated in favor of `packet_data_hex`, in order to provide standardized encoding/decoding of packet data in events. While the `packet_data` event still exists, all relayers and IBC Event consumers are strongly encouraged to switch over to using `packet_data_hex` as soon as possible. - -The `packet_ack` attribute has also been deprecated in favor of `packet_ack_hex` for the same reason stated above. All relayers and IBC Event consumers are strongly encouraged to switch over to using `packet_ack_hex` as soon as possible. - -The `consensus_height` attribute has been removed in the Misbehaviour event emitted. IBC clients no longer have a frozen height and misbehaviour does not necessarily have an associated height. - -## Relevant SDK changes - -- (codec) [\#9226](https://github.com/cosmos/cosmos-sdk/pull/9226) Rename codec interfaces and methods, to follow a general Go interfaces: - - `codec.Marshaler` → `codec.Codec` (this defines objects which serialize other objects) - - `codec.BinaryMarshaler` → `codec.BinaryCodec` - - `codec.JSONMarshaler` → `codec.JSONCodec` - - Removed `BinaryBare` suffix from `BinaryCodec` methods (`MarshalBinaryBare`, `UnmarshalBinaryBare`, ...) - - Removed `Binary` infix from `BinaryCodec` methods (`MarshalBinaryLengthPrefixed`, `UnmarshalBinaryLengthPrefixed`, ...) diff --git a/docs/docs/05-migrations/03-v1-to-v2.md b/docs/docs/05-migrations/03-v1-to-v2.md deleted file mode 100644 index 77d3de4e87f..00000000000 --- a/docs/docs/05-migrations/03-v1-to-v2.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: IBC-Go v1 to v2 -sidebar_label: IBC-Go v1 to v2 -sidebar_position: 3 -slug: /migrations/v1-to-v2 ---- -# Migrating from ibc-go v1 to v2 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -```go -github.com/cosmos/ibc-go -> github.com/cosmos/ibc-go/v2 -``` - -## Chains - -- No relevant changes were made in this release. - -## IBC Apps - -A new function has been added to the app module interface: - -```go -// NegotiateAppVersion performs application version negotiation given the provided channel ordering, connectionID, portID, counterparty and proposed version. -// An error is returned if version negotiation cannot be performed. For example, an application module implementing this interface -// may decide to return an error in the event of the proposed version being incompatible with it's own -NegotiateAppVersion( - ctx sdk.Context, - order channeltypes.Order, - connectionID string, - portID string, - counterparty channeltypes.Counterparty, - proposedVersion string, -) (version string, err error) -``` - -This function should perform application version negotiation and return the negotiated version. If the version cannot be negotiated, an error should be returned. This function is only used on the client side. - -### `sdk.Result` removed - -`sdk.Result` has been removed as a return value in the application callbacks. Previously it was being discarded by core IBC and was thus unused. - -## Relayers - -A new gRPC has been added to 05-port, `AppVersion`. It returns the negotiated app version. This function should be used for the `ChanOpenTry` channel handshake step to decide upon the application version which should be set in the channel. - -## IBC Light Clients - -- No relevant changes were made in this release. diff --git a/docs/docs/05-migrations/04-v2-to-v3.md b/docs/docs/05-migrations/04-v2-to-v3.md deleted file mode 100644 index 9c6433e0e49..00000000000 --- a/docs/docs/05-migrations/04-v2-to-v3.md +++ /dev/null @@ -1,186 +0,0 @@ ---- -title: IBC-Go v2 to v3 -sidebar_label: IBC-Go v2 to v3 -sidebar_position: 4 -slug: /migrations/v2-to-v3 ---- - -# Migrating from ibc-go v2 to v3 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -```go -github.com/cosmos/ibc-go/v2 -> github.com/cosmos/ibc-go/v3 -``` - -No genesis or in-place migrations are required when upgrading from v1 or v2 of ibc-go. - -## Chains - -### ICS20 - -The `transferkeeper.NewKeeper(...)` now takes in an ICS4Wrapper. -The ICS4Wrapper should be the IBC Channel Keeper unless ICS 20 is being connected to a middleware application. - -### ICS27 - -ICS27 Interchain Accounts has been added as a supported IBC application of ibc-go. -Please see the [ICS27 documentation](../02-apps/02-interchain-accounts/01-overview.md) for more information. - -### Upgrade Proposal - -If the chain will adopt ICS27, it must set the appropriate params during the execution of the upgrade handler in `app.go`: - -```go -app.UpgradeKeeper.SetUpgradeHandler("v3", - func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - // set the ICS27 consensus version so InitGenesis is not run - fromVM[icatypes.ModuleName] = icamodule.ConsensusVersion() - - // create ICS27 Controller submodule params - controllerParams := icacontrollertypes.Params{ - ControllerEnabled: true, - } - - // create ICS27 Host submodule params - hostParams := icahosttypes.Params{ - HostEnabled: true, - AllowMessages: []string{"/cosmos.bank.v1beta1.MsgSend", ...}, - } - - // initialize ICS27 module - icamodule.InitModule(ctx, controllerParams, hostParams) - - ... - - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) -``` - -The host and controller submodule params only need to be set if the chain integrates those submodules. -For example, if a chain chooses not to integrate a controller submodule, it may pass empty params into `InitModule`. - -#### Add `StoreUpgrades` for ICS27 module - -For ICS27 it is also necessary to [manually add store upgrades](https://docs.cosmos.network/main/learn/advanced/upgrade#add-storeupgrades-for-new-modules) for the new ICS27 module and then configure the store loader to apply those upgrades in `app.go`: - -```go -if upgradeInfo.Name == "v3" && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { - storeUpgrades := store.StoreUpgrades{ - Added: []string{icacontrollertypes.StoreKey, icahosttypes.StoreKey}, - } - - app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) -} -``` - -This ensures that the new module's stores are added to the multistore before the migrations begin. -The host and controller submodule keys only need to be added if the chain integrates those submodules. -For example, if a chain chooses not to integrate a controller submodule, it does not need to add the controller key to the `Added` field. - -### Genesis migrations - -If the chain will adopt ICS27 and chooses to upgrade via a genesis export, then the ICS27 parameters must be set during genesis migration. - -The migration code required may look like: - -```go - controllerGenesisState := icatypes.DefaultControllerGenesis() - // overwrite parameters as desired - controllerGenesisState.Params = icacontrollertypes.Params{ - ControllerEnabled: true, - } - - hostGenesisState := icatypes.DefaultHostGenesis() - // overwrite parameters as desired - hostGenesisState.Params = icahosttypes.Params{ - HostEnabled: true, - AllowMessages: []string{"/cosmos.bank.v1beta1.MsgSend", ...}, - } - - icaGenesisState := icatypes.NewGenesisState(controllerGenesisState, hostGenesisState) - - // set new ics27 genesis state - appState[icatypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(icaGenesisState) -``` - -### Ante decorator - -The field of type `channelkeeper.Keeper` in the `AnteDecorator` structure has been replaced with a field of type `*keeper.Keeper`: - -```diff -type AnteDecorator struct { -- k channelkeeper.Keeper -+ k *keeper.Keeper -} - -- func NewAnteDecorator(k channelkeeper.Keeper) AnteDecorator { -+ func NewAnteDecorator(k *keeper.Keeper) AnteDecorator { - return AnteDecorator{k: k} -} -``` - -## IBC Apps - -### `OnChanOpenTry` must return negotiated application version - -The `OnChanOpenTry` application callback has been modified. -The return signature now includes the application version. -IBC applications must perform application version negoitation in `OnChanOpenTry` using the counterparty version. -The negotiated application version then must be returned in `OnChanOpenTry` to core IBC. -Core IBC will set this version in the TRYOPEN channel. - -### `OnChanOpenAck` will take additional `counterpartyChannelID` argument - -The `OnChanOpenAck` application callback has been modified. -The arguments now include the counterparty channel id. - -### `NegotiateAppVersion` removed from `IBCModule` interface - -Previously this logic was handled by the `NegotiateAppVersion` function. -Relayers would query this function before calling `ChanOpenTry`. -Applications would then need to verify that the passed in version was correct. -Now applications will perform this version negotiation during the channel handshake, thus removing the need for `NegotiateAppVersion`. - -### Channel state will not be set before application callback - -The channel handshake logic has been reorganized within core IBC. -Channel state will not be set in state after the application callback is performed. -Applications must rely only on the passed in channel parameters instead of querying the channel keeper for channel state. - -### IBC application callbacks moved from `AppModule` to `IBCModule` - -Previously, IBC module callbacks were apart of the `AppModule` type. -The recommended approach is to create an `IBCModule` type and move the IBC module callbacks from `AppModule` to `IBCModule` in a separate file `ibc_module.go`. - -The mock module go API has been broken in this release by applying the above format. -The IBC module callbacks have been moved from the mock modules `AppModule` into a new type `IBCModule`. - -As apart of this release, the mock module now supports middleware testing. Please see the [README](https://github.com/cosmos/ibc-go/blob/v3.0.0/testing/README.md#middleware-testing) for more information. - -Please review the [mock](https://github.com/cosmos/ibc-go/blob/v3.0.0/testing/mock/ibc_module.go) and [transfer](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/transfer/ibc_module.go) modules as examples. Additionally, [simapp](https://github.com/cosmos/ibc-go/blob/v3.0.0/testing/simapp/app.go) provides an example of how `IBCModule` types should now be added to the IBC router in favour of `AppModule`. - -### IBC testing package - -`TestChain`s are now created with chainID's beginning from an index of 1. Any calls to `GetChainID(0)` will now fail. Please increment all calls to `GetChainID` by 1. - -## Relayers - -`AppVersion` gRPC has been removed. -The `version` string in `MsgChanOpenTry` has been deprecated and will be ignored by core IBC. -Relayers no longer need to determine the version to use on the `ChanOpenTry` step. -IBC applications will determine the correct version using the counterparty version. - -## IBC Light Clients - -The `GetProofSpecs` function has been removed from the `ClientState` interface. This function was previously unused by core IBC. Light clients which don't use this function may remove it. diff --git a/docs/docs/05-migrations/05-v3-to-v4.md b/docs/docs/05-migrations/05-v3-to-v4.md deleted file mode 100644 index d2407df20e8..00000000000 --- a/docs/docs/05-migrations/05-v3-to-v4.md +++ /dev/null @@ -1,159 +0,0 @@ ---- -title: IBC-Go v3 to v4 -sidebar_label: IBC-Go v3 to v4 -sidebar_position: 5 -slug: /migrations/v3-to-v4 ---- -# Migrating from ibc-go v3 to v4 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -```go -github.com/cosmos/ibc-go/v3 -> github.com/cosmos/ibc-go/v4 -``` - -No genesis or in-place migrations required when upgrading from v1 or v2 of ibc-go. - -## Chains - -### ICS27 - Interchain Accounts - -The controller submodule implements now the 05-port `Middleware` interface instead of the 05-port `IBCModule` interface. Chains that integrate the controller submodule, need to create it with the `NewIBCMiddleware` constructor function. For example: - -```diff -- icacontroller.NewIBCModule(app.ICAControllerKeeper, icaAuthIBCModule) -+ icacontroller.NewIBCMiddleware(icaAuthIBCModule, app.ICAControllerKeeper) -``` - -where `icaAuthIBCModule` is the Interchain Accounts authentication IBC Module. - -### ICS29 - Fee Middleware - -The Fee Middleware module, as the name suggests, plays the role of an IBC middleware and as such must be configured by chain developers to route and handle IBC messages correctly. - -Please read the Fee Middleware [integration documentation](https://ibc.cosmos.network/main/middleware/ics29-fee/integration.html) for an in depth guide on how to congfigure the module correctly in order to incentivize IBC packets. - -Take a look at the following diff for an [example setup](https://github.com/cosmos/ibc-go/pull/1432/files#diff-d18972debee5e64f16e40807b2ae112ddbe609504a93ea5e1c80a5d489c3a08aL366) of how to incentivize ics27 channels. - -### Migration to fix support for base denoms with slashes - -As part of [v1.5.0](https://github.com/cosmos/ibc-go/releases/tag/v1.5.0), [v2.3.0](https://github.com/cosmos/ibc-go/releases/tag/v2.3.0) and [v3.1.0](https://github.com/cosmos/ibc-go/releases/tag/v3.1.0) some [migration handler code sample was documented](./01-support-denoms-with-slashes.md#upgrade-proposal) that needs to run in order to correct the trace information of coins transferred using ICS20 whose base denom contains slashes. - -Based on feedback from the community we add now an improved solution to run the same migration that does not require copying a large piece of code over from the migration document, but instead requires only adding a one-line upgrade handler. - -If the chain will migrate to supporting base denoms with slashes, it must set the appropriate params during the execution of the upgrade handler in `app.go`: - -```go -app.UpgradeKeeper.SetUpgradeHandler("MigrateTraces", - func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - // transfer module consensus version has been bumped to 2 - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) -``` - -If a chain receives coins of a base denom with slashes before it upgrades to supporting it, the receive may pass however the trace information will be incorrect. - -E.g. If a base denom of `testcoin/testcoin/testcoin` is sent to a chain that does not support slashes in the base denom, the receive will be successful. However, the trace information stored on the receiving chain will be: `Trace: "transfer/{channel-id}/testcoin/testcoin", BaseDenom: "testcoin"`. - -This incorrect trace information must be corrected when the chain does upgrade to fully supporting denominations with slashes. - -## IBC Apps - -### ICS03 - Connection - -Crossing hellos have been removed from 03-connection handshake negotiation. -`PreviousConnectionId` in `MsgConnectionOpenTry` has been deprecated and is no longer used by core IBC. - -`NewMsgConnectionOpenTry` no longer takes in the `PreviousConnectionId` as crossing hellos are no longer supported. A non-empty `PreviousConnectionId` will fail basic validation for this message. - -### ICS04 - Channel - -The `WriteAcknowledgement` API now takes the `exported.Acknowledgement` type instead of passing in the acknowledgement byte array directly. -This is an API breaking change and as such IBC application developers will have to update any calls to `WriteAcknowledgement`. - -The `OnChanOpenInit` application callback has been modified. -The return signature now includes the application version as detailed in the latest IBC [spec changes](https://github.com/cosmos/ibc/pull/629). - -The `NewErrorAcknowledgement` method signature has changed. -It now accepts an `error` rather than a `string`. This was done in order to prevent accidental state changes. -All error acknowledgements now contain a deterministic ABCI code and error message. It is the responsibility of the application developer to emit error details in events. - -Crossing hellos have been removed from 04-channel handshake negotiation. -IBC Applications no longer need to account from already claimed capabilities in the `OnChanOpenTry` callback. The capability provided by core IBC must be able to be claimed with error. -`PreviousChannelId` in `MsgChannelOpenTry` has been deprecated and is no longer used by core IBC. - -`NewMsgChannelOpenTry` no longer takes in the `PreviousChannelId` as crossing hellos are no longer supported. A non-empty `PreviousChannelId` will fail basic validation for this message. - -### ICS27 - Interchain Accounts - -The `RegisterInterchainAccount` API has been modified to include an additional `version` argument. This change has been made in order to support ICS29 fee middleware, for relayer incentivization of ICS27 packets. -Consumers of the `RegisterInterchainAccount` are now expected to build the appropriate JSON encoded version string themselves and pass it accordingly. -This should be constructed within the interchain accounts authentication module which leverages the APIs exposed via the interchain accounts `controllerKeeper`. If an empty string is passed in the `version` argument, then the version will be initialized to a default value in the `OnChanOpenInit` callback of the controller's handler, so that channel handshake can proceed. - -The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, msg.Owner, string(appVersion)); err != nil { - return err -} -``` - -Similarly, if the application stack is configured to route through ICS29 fee middleware and a fee enabled channel is desired, construct the appropriate ICS29 `Metadata` type: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -feeMetadata := feetypes.Metadata{ - AppVersion: string(appVersion), - FeeVersion: feetypes.Version, -} - -feeEnabledVersion, err := feetypes.ModuleCdc.MarshalJSON(&feeMetadata) -if err != nil { - return err -} - -if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, msg.Owner, string(feeEnabledVersion)); err != nil { - return err -} -``` - -## Relayers - -When using the `DenomTrace` gRPC, the full IBC denomination with the `ibc/` prefix may now be passed in. - -Crossing hellos are no longer supported by core IBC for 03-connection and 04-channel. The handshake should be completed in the logical 4 step process (INIT, TRY, ACK, CONFIRM). diff --git a/docs/docs/05-migrations/06-v4-to-v5.md b/docs/docs/05-migrations/06-v4-to-v5.md deleted file mode 100644 index d5055d5006a..00000000000 --- a/docs/docs/05-migrations/06-v4-to-v5.md +++ /dev/null @@ -1,441 +0,0 @@ ---- -title: IBC-Go v4 to v5 -sidebar_label: IBC-Go v4 to v5 -sidebar_position: 6 -slug: /migrations/v4-to-v5 ---- - -# Migrating from v4 to v5 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- [Chains](#chains) -- [IBC Apps](#ibc-apps) -- [Relayers](#relayers) -- [IBC Light Clients](#ibc-light-clients) - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -```go -github.com/cosmos/ibc-go/v4 -> github.com/cosmos/ibc-go/v5 -``` - -## Chains - -### Ante decorator - -The `AnteDecorator` type in `core/ante` has been renamed to `RedundantRelayDecorator` (and the corresponding constructor function to `NewRedundantRelayDecorator`). Therefore in the function that creates the instance of the `sdk.AnteHandler` type (e.g. `NewAnteHandler`) the change would be like this: - -```diff -func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { - // parameter validation - - anteDecorators := []sdk.AnteDecorator{ - // other ante decorators -- ibcante.NewAnteDecorator(opts.IBCkeeper), -+ ibcante.NewRedundantRelayDecorator(options.IBCKeeper), - } - - return sdk.ChainAnteDecorators(anteDecorators...), nil -} -``` - -The `AnteDecorator` was actually renamed twice, but in [this PR](https://github.com/cosmos/ibc-go/pull/1820) you can see the changes made for the final rename. - -## IBC Apps - -### Core - -The `key` parameter of the `NewKeeper` function in `modules/core/keeper` is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`): - -```diff -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - stakingKeeper clienttypes.StakingKeeper, - upgradeKeeper clienttypes.UpgradeKeeper, - scopedKeeper capabilitykeeper.ScopedKeeper, -) *Keeper -``` - -The `RegisterRESTRoutes` function in `modules/core` has been removed. - -### ICS03 - Connection - -The `key` parameter of the `NewKeeper` function in `modules/core/03-connection/keeper` is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`): - -```diff -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - ck types.ClientKeeper -) Keeper -``` - -### ICS04 - Channel - -The function `NewPacketId` in `modules/core/04-channel/types` has been renamed to `NewPacketID`: - -```diff -- func NewPacketId( -+ func NewPacketID( - portID, - channelID string, - seq uint64 -) PacketId -``` - -The `key` parameter of the `NewKeeper` function in `modules/core/04-channel/keeper` is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`): - -```diff -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - clientKeeper types.ClientKeeper, - connectionKeeper types.ConnectionKeeper, - portKeeper types.PortKeeper, - scopedKeeper capabilitykeeper.ScopedKeeper, -) Keeper -``` - -### ICS20 - Transfer - -The `key` parameter of the `NewKeeper` function in `modules/apps/transfer/keeper` is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`): - -```diff -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - ics4Wrapper types.ICS4Wrapper, - channelKeeper types.ChannelKeeper, - portKeeper types.PortKeeper, - authKeeper types.AccountKeeper, - bankKeeper types.BankKeeper, - scopedKeeper capabilitykeeper.ScopedKeeper, -) Keeper -``` - -The `amount` parameter of function `GetTransferCoin` in `modules/apps/transfer/types` is now of type `math.Int` (`"cosmossdk.io/math"`): - -```diff -func GetTransferCoin( - portID, channelID, baseDenom string, -- amount sdk.Int -+ amount math.Int -) sdk.Coin -``` - -The `RegisterRESTRoutes` function in `modules/apps/transfer` has been removed. - -### ICS27 - Interchain Accounts - -The `key` and `msgRouter` parameters of the `NewKeeper` functions in - -- `modules/apps/27-interchain-accounts/controller/keeper` -- and `modules/apps/27-interchain-accounts/host/keeper` - -have changed type. The `key` parameter is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`), and the `msgRouter` parameter is now of type `*icatypes.MessageRouter` (where `icatypes` is an import alias for `"github.com/cosmos/ibc-go/v5/modules/apps/27-interchain-accounts/types"`): - -```diff -// NewKeeper creates a new interchain accounts controller Keeper instance -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - ics4Wrapper icatypes.ICS4Wrapper, - channelKeeper icatypes.ChannelKeeper, - portKeeper icatypes.PortKeeper, - scopedKeeper capabilitykeeper.ScopedKeeper, -- msgRouter *baseapp.MsgServiceRouter, -+ msgRouter *icatypes.MessageRouter, -) Keeper -``` - -```diff -// NewKeeper creates a new interchain accounts host Keeper instance -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - channelKeeper icatypes.ChannelKeeper, - portKeeper icatypes.PortKeeper, - accountKeeper icatypes.AccountKeeper, - scopedKeeper capabilitykeeper.ScopedKeeper, -- msgRouter *baseapp.MsgServiceRouter, -+ msgRouter *icatypes.MessageRouter, -) Keeper -``` - -The new `MessageRouter` interface is defined as: - -```go -type MessageRouter interface { - Handler(msg sdk.Msg) baseapp.MsgServiceHandler -} -``` - -The `RegisterRESTRoutes` function in `modules/apps/27-interchain-accounts` has been removed. - -An additional parameter, `ics4Wrapper` has been added to the `host` submodule `NewKeeper` function in `modules/apps/27-interchain-accounts/host/keeper`. -This allows the `host` submodule to correctly unwrap the channel version for channel reopening handshakes in the `OnChanOpenTry` callback. - -```diff -func NewKeeper( - cdc codec.BinaryCodec, - key storetypes.StoreKey, - paramSpace paramtypes.Subspace, -+ ics4Wrapper icatypes.ICS4Wrapper, - channelKeeper icatypes.ChannelKeeper, - portKeeper icatypes.PortKeeper, - accountKeeper icatypes.AccountKeeper, - scopedKeeper icatypes.ScopedKeeper, - msgRouter icatypes.MessageRouter, -) Keeper -``` - -#### Cosmos SDK message handler responses in packet acknowledgement - -The construction of the transaction response of a message execution on the host chain has changed. The `Data` field in the `sdk.TxMsgData` has been deprecated and since Cosmos SDK 0.46 the `MsgResponses` field contains the message handler responses packed into `Any`s. - -For chains on Cosmos SDK 0.45 and below, the message response was constructed like this: - -```go -txMsgData := &sdk.TxMsgData{ - Data: make([]*sdk.MsgData, len(msgs)), -} - -for i, msg := range msgs { - // message validation - - msgResponse, err := k.executeMsg(cacheCtx, msg) - // return if err != nil - - txMsgData.Data[i] = &sdk.MsgData{ - MsgType: sdk.MsgTypeURL(msg), - Data: msgResponse, - } -} - -// emit events - -txResponse, err := proto.Marshal(txMsgData) -// return if err != nil - -return txResponse, nil -``` - -And for chains on Cosmos SDK 0.46 and above, it is now done like this: - -```go -txMsgData := &sdk.TxMsgData{ - MsgResponses: make([]*codectypes.Any, len(msgs)), -} - -for i, msg := range msgs { - // message validation - - protoAny, err := k.executeMsg(cacheCtx, msg) - // return if err != nil - - txMsgData.MsgResponses[i] = protoAny -} - -// emit events - -txResponse, err := proto.Marshal(txMsgData) -// return if err != nil - -return txResponse, nil -``` - -When handling the acknowledgement in the `OnAcknowledgementPacket` callback of a custom ICA controller module, then depending on whether `txMsgData.Data` is empty or not, the logic to handle the message handler response will be different. **Only controller chains on Cosmos SDK 0.46 or above will be able to write the logic needed to handle the response from a host chain on Cosmos SDK 0.46 or above.** - -```go -var ack channeltypes.Acknowledgement -if err := channeltypes.SubModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { - return err -} - -var txMsgData sdk.TxMsgData -if err := proto.Unmarshal(ack.GetResult(), txMsgData); err != nil { - return err -} - -switch len(txMsgData.Data) { -case 0: // for SDK 0.46 and above - for _, msgResponse := range txMsgData.MsgResponses { - // unmarshall msgResponse and execute logic based on the response - } - return nil -default: // for SDK 0.45 and below - for _, msgData := range txMsgData.Data { - // unmarshall msgData and execute logic based on the response - } -} -``` - -See [ADR-03](/architecture/adr-003-ics27-acknowledgement#next-major-version-format) for more information or the [corrresponding documentation about authentication modules](../02-apps/02-interchain-accounts/03-auth-modules.md#onacknowledgementpacket). - -### ICS29 - Fee Middleware - -The `key` parameter of the `NewKeeper` function in `modules/apps/29-fee` is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`): - -```diff -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - ics4Wrapper types.ICS4Wrapper, - channelKeeper types.ChannelKeeper, - portKeeper types.PortKeeper, - authKeeper types.AccountKeeper, - bankKeeper types.BankKeeper, -) Keeper -``` - -The `RegisterRESTRoutes` function in `modules/apps/29-fee` has been removed. - -### IBC testing package - -The `MockIBCApp` type has been renamed to `IBCApp` (and the corresponding constructor function to `NewIBCApp`). This has resulted therefore in: - -- The `IBCApp` field of the `*IBCModule` in `testing/mock` to change its type as well to `*IBCApp`: - -```diff -type IBCModule struct { - appModule *AppModule -- IBCApp *MockIBCApp // base application of an IBC middleware stack -+ IBCApp *IBCApp // base application of an IBC middleware stack -} -``` - -- The `app` parameter to `*NewIBCModule` in `testing/mock` to change its type as well to `*IBCApp`: - -```diff -func NewIBCModule( - appModule *AppModule, -- app *MockIBCApp -+ app *IBCApp -) IBCModule -``` - -The `MockEmptyAcknowledgement` type has been renamed to `EmptyAcknowledgement` (and the corresponding constructor function to `NewEmptyAcknowledgement`). - -The `TestingApp` interface in `testing` has gone through some modifications: - -- The return type of the function `GetStakingKeeper` is not the concrete type `stakingkeeper.Keeper` anymore (where `stakingkeeper` is an import alias for `"github.com/cosmos/cosmos-sdk/x/staking/keeper"`), but it has been changed to the interface `ibctestingtypes.StakingKeeper` (where `ibctestingtypes` is an import alias for `""github.com/cosmos/ibc-go/v5/testing/types"`). See this [PR](https://github.com/cosmos/ibc-go/pull/2028) for more details. The `StakingKeeper` interface is defined as: - -```go -type StakingKeeper interface { - GetHistoricalInfo(ctx sdk.Context, height int64) (stakingtypes.HistoricalInfo, bool) -} -``` - -- The return type of the function `LastCommitID` has changed to `storetypes.CommitID` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`). - -See the following `git diff` for more details: - -```diff -type TestingApp interface { - abci.Application - - // ibc-go additions - GetBaseApp() *baseapp.BaseApp -- GetStakingKeeper() stakingkeeper.Keeper -+ GetStakingKeeper() ibctestingtypes.StakingKeeper - GetIBCKeeper() *keeper.Keeper - GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper - GetTxConfig() client.TxConfig - - // Implemented by SimApp - AppCodec() codec.Codec - - // Implemented by BaseApp -- LastCommitID() sdk.CommitID -+ LastCommitID() storetypes.CommitID - LastBlockHeight() int64 -} -``` - -The `powerReduction` parameter of the function `SetupWithGenesisValSet` in `testing` is now of type `math.Int` (`"cosmossdk.io/math"`): - -```diff -func SetupWithGenesisValSet( - t *testing.T, - valSet *tmtypes.ValidatorSet, - genAccs []authtypes.GenesisAccount, - chainID string, -- powerReduction sdk.Int, -+ powerReduction math.Int, - balances ...banktypes.Balance -) TestingApp -``` - -The `accAmt` parameter of the functions - -- `AddTestAddrsFromPubKeys` , -- `AddTestAddrs` -- and `AddTestAddrsIncremental` - -in `testing/simapp` are now of type `math.Int` (`"cosmossdk.io/math"`): - -```diff -func AddTestAddrsFromPubKeys( - app *SimApp, - ctx sdk.Context, - pubKeys []cryptotypes.PubKey, -- accAmt sdk.Int, -+ accAmt math.Int -) -func addTestAddrs( - app *SimApp, - ctx sdk.Context, - accNum int, -- accAmt sdk.Int, -+ accAmt math.Int, - strategy GenerateAccountStrategy -) []sdk.AccAddress -func AddTestAddrsIncremental( - app *SimApp, - ctx sdk.Context, - accNum int, -- accAmt sdk.Int, -+ accAmt math.Int -) []sdk.AccAddress -``` - -The `RegisterRESTRoutes` function in `testing/mock` has been removed. - -## Relayers - -- No relevant changes were made in this release. - -## IBC Light Clients - -### ICS02 - Client - -The `key` parameter of the `NewKeeper` function in `modules/core/02-client/keeper` is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`): - -```diff -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - sk types.StakingKeeper, - uk types.UpgradeKeeper -) Keeper -``` diff --git a/docs/docs/05-migrations/07-v5-to-v6.md b/docs/docs/05-migrations/07-v5-to-v6.md deleted file mode 100644 index 4c7df21335a..00000000000 --- a/docs/docs/05-migrations/07-v5-to-v6.md +++ /dev/null @@ -1,299 +0,0 @@ ---- -title: IBC-Go v5 to v6 -sidebar_label: IBC-Go v5 to v6 -sidebar_position: 7 -slug: /migrations/v5-to-v6 ---- - -# Migrating from ibc-go v5 to v6 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -## Chains - -The `ibc-go/v6` release introduces a new set of migrations for `27-interchain-accounts`. Ownership of ICS27 channel capabilities is transferred from ICS27 authentication modules and will now reside with the ICS27 controller submodule moving forward. - -For chains which contain a custom authentication module using the ICS27 controller submodule this requires a migration function to be included in the chain upgrade handler. A subsequent migration handler is run automatically, asserting the ownership of ICS27 channel capabilities has been transferred successfully. - -This migration is not required for chains which *do not* contain a custom authentication module using the ICS27 controller submodule. - -This migration facilitates the addition of the ICS27 controller submodule `MsgServer` which provides a standardised approach to integrating existing forms of authentication such as `x/gov` and `x/group` provided by the Cosmos SDK. - -For more information please refer to [ADR 009](/architecture/adr-009-v6-ics27-msgserver). - -### Upgrade proposal - -Please refer to [PR #2383](https://github.com/cosmos/ibc-go/pull/2383) for integrating the ICS27 channel capability migration logic or follow the steps outlined below: - -1. Add the upgrade migration logic to chain distribution. This may be, for example, maintained under a package `app/upgrades/v6`. - -```go -package v6 - -import ( - "github.com/cosmos/cosmos-sdk/codec" - storetypes "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" - upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - - v6 "github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts/controller/migrations/v6" -) - -const ( - UpgradeName = "v6" -) - -func CreateUpgradeHandler( - mm *module.Manager, - configurator module.Configurator, - cdc codec.BinaryCodec, - capabilityStoreKey *storetypes.KVStoreKey, - capabilityKeeper *capabilitykeeper.Keeper, - moduleName string, -) upgradetypes.UpgradeHandler { - return func(ctx sdk.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { - if err := v6.MigrateICS27ChannelCapability(ctx, cdc, capabilityStoreKey, capabilityKeeper, moduleName); err != nil { - return nil, err - } - - return mm.RunMigrations(ctx, configurator, vm) - } -} -``` - -2. Set the upgrade handler in `app.go`. The `moduleName` parameter refers to the authentication module's `ScopedKeeper` name. This is the name provided upon instantiation in `app.go` via the [`x/capability` keeper `ScopeToModule(moduleName string)`](https://github.com/cosmos/cosmos-sdk/blob/v0.46.1/x/capability/keeper/keeper.go#L70) method. [See here for an example in `simapp`](https://github.com/cosmos/ibc-go/blob/v5.0.0/testing/simapp/app.go#L304). - -```go -app.UpgradeKeeper.SetUpgradeHandler( - v6.UpgradeName, - v6.CreateUpgradeHandler( - app.mm, - app.configurator, - app.appCodec, - app.keys[capabilitytypes.ModuleName], - app.CapabilityKeeper, - >>>> moduleName <<<<, - ), -) -``` - -## IBC Apps - -### ICS27 - Interchain Accounts - -#### Controller APIs - -In previous releases of ibc-go, chain developers integrating the ICS27 interchain accounts controller functionality were expected to create a custom `Base Application` referred to as an authentication module, see the section [Building an authentication module](../02-apps/02-interchain-accounts/03-auth-modules.md) from the documentation. - -The `Base Application` was intended to be composed with the ICS27 controller submodule `Keeper` and faciliate many forms of message authentication depending on a chain's particular use case. - -Prior to ibc-go v6 the controller submodule exposed only these two functions (to which we will refer as the legacy APIs): - -- [`RegisterInterchainAccount`](https://github.com/cosmos/ibc-go/blob/v5.0.0/modules/apps/27-interchain-accounts/controller/keeper/account.go#L19) -- [`SendTx`](https://github.com/cosmos/ibc-go/blob/v5.0.0/modules/apps/27-interchain-accounts/controller/keeper/relay.go#L18) - -However, these functions have now been deprecated in favour of the new controller submodule `MsgServer` and will be removed in later releases. - -Both APIs remain functional and maintain backwards compatibility in ibc-go v6, however consumers of these APIs are now recommended to follow the message passing paradigm outlined in Cosmos SDK [ADR 031](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-031-msg-service.md) and [ADR 033](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-033-protobuf-inter-module-comm.md). This is facilitated by the Cosmos SDK [`MsgServiceRouter`](https://github.com/cosmos/cosmos-sdk/blob/main/baseapp/msg_service_router.go#L17) and chain developers creating custom application logic can now omit the ICS27 controller submodule `Keeper` from their module and instead depend on message routing. - -Depending on the use case, developers of custom authentication modules face one of three scenarios: - -![auth-module-decision-tree.png](./images/auth-module-decision-tree.png) - -**My authentication module needs to access IBC packet callbacks** - -Application developers that wish to consume IBC packet callbacks and react upon packet acknowledgements **must** continue using the controller submodule's legacy APIs. The authentication modules will not need a `ScopedKeeper` anymore, though, because the channel capability will be claimed by the controller submodule. For example, given an Interchain Accounts authentication module keeper `ICAAuthKeeper`, the authentication module's `ScopedKeeper` (`scopedICAAuthKeeper`) is not needed anymore and can be removed for the argument list of the keeper constructor function, as shown here: - -```diff -app.ICAAuthKeeper = icaauthkeeper.NewKeeper( - appCodec, - keys[icaauthtypes.StoreKey], - app.ICAControllerKeeper, -- scopedICAAuthKeeper, -) -``` - -Please note that the authentication module's `ScopedKeeper` name is still needed as part of the channel capability migration described in section [Upgrade proposal](#upgrade-proposal) above. Therefore the authentication module's `ScopedKeeper` cannot be completely removed from the chain code until the migration has run. - -In the future, the use of the legacy APIs for accessing packet callbacks will be replaced by IBC Actor Callbacks (see [ADR 008](https://github.com/cosmos/ibc-go/pull/1976) for more details) and it will also be possible to access them with the `MsgServiceRouter`. - -**My authentication module does not need access to IBC packet callbacks** - -The authentication module can migrate from using the legacy APIs and it can be composed instead with the `MsgServiceRouter`, so that the authentication module is able to pass messages to the controller submodule's `MsgServer` to register interchain accounts and send packets to the interchain account. For example, given an Interchain Accounts authentication module keeper `ICAAuthKeeper`, the ICS27 controller submodule keeper (`ICAControllerKeeper`) and authentication module scoped keeper (`scopedICAAuthKeeper`) are not needed anymore and can be replaced with the `MsgServiceRouter`, as shown here: - -```diff -app.ICAAuthKeeper = icaauthkeeper.NewKeeper( - appCodec, - keys[icaauthtypes.StoreKey], -- app.ICAControllerKeeper, -- scopedICAAuthKeeper, -+ app.MsgServiceRouter(), -) -``` - -In your authentication module you can route messages to the controller submodule's `MsgServer` instead of using the legacy APIs. For example, for registering an interchain account: - -```diff -- if err := keeper.icaControllerKeeper.RegisterInterchainAccount( -- ctx, -- connectionID, -- owner.String(), -- version, -- ); err != nil { -- return err -- } -+ msg := controllertypes.NewMsgRegisterInterchainAccount( -+ connectionID, -+ owner.String(), -+ version, -+ ) -+ handler := keeper.msgRouter.Handler(msg) -+ res, err := handler(ctx, msg) -+ if err != nil { -+ return err -+ } -``` - -where `controllertypes` is an import alias for `"github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts/controller/types"`. - -In addition, in this use case the authentication module does not need to implement the `IBCModule` interface anymore. - -**I do not need a custom authentication module anymore** - -If your authentication module does not have any extra functionality compared to the default authentication module added in ibc-go v6 (the `MsgServer`), or if you can use a generic authentication module, such as the `x/auth`, `x/gov` or `x/group` modules from the Cosmos SDK (v0.46 and later), then you can remove your authentication module completely and use instead the gRPC endpoints of the `MsgServer` or the CLI added in ibc-go v6. - -Please remember that the authentication module's `ScopedKeeper` name is still needed as part of the channel capability migration described in section [Upgrade proposal](#upgrade-proposal) above. - -#### Host params - -The ICS27 host submodule default params have been updated to include the `AllowAllHostMsgs` wildcard `*`. -This enables execution of any `sdk.Msg` type for ICS27 registered on the host chain `InterfaceRegistry`. - -```diff -// AllowAllHostMsgs holds the string key that allows all message types on interchain accounts host module -const AllowAllHostMsgs = "*" - -... - -// DefaultParams is the default parameter configuration for the host submodule -func DefaultParams() Params { -- return NewParams(DefaultHostEnabled, nil) -+ return NewParams(DefaultHostEnabled, []string{AllowAllHostMsgs}) -} -``` - -#### API breaking changes - -`SerializeCosmosTx` takes in a `[]proto.Message` instead of `[]sdk.Message`. This allows for the serialization of proto messages without requiring the fulfillment of the `sdk.Msg` interface. - -The `27-interchain-accounts` genesis types have been moved to their own package: `modules/apps/27-interchain-acccounts/genesis/types`. -This change facilitates the addition of the ICS27 controller submodule `MsgServer` and avoids cyclic imports. This should have minimal disruption to chain developers integrating `27-interchain-accounts`. - -The ICS27 host submodule `NewKeeper` function in `modules/apps/27-interchain-acccounts/host/keeper` now includes an additional parameter of type `ICS4Wrapper`. -This provides the host submodule with the ability to correctly unwrap channel versions in the event of a channel reopening handshake. - -```diff -func NewKeeper( - cdc codec.BinaryCodec, key storetypes.StoreKey, paramSpace paramtypes.Subspace, -- channelKeeper icatypes.ChannelKeeper, portKeeper icatypes.PortKeeper, -+ ics4Wrapper icatypes.ICS4Wrapper, channelKeeper icatypes.ChannelKeeper, portKeeper icatypes.PortKeeper, - accountKeeper icatypes.AccountKeeper, scopedKeeper icatypes.ScopedKeeper, msgRouter icatypes.MessageRouter, -) Keeper -``` - -### ICS29 - `NewKeeper` API change - -The `NewKeeper` function of ICS29 has been updated to remove the `paramSpace` parameter as it was unused. - -```diff -func NewKeeper( -- cdc codec.BinaryCodec, key storetypes.StoreKey, paramSpace paramtypes.Subspace, -- ics4Wrapper types.ICS4Wrapper, channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, -+ cdc codec.BinaryCodec, key storetypes.StoreKey, -+ ics4Wrapper types.ICS4Wrapper, channelKeeper types.ChannelKeeper, -+ portKeeper types.PortKeeper, authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, -) Keeper { -``` - -### ICS20 - `SendTransfer` is no longer exported - -The `SendTransfer` function of ICS20 has been removed. IBC transfers should now be initiated with `MsgTransfer` and routed to the ICS20 `MsgServer`. - -See below for example: - -```go -if handler := msgRouter.Handler(msgTransfer); handler != nil { - if err := msgTransfer.ValidateBasic(); err != nil { - return nil, err - } - - res, err := handler(ctx, msgTransfer) - if err != nil { - return nil, err - } -} -``` - -### ICS04 - `SendPacket` API change - -The `SendPacket` API has been simplified: - -```diff -// SendPacket is called by a module in order to send an IBC packet on a channel -func (k Keeper) SendPacket( - ctx sdk.Context, - channelCap *capabilitytypes.Capability, -- packet exported.PacketI, --) error { -+ sourcePort string, -+ sourceChannel string, -+ timeoutHeight clienttypes.Height, -+ timeoutTimestamp uint64, -+ data []byte, -+) (uint64, error) { -``` - -Callers no longer need to pass in a pre-constructed packet. -The destination port/channel identifiers and the packet sequence will be determined by core IBC. -`SendPacket` will return the packet sequence. - -### IBC testing package - -The `SendPacket` API has been simplified: - -```diff -// SendPacket is called by a module in order to send an IBC packet on a channel -func (k Keeper) SendPacket( - ctx sdk.Context, - channelCap *capabilitytypes.Capability, -- packet exported.PacketI, --) error { -+ sourcePort string, -+ sourceChannel string, -+ timeoutHeight clienttypes.Height, -+ timeoutTimestamp uint64, -+ data []byte, -+) (uint64, error) { -``` - -Callers no longer need to pass in a pre-constructed packet. `SendPacket` will return the packet sequence. - -## Relayers - -- No relevant changes were made in this release. - -## IBC Light Clients - -- No relevant changes were made in this release. diff --git a/docs/docs/05-migrations/08-v6-to-v7.md b/docs/docs/05-migrations/08-v6-to-v7.md deleted file mode 100644 index da47b395021..00000000000 --- a/docs/docs/05-migrations/08-v6-to-v7.md +++ /dev/null @@ -1,357 +0,0 @@ ---- -title: IBC-Go v6 to v7 -sidebar_label: IBC-Go v6 to v7 -sidebar_position: 8 -slug: /migrations/v6-to-v7 ---- -# Migrating from ibc-go v6 to v7 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -## Chains - -Chains will perform automatic migrations to remove existing localhost clients and to migrate the solomachine to v3 of the protobuf definition. - -An optional upgrade handler has been added to prune expired tendermint consensus states. It may be used during any upgrade (from v7 onwards). -Add the following to the function call to the upgrade handler in `app/app.go`, to perform the optional state pruning. - -```go -import ( - // ... - ibctmmigrations "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint/migrations" -) - -// ... - -app.UpgradeKeeper.SetUpgradeHandler( - upgradeName, - func(ctx sdk.Context, _ upgradetypes.Plan, _ module.VersionMap) (module.VersionMap, error) { - // prune expired tendermint consensus states to save storage space - _, err := ibctmmigrations.PruneExpiredConsensusStates(ctx, app.Codec, app.IBCKeeper.ClientKeeper) - if err != nil { - return nil, err - } - - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }, -) -``` - -Checkout the logs to see how many consensus states are pruned. - -### Light client registration - -Chains must explicitly register the types of any light client modules it wishes to integrate. - -#### Tendermint registration - -To register the tendermint client, modify the `app.go` file to include the tendermint `AppModuleBasic`: - -```diff -import ( - // ... -+ ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" -) - -// ... - -ModuleBasics = module.NewBasicManager( - ... - ibc.AppModuleBasic{}, -+ ibctm.AppModuleBasic{}, - ... -) -``` - -It may be useful to reference the [PR](https://github.com/cosmos/ibc-go/pull/2825) which added the `AppModuleBasic` for the tendermint client. - -#### Solo machine registration - -To register the solo machine client, modify the `app.go` file to include the solo machine `AppModuleBasic`: - -```diff -import ( - // ... -+ solomachine "github.com/cosmos/ibc-go/v7/modules/light-clients/06-solomachine" -) - -// ... - -ModuleBasics = module.NewBasicManager( - ... - ibc.AppModuleBasic{}, -+ solomachine.AppModuleBasic{}, - ... -) -``` - -It may be useful to reference the [PR](https://github.com/cosmos/ibc-go/pull/2826) which added the `AppModuleBasic` for the solo machine client. - -### Testing package API - -The `SetChannelClosed` utility method in `testing/endpoint.go` has been updated to `SetChannelState`, which will take a `channeltypes.State` argument so that the `ChannelState` can be set to any of the possible channel states. - -## IBC Apps - -- No relevant changes were made in this release. - -## Relayers - -- No relevant changes were made in this release. - -## IBC Light Clients - -### `ClientState` interface changes - -The `VerifyUpgradeAndUpdateState` function has been modified. The client state and consensus state return values have been removed. - -Light clients **must** handle all management of client and consensus states including the setting of updated client state and consensus state in the client store. - -The `Initialize` method is now expected to set the initial client state, consensus state and any client-specific metadata in the provided store upon client creation. - -The `CheckHeaderAndUpdateState` method has been split into 4 new methods: - -- `VerifyClientMessage` verifies a `ClientMessage`. A `ClientMessage` could be a `Header`, `Misbehaviour`, or batch update. Calls to `CheckForMisbehaviour`, `UpdateState`, and `UpdateStateOnMisbehaviour` will assume that the content of the `ClientMessage` has been verified and can be trusted. An error should be returned if the `ClientMessage` fails to verify. - -- `CheckForMisbehaviour` checks for evidence of a misbehaviour in `Header` or `Misbehaviour` types. - -- `UpdateStateOnMisbehaviour` performs appropriate state changes on a `ClientState` given that misbehaviour has been detected and verified. - -- `UpdateState` updates and stores as necessary any associated information for an IBC client, such as the `ClientState` and corresponding `ConsensusState`. An error is returned if `ClientMessage` is of type `Misbehaviour`. Upon successful update, a list containing the updated consensus state height is returned. - -The `CheckMisbehaviourAndUpdateState` function has been removed from `ClientState` interface. This functionality is now encapsulated by the usage of `VerifyClientMessage`, `CheckForMisbehaviour`, `UpdateStateOnMisbehaviour`. - -The function `GetTimestampAtHeight` has been added to the `ClientState` interface. It should return the timestamp for a consensus state associated with the provided height. - -Prior to ibc-go/v7 the `ClientState` interface defined a method for each data type which was being verified in the counterparty state store. -The state verification functions for all IBC data types have been consolidated into two generic methods, `VerifyMembership` and `VerifyNonMembership`. -Both are expected to be provided with a standardised key path, `exported.Path`, as defined in [ICS 24 host requirements](https://github.com/cosmos/ibc/tree/main/spec/core/ics-024-host-requirements). Membership verification requires callers to provide the marshalled value `[]byte`. Delay period values should be zero for non-packet processing verification. A zero proof height is now allowed by core IBC and may be passed into `VerifyMembership` and `VerifyNonMembership`. Light clients are responsible for returning an error if a zero proof height is invalid behaviour. - -See below for an example of how ibc-go now performs channel state verification. - -```go -merklePath := commitmenttypes.NewMerklePath(host.ChannelPath(portID, channelID)) -merklePath, err := commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) -if err != nil { - return err -} - -channelEnd, ok := channel.(channeltypes.Channel) -if !ok { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "invalid channel type %T", channel) -} - -bz, err := k.cdc.Marshal(&channelEnd) -if err != nil { - return err -} - -if err := clientState.VerifyMembership( - ctx, clientStore, k.cdc, height, - 0, 0, // skip delay period checks for non-packet processing verification - proof, merklePath, bz, -); err != nil { - return sdkerrors.Wrapf(err, "failed channel state verification for client (%s)", clientID) -} -``` - -### `Header` and `Misbehaviour` - -`exported.Header` and `exported.Misbehaviour` interface types have been merged and renamed to `ClientMessage` interface. - -`GetHeight` function has been removed from `exported.Header` and thus is not included in the `ClientMessage` interface - -### `ConsensusState` - -The `GetRoot` function has been removed from consensus state interface since it was not used by core IBC. - -### Client keeper - -Keeper function `CheckMisbehaviourAndUpdateState` has been removed since function `UpdateClient` can now handle updating `ClientState` on `ClientMessage` type which can be any `Misbehaviour` implementations. - -### SDK message - -`MsgSubmitMisbehaviour` is deprecated since `MsgUpdateClient` can now submit a `ClientMessage` type which can be any `Misbehaviour` implementations. - -The field `header` in `MsgUpdateClient` has been renamed to `client_message`. - -## Solomachine - -The `06-solomachine` client implementation has been simplified in ibc-go/v7. In-place store migrations have been added to migrate solomachine clients from `v2` to `v3`. - -### `ClientState` - -The `ClientState` protobuf message definition has been updated to remove the deprecated `bool` field `allow_update_after_proposal`. - -```diff -message ClientState { - option (gogoproto.goproto_getters) = false; - - uint64 sequence = 1; - bool is_frozen = 2 [(gogoproto.moretags) = "yaml:\"is_frozen\""]; - ConsensusState consensus_state = 3 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; -- bool allow_update_after_proposal = 4 [(gogoproto.moretags) = "yaml:\"allow_update_after_proposal\""]; -} -``` - -### `Header` and `Misbehaviour` - -The `06-solomachine` protobuf message `Header` has been updated to remove the `sequence` field. This field was seen as redundant as the implementation can safely rely on the `sequence` value maintained within the `ClientState`. - -```diff -message Header { - option (gogoproto.goproto_getters) = false; - -- uint64 sequence = 1; -- uint64 timestamp = 2; -- bytes signature = 3; -- google.protobuf.Any new_public_key = 4 [(gogoproto.moretags) = "yaml:\"new_public_key\""]; -- string new_diversifier = 5 [(gogoproto.moretags) = "yaml:\"new_diversifier\""]; -+ uint64 timestamp = 1; -+ bytes signature = 2; -+ google.protobuf.Any new_public_key = 3 [(gogoproto.moretags) = "yaml:\"new_public_key\""]; -+ string new_diversifier = 4 [(gogoproto.moretags) = "yaml:\"new_diversifier\""]; -} -``` - -Similarly, the `Misbehaviour` protobuf message has been updated to remove the `client_id` field. - -```diff -message Misbehaviour { - option (gogoproto.goproto_getters) = false; - -- string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; -- uint64 sequence = 2; -- SignatureAndData signature_one = 3 [(gogoproto.moretags) = "yaml:\"signature_one\""]; -- SignatureAndData signature_two = 4 [(gogoproto.moretags) = "yaml:\"signature_two\""]; -+ uint64 sequence = 1; -+ SignatureAndData signature_one = 2 [(gogoproto.moretags) = "yaml:\"signature_one\""]; -+ SignatureAndData signature_two = 3 [(gogoproto.moretags) = "yaml:\"signature_two\""]; -} -``` - -### `SignBytes` - -Most notably, the `SignBytes` protobuf definition has been modified to replace the `data_type` field with a new field, `path`. The `path` field is defined as `bytes` and represents a serialized [ICS-24](https://github.com/cosmos/ibc/tree/main/spec/core/ics-024-host-requirements) standardized key path under which the `data` is stored. - -```diff -message SignBytes { - option (gogoproto.goproto_getters) = false; - - uint64 sequence = 1; - uint64 timestamp = 2; - string diversifier = 3; -- DataType data_type = 4 [(gogoproto.moretags) = "yaml:\"data_type\""]; -+ bytes path = 4; - bytes data = 5; -} -``` - -The `DataType` enum and all associated data types have been removed, greatly reducing the number of message definitions and complexity in constructing the `SignBytes` message type. Likewise, solomachine implementations must now use the serialized `path` value when constructing `SignatureAndData` for signature verification of `SignBytes` data. - -```diff -message SignatureAndData { - option (gogoproto.goproto_getters) = false; - - bytes signature = 1; -- DataType data_type = 2 [(gogoproto.moretags) = "yaml:\"data_type\""]; -+ bytes path = 2; - bytes data = 3; - uint64 timestamp = 4; -} -``` - -For more information, please refer to [ADR-007](https://github.com/cosmos/ibc-go/blob/02-client-refactor-beta1/docs/architecture/adr-007-solomachine-signbytes.md). - -### IBC module constants - -IBC module constants have been moved from the `host` package to the `exported` package. Any usages will need to be updated. - -```diff -import ( - // ... -- host "github.com/cosmos/ibc-go/v7/modules/core/24-host" -+ ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" - // ... -) - -- host.ModuleName -+ ibcexported.ModuleName - -- host.StoreKey -+ ibcexported.StoreKey - -- host.QuerierRoute -+ ibcexported.QuerierRoute - -- host.RouterKey -+ ibcexported.RouterKey -``` - -## Upgrading to Cosmos SDK 0.47 - -The following should be considered as complementary to [Cosmos SDK v0.47 UPGRADING.md](https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc2/UPGRADING.md). - -### Protobuf - -Protobuf code generation, linting and formatting have been updated to leverage the `ghcr.io/cosmos/proto-builder:0.11.5` docker container. IBC protobuf definitions are now packaged and published to [buf.build/cosmos/ibc](https://buf.build/cosmos/ibc) via CI workflows. The `third_party/proto` directory has been removed in favour of dependency management using [buf.build](https://docs.buf.build/introduction). - -### App modules - -Legacy APIs of the `AppModule` interface have been removed from ibc-go modules. For example, for - -```diff -- // Route implements the AppModule interface -- func (am AppModule) Route() sdk.Route { -- return sdk.Route{} -- } -- -- // QuerierRoute implements the AppModule interface -- func (AppModule) QuerierRoute() string { -- return types.QuerierRoute -- } -- -- // LegacyQuerierHandler implements the AppModule interface -- func (am AppModule) LegacyQuerierHandler(*codec.LegacyAmino) sdk.Querier { -- return nil -- } -- -- // ProposalContents doesn't return any content functions for governance proposals. -- func (AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalContent { -- return nil -- } -``` - -### Imports - -Imports for ics23 have been updated as the repository have been migrated from confio to cosmos. - -```diff -import ( - // ... -- ics23 "github.com/confio/ics23/go" -+ ics23 "github.com/cosmos/ics23/go" - // ... -) -``` - -Imports for gogoproto have been updated. - -```diff -import ( - // ... -- "github.com/gogo/protobuf/proto" -+ "github.com/cosmos/gogoproto/proto" - // ... -) -``` diff --git a/docs/docs/05-migrations/09-v7-to-v7_1.md b/docs/docs/05-migrations/09-v7-to-v7_1.md deleted file mode 100644 index 30d9578dbc2..00000000000 --- a/docs/docs/05-migrations/09-v7-to-v7_1.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: IBC-Go v7 to v7.1 -sidebar_label: IBC-Go v7 to v7.1 -sidebar_position: 9 -slug: /migrations/v7-to-v7_1 ---- - -# Migrating from v7 to v7.1 - -This guide provides instructions for migrating to version `v7.1.0` of ibc-go. - -There are four sections based on the four potential user groups of this document: - -- [Migrating from v7 to v7.1](#migrating-from-v7-to-v71) - - [Chains](#chains) - - [IBC Apps](#ibc-apps) - - [Relayers](#relayers) - - [IBC Light Clients](#ibc-light-clients) - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated on major version releases. - -## Chains - -In the previous release of ibc-go, the localhost `v1` light client module was deprecated and removed. The ibc-go `v7.1.0` release introduces `v2` of the 09-localhost light client module. - -An [automatic migration handler](https://github.com/cosmos/ibc-go/blob/v7.2.0/modules/core/module.go#L127-L145) is configured in the core IBC module to set the localhost `ClientState` and sentinel `ConnectionEnd` in state. - -In order to use the 09-localhost client chains must update the `AllowedClients` parameter in the 02-client submodule of core IBC. This can be configured directly in the application upgrade handler or alternatively updated via the legacy governance parameter change proposal. -We **strongly** recommend chains to perform this action so that intra-ledger communication can be carried out using the familiar IBC interfaces. - -See the upgrade handler code sample provided below or [follow this link](https://github.com/cosmos/ibc-go/blob/v7.2.0/testing/simapp/upgrades/upgrades.go#L85) for the upgrade handler used by the ibc-go simapp. - -```go -func CreateV7LocalhostUpgradeHandler( - mm *module.Manager, - configurator module.Configurator, - clientKeeper clientkeeper.Keeper, -) upgradetypes.UpgradeHandler { - return func(ctx sdk.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { - // explicitly update the IBC 02-client params, adding the localhost client type - params := clientKeeper.GetParams(ctx) - params.AllowedClients = append(params.AllowedClients, exported.Localhost) - clientKeeper.SetParams(ctx, params) - - return mm.RunMigrations(ctx, configurator, vm) - } -} -``` - -### Transfer migration - -An [automatic migration handler](https://github.com/cosmos/ibc-go/blob/v7.2.0/modules/apps/transfer/module.go#L111-L113) is configured in the transfer module to set the total amount in escrow for all denominations of coins that have been sent out. For each denomination a state entry is added with the total amount of coins in escrow regardless of the channel from which they were transferred. - -## IBC Apps - -- No relevant changes were made in this release. - -## Relayers - -The event attribute `packet_connection` (`connectiontypes.AttributeKeyConnection`) has been deprecated. -Please use the `connection_id` attribute (`connectiontypes.AttributeKeyConnectionID`) which is emitted by all channel events. -Only send packet, receive packet, write acknowledgement, and acknowledge packet events used `packet_connection` previously. - -## IBC Light Clients - -- No relevant changes were made in this release. diff --git a/docs/docs/05-migrations/10-v7_2-to-v7_3.md b/docs/docs/05-migrations/10-v7_2-to-v7_3.md deleted file mode 100644 index 8fc76f67c27..00000000000 --- a/docs/docs/05-migrations/10-v7_2-to-v7_3.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: IBC-Go v7.2 to v7.3 -sidebar_label: IBC-Go v7.2 to v7.3 -sidebar_position: 10 -slug: /migrations/v7_2-to-v7_3 ---- - -# Migrating from v7.2 to v7.3 - -This guide provides instructions for migrating to version `v7.3.0` of ibc-go. - -There are four sections based on the four potential user groups of this document: - -- [Migrating from v7.2 to v7.3](#migrating-from-v72-to-v73) - - [Chains](#chains) - - [IBC Apps](#ibc-apps) - - [Relayers](#relayers) - - [IBC Light Clients](#ibc-light-clients) - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated on major version releases. - -## Chains - -- No relevant changes were made in this release. - -## IBC Apps - -A set of interfaces have been added that IBC applications may optionally implement. Developers interested in integrating their applications with the [callbacks middleware](../04-middleware/02-callbacks/01-overview.md) should implement these interfaces so that the callbacks middleware can retrieve the desired callback addresses on the source and destination chains and execute actions on packet lifecycle events. The interfaces are [`PacketDataUnmarshaler`](https://github.com/cosmos/ibc-go/blob/v7.3.0-rc1/modules/core/05-port/types/module.go#L142-L147), [`PacketDataProvider`](https://github.com/cosmos/ibc-go/blob/v7.3.0-rc1/modules/core/exported/packet.go#L43-L52) and [`PacketData`](https://github.com/cosmos/ibc-go/blob/v7.3.0-rc1/modules/core/exported/packet.go#L36-L41). - -Sample implementations are available for reference. For `transfer`: - -- [`PacketDataUnmarshaler`](https://github.com/cosmos/ibc-go/blob/v7.3.0-rc1/modules/apps/transfer/ibc_module.go#L303-L313), -- [`PacketDataProvider`](https://github.com/cosmos/ibc-go/blob/v7.3.0-rc1/modules/apps/transfer/types/packet.go#L85-L105) -- and [`PacketData`](https://github.com/cosmos/ibc-go/blob/v7.3.0-rc1/modules/apps/transfer/types/packet.go#L74-L83). - -For `27-interchain-accounts`: - -- [`PacketDataUnmarshaler`](https://github.com/cosmos/ibc-go/blob/v7.3.0-rc1/modules/apps/27-interchain-accounts/controller/ibc_middleware.go#L258-L268), -- [`PacketDataProvider`](https://github.com/cosmos/ibc-go/blob/v7.3.0-rc1/modules/apps/27-interchain-accounts/types/packet.go#L94-L114) -- and [`PacketData`](https://github.com/cosmos/ibc-go/blob/v7.3.0-rc1/modules/apps/27-interchain-accounts/types/packet.go#L78-L92). - -## Relayers - -- No relevant changes were made in this release. - -## IBC Light Clients - -### 06-solomachine - -Solo machines are now expected to sign data on a path that 1) does not include a connection prefix (e.g `ibc`) and 2) does not escape any characters. See PR [#4429](https://github.com/cosmos/ibc-go/pull/4429) for more details. We recommend **NOT** using the solo machine light client of versions lower than v7.3.0. diff --git a/docs/docs/05-migrations/11-v7-to-v8.md b/docs/docs/05-migrations/11-v7-to-v8.md deleted file mode 100644 index 63971504d3f..00000000000 --- a/docs/docs/05-migrations/11-v7-to-v8.md +++ /dev/null @@ -1,211 +0,0 @@ ---- -title: IBC-Go v7 to v8 -sidebar_label: IBC-Go v7 to v8 -sidebar_position: 11 -slug: /migrations/v7-to-v8 ---- - -# Migrating from v7 to v8 - -This guide provides instructions for migrating to version `v8.0.0` of ibc-go. - -There are four sections based on the four potential user groups of this document: - -- [Migrating from v7 to v8](#migrating-from-v7-to-v8) - - [Chains](#chains) - - [IBC Apps](#ibc-apps) - - [Relayers](#relayers) - - [IBC Light Clients](#ibc-light-clients) - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated on major version releases. - -## Chains - -The type of the `PortKeeper` field of the IBC keeper have been changed to `*portkeeper.Keeper`: - -```diff -// Keeper defines each ICS keeper for IBC -type Keeper struct { - // implements gRPC QueryServer interface - types.QueryServer - - cdc codec.BinaryCodec - - ClientKeeper clientkeeper.Keeper - ConnectionKeeper connectionkeeper.Keeper - ChannelKeeper channelkeeper.Keeper -- PortKeeper portkeeper.Keeper -+ PortKeeper *portkeeper.Keeper - Router *porttypes.Router - - authority string -} -``` - -See [this PR](https://github.com/cosmos/ibc-go/pull/4703/files#diff-d18972debee5e64f16e40807b2ae112ddbe609504a93ea5e1c80a5d489c3a08a) for the changes required in `app.go`. - -An extra parameter `totalEscrowed` of type `sdk.Coins` has been added to transfer module's [`NewGenesisState` function](https://github.com/cosmos/ibc-go/blob/v8.0.0-beta.0/modules/apps/transfer/types/genesis.go#L10). This parameter specifies the total amount of tokens that are in the module's escrow accounts. - -### Cosmos SDK v0.50 upgrade - -Version `v8.0.0` of ibc-go upgrades to Cosmos SDK v0.50. Please follow the [Cosmos SDK v0.50 upgrading guide](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-rc.0/UPGRADING.md) to account for its API breaking changes. - -### Authority - -An authority identifier (e.g. an address) needs to be passed in the `NewKeeper` functions of the following keepers: - -- You must pass the `authority` to the ica/host keeper. ([#3520](https://github.com/cosmos/ibc-go/pull/3520)) See [diff](https://github.com/cosmos/ibc-go/pull/3520/files#diff-d18972debee5e64f16e40807b2ae112ddbe609504a93ea5e1c80a5d489c3a08a). - -```diff -// app.go - -// ICA Host keeper -app.ICAHostKeeper = icahostkeeper.NewKeeper( - appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), - app.IBCFeeKeeper, // use ics29 fee as ics4Wrapper in middleware stack - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), -+ authtypes.NewModuleAddress(govtypes.ModuleName).String(), -) -``` - -- You must pass the `authority` to the ica/controller keeper. ([#3590](https://github.com/cosmos/ibc-go/pull/3590)) See [diff](https://github.com/cosmos/ibc-go/pull/3590/files#diff-d18972debee5e64f16e40807b2ae112ddbe609504a93ea5e1c80a5d489c3a08a). - -```diff -// app.go - -// ICA Controller keeper -app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( - appCodec, keys[icacontrollertypes.StoreKey], app.GetSubspace(icacontrollertypes.SubModuleName), - app.IBCFeeKeeper, // use ics29 fee as ics4Wrapper in middleware stack - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - scopedICAControllerKeeper, app.MsgServiceRouter(), -+ authtypes.NewModuleAddress(govtypes.ModuleName).String(), -) -``` - -- You must pass the `authority` to the ibctransfer keeper. ([#3553](https://github.com/cosmos/ibc-go/pull/3553)) See [diff](https://github.com/cosmos/ibc-go/pull/3553/files#diff-d18972debee5e64f16e40807b2ae112ddbe609504a93ea5e1c80a5d489c3a08a). - -```diff -// app.go - -// Create Transfer Keeper and pass IBCFeeKeeper as expected Channel and PortKeeper -// since fee middleware will wrap the IBCKeeper for underlying application. -app.TransferKeeper = ibctransferkeeper.NewKeeper( - appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName), - app.IBCFeeKeeper, // ISC4 Wrapper: fee IBC middleware - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, app.BankKeeper, scopedTransferKeeper, -+ authtypes.NewModuleAddress(govtypes.ModuleName).String(), -) -``` - -- You should pass the `authority` to the IBC keeper. ([#3640](https://github.com/cosmos/ibc-go/pull/3640) and [#3650](https://github.com/cosmos/ibc-go/pull/3650)) See [diff](https://github.com/cosmos/ibc-go/pull/3640/files#diff-d18972debee5e64f16e40807b2ae112ddbe609504a93ea5e1c80a5d489c3a08a). - -```diff -// app.go - -// IBC Keepers -app.IBCKeeper = ibckeeper.NewKeeper( - appCodec, - keys[ibcexported.StoreKey], - app.GetSubspace(ibcexported.ModuleName), - app.StakingKeeper, - app.UpgradeKeeper, - scopedIBCKeeper, -+ authtypes.NewModuleAddress(govtypes.ModuleName).String(), -) -``` - -The authority determines the transaction signer allowed to execute certain messages (e.g. `MsgUpdateParams`). - -### Testing package - -- The function `SetupWithGenesisAccounts` has been removed. -- The function [`RelayPacketWithResults`](https://github.com/cosmos/ibc-go/blob/v8.0.0-beta.0/testing/path.go#L66) has been added. This function returns the result of the packet receive transaction, the acknowledgement written on the receiving chain, an error if a relay step fails or the packet commitment does not exist on either chain. - -### Params migration - -Params are now self managed in the following submodules: - -- ica/controller [#3590](https://github.com/cosmos/ibc-go/pull/3590) -- ica/host [#3520](https://github.com/cosmos/ibc-go/pull/3520) -- ibc/connection [#3650](https://github.com/cosmos/ibc-go/pull/3650) -- ibc/client [#3640](https://github.com/cosmos/ibc-go/pull/3640) -- ibc/transfer [#3553](https://github.com/cosmos/ibc-go/pull/3553) - -Each module has a corresponding `MsgUpdateParams` message with a `Params` which can be specified in full to update the modules' `Params`. - -Legacy params subspaces must still be initialised in app.go in order to successfully migrate from x/params to the new self-contained approach. See reference: - -### Governance V1 migration - -Proposals have been migrated to [gov v1 messages](https://docs.cosmos.network/v0.50/modules/gov#messages) ref: [#4620](https://github.com/cosmos/ibc-go/pull/4620). The proposal `ClientUpdateProposal` has been deprecated and [`MsgRecoverClient`](https://github.com/cosmos/ibc-go/blob/v8.0.0-beta.0/proto/ibc/core/client/v1/tx.proto#L121-L134) should be used instead. Likewise, the proposal `UpgradeProposal` has been deprecated and [`MsgIBCSoftwareUpgrade`](https://github.com/cosmos/ibc-go/blob/v8.0.0-beta.0/proto/ibc/core/client/v1/tx.proto#L139-L154) should be used instead. Both proposals will be removed in the next major release. - -`MsgRecoverClient` and `MsgIBCSoftwareUpgrade` will only be allowed to be executed if the signer is the authority designated at the time of instantiating the IBC keeper. So please make sure that the correct authority is provided to the IBC keeper. - -Remove the `UpgradeProposalHandler` and `UpdateClientProposalHandler` from the `BasicModuleManager`: - -```diff -app.BasicModuleManager = module.NewBasicManagerFromManager( - app.ModuleManager, - map[string]module.AppModuleBasic{ - genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), - govtypes.ModuleName: gov.NewAppModuleBasic( - []govclient.ProposalHandler{ - paramsclient.ProposalHandler, -- ibcclientclient.UpdateClientProposalHandler, -- ibcclientclient.UpgradeProposalHandler, - }, - ), -}) -``` - -Support for in-flight legacy recover client proposals (i.e. `ClientUpdateProposal`) will be made for v8, but chains should use `MsgRecoverClient` only afterwards to avoid in-flight client recovery failing when upgrading to v9. See [this issue](https://github.com/cosmos/ibc-go/issues/4721) for more information. - -Please note that ibc-go offers facilities to test an ibc-go upgrade: - -- All e2e tests of the repository can be [run with custom Docker chain images](https://github.com/cosmos/ibc-go/blob/fec07ec55ca3e35f49a62bc6b1243c27cdf7799d/e2e/README.md#running-tests-with-custom-images). -- An [importable workflow](https://github.com/cosmos/ibc-go/blob/fec07ec55ca3e35f49a62bc6b1243c27cdf7799d/e2e/README.md#importable-workflow) that can be used from any other repository to test chain upgrades. - -### Transfer migration - -An [automatic migration handler](https://github.com/cosmos/ibc-go/blob/v8.0.0-beta.0/modules/apps/transfer/module.go#L136) is configured in the transfer module to set the [denomination metadata](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-rc.0/proto/cosmos/bank/v1beta1/bank.proto#L96-L125) for the IBC denominations of all vouchers minted by the transfer module. - -## IBC Apps - -### ICS20 - Transfer - -- The function `IsBound` has been renamed to [`hasCapability`](https://github.com/cosmos/ibc-go/blob/v8.0.0-beta.0/modules/apps/transfer/keeper/keeper.go#L98) and made unexported. - -### ICS27 - Interchain Accounts - -- Functions [`SerializeCosmosTx`](https://github.com/cosmos/ibc-go/blob/v8.0.0-beta.0/modules/apps/27-interchain-accounts/types/codec.go#L32) and [`DeserializeCosmosTx`](https://github.com/cosmos/ibc-go/blob/v8.0.0-beta.0/modules/apps/27-interchain-accounts/types/codec.go#L76) now accept an extra parameter `encoding` of type `string` that specifies the format in which the transaction messages are marshaled. Both [protobuf and proto3 JSON formats](https://github.com/cosmos/ibc-go/blob/v8.0.0-beta.0/modules/apps/27-interchain-accounts/types/metadata.go#L14-L17) are supported. -- The function `IsBound` of controller submodule has been renamed to [`hasCapability`](https://github.com/cosmos/ibc-go/blob/v8.0.0-beta.0/modules/apps/27-interchain-accounts/controller/keeper/keeper.go#L112) and made unexported. -- The function `IsBound` of host submodule has been renamed to [`hasCapability`](https://github.com/cosmos/ibc-go/blob/v8.0.0-beta.0/modules/apps/27-interchain-accounts/host/keeper/keeper.go#L95) and made unexported. - -## Relayers - -- Getter functions in `MsgChannelOpenInitResponse`, `MsgChannelOpenTryResponse`, `MsgTransferResponse`, `MsgRegisterInterchainAccountResponse` and `MsgSendTxResponse` have been removed. The fields can be accessed directly. -- `channeltypes.EventTypeTimeoutPacketOnClose` (where `channeltypes` is an import alias for `"github.com/cosmos/ibc-go/v8/modules/core/04-channel"`) has been removed, since core IBC does not emit any event with this key. -- Attribute with key `counterparty_connection_id` has been removed from event with key `connectiontypes.EventTypeConnectionOpenInit` (where `connectiontypes` is an import alias for `"github.com/cosmos/ibc-go/v8/modules/core/03-connection/types"`) and attribute with key `counterparty_channel_id` has been removed from event with key `channeltypes.EventTypeChannelOpenInit` (where `channeltypes` is an import alias for `"github.com/cosmos/ibc-go/v8/modules/core/04-channel"`) since both (counterparty connection ID and counterparty channel ID) are empty on `ConnectionOpenInit` and `ChannelOpenInit` respectively. -- As part of the migration to [governance V1 messages](#governance-v1-migration) the following changes in events have been made: - -```diff -// IBC client events vars -var ( - EventTypeCreateClient = "create_client" - EventTypeUpdateClient = "update_client" - EventTypeUpgradeClient = "upgrade_client" - EventTypeSubmitMisbehaviour = "client_misbehaviour" -- EventTypeUpdateClientProposal = "update_client_proposal" -- EventTypeUpgradeClientProposal = "upgrade_client_proposal" -+ EventTypeRecoverClient = "recover_client" -+ EventTypeScheduleIBCSoftwareUpgrade = "schedule_ibc_software_upgrade" - EventTypeUpgradeChain = "upgrade_chain" -) -``` - -## IBC Light Clients - -- Functions `Pretty` and `String` of type `MerklePath` have been [removed](https://github.com/cosmos/ibc-go/pull/4459/files#diff-dd94ec1dde9b047c0cdfba204e30dad74a81de202e3b09ac5b42f493153811af). diff --git a/docs/docs/05-migrations/_category_.json b/docs/docs/05-migrations/_category_.json deleted file mode 100644 index 21f91f851a4..00000000000 --- a/docs/docs/05-migrations/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Migrations", - "position": 5, - "link": null -} \ No newline at end of file diff --git a/docs/docs/05-migrations/images/auth-module-decision-tree.png b/docs/docs/05-migrations/images/auth-module-decision-tree.png deleted file mode 100644 index dc2c98e6618..00000000000 Binary files a/docs/docs/05-migrations/images/auth-module-decision-tree.png and /dev/null differ diff --git a/docs/docs/05-migrations/migration.template.md b/docs/docs/05-migrations/migration.template.md deleted file mode 100644 index dc546603012..00000000000 --- a/docs/docs/05-migrations/migration.template.md +++ /dev/null @@ -1,28 +0,0 @@ -# Migrating from to - -This guide provides instructions for migrating to a new version of ibc-go. - -There are four sections based on the four potential user groups of this document: - -- [Chains](#chains) -- [IBC Apps](#ibc-apps) -- [Relayers](#relayers) -- [IBC Light Clients](#ibc-light-clients) - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated on major version releases. - -## Chains - -- No relevant changes were made in this release. - -## IBC Apps - -- No relevant changes were made in this release. - -## Relayers - -- No relevant changes were made in this release. - -## IBC Light Clients - -- No relevant changes were made in this release. diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js deleted file mode 100644 index aae11c4670f..00000000000 --- a/docs/docusaurus.config.js +++ /dev/null @@ -1,285 +0,0 @@ -// @ts-check -// Note: type annotations allow type checking and IDEs autocompletion - -const lightCodeTheme = require("prism-react-renderer/themes/github"); -const darkCodeTheme = require("prism-react-renderer/themes/dracula"); - -/** @type {import('@docusaurus/types').Config} */ -const config = { - title: "IBC-Go", - tagline: "Documentation for IBC-Go", - favicon: "img/white-cosmos-icon.svg", - - // Set the production url of your site here - // for local production tests, set to http://localhost:3000/ - url: "https://ibc.cosmos.network", - // Set the // pathname under which your site is served - // For GitHub pages deployment, it is often '//' - baseUrl: "/", - - // GitHub pages deployment config. - // If you aren't using GitHub pages, you don't need these. - organizationName: "cosmos", // Usually your GitHub org/user name. - projectName: "ibc-go", // Usually your repo name. - deploymentBranch: "gh-pages", - trailingSlash: false, - - onBrokenLinks: "log", - onBrokenMarkdownLinks: "log", - - // Even if you don't use internalization, you can use this field to set useful - // metadata like html lang. For example, if your site is Chinese, you may want - // to replace "en" with "zh-Hans". - i18n: { - defaultLocale: "en", - locales: ["en"], - }, - - presets: [ - [ - "classic", - /** @type {import('@docusaurus/preset-classic').Options} */ - ({ - docs: { - sidebarPath: require.resolve("./sidebars.js"), - // Routed the docs to the root path - routeBasePath: "/", - // Exclude template markdown files from the docs - exclude: ["**/*.template.md"], - // Select the latest version - lastVersion: "v7.3.x", - // Assign banners to specific versions - versions: { - current: { - path: "main", - banner: "unreleased", - }, - "v7.3.x": { - path: "v7.3.x", - banner: "none", - }, - "v6.2.x": { - path: "v6.2.x", - banner: "none", - }, - "v5.3.x": { - path: "v5.3.x", - banner: "none", - }, - "v4.4.x": { - path: "v4.4.x", - banner: "none", - }, - }, - }, - theme: { - customCss: require.resolve("./src/css/custom.css"), - }, - }), - ], - ], - - themeConfig: - /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ - ({ - image: "img/ibc-go-image.png", - navbar: { - logo: { - alt: "IBC Logo", - src: "img/black-ibc-logo.svg", - srcDark: "img/white-ibc-logo.svg", - href: "/main/", - }, - items: [ - { - type: "docSidebar", - sidebarId: "defaultSidebar", - position: "left", - label: "Documentation", - }, - { - type: "doc", - position: "left", - docId: "README", - docsPluginId: "adrs", - label: "Architecture Decision Records", - }, - { - type: "docsVersionDropdown", - position: "right", - dropdownActiveClassDisabled: true, - }, - { - href: "https://github.com/cosmos/ibc-go", - html: ` - - - `, - position: "right", - }, - ], - }, - footer: { - links: [ - { - items: [ - { - html: `Cosmos Logo`, - }, - ], - }, - { - title: "Documentation", - items: [ - { - label: "Hermes Relayer", - href: "https://hermes.informal.systems/", - }, - { - label: "Cosmos Hub", - href: "https://hub.cosmos.network", - }, - { - label: "CometBFT", - href: "https://docs.cometbft.com", - }, - ], - }, - { - title: "Community", - items: [ - { - label: "Discord", - href: "https://discord.gg/Wtmk6ZNa8G", - }, - { - label: "Twitter", - href: "https://twitter.com/interchain_io", - }, - { - label: "YouTube", - href: "https://www.youtube.com/@interchain_io", - }, - ], - }, - { - title: "Other Tools", - items: [ - { - label: "Go Relayer", - href: "https://github.com/cosmos/relayer", - }, - { - label: "ibc-rs", - href: "https://github.com/cosmos/ibc-rs", - }, - { - label: "interchaintest", - href: "https://github.com/strangelove-ventures/interchaintest", - }, - { - label: "CosmWasm", - href: "https://cosmwasm.com/", - }, - ], - }, - { - title: "More", - items: [ - { - label: "GitHub", - href: "https://github.com/cosmos/ibc-go", - }, - { - label: "IBC Protocol Website", - href: "https://www.ibcprotocol.dev/", - }, - { - label: "Privacy Policy", - href: "https://v1.cosmos.network/privacy", - }, - ], - }, - ], - logo: { - alt: "Large IBC Logo", - src: "img/black-large-ibc-logo.svg", - srcDark: "img/white-large-ibc-logo.svg", - width: 275, - }, - copyright: `

The development of IBC-Go is led primarily by Interchain GmbH. Funding for this development comes primarily from the Interchain Foundation, a Swiss non-profit.

`, - }, - prism: { - theme: lightCodeTheme, - darkTheme: darkCodeTheme, - additionalLanguages: ["protobuf", "go-module"], - }, - }), - themes: ["@you54f/theme-github-codeblock"], - plugins: [ - [ - "@docusaurus/plugin-content-docs", - { - id: "adrs", - path: "architecture", - routeBasePath: "architecture", - sidebarPath: require.resolve("./sidebars.js"), - exclude: ["**/*.template.md"], - }, - ], - [ - "@docusaurus/plugin-content-docs", - { - id: "events", - path: "events", - routeBasePath: "events", - sidebarPath: false, - exclude: ["**/*.template.md"], - }, - ], - [ - "@docusaurus/plugin-content-docs", - { - id: "params", - path: "params", - routeBasePath: "params", - sidebarPath: false, - exclude: ["**/*.template.md"], - }, - ], - [ - "@docusaurus/plugin-client-redirects", - { - // makes the default page next in production - redirects: [ - { - from: ["/", "/master", "/next", "/docs"], - to: "/main/", - }, - ], - }, - ], - [ - require.resolve("@easyops-cn/docusaurus-search-local"), - { - indexBlog: false, - docsRouteBasePath: ["/", "architecture"], - highlightSearchTermsOnTargetPage: true, - }, - ], - async function myPlugin(context, options) { - return { - name: "docusaurus-tailwindcss", - configurePostCss(postcssOptions) { - postcssOptions.plugins.push(require("postcss-import")); - postcssOptions.plugins.push(require("tailwindcss/nesting")); - postcssOptions.plugins.push(require("tailwindcss")); - postcssOptions.plugins.push(require("autoprefixer")); - return postcssOptions; - }, - }; - }, - ], -}; - -module.exports = config; diff --git a/docs/events/events.md b/docs/events/events.md deleted file mode 100644 index 0d4cdb842f8..00000000000 --- a/docs/events/events.md +++ /dev/null @@ -1,272 +0,0 @@ -# Events - -:::danger -This document is unmaintained and may be out of date! -::: - -The IBC module emits the following events. It can be expected that the type `message`, -with an attirbute key of `action` will represent the first event for each message -being processed as emitted by the SDK's baseapp. Each IBC TAO message will -also emit its module name in the format 'ibc_sub-modulename'. - -All the events for the Channel handshakes, `SendPacket`, `RecvPacket`, `AcknowledgePacket`, -`TimeoutPacket` and `TimeoutOnClose` will emit additional events not specified here due to -callbacks to IBC applications. - -## ICS 02 - Client - -### MsgCreateClient - -| Type | Attribute Key | Attribute Value | -| ------------- | ---------------- | ----------------- | -| create_client | client_id | {clientId} | -| create_client | client_type | {clientType} | -| create_client | consensus_height | {consensusHeight} | -| message | action | create_client | -| message | module | ibc_client | - -### MsgUpdateClient - -| Type | Attribute Key | Attribute Value | -| ------------- | ---------------- | ----------------- | -| update_client | client_id | {clientId} | -| update_client | client_type | {clientType} | -| update_client | consensus_height | {consensusHeight} | -| update_client | header | {header} | -| message | action | update_client | -| message | module | ibc_client | - -### MsgSubmitMisbehaviour - -| Type | Attribute Key | Attribute Value | -| ------------------- | ---------------- | ------------------- | -| client_misbehaviour | client_id | {clientId} | -| client_misbehaviour | client_type | {clientType} | -| client_misbehaviour | consensus_height | {consensusHeight} | -| message | action | client_misbehaviour | -| message | module | evidence | -| message | sender | {senderAddress} | -| submit_evidence | evidence_hash | {evidenceHash} | - -### UpdateClientProposal - -| Type | Attribute Key | Attribute Value | -| ---------------------- | ---------------- | ----------------- | -| update_client_proposal | client_id | {clientId} | -| update_client_proposal | client_type | {clientType} | -| update_client_proposal | consensus_height | {consensusHeight} | - -### IBCSoftwareUpgrade - -| Type | Attribute Key | Attribute Value | -|-------------------------------|---------------------|---------------------------------| -| schedule_ibc_software_upgrade | title | {title} | -| schedule_ibc_software_upgrade | upgrade_plan_height | {plan.height} | - -## ICS 03 - Connection - -### MsgConnectionOpenInit - -| Type | Attribute Key | Attribute Value | -| -------------------- | ---------------------- | ----------------------- | -| connection_open_init | connection_id | {connectionId} | -| connection_open_init | client_id | {clientId} | -| connection_open_init | counterparty_client_id | {counterparty.clientId} | -| message | action | connection_open_init | -| message | module | ibc_connection | - -### MsgConnectionOpenTry - -| Type | Attribute Key | Attribute Value | -| ------------------- | -------------------------- | --------------------------- | -| connection_open_try | connection_id | {connectionId} | -| connection_open_try | client_id | {clientId} | -| connection_open_try | counterparty_client_id | {counterparty.clientId | -| connection_open_try | counterparty_connection_id | {counterparty.connectionId} | -| message | action | connection_open_try | -| message | module | ibc_connection | - -### MsgConnectionOpenAck - -| Type | Attribute Key | Attribute Value | -| ------------------- | -------------------------- | --------------------------- | -| connection_open_ack | connection_id | {connectionId} | -| connection_open_ack | client_id | {clientId} | -| connection_open_ack | counterparty_client_id | {counterparty.clientId} | -| connection_open_ack | counterparty_connection_id | {counterparty.connectionId} | -| message | module | ibc_connection | -| message | action | connection_open_ack | - -### MsgConnectionOpenConfirm - -| Type | Attribute Key | Attribute Value | -| ----------------------- | -------------------------- | --------------------------- | -| connection_open_confirm | connection_id | {connectionId} | -| connection_open_confirm | client_id | {clientId} | -| connection_open_confirm | counterparty_client_id | {counterparty.clientId} | -| connection_open_confirm | counterparty_connection_id | {counterparty.connectionId} | -| message | action | connection_open_confirm | -| message | module | ibc_connection | - -## ICS 04 - Channel - -### MsgChannelOpenInit - -| Type | Attribute Key | Attribute Value | -| ----------------- | -------------------- | ----------------------------- | -| channel_open_init | port_id | {portId} | -| channel_open_init | channel_id | {channelId} | -| channel_open_init | counterparty_port_id | {channel.counterparty.portId} | -| channel_open_init | connection_id | {channel.connectionHops} | -| message | action | channel_open_init | -| message | module | ibc_channel | - -### MsgChannelOpenTry - -| Type | Attribute Key | Attribute Value | -| ---------------- | ----------------------- | -------------------------------- | -| channel_open_try | port_id | {portId} | -| channel_open_try | channel_id | {channelId} | -| channel_open_try | counterparty_port_id | {channel.counterparty.portId} | -| channel_open_try | counterparty_channel_id | {channel.counterparty.channelId} | -| channel_open_try | connection_id | {channel.connectionHops} | -| message | action | channel_open_try | -| message | module | ibc_channel | - -### MsgChannelOpenAck - -| Type | Attribute Key | Attribute Value | -| ---------------- | ----------------------- | -------------------------------- | -| channel_open_ack | port_id | {portId} | -| channel_open_ack | channel_id | {channelId} | -| channel_open_ack | counterparty_port_id | {channel.counterparty.portId} | -| channel_open_ack | counterparty_channel_id | {channel.counterparty.channelId} | -| channel_open_ack | connection_id | {channel.connectionHops} | -| message | action | channel_open_ack | -| message | module | ibc_channel | - -### MsgChannelOpenConfirm - -| Type | Attribute Key | Attribute Value | -| -------------------- | ----------------------- | -------------------------------- | -| channel_open_confirm | port_id | {portId} | -| channel_open_confirm | channel_id | {channelId} | -| channel_open_confirm | counterparty_port_id | {channel.counterparty.portId} | -| channel_open_confirm | counterparty_channel_id | {channel.counterparty.channelId} | -| channel_open_confirm | connection_id | {channel.connectionHops} | -| message | module | ibc_channel | -| message | action | channel_open_confirm | - -### MsgChannelCloseInit - -| Type | Attribute Key | Attribute Value | -| ------------------ | ----------------------- | -------------------------------- | -| channel_close_init | port_id | {portId} | -| channel_close_init | channel_id | {channelId} | -| channel_close_init | counterparty_port_id | {channel.counterparty.portId} | -| channel_close_init | counterparty_channel_id | {channel.counterparty.channelId} | -| channel_close_init | connection_id | {channel.connectionHops} | -| message | action | channel_close_init | -| message | module | ibc_channel | - -### MsgChannelCloseConfirm - -| Type | Attribute Key | Attribute Value | -| --------------------- | ----------------------- | -------------------------------- | -| channel_close_confirm | port_id | {portId} | -| channel_close_confirm | channel_id | {channelId} | -| channel_close_confirm | counterparty_port_id | {channel.counterparty.portId} | -| channel_close_confirm | counterparty_channel_id | {channel.counterparty.channelId} | -| channel_close_confirm | connection_id | {channel.connectionHops} | -| message | action | channel_close_confirm | -| message | module | ibc_channel | - -### SendPacket (application module call) - -| Type | Attribute Key | Attribute Value | Status | -| ----------- | ------------------------ | -------------------------------- | ---------- | -| send_packet | packet_data | {data} | Deprecated | -| send_packet | packet_data_hex | {hex.Encode(data)} | | -| send_packet | packet_timeout_height | {timeoutHeight} | | -| send_packet | packet_timeout_timestamp | {timeoutTimestamp} | | -| send_packet | packet_sequence | {sequence} | | -| send_packet | packet_src_port | {sourcePort} | | -| send_packet | packet_src_channel | {sourceChannel} | | -| send_packet | packet_dst_port | {destinationPort} | | -| send_packet | packet_dst_channel | {destinationChannel} | | -| send_packet | packet_channel_ordering | {channel.Ordering} | | -| send_packet | packet_connection | {channel.ConnectionHops[0]} | Deprecated | -| send_packet | connection_id | {channel.ConnectionHops[0]} | | -| message | action | application-module-defined-field | | -| message | module | ibc_channel | | - -### MsgRecvPacket - -| Type | Attribute Key | Attribute Value | Status | -| ----------- | ------------------------ | --------------------------- | ---------- | -| recv_packet | packet_data | {data} | Deprecated | -| recv_packet | packet_data_hex | {hex.Encode(data)} | | -| recv_packet | packet_timeout_height | {timeoutHeight} | | -| recv_packet | packet_timeout_timestamp | {timeoutTimestamp} | | -| recv_packet | packet_sequence | {sequence} | | -| recv_packet | packet_src_port | {sourcePort} | | -| recv_packet | packet_src_channel | {sourceChannel} | | -| recv_packet | packet_dst_port | {destinationPort} | | -| recv_packet | packet_dst_channel | {destinationChannel} | | -| recv_packet | packet_channel_ordering | {channel.Ordering} | | -| recv_packet | packet_connection | {channel.ConnectionHops[0]} | Deprecated | -| recv_packet | connection_id | {channel.ConnectionHops[0]} | | -| message | action | recv_packet | | -| message | module | ibc_channel | | - -| Type | Attribute Key | Attribute Value | Status | -| --------------------- | ------------------------ | --------------------------- | ---------- | -| write_acknowledgement | packet_data | {data} | Deprecated | -| write_acknowledgement | packet_data_hex | {hex.Encode(data)} | | -| write_acknowledgement | packet_timeout_height | {timeoutHeight} | | -| write_acknowledgement | packet_timeout_timestamp | {timeoutTimestamp} | | -| write_acknowledgement | packet_sequence | {sequence} | | -| write_acknowledgement | packet_src_port | {sourcePort} | | -| write_acknowledgement | packet_src_channel | {sourceChannel} | | -| write_acknowledgement | packet_dst_port | {destinationPort} | | -| write_acknowledgement | packet_dst_channel | {destinationChannel} | | -| write_acknowledgement | packet_ack | {ack} | Deprecated | -| write_acknowledgement | packet_ack_hex | {hex.Encode(ack)} | | -| write_acknowledgement | packet_channel_ordering | {channel.Ordering} | | -| write_acknowledgement | packet_connection | {channel.ConnectionHops[0]} | Deprecated | -| write_acknowledgement | connection_id | {channel.ConnectionHops[0]} | | -| message | action | write_acknowledgement | | -| message | module | ibc_channel | | - -### MsgAcknowledgePacket - -| Type | Attribute Key | Attribute Value | Status | -| ------------------ | ------------------------ | --------------------------- | ---------- | -| acknowledge_packet | packet_timeout_height | {timeoutHeight} | | -| acknowledge_packet | packet_timeout_timestamp | {timeoutTimestamp} | | -| acknowledge_packet | packet_sequence | {sequence} | | -| acknowledge_packet | packet_src_port | {sourcePort} | | -| acknowledge_packet | packet_src_channel | {sourceChannel} | | -| acknowledge_packet | packet_dst_port | {destinationPort} | | -| acknowledge_packet | packet_dst_channel | {destinationChannel} | | -| acknowledge_packet | packet_channel_ordering | {channel.Ordering} | | -| acknowledge_packet | packet_connection | {channel.ConnectionHops[0]} | Deprecated | -| acknowledge_packet | connection_id | {channel.ConnectionHops[0]} | | -| message | action | acknowledge_packet | | -| message | module | ibc_channel | | - -### MsgTimeoutPacket & MsgTimeoutOnClose - -| Type | Attribute Key | Attribute Value | -| -------------- | ------------------------ | --------------------------- | -| timeout_packet | packet_timeout_height | {timeoutHeight} | -| timeout_packet | packet_timeout_timestamp | {timeoutTimestamp} | -| timeout_packet | packet_sequence | {sequence} | -| timeout_packet | packet_src_port | {sourcePort} | -| timeout_packet | packet_src_channel | {sourceChannel} | -| timeout_packet | packet_dst_port | {destinationPort} | -| timeout_packet | packet_dst_channel | {destinationChannel} | -| timeout_packet | packet_channel_ordering | {channel.Ordering} | -| timeout_packet | connection_id | {channel.ConnectionHops[0]} | -| message | action | timeout_packet | -| message | module | ibc_channel | diff --git a/docs/package-lock.json b/docs/package-lock.json deleted file mode 100644 index b90b77634d3..00000000000 --- a/docs/package-lock.json +++ /dev/null @@ -1,22744 +0,0 @@ -{ - "name": "docs", - "version": "0.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "docs", - "version": "0.0.0", - "dependencies": { - "@docusaurus/core": "^2.4.3", - "@docusaurus/plugin-client-redirects": "^2.4.3", - "@docusaurus/plugin-content-docs": "^2.4.3", - "@docusaurus/preset-classic": "^2.4.3", - "@easyops-cn/docusaurus-search-local": "^0.36.0", - "@mdx-js/react": "^1.6.22", - "@you54f/theme-github-codeblock": "^0.1.1", - "autoprefixer": "^10.4.14", - "clsx": "^1.2.1", - "postcss": "^8.4.23", - "postcss-import": "^15.1.0", - "prism-react-renderer": "^1.3.5", - "react": "^17.0.2", - "react-dom": "^17.0.2", - "tailwindcss": "^3.3.1" - }, - "devDependencies": { - "@docusaurus/module-type-aliases": "^2.4.3" - }, - "engines": { - "node": ">=16.14" - } - }, - "node_modules/@algolia/autocomplete-core": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.9.3.tgz", - "integrity": "sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==", - "dependencies": { - "@algolia/autocomplete-plugin-algolia-insights": "1.9.3", - "@algolia/autocomplete-shared": "1.9.3" - } - }, - "node_modules/@algolia/autocomplete-plugin-algolia-insights": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.9.3.tgz", - "integrity": "sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==", - "dependencies": { - "@algolia/autocomplete-shared": "1.9.3" - }, - "peerDependencies": { - "search-insights": ">= 1 < 3" - } - }, - "node_modules/@algolia/autocomplete-preset-algolia": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.9.3.tgz", - "integrity": "sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==", - "dependencies": { - "@algolia/autocomplete-shared": "1.9.3" - }, - "peerDependencies": { - "@algolia/client-search": ">= 4.9.1 < 6", - "algoliasearch": ">= 4.9.1 < 6" - } - }, - "node_modules/@algolia/autocomplete-shared": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.9.3.tgz", - "integrity": "sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==", - "peerDependencies": { - "@algolia/client-search": ">= 4.9.1 < 6", - "algoliasearch": ">= 4.9.1 < 6" - } - }, - "node_modules/@algolia/cache-browser-local-storage": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.20.0.tgz", - "integrity": "sha512-uujahcBt4DxduBTvYdwO3sBfHuJvJokiC3BP1+O70fglmE1ShkH8lpXqZBac1rrU3FnNYSUs4pL9lBdTKeRPOQ==", - "dependencies": { - "@algolia/cache-common": "4.20.0" - } - }, - "node_modules/@algolia/cache-common": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.20.0.tgz", - "integrity": "sha512-vCfxauaZutL3NImzB2G9LjLt36vKAckc6DhMp05An14kVo8F1Yofb6SIl6U3SaEz8pG2QOB9ptwM5c+zGevwIQ==" - }, - "node_modules/@algolia/cache-in-memory": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.20.0.tgz", - "integrity": "sha512-Wm9ak/IaacAZXS4mB3+qF/KCoVSBV6aLgIGFEtQtJwjv64g4ePMapORGmCyulCFwfePaRAtcaTbMcJF+voc/bg==", - "dependencies": { - "@algolia/cache-common": "4.20.0" - } - }, - "node_modules/@algolia/client-account": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.20.0.tgz", - "integrity": "sha512-GGToLQvrwo7am4zVkZTnKa72pheQeez/16sURDWm7Seyz+HUxKi3BM6fthVVPUEBhtJ0reyVtuK9ArmnaKl10Q==", - "dependencies": { - "@algolia/client-common": "4.20.0", - "@algolia/client-search": "4.20.0", - "@algolia/transporter": "4.20.0" - } - }, - "node_modules/@algolia/client-analytics": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.20.0.tgz", - "integrity": "sha512-EIr+PdFMOallRdBTHHdKI3CstslgLORQG7844Mq84ib5oVFRVASuuPmG4bXBgiDbcsMLUeOC6zRVJhv1KWI0ug==", - "dependencies": { - "@algolia/client-common": "4.20.0", - "@algolia/client-search": "4.20.0", - "@algolia/requester-common": "4.20.0", - "@algolia/transporter": "4.20.0" - } - }, - "node_modules/@algolia/client-common": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.20.0.tgz", - "integrity": "sha512-P3WgMdEss915p+knMMSd/fwiHRHKvDu4DYRrCRaBrsfFw7EQHon+EbRSm4QisS9NYdxbS04kcvNoavVGthyfqQ==", - "dependencies": { - "@algolia/requester-common": "4.20.0", - "@algolia/transporter": "4.20.0" - } - }, - "node_modules/@algolia/client-personalization": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.20.0.tgz", - "integrity": "sha512-N9+zx0tWOQsLc3K4PVRDV8GUeOLAY0i445En79Pr3zWB+m67V+n/8w4Kw1C5LlbHDDJcyhMMIlqezh6BEk7xAQ==", - "dependencies": { - "@algolia/client-common": "4.20.0", - "@algolia/requester-common": "4.20.0", - "@algolia/transporter": "4.20.0" - } - }, - "node_modules/@algolia/client-search": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.20.0.tgz", - "integrity": "sha512-zgwqnMvhWLdpzKTpd3sGmMlr4c+iS7eyyLGiaO51zDZWGMkpgoNVmltkzdBwxOVXz0RsFMznIxB9zuarUv4TZg==", - "dependencies": { - "@algolia/client-common": "4.20.0", - "@algolia/requester-common": "4.20.0", - "@algolia/transporter": "4.20.0" - } - }, - "node_modules/@algolia/events": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", - "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" - }, - "node_modules/@algolia/logger-common": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.20.0.tgz", - "integrity": "sha512-xouigCMB5WJYEwvoWW5XDv7Z9f0A8VoXJc3VKwlHJw/je+3p2RcDXfksLI4G4lIVncFUYMZx30tP/rsdlvvzHQ==" - }, - "node_modules/@algolia/logger-console": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.20.0.tgz", - "integrity": "sha512-THlIGG1g/FS63z0StQqDhT6bprUczBI8wnLT3JWvfAQDZX5P6fCg7dG+pIrUBpDIHGszgkqYEqECaKKsdNKOUA==", - "dependencies": { - "@algolia/logger-common": "4.20.0" - } - }, - "node_modules/@algolia/requester-browser-xhr": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.20.0.tgz", - "integrity": "sha512-HbzoSjcjuUmYOkcHECkVTwAelmvTlgs48N6Owt4FnTOQdwn0b8pdht9eMgishvk8+F8bal354nhx/xOoTfwiAw==", - "dependencies": { - "@algolia/requester-common": "4.20.0" - } - }, - "node_modules/@algolia/requester-common": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.20.0.tgz", - "integrity": "sha512-9h6ye6RY/BkfmeJp7Z8gyyeMrmmWsMOCRBXQDs4mZKKsyVlfIVICpcSibbeYcuUdurLhIlrOUkH3rQEgZzonng==" - }, - "node_modules/@algolia/requester-node-http": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.20.0.tgz", - "integrity": "sha512-ocJ66L60ABSSTRFnCHIEZpNHv6qTxsBwJEPfYaSBsLQodm0F9ptvalFkHMpvj5DfE22oZrcrLbOYM2bdPJRHng==", - "dependencies": { - "@algolia/requester-common": "4.20.0" - } - }, - "node_modules/@algolia/transporter": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.20.0.tgz", - "integrity": "sha512-Lsii1pGWOAISbzeyuf+r/GPhvHMPHSPrTDWNcIzOE1SG1inlJHICaVe2ikuoRjcpgxZNU54Jl+if15SUCsaTUg==", - "dependencies": { - "@algolia/cache-common": "4.20.0", - "@algolia/logger-common": "4.20.0", - "@algolia/requester-common": "4.20.0" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz", - "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz", - "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-compilation-targets": "^7.21.4", - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.4", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.4", - "@babel/types": "^7.21.4", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", - "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", - "dependencies": { - "@babel/types": "^7.21.4", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", - "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", - "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.18.6", - "@babel/types": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz", - "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==", - "dependencies": { - "@babel/compat-data": "^7.21.4", - "@babel/helper-validator-option": "^7.21.0", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.21.4.tgz", - "integrity": "sha512-46QrX2CQlaFRF4TkwfTt6nJD7IHq8539cCL7SDpqWSDeJKY1xylKKY5F/33mJhLZ3mFvKv2gGrVS6NkyF6qs+Q==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-member-expression-to-functions": "^7.21.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-replace-supers": "^7.20.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/helper-split-export-declaration": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.21.4.tgz", - "integrity": "sha512-M00OuhU+0GyZ5iBBN9czjugzWrEq2vDpf/zCYHxxf93ul/Q5rv+a5h+/+0WnI1AebHNVtl5bFV0qsJoH23DbfA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "regexpu-core": "^5.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", - "dependencies": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", - "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.21.0.tgz", - "integrity": "sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q==", - "dependencies": { - "@babel/types": "^7.21.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", - "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", - "dependencies": { - "@babel/types": "^7.21.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", - "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.2", - "@babel/types": "^7.21.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", - "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", - "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-wrap-function": "^7.18.9", - "@babel/types": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz", - "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-member-expression-to-functions": "^7.20.7", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.7", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", - "dependencies": { - "@babel/types": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", - "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", - "dependencies": { - "@babel/types": "^7.20.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", - "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", - "dependencies": { - "@babel/helper-function-name": "^7.19.0", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", - "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", - "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz", - "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-proposal-optional-chaining": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", - "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz", - "integrity": "sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", - "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", - "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", - "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", - "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", - "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", - "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", - "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", - "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", - "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", - "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0.tgz", - "integrity": "sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", - "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", - "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz", - "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", - "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz", - "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", - "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==", - "dependencies": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", - "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.21.0.tgz", - "integrity": "sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.21.0.tgz", - "integrity": "sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-replace-supers": "^7.20.7", - "@babel/helper-split-export-declaration": "^7.18.6", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz", - "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/template": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.21.3.tgz", - "integrity": "sha512-bp6hwMFzuiE4HqYEyoGJ/V2LeIWn+hLVKc4pnj++E5XQptwhtcGmSayM029d/j2X1bPKGTlsyPwAubuU22KhMA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", - "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", - "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", - "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.21.0.tgz", - "integrity": "sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", - "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", - "dependencies": { - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", - "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", - "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz", - "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==", - "dependencies": { - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.21.2.tgz", - "integrity": "sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA==", - "dependencies": { - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-simple-access": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz", - "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==", - "dependencies": { - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-identifier": "^7.19.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", - "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", - "dependencies": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", - "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.20.5", - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", - "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", - "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.21.3.tgz", - "integrity": "sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", - "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-constant-elements": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.21.3.tgz", - "integrity": "sha512-4DVcFeWe/yDYBLp0kBmOGFJ6N2UYg7coGid1gdxb4co62dy/xISDMaYBXBVXEDhfgMk7qkbcYiGtwd5Q/hwDDQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz", - "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.21.0.tgz", - "integrity": "sha512-6OAWljMvQrZjR2DaNhVfRz6dkCAVV+ymcLUmaf8bccGOHn2v5rHJK3tTpij0BuhdYWP4LLaqj5lwcdlpAAPuvg==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-jsx": "^7.18.6", - "@babel/types": "^7.21.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz", - "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==", - "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz", - "integrity": "sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", - "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "regenerator-transform": "^0.15.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", - "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.21.4.tgz", - "integrity": "sha512-1J4dhrw1h1PqnNNpzwxQ2UBymJUF8KuPjAAnlLwZcGhHAIqUigFW7cdK6GHoB64ubY4qXQNYknoUeks4Wz7CUA==", - "dependencies": { - "@babel/helper-module-imports": "^7.21.4", - "@babel/helper-plugin-utils": "^7.20.2", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", - "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz", - "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", - "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", - "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", - "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typescript": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.21.3.tgz", - "integrity": "sha512-RQxPz6Iqt8T0uw/WsJNReuBpWpBqs/n7mNo18sKLoTbMp+UrEekhH+pKSVC7gWz+DNjo9gryfV8YzCiT45RgMw==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-typescript": "^7.20.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", - "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", - "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.21.4.tgz", - "integrity": "sha512-2W57zHs2yDLm6GD5ZpvNn71lZ0B/iypSdIeq25OurDKji6AdzV07qp4s3n1/x5BqtiGaTrPN3nerlSCaC5qNTw==", - "dependencies": { - "@babel/compat-data": "^7.21.4", - "@babel/helper-compilation-targets": "^7.21.4", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-option": "^7.21.0", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.20.7", - "@babel/plugin-proposal-async-generator-functions": "^7.20.7", - "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-class-static-block": "^7.21.0", - "@babel/plugin-proposal-dynamic-import": "^7.18.6", - "@babel/plugin-proposal-export-namespace-from": "^7.18.9", - "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.20.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", - "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.20.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.21.0", - "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.21.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.20.0", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.20.7", - "@babel/plugin-transform-async-to-generator": "^7.20.7", - "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.21.0", - "@babel/plugin-transform-classes": "^7.21.0", - "@babel/plugin-transform-computed-properties": "^7.20.7", - "@babel/plugin-transform-destructuring": "^7.21.3", - "@babel/plugin-transform-dotall-regex": "^7.18.6", - "@babel/plugin-transform-duplicate-keys": "^7.18.9", - "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.21.0", - "@babel/plugin-transform-function-name": "^7.18.9", - "@babel/plugin-transform-literals": "^7.18.9", - "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.20.11", - "@babel/plugin-transform-modules-commonjs": "^7.21.2", - "@babel/plugin-transform-modules-systemjs": "^7.20.11", - "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.20.5", - "@babel/plugin-transform-new-target": "^7.18.6", - "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.21.3", - "@babel/plugin-transform-property-literals": "^7.18.6", - "@babel/plugin-transform-regenerator": "^7.20.5", - "@babel/plugin-transform-reserved-words": "^7.18.6", - "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.20.7", - "@babel/plugin-transform-sticky-regex": "^7.18.6", - "@babel/plugin-transform-template-literals": "^7.18.9", - "@babel/plugin-transform-typeof-symbol": "^7.18.9", - "@babel/plugin-transform-unicode-escapes": "^7.18.10", - "@babel/plugin-transform-unicode-regex": "^7.18.6", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.21.4", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "core-js-compat": "^3.25.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-react": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.18.6.tgz", - "integrity": "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-transform-react-display-name": "^7.18.6", - "@babel/plugin-transform-react-jsx": "^7.18.6", - "@babel/plugin-transform-react-jsx-development": "^7.18.6", - "@babel/plugin-transform-react-pure-annotations": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-typescript": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.21.4.tgz", - "integrity": "sha512-sMLNWY37TCdRH/bJ6ZeeOH1nPuanED7Ai9Y/vH31IPqalioJ6ZNFUWONsakhv4r4n+I6gm5lmoE0olkgib/j/A==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-option": "^7.21.0", - "@babel/plugin-syntax-jsx": "^7.21.4", - "@babel/plugin-transform-modules-commonjs": "^7.21.2", - "@babel/plugin-transform-typescript": "^7.21.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" - }, - "node_modules/@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", - "dependencies": { - "regenerator-runtime": "^0.13.11" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.21.0.tgz", - "integrity": "sha512-TDD4UJzos3JJtM+tHX+w2Uc+KWj7GV+VKKFdMVd2Rx8sdA19hcc3P3AHFYd5LVOw+pYuSd5lICC3gm52B6Rwxw==", - "dependencies": { - "core-js-pure": "^3.25.1", - "regenerator-runtime": "^0.13.11" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz", - "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", - "dependencies": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.4", - "@babel/types": "^7.21.4", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", - "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "optional": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "peer": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "peer": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@docsearch/css": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.5.2.tgz", - "integrity": "sha512-SPiDHaWKQZpwR2siD0KQUwlStvIAnEyK6tAE2h2Wuoq8ue9skzhlyVQ1ddzOxX6khULnAALDiR/isSF3bnuciA==" - }, - "node_modules/@docsearch/react": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.5.2.tgz", - "integrity": "sha512-9Ahcrs5z2jq/DcAvYtvlqEBHImbm4YJI8M9y0x6Tqg598P40HTEkX7hsMcIuThI+hTFxRGZ9hll0Wygm2yEjng==", - "dependencies": { - "@algolia/autocomplete-core": "1.9.3", - "@algolia/autocomplete-preset-algolia": "1.9.3", - "@docsearch/css": "3.5.2", - "algoliasearch": "^4.19.1" - }, - "peerDependencies": { - "@types/react": ">= 16.8.0 < 19.0.0", - "react": ">= 16.8.0 < 19.0.0", - "react-dom": ">= 16.8.0 < 19.0.0", - "search-insights": ">= 1 < 3" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "search-insights": { - "optional": true - } - } - }, - "node_modules/@docusaurus/core": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.4.3.tgz", - "integrity": "sha512-dWH5P7cgeNSIg9ufReX6gaCl/TmrGKD38Orbwuz05WPhAQtFXHd5B8Qym1TiXfvUNvwoYKkAJOJuGe8ou0Z7PA==", - "dependencies": { - "@babel/core": "^7.18.6", - "@babel/generator": "^7.18.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-transform-runtime": "^7.18.6", - "@babel/preset-env": "^7.18.6", - "@babel/preset-react": "^7.18.6", - "@babel/preset-typescript": "^7.18.6", - "@babel/runtime": "^7.18.6", - "@babel/runtime-corejs3": "^7.18.6", - "@babel/traverse": "^7.18.8", - "@docusaurus/cssnano-preset": "2.4.3", - "@docusaurus/logger": "2.4.3", - "@docusaurus/mdx-loader": "2.4.3", - "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/utils": "2.4.3", - "@docusaurus/utils-common": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "@slorber/static-site-generator-webpack-plugin": "^4.0.7", - "@svgr/webpack": "^6.2.1", - "autoprefixer": "^10.4.7", - "babel-loader": "^8.2.5", - "babel-plugin-dynamic-import-node": "^2.3.3", - "boxen": "^6.2.1", - "chalk": "^4.1.2", - "chokidar": "^3.5.3", - "clean-css": "^5.3.0", - "cli-table3": "^0.6.2", - "combine-promises": "^1.1.0", - "commander": "^5.1.0", - "copy-webpack-plugin": "^11.0.0", - "core-js": "^3.23.3", - "css-loader": "^6.7.1", - "css-minimizer-webpack-plugin": "^4.0.0", - "cssnano": "^5.1.12", - "del": "^6.1.1", - "detect-port": "^1.3.0", - "escape-html": "^1.0.3", - "eta": "^2.0.0", - "file-loader": "^6.2.0", - "fs-extra": "^10.1.0", - "html-minifier-terser": "^6.1.0", - "html-tags": "^3.2.0", - "html-webpack-plugin": "^5.5.0", - "import-fresh": "^3.3.0", - "leven": "^3.1.0", - "lodash": "^4.17.21", - "mini-css-extract-plugin": "^2.6.1", - "postcss": "^8.4.14", - "postcss-loader": "^7.0.0", - "prompts": "^2.4.2", - "react-dev-utils": "^12.0.1", - "react-helmet-async": "^1.3.0", - "react-loadable": "npm:@docusaurus/react-loadable@5.5.2", - "react-loadable-ssr-addon-v5-slorber": "^1.0.1", - "react-router": "^5.3.3", - "react-router-config": "^5.1.1", - "react-router-dom": "^5.3.3", - "rtl-detect": "^1.0.4", - "semver": "^7.3.7", - "serve-handler": "^6.1.3", - "shelljs": "^0.8.5", - "terser-webpack-plugin": "^5.3.3", - "tslib": "^2.4.0", - "update-notifier": "^5.1.0", - "url-loader": "^4.1.1", - "wait-on": "^6.0.1", - "webpack": "^5.73.0", - "webpack-bundle-analyzer": "^4.5.0", - "webpack-dev-server": "^4.9.3", - "webpack-merge": "^5.8.0", - "webpackbar": "^5.0.2" - }, - "bin": { - "docusaurus": "bin/docusaurus.mjs" - }, - "engines": { - "node": ">=16.14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/cssnano-preset": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.4.3.tgz", - "integrity": "sha512-ZvGSRCi7z9wLnZrXNPG6DmVPHdKGd8dIn9pYbEOFiYihfv4uDR3UtxogmKf+rT8ZlKFf5Lqne8E8nt08zNM8CA==", - "dependencies": { - "cssnano-preset-advanced": "^5.3.8", - "postcss": "^8.4.14", - "postcss-sort-media-queries": "^4.2.1", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=16.14" - } - }, - "node_modules/@docusaurus/logger": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.4.3.tgz", - "integrity": "sha512-Zxws7r3yLufk9xM1zq9ged0YHs65mlRmtsobnFkdZTxWXdTYlWWLWdKyNKAsVC+D7zg+pv2fGbyabdOnyZOM3w==", - "dependencies": { - "chalk": "^4.1.2", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=16.14" - } - }, - "node_modules/@docusaurus/mdx-loader": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.4.3.tgz", - "integrity": "sha512-b1+fDnWtl3GiqkL0BRjYtc94FZrcDDBV1j8446+4tptB9BAOlePwG2p/pK6vGvfL53lkOsszXMghr2g67M0vCw==", - "dependencies": { - "@babel/parser": "^7.18.8", - "@babel/traverse": "^7.18.8", - "@docusaurus/logger": "2.4.3", - "@docusaurus/utils": "2.4.3", - "@mdx-js/mdx": "^1.6.22", - "escape-html": "^1.0.3", - "file-loader": "^6.2.0", - "fs-extra": "^10.1.0", - "image-size": "^1.0.1", - "mdast-util-to-string": "^2.0.0", - "remark-emoji": "^2.2.0", - "stringify-object": "^3.3.0", - "tslib": "^2.4.0", - "unified": "^9.2.2", - "unist-util-visit": "^2.0.3", - "url-loader": "^4.1.1", - "webpack": "^5.73.0" - }, - "engines": { - "node": ">=16.14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/module-type-aliases": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-2.4.3.tgz", - "integrity": "sha512-cwkBkt1UCiduuvEAo7XZY01dJfRn7UR/75mBgOdb1hKknhrabJZ8YH+7savd/y9kLExPyrhe0QwdS9GuzsRRIA==", - "dependencies": { - "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/types": "2.4.3", - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router-config": "*", - "@types/react-router-dom": "*", - "react-helmet-async": "*", - "react-loadable": "npm:@docusaurus/react-loadable@5.5.2" - }, - "peerDependencies": { - "react": "*", - "react-dom": "*" - } - }, - "node_modules/@docusaurus/plugin-client-redirects": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-2.4.3.tgz", - "integrity": "sha512-iCwc/zH8X6eNtLYdyUJFY6+GbsbRgMgvAC/TmSmCYTmwnoN5Y1Bc5OwUkdtoch0XKizotJMRAmGIAhP8sAetdQ==", - "dependencies": { - "@docusaurus/core": "2.4.3", - "@docusaurus/logger": "2.4.3", - "@docusaurus/utils": "2.4.3", - "@docusaurus/utils-common": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "eta": "^2.0.0", - "fs-extra": "^10.1.0", - "lodash": "^4.17.21", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=16.14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/plugin-content-blog": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.4.3.tgz", - "integrity": "sha512-PVhypqaA0t98zVDpOeTqWUTvRqCEjJubtfFUQ7zJNYdbYTbS/E/ytq6zbLVsN/dImvemtO/5JQgjLxsh8XLo8Q==", - "dependencies": { - "@docusaurus/core": "2.4.3", - "@docusaurus/logger": "2.4.3", - "@docusaurus/mdx-loader": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils": "2.4.3", - "@docusaurus/utils-common": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "cheerio": "^1.0.0-rc.12", - "feed": "^4.2.2", - "fs-extra": "^10.1.0", - "lodash": "^4.17.21", - "reading-time": "^1.5.0", - "tslib": "^2.4.0", - "unist-util-visit": "^2.0.3", - "utility-types": "^3.10.0", - "webpack": "^5.73.0" - }, - "engines": { - "node": ">=16.14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/plugin-content-docs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.4.3.tgz", - "integrity": "sha512-N7Po2LSH6UejQhzTCsvuX5NOzlC+HiXOVvofnEPj0WhMu1etpLEXE6a4aTxrtg95lQ5kf0xUIdjX9sh3d3G76A==", - "dependencies": { - "@docusaurus/core": "2.4.3", - "@docusaurus/logger": "2.4.3", - "@docusaurus/mdx-loader": "2.4.3", - "@docusaurus/module-type-aliases": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "@types/react-router-config": "^5.0.6", - "combine-promises": "^1.1.0", - "fs-extra": "^10.1.0", - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "lodash": "^4.17.21", - "tslib": "^2.4.0", - "utility-types": "^3.10.0", - "webpack": "^5.73.0" - }, - "engines": { - "node": ">=16.14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/plugin-content-pages": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.4.3.tgz", - "integrity": "sha512-txtDVz7y3zGk67q0HjG0gRttVPodkHqE0bpJ+7dOaTH40CQFLSh7+aBeGnPOTl+oCPG+hxkim4SndqPqXjQ8Bg==", - "dependencies": { - "@docusaurus/core": "2.4.3", - "@docusaurus/mdx-loader": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "fs-extra": "^10.1.0", - "tslib": "^2.4.0", - "webpack": "^5.73.0" - }, - "engines": { - "node": ">=16.14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/plugin-debug": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.4.3.tgz", - "integrity": "sha512-LkUbuq3zCmINlFb+gAd4ZvYr+bPAzMC0hwND4F7V9bZ852dCX8YoWyovVUBKq4er1XsOwSQaHmNGtObtn8Av8Q==", - "dependencies": { - "@docusaurus/core": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils": "2.4.3", - "fs-extra": "^10.1.0", - "react-json-view": "^1.21.3", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=16.14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/plugin-google-analytics": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.4.3.tgz", - "integrity": "sha512-KzBV3k8lDkWOhg/oYGxlK5o9bOwX7KpPc/FTWoB+SfKhlHfhq7qcQdMi1elAaVEIop8tgK6gD1E58Q+XC6otSQ==", - "dependencies": { - "@docusaurus/core": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=16.14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/plugin-google-gtag": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.4.3.tgz", - "integrity": "sha512-5FMg0rT7sDy4i9AGsvJC71MQrqQZwgLNdDetLEGDHLfSHLvJhQbTCUGbGXknUgWXQJckcV/AILYeJy+HhxeIFA==", - "dependencies": { - "@docusaurus/core": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=16.14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/plugin-google-tag-manager": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.4.3.tgz", - "integrity": "sha512-1jTzp71yDGuQiX9Bi0pVp3alArV0LSnHXempvQTxwCGAEzUWWaBg4d8pocAlTpbP9aULQQqhgzrs8hgTRPOM0A==", - "dependencies": { - "@docusaurus/core": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=16.14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/plugin-sitemap": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.4.3.tgz", - "integrity": "sha512-LRQYrK1oH1rNfr4YvWBmRzTL0LN9UAPxBbghgeFRBm5yloF6P+zv1tm2pe2hQTX/QP5bSKdnajCvfnScgKXMZQ==", - "dependencies": { - "@docusaurus/core": "2.4.3", - "@docusaurus/logger": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils": "2.4.3", - "@docusaurus/utils-common": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "fs-extra": "^10.1.0", - "sitemap": "^7.1.1", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=16.14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/preset-classic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.4.3.tgz", - "integrity": "sha512-tRyMliepY11Ym6hB1rAFSNGwQDpmszvWYJvlK1E+md4SW8i6ylNHtpZjaYFff9Mdk3i/Pg8ItQq9P0daOJAvQw==", - "dependencies": { - "@docusaurus/core": "2.4.3", - "@docusaurus/plugin-content-blog": "2.4.3", - "@docusaurus/plugin-content-docs": "2.4.3", - "@docusaurus/plugin-content-pages": "2.4.3", - "@docusaurus/plugin-debug": "2.4.3", - "@docusaurus/plugin-google-analytics": "2.4.3", - "@docusaurus/plugin-google-gtag": "2.4.3", - "@docusaurus/plugin-google-tag-manager": "2.4.3", - "@docusaurus/plugin-sitemap": "2.4.3", - "@docusaurus/theme-classic": "2.4.3", - "@docusaurus/theme-common": "2.4.3", - "@docusaurus/theme-search-algolia": "2.4.3", - "@docusaurus/types": "2.4.3" - }, - "engines": { - "node": ">=16.14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/react-loadable": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", - "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", - "dependencies": { - "@types/react": "*", - "prop-types": "^15.6.2" - }, - "peerDependencies": { - "react": "*" - } - }, - "node_modules/@docusaurus/theme-classic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.4.3.tgz", - "integrity": "sha512-QKRAJPSGPfDY2yCiPMIVyr+MqwZCIV2lxNzqbyUW0YkrlmdzzP3WuQJPMGLCjWgQp/5c9kpWMvMxjhpZx1R32Q==", - "dependencies": { - "@docusaurus/core": "2.4.3", - "@docusaurus/mdx-loader": "2.4.3", - "@docusaurus/module-type-aliases": "2.4.3", - "@docusaurus/plugin-content-blog": "2.4.3", - "@docusaurus/plugin-content-docs": "2.4.3", - "@docusaurus/plugin-content-pages": "2.4.3", - "@docusaurus/theme-common": "2.4.3", - "@docusaurus/theme-translations": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils": "2.4.3", - "@docusaurus/utils-common": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "@mdx-js/react": "^1.6.22", - "clsx": "^1.2.1", - "copy-text-to-clipboard": "^3.0.1", - "infima": "0.2.0-alpha.43", - "lodash": "^4.17.21", - "nprogress": "^0.2.0", - "postcss": "^8.4.14", - "prism-react-renderer": "^1.3.5", - "prismjs": "^1.28.0", - "react-router-dom": "^5.3.3", - "rtlcss": "^3.5.0", - "tslib": "^2.4.0", - "utility-types": "^3.10.0" - }, - "engines": { - "node": ">=16.14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/theme-common": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.4.3.tgz", - "integrity": "sha512-7KaDJBXKBVGXw5WOVt84FtN8czGWhM0lbyWEZXGp8AFfL6sZQfRTluFp4QriR97qwzSyOfQb+nzcDZZU4tezUw==", - "dependencies": { - "@docusaurus/mdx-loader": "2.4.3", - "@docusaurus/module-type-aliases": "2.4.3", - "@docusaurus/plugin-content-blog": "2.4.3", - "@docusaurus/plugin-content-docs": "2.4.3", - "@docusaurus/plugin-content-pages": "2.4.3", - "@docusaurus/utils": "2.4.3", - "@docusaurus/utils-common": "2.4.3", - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router-config": "*", - "clsx": "^1.2.1", - "parse-numeric-range": "^1.3.0", - "prism-react-renderer": "^1.3.5", - "tslib": "^2.4.0", - "use-sync-external-store": "^1.2.0", - "utility-types": "^3.10.0" - }, - "engines": { - "node": ">=16.14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/theme-search-algolia": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.3.tgz", - "integrity": "sha512-jziq4f6YVUB5hZOB85ELATwnxBz/RmSLD3ksGQOLDPKVzat4pmI8tddNWtriPpxR04BNT+ZfpPUMFkNFetSW1Q==", - "dependencies": { - "@docsearch/react": "^3.1.1", - "@docusaurus/core": "2.4.3", - "@docusaurus/logger": "2.4.3", - "@docusaurus/plugin-content-docs": "2.4.3", - "@docusaurus/theme-common": "2.4.3", - "@docusaurus/theme-translations": "2.4.3", - "@docusaurus/utils": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "algoliasearch": "^4.13.1", - "algoliasearch-helper": "^3.10.0", - "clsx": "^1.2.1", - "eta": "^2.0.0", - "fs-extra": "^10.1.0", - "lodash": "^4.17.21", - "tslib": "^2.4.0", - "utility-types": "^3.10.0" - }, - "engines": { - "node": ">=16.14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/theme-translations": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.4.3.tgz", - "integrity": "sha512-H4D+lbZbjbKNS/Zw1Lel64PioUAIT3cLYYJLUf3KkuO/oc9e0QCVhIYVtUI2SfBCF2NNdlyhBDQEEMygsCedIg==", - "dependencies": { - "fs-extra": "^10.1.0", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=16.14" - } - }, - "node_modules/@docusaurus/types": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.4.3.tgz", - "integrity": "sha512-W6zNLGQqfrp/EoPD0bhb9n7OobP+RHpmvVzpA+Z/IuU3Q63njJM24hmT0GYboovWcDtFmnIJC9wcyx4RVPQscw==", - "dependencies": { - "@types/history": "^4.7.11", - "@types/react": "*", - "commander": "^5.1.0", - "joi": "^17.6.0", - "react-helmet-async": "^1.3.0", - "utility-types": "^3.10.0", - "webpack": "^5.73.0", - "webpack-merge": "^5.8.0" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/utils": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.4.3.tgz", - "integrity": "sha512-fKcXsjrD86Smxv8Pt0TBFqYieZZCPh4cbf9oszUq/AMhZn3ujwpKaVYZACPX8mmjtYx0JOgNx52CREBfiGQB4A==", - "dependencies": { - "@docusaurus/logger": "2.4.3", - "@svgr/webpack": "^6.2.1", - "escape-string-regexp": "^4.0.0", - "file-loader": "^6.2.0", - "fs-extra": "^10.1.0", - "github-slugger": "^1.4.0", - "globby": "^11.1.0", - "gray-matter": "^4.0.3", - "js-yaml": "^4.1.0", - "lodash": "^4.17.21", - "micromatch": "^4.0.5", - "resolve-pathname": "^3.0.0", - "shelljs": "^0.8.5", - "tslib": "^2.4.0", - "url-loader": "^4.1.1", - "webpack": "^5.73.0" - }, - "engines": { - "node": ">=16.14" - }, - "peerDependencies": { - "@docusaurus/types": "*" - }, - "peerDependenciesMeta": { - "@docusaurus/types": { - "optional": true - } - } - }, - "node_modules/@docusaurus/utils-common": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.4.3.tgz", - "integrity": "sha512-/jascp4GbLQCPVmcGkPzEQjNaAk3ADVfMtudk49Ggb+131B1WDD6HqlSmDf8MxGdy7Dja2gc+StHf01kiWoTDQ==", - "dependencies": { - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=16.14" - }, - "peerDependencies": { - "@docusaurus/types": "*" - }, - "peerDependenciesMeta": { - "@docusaurus/types": { - "optional": true - } - } - }, - "node_modules/@docusaurus/utils-validation": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.4.3.tgz", - "integrity": "sha512-G2+Vt3WR5E/9drAobP+hhZQMaswRwDlp6qOMi7o7ZypB+VO7N//DZWhZEwhcRGepMDJGQEwtPv7UxtYwPL9PBw==", - "dependencies": { - "@docusaurus/logger": "2.4.3", - "@docusaurus/utils": "2.4.3", - "joi": "^17.6.0", - "js-yaml": "^4.1.0", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=16.14" - } - }, - "node_modules/@easyops-cn/autocomplete.js": { - "version": "0.38.1", - "resolved": "https://registry.npmjs.org/@easyops-cn/autocomplete.js/-/autocomplete.js-0.38.1.tgz", - "integrity": "sha512-drg76jS6syilOUmVNkyo1c7ZEBPcPuK+aJA7AksM5ZIIbV57DMHCywiCr+uHyv8BE5jUTU98j/H7gVrkHrWW3Q==", - "dependencies": { - "cssesc": "^3.0.0", - "immediate": "^3.2.3" - } - }, - "node_modules/@easyops-cn/docusaurus-search-local": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@easyops-cn/docusaurus-search-local/-/docusaurus-search-local-0.36.0.tgz", - "integrity": "sha512-4R8tLYQc1aLTJcqIYHd7Np/wh6/psfHmGbNuJMwAFW7bJ6KyStlagBdXzv3k3SCqpo5emW2IUNYmHmN+8xvB6A==", - "dependencies": { - "@docusaurus/plugin-content-docs": "^2.0.0-rc.1", - "@docusaurus/theme-translations": "^2.0.0-rc.1", - "@docusaurus/utils": "^2.0.0-rc.1", - "@docusaurus/utils-common": "^2.0.0-rc.1", - "@docusaurus/utils-validation": "^2.0.0-rc.1", - "@easyops-cn/autocomplete.js": "^0.38.1", - "@node-rs/jieba": "^1.6.0", - "cheerio": "^1.0.0-rc.3", - "clsx": "^1.1.1", - "debug": "^4.2.0", - "fs-extra": "^10.0.0", - "klaw-sync": "^6.0.0", - "lunr": "^2.3.9", - "lunr-languages": "^1.4.0", - "mark.js": "^8.11.1", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "@docusaurus/theme-common": "^2.0.0-rc.1", - "react": "^16.14.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/@hapi/hoek": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" - }, - "node_modules/@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", - "dependencies": { - "@sinclair/typebox": "^0.25.16" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", - "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", - "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" - }, - "node_modules/@mdx-js/mdx": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-1.6.22.tgz", - "integrity": "sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==", - "dependencies": { - "@babel/core": "7.12.9", - "@babel/plugin-syntax-jsx": "7.12.1", - "@babel/plugin-syntax-object-rest-spread": "7.8.3", - "@mdx-js/util": "1.6.22", - "babel-plugin-apply-mdx-type-prop": "1.6.22", - "babel-plugin-extract-import-names": "1.6.22", - "camelcase-css": "2.0.1", - "detab": "2.0.4", - "hast-util-raw": "6.0.1", - "lodash.uniq": "4.5.0", - "mdast-util-to-hast": "10.0.1", - "remark-footnotes": "2.0.0", - "remark-mdx": "1.6.22", - "remark-parse": "8.0.3", - "remark-squeeze-paragraphs": "4.0.0", - "style-to-object": "0.3.0", - "unified": "9.2.0", - "unist-builder": "2.0.3", - "unist-util-visit": "2.0.3" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mdx-js/mdx/node_modules/@babel/core": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.7", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.9", - "@babel/types": "^7.12.7", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@mdx-js/mdx/node_modules/@babel/plugin-syntax-jsx": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@mdx-js/mdx/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/@mdx-js/mdx/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@mdx-js/mdx/node_modules/unified": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", - "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", - "dependencies": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mdx-js/react": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-1.6.22.tgz", - "integrity": "sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "react": "^16.13.1 || ^17.0.0" - } - }, - "node_modules/@mdx-js/util": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz", - "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@node-rs/jieba": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba/-/jieba-1.7.0.tgz", - "integrity": "sha512-Hm1JIlejxkWe1FSFZRns/g1j5hZmp357n+0n2BluABA4KLZ8EraHfPmPRmVMW6vbdMZObTYIVu5aVrPnUfBOxg==", - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "optionalDependencies": { - "@node-rs/jieba-android-arm-eabi": "1.7.0", - "@node-rs/jieba-android-arm64": "1.7.0", - "@node-rs/jieba-darwin-arm64": "1.7.0", - "@node-rs/jieba-darwin-x64": "1.7.0", - "@node-rs/jieba-freebsd-x64": "1.7.0", - "@node-rs/jieba-linux-arm-gnueabihf": "1.7.0", - "@node-rs/jieba-linux-arm64-gnu": "1.7.0", - "@node-rs/jieba-linux-arm64-musl": "1.7.0", - "@node-rs/jieba-linux-x64-gnu": "1.7.0", - "@node-rs/jieba-linux-x64-musl": "1.7.0", - "@node-rs/jieba-win32-arm64-msvc": "1.7.0", - "@node-rs/jieba-win32-ia32-msvc": "1.7.0", - "@node-rs/jieba-win32-x64-msvc": "1.7.0" - } - }, - "node_modules/@node-rs/jieba-android-arm-eabi": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-android-arm-eabi/-/jieba-android-arm-eabi-1.7.0.tgz", - "integrity": "sha512-XF4OYcZCyDiBK+jm1Zmt2o+xEO7K2K5OvUC3MTc9jd3Lwvy3EdHp8tpGvEp8PxfVFe2/JxNzX4OQQQP3Dhmk9A==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/jieba-android-arm64": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-android-arm64/-/jieba-android-arm64-1.7.0.tgz", - "integrity": "sha512-9oWwFVr/37T89WC+jjiI9A6u0zUJNTJl5ZC4CMxX45MVMokWI7bBXU7t7qBmMdFBzj+OFwDd3sm1fh4vl7NSWA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/jieba-darwin-arm64": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-darwin-arm64/-/jieba-darwin-arm64-1.7.0.tgz", - "integrity": "sha512-9gBuxJCNITNI/gU5l8eeVGQ9MAf0BV86lfeo9TeU61vJCy6sqyx26wFMLODQgLNdiMP+q/fZme/G0hfZUjfPVA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/jieba-darwin-x64": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-darwin-x64/-/jieba-darwin-x64-1.7.0.tgz", - "integrity": "sha512-FFUSMY4tl0Prpxa1SHy7Yzze2KfV/bZzccpO5nd+a8zCKbiX6gVkJ89FfxSAD2QrXUGkZvJYiPmu5nkZItqRZQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/jieba-freebsd-x64": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-freebsd-x64/-/jieba-freebsd-x64-1.7.0.tgz", - "integrity": "sha512-QFz2pz0Br+621QbKkgQPqTn90j1kcCD9jaI++qTLNHJGlWLRn6sFoAjb+jQEQEy9aE7VqfIV56eaVcCoU5VO2w==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/jieba-linux-arm-gnueabihf": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm-gnueabihf/-/jieba-linux-arm-gnueabihf-1.7.0.tgz", - "integrity": "sha512-kHJxO2sd7gMKqI1YS5DjABEcRwRemaCtgbKSuUqEaHGmUz9nAaUF6FSY8U4rXwr7HXt+kQa4NgyYDjgz+Pscrw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/jieba-linux-arm64-gnu": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm64-gnu/-/jieba-linux-arm64-gnu-1.7.0.tgz", - "integrity": "sha512-3qoCV9pF6llPBGDMu7K8JdHjI10WPkrq6P2gpZESqekcE4DatV6DcU9FWR+QL7MK/7meoE3/Zhjm7OK+qBd8gg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/jieba-linux-arm64-musl": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm64-musl/-/jieba-linux-arm64-musl-1.7.0.tgz", - "integrity": "sha512-xv6hvzOV7iTCq7mM8SWhC3zEk6CqmBwhOSlfbb3gvPkc4U1UA1hmvcrD7oO5Qn+U+nuswysGCdVU6Z5AypLDfg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/jieba-linux-x64-gnu": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-x64-gnu/-/jieba-linux-x64-gnu-1.7.0.tgz", - "integrity": "sha512-NpelWidMSNLoFTw+ov3y5jhJZjapHwEnh0Fyfm/7mvqkdwzVyedqNj22etRGum+nsAosMotCUWUznIMAD075gQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/jieba-linux-x64-musl": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-x64-musl/-/jieba-linux-x64-musl-1.7.0.tgz", - "integrity": "sha512-yG4F8sy+fW4RbhyKXmEMT/JGuQuKH0TGymCEGYgT0km2I60iys63jWf2VTzCtrx583wxN5XoHv5HN60nhtIBtw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/jieba-win32-arm64-msvc": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-arm64-msvc/-/jieba-win32-arm64-msvc-1.7.0.tgz", - "integrity": "sha512-R6l/BSMs6R6BwpZS6DIDZuAEjUIPdAHgyi+xptP3mICjm6U+GMsvsRTeZkIJ7a/yzYUfqvz54VpQsfE5f0psBQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/jieba-win32-ia32-msvc": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-ia32-msvc/-/jieba-win32-ia32-msvc-1.7.0.tgz", - "integrity": "sha512-FwibbuizEjzom02K2JM2T8tL0VlxW5xGDDy3L3dgx46xIGE85PwGYjgju+eDt4UODgxDsxGC4DUMMZf3XvCc7A==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/jieba-win32-x64-msvc": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-x64-msvc/-/jieba-win32-x64-msvc-1.7.0.tgz", - "integrity": "sha512-pJv7nluB6azhsOWvJB86Dyfg/M7n9k49bs9Bwmsylz9uhdZX9QnEShDW934RdmnjPYQ5aPgsSFrY6NXP/aovUA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@polka/url": { - "version": "1.0.0-next.21", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", - "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==" - }, - "node_modules/@sideway/address": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", - "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@sideway/formula": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" - }, - "node_modules/@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" - }, - "node_modules/@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==" - }, - "node_modules/@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/@slorber/static-site-generator-webpack-plugin": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.7.tgz", - "integrity": "sha512-Ug7x6z5lwrz0WqdnNFOMYrDQNTPAprvHLSh6+/fmml3qUiz6l5eq+2MzLKWtn/q5K5NpSiFsZTP/fck/3vjSxA==", - "dependencies": { - "eval": "^0.1.8", - "p-map": "^4.0.0", - "webpack-sources": "^3.2.2" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@svgr/babel-plugin-add-jsx-attribute": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.5.1.tgz", - "integrity": "sha512-9PYGcXrAxitycIjRmZB+Q0JaN07GZIWaTBIGQzfaZv+qr1n8X1XUEJ5rZ/vx6OVD9RRYlrNnXWExQXcmZeD/BQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-7.0.0.tgz", - "integrity": "sha512-iiZaIvb3H/c7d3TH2HBeK91uI2rMhZNwnsIrvd7ZwGLkFw6mmunOCoVnjdYua662MqGFxlN9xTq4fv9hgR4VXQ==", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-7.0.0.tgz", - "integrity": "sha512-sQQmyo+qegBx8DfFc04PFmIO1FP1MHI1/QEpzcIcclo5OAISsOJPW76ZIs0bDyO/DBSJEa/tDa1W26pVtt0FRw==", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.5.1.tgz", - "integrity": "sha512-8DPaVVE3fd5JKuIC29dqyMB54sA6mfgki2H2+swh+zNJoynC8pMPzOkidqHOSc6Wj032fhl8Z0TVn1GiPpAiJg==", - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-svg-dynamic-title": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.5.1.tgz", - "integrity": "sha512-FwOEi0Il72iAzlkaHrlemVurgSQRDFbk0OC8dSvD5fSBPHltNh7JtLsxmZUhjYBZo2PpcU/RJvvi6Q0l7O7ogw==", - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-svg-em-dimensions": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.5.1.tgz", - "integrity": "sha512-gWGsiwjb4tw+ITOJ86ndY/DZZ6cuXMNE/SjcDRg+HLuCmwpcjOktwRF9WgAiycTqJD/QXqL2f8IzE2Rzh7aVXA==", - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-transform-react-native-svg": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.5.1.tgz", - "integrity": "sha512-2jT3nTayyYP7kI6aGutkyfJ7UMGtuguD72OjeGLwVNyfPRBD8zQthlvL+fAbAKk5n9ZNcvFkp/b1lZ7VsYqVJg==", - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-transform-svg-component": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.5.1.tgz", - "integrity": "sha512-a1p6LF5Jt33O3rZoVRBqdxL350oge54iZWHNI6LJB5tQ7EelvD/Mb1mfBiZNAan0dt4i3VArkFRjA4iObuNykQ==", - "engines": { - "node": ">=12" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-preset": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-6.5.1.tgz", - "integrity": "sha512-6127fvO/FF2oi5EzSQOAjo1LE3OtNVh11R+/8FXa+mHx1ptAaS4cknIjnUA7e6j6fwGGJ17NzaTJFUwOV2zwCw==", - "dependencies": { - "@svgr/babel-plugin-add-jsx-attribute": "^6.5.1", - "@svgr/babel-plugin-remove-jsx-attribute": "*", - "@svgr/babel-plugin-remove-jsx-empty-expression": "*", - "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.5.1", - "@svgr/babel-plugin-svg-dynamic-title": "^6.5.1", - "@svgr/babel-plugin-svg-em-dimensions": "^6.5.1", - "@svgr/babel-plugin-transform-react-native-svg": "^6.5.1", - "@svgr/babel-plugin-transform-svg-component": "^6.5.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/core": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.5.1.tgz", - "integrity": "sha512-/xdLSWxK5QkqG524ONSjvg3V/FkNyCv538OIBdQqPNaAta3AsXj/Bd2FbvR87yMbXO2hFSWiAe/Q6IkVPDw+mw==", - "dependencies": { - "@babel/core": "^7.19.6", - "@svgr/babel-preset": "^6.5.1", - "@svgr/plugin-jsx": "^6.5.1", - "camelcase": "^6.2.0", - "cosmiconfig": "^7.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/hast-util-to-babel-ast": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.5.1.tgz", - "integrity": "sha512-1hnUxxjd83EAxbL4a0JDJoD3Dao3hmjvyvyEV8PzWmLK3B9m9NPlW7GKjFyoWE8nM7HnXzPcmmSyOW8yOddSXw==", - "dependencies": { - "@babel/types": "^7.20.0", - "entities": "^4.4.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/plugin-jsx": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.5.1.tgz", - "integrity": "sha512-+UdQxI3jgtSjCykNSlEMuy1jSRQlGC7pqBCPvkG/2dATdWo082zHTTK3uhnAju2/6XpE6B5mZ3z4Z8Ns01S8Gw==", - "dependencies": { - "@babel/core": "^7.19.6", - "@svgr/babel-preset": "^6.5.1", - "@svgr/hast-util-to-babel-ast": "^6.5.1", - "svg-parser": "^2.0.4" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@svgr/core": "^6.0.0" - } - }, - "node_modules/@svgr/plugin-svgo": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-6.5.1.tgz", - "integrity": "sha512-omvZKf8ixP9z6GWgwbtmP9qQMPX4ODXi+wzbVZgomNFsUIlHA1sf4fThdwTWSsZGgvGAG6yE+b/F5gWUkcZ/iQ==", - "dependencies": { - "cosmiconfig": "^7.0.1", - "deepmerge": "^4.2.2", - "svgo": "^2.8.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@svgr/core": "*" - } - }, - "node_modules/@svgr/webpack": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-6.5.1.tgz", - "integrity": "sha512-cQ/AsnBkXPkEK8cLbv4Dm7JGXq2XrumKnL1dRpJD9rIO2fTIlJI9a1uCciYG1F2aUsox/hJQyNGbt3soDxSRkA==", - "dependencies": { - "@babel/core": "^7.19.6", - "@babel/plugin-transform-react-constant-elements": "^7.18.12", - "@babel/preset-env": "^7.19.4", - "@babel/preset-react": "^7.18.6", - "@babel/preset-typescript": "^7.18.6", - "@svgr/core": "^6.5.1", - "@svgr/plugin-jsx": "^6.5.1", - "@svgr/plugin-svgo": "^6.5.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dependencies": { - "defer-to-connect": "^1.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "peer": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "peer": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "peer": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "peer": true - }, - "node_modules/@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/bonjour": { - "version": "3.5.10", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", - "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", - "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", - "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" - } - }, - "node_modules/@types/eslint": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz", - "integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" - }, - "node_modules/@types/express": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", - "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.33", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", - "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "node_modules/@types/hast": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", - "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/history": { - "version": "4.7.11", - "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", - "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" - }, - "node_modules/@types/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" - }, - "node_modules/@types/http-proxy": { - "version": "1.17.10", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.10.tgz", - "integrity": "sha512-Qs5aULi+zV1bwKAg5z1PWnDXWmsn+LxIvUGv6E2+OOMYhclZMO+OXd9pYVf2gLykf2I7IV2u7oTHwChPNsvJ7g==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" - }, - "node_modules/@types/mdast": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.11.tgz", - "integrity": "sha512-Y/uImid8aAwrEA24/1tcRZwpxX3pIFTSilcNDKSPn+Y2iDywSEachzRuvgAYYLR3wpGXAsMbv5lvKLDZLeYPAw==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/mime": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", - "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" - }, - "node_modules/@types/node": { - "version": "18.15.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", - "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" - }, - "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" - }, - "node_modules/@types/parse5": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz", - "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==" - }, - "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" - }, - "node_modules/@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" - }, - "node_modules/@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" - }, - "node_modules/@types/react": { - "version": "18.0.37", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.37.tgz", - "integrity": "sha512-4yaZZtkRN3ZIQD3KSEwkfcik8s0SWV+82dlJot1AbGYHCzJkWP3ENBY6wYeDRmKZ6HkrgoGAmR2HqdwYGp6OEw==", - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-router": { - "version": "5.1.20", - "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", - "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", - "dependencies": { - "@types/history": "^4.7.11", - "@types/react": "*" - } - }, - "node_modules/@types/react-router-config": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.7.tgz", - "integrity": "sha512-pFFVXUIydHlcJP6wJm7sDii5mD/bCmmAY0wQzq+M+uX7bqS95AQqHZWP1iNMKrWVQSuHIzj5qi9BvrtLX2/T4w==", - "dependencies": { - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router": "^5.1.0" - } - }, - "node_modules/@types/react-router-dom": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", - "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", - "dependencies": { - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router": "*" - } - }, - "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" - }, - "node_modules/@types/sax": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.5.tgz", - "integrity": "sha512-9jWta97bBVC027/MShr3gLab8gPhKy4l6qpb+UJLF5pDm3501NvA7uvqVCW+REFtx00oTi6Cq9JzLwgq6evVgw==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" - }, - "node_modules/@types/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", - "dependencies": { - "@types/express": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", - "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", - "dependencies": { - "@types/mime": "*", - "@types/node": "*" - } - }, - "node_modules/@types/sockjs": { - "version": "0.3.33", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", - "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/unist": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", - "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" - }, - "node_modules/@types/ws": { - "version": "8.5.4", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", - "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==" - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==" - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==" - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==" - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==" - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" - }, - "node_modules/@you54f/theme-github-codeblock": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@you54f/theme-github-codeblock/-/theme-github-codeblock-0.1.1.tgz", - "integrity": "sha512-SFbkHzwfsfShYd9yL818P9P7AlSBQgDC92pyQWZqJV/PMdgfCh5ZsK/pt/1s/jy0wvYi4pFTwOEQ0+vhdy324w==" - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/accepts/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/accepts/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/address": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", - "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/algoliasearch": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.20.0.tgz", - "integrity": "sha512-y+UHEjnOItoNy0bYO+WWmLWBlPwDjKHW6mNHrPi0NkuhpQOOEbrkwQH/wgKFDLh7qlKjzoKeiRtlpewDPDG23g==", - "dependencies": { - "@algolia/cache-browser-local-storage": "4.20.0", - "@algolia/cache-common": "4.20.0", - "@algolia/cache-in-memory": "4.20.0", - "@algolia/client-account": "4.20.0", - "@algolia/client-analytics": "4.20.0", - "@algolia/client-common": "4.20.0", - "@algolia/client-personalization": "4.20.0", - "@algolia/client-search": "4.20.0", - "@algolia/logger-common": "4.20.0", - "@algolia/logger-console": "4.20.0", - "@algolia/requester-browser-xhr": "4.20.0", - "@algolia/requester-common": "4.20.0", - "@algolia/requester-node-http": "4.20.0", - "@algolia/transporter": "4.20.0" - } - }, - "node_modules/algoliasearch-helper": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.14.2.tgz", - "integrity": "sha512-FjDSrjvQvJT/SKMW74nPgFpsoPUwZCzGbCqbp8HhBFfSk/OvNFxzCaCmuO0p7AWeLy1gD+muFwQEkBwcl5H4pg==", - "dependencies": { - "@algolia/events": "^4.0.1" - }, - "peerDependencies": { - "algoliasearch": ">= 3.1 < 6" - } - }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dependencies": { - "string-width": "^4.1.0" - } - }, - "node_modules/ansi-align/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/ansi-align/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "engines": [ - "node >= 0.8.0" - ], - "bin": { - "ansi-html": "bin/ansi-html" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - } - ], - "dependencies": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", - "dependencies": { - "follow-redirects": "^1.14.7" - } - }, - "node_modules/babel-loader": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz", - "integrity": "sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==", - "dependencies": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^2.0.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" - }, - "engines": { - "node": ">= 8.9" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "webpack": ">=2" - } - }, - "node_modules/babel-plugin-apply-mdx-type-prop": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz", - "integrity": "sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==", - "dependencies": { - "@babel/helper-plugin-utils": "7.10.4", - "@mdx-js/util": "1.6.22" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "@babel/core": "^7.11.6" - } - }, - "node_modules/babel-plugin-apply-mdx-type-prop/node_modules/@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dependencies": { - "object.assign": "^4.1.0" - } - }, - "node_modules/babel-plugin-extract-import-names": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz", - "integrity": "sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==", - "dependencies": { - "@babel/helper-plugin-utils": "7.10.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/babel-plugin-extract-import-names/node_modules/@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", - "dependencies": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3", - "core-js-compat": "^3.25.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/bail": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", - "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base16": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", - "integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==" - }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" - }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/bonjour-service": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", - "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", - "dependencies": { - "array-flatten": "^2.1.2", - "dns-equal": "^1.0.0", - "fast-deep-equal": "^3.1.3", - "multicast-dns": "^7.2.5" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - }, - "node_modules/boxen": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", - "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", - "dependencies": { - "ansi-align": "^3.0.1", - "camelcase": "^6.2.0", - "chalk": "^4.1.2", - "cli-boxes": "^3.0.0", - "string-width": "^5.0.1", - "type-fest": "^2.5.0", - "widest-line": "^4.0.1", - "wrap-ansi": "^8.0.1" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cacheable-request/node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "dependencies": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "dependencies": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001480", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001480.tgz", - "integrity": "sha512-q7cpoPPvZYgtyC4VaBSN0Bt+PJ4c4EYRf0DrduInOz2SkFpHD5p3LnvEpqBp7UnJn+8x1Ogl1s38saUxe+ihQQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/ccount": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", - "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-legacy": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-reference-invalid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", - "dependencies": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" - }, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" - } - }, - "node_modules/cheerio-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", - "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", - "dependencies": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "engines": { - "node": ">=6.0" - } - }, - "node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/clean-css": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", - "integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==", - "dependencies": { - "source-map": "~0.6.0" - }, - "engines": { - "node": ">= 10.0" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-boxes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", - "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-table3": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", - "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", - "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" - } - }, - "node_modules/cli-table3/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/cli-table3/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/collapse-white-space": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", - "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" - }, - "node_modules/combine-promises": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/combine-promises/-/combine-promises-1.1.0.tgz", - "integrity": "sha512-ZI9jvcLDxqwaXEixOhArm3r7ReIivsXkpbyEWyeOhzz1QS0iSgBPnWvEqvIQtYyamGCYA88gFhmUrs9hrrQ0pg==", - "engines": { - "node": ">=10" - } - }, - "node_modules/comma-separated-tokens": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", - "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compressible/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/compression/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dependencies": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/connect-history-api-fallback": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/consola": { - "version": "2.15.3", - "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", - "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" - }, - "node_modules/content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" - }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "node_modules/copy-text-to-clipboard": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz", - "integrity": "sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/copy-webpack-plugin": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", - "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", - "dependencies": { - "fast-glob": "^3.2.11", - "glob-parent": "^6.0.1", - "globby": "^13.1.1", - "normalize-path": "^3.0.0", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - } - }, - "node_modules/copy-webpack-plugin/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/copy-webpack-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/copy-webpack-plugin/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/copy-webpack-plugin/node_modules/globby": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", - "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", - "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/copy-webpack-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/copy-webpack-plugin/node_modules/schema-utils": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.1.tgz", - "integrity": "sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ==", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/copy-webpack-plugin/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/core-js": { - "version": "3.30.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.30.1.tgz", - "integrity": "sha512-ZNS5nbiSwDTq4hFosEDqm65izl2CWmLz0hARJMyNQBgkUZMIF51cQiMvIQKA6hvuaeWxQDP3hEedM1JZIgTldQ==", - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-js-compat": { - "version": "3.30.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.30.1.tgz", - "integrity": "sha512-d690npR7MC6P0gq4npTl5n2VQeNAmUrJ90n+MHiKS7W2+xno4o3F5GDEuylSdi6EJ3VssibSGXOa1r3YXD3Mhw==", - "dependencies": { - "browserslist": "^4.21.5" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-js-pure": { - "version": "3.30.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.30.1.tgz", - "integrity": "sha512-nXBEVpmUnNRhz83cHd9JRQC52cTMcuXAmR56+9dSMpRdpeA4I1PX6yjmhd71Eyc/wXNsdBdUDIj1QTIeZpU5Tg==", - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cosmiconfig-typescript-loader": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.3.0.tgz", - "integrity": "sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q==", - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "peerDependencies": { - "@types/node": "*", - "cosmiconfig": ">=7", - "ts-node": ">=10", - "typescript": ">=3" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "peer": true - }, - "node_modules/cross-fetch": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", - "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", - "dependencies": { - "node-fetch": "^2.6.12" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/css-declaration-sorter": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz", - "integrity": "sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew==", - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.0.9" - } - }, - "node_modules/css-loader": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", - "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", - "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.19", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.3.8" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/css-minimizer-webpack-plugin": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-4.2.2.tgz", - "integrity": "sha512-s3Of/4jKfw1Hj9CxEO1E5oXhQAxlayuHO2y/ML+C6I9sQ7FdzfEV6QgMLN3vI+qFsjJGIAFLKtQK7t8BOXAIyA==", - "dependencies": { - "cssnano": "^5.1.8", - "jest-worker": "^29.1.2", - "postcss": "^8.4.17", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "@parcel/css": { - "optional": true - }, - "@swc/css": { - "optional": true - }, - "clean-css": { - "optional": true - }, - "csso": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "lightningcss": { - "optional": true - } - } - }, - "node_modules/css-minimizer-webpack-plugin/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/css-minimizer-webpack-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/css-minimizer-webpack-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/css-minimizer-webpack-plugin/node_modules/schema-utils": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.1.tgz", - "integrity": "sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ==", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cssnano": { - "version": "5.1.15", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", - "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", - "dependencies": { - "cssnano-preset-default": "^5.2.14", - "lilconfig": "^2.0.3", - "yaml": "^1.10.2" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/cssnano" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/cssnano-preset-advanced": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.10.tgz", - "integrity": "sha512-fnYJyCS9jgMU+cmHO1rPSPf9axbQyD7iUhLO5Df6O4G+fKIOMps+ZbU0PdGFejFBBZ3Pftf18fn1eG7MAPUSWQ==", - "dependencies": { - "autoprefixer": "^10.4.12", - "cssnano-preset-default": "^5.2.14", - "postcss-discard-unused": "^5.1.0", - "postcss-merge-idents": "^5.1.1", - "postcss-reduce-idents": "^5.2.0", - "postcss-zindex": "^5.1.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/cssnano-preset-default": { - "version": "5.2.14", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", - "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", - "dependencies": { - "css-declaration-sorter": "^6.3.1", - "cssnano-utils": "^3.1.0", - "postcss-calc": "^8.2.3", - "postcss-colormin": "^5.3.1", - "postcss-convert-values": "^5.1.3", - "postcss-discard-comments": "^5.1.2", - "postcss-discard-duplicates": "^5.1.0", - "postcss-discard-empty": "^5.1.1", - "postcss-discard-overridden": "^5.1.0", - "postcss-merge-longhand": "^5.1.7", - "postcss-merge-rules": "^5.1.4", - "postcss-minify-font-values": "^5.1.0", - "postcss-minify-gradients": "^5.1.1", - "postcss-minify-params": "^5.1.4", - "postcss-minify-selectors": "^5.2.1", - "postcss-normalize-charset": "^5.1.0", - "postcss-normalize-display-values": "^5.1.0", - "postcss-normalize-positions": "^5.1.1", - "postcss-normalize-repeat-style": "^5.1.1", - "postcss-normalize-string": "^5.1.0", - "postcss-normalize-timing-functions": "^5.1.0", - "postcss-normalize-unicode": "^5.1.1", - "postcss-normalize-url": "^5.1.0", - "postcss-normalize-whitespace": "^5.1.1", - "postcss-ordered-values": "^5.1.3", - "postcss-reduce-initial": "^5.1.2", - "postcss-reduce-transforms": "^5.1.0", - "postcss-svgo": "^5.1.0", - "postcss-unique-selectors": "^5.1.1" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/cssnano-utils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", - "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", - "dependencies": { - "css-tree": "^1.1.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", - "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" - }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "engines": { - "node": ">=8" - } - }, - "node_modules/define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/del": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", - "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", - "dependencies": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detab": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detab/-/detab-2.0.4.tgz", - "integrity": "sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==", - "dependencies": { - "repeat-string": "^1.5.4" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" - }, - "node_modules/detect-port": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", - "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", - "dependencies": { - "address": "^1.0.1", - "debug": "4" - }, - "bin": { - "detect": "bin/detect-port.js", - "detect-port": "bin/detect-port.js" - } - }, - "node_modules/detect-port-alt": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", - "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", - "dependencies": { - "address": "^1.0.1", - "debug": "^2.6.0" - }, - "bin": { - "detect": "bin/detect-port", - "detect-port": "bin/detect-port" - }, - "engines": { - "node": ">= 4.2.1" - } - }, - "node_modules/detect-port-alt/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/detect-port-alt/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "peer": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" - }, - "node_modules/dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" - }, - "node_modules/dns-packet": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.0.tgz", - "integrity": "sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ==", - "dependencies": { - "@leichtgewicht/ip-codec": "^2.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "dependencies": { - "utila": "~0.4" - } - }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dot-prop/node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" - }, - "node_modules/duplexer3": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", - "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==" - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "node_modules/electron-to-chromium": { - "version": "1.4.368", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.368.tgz", - "integrity": "sha512-e2aeCAixCj9M7nJxdB/wDjO6mbYX+lJJxSJCXDzlr5YPGYVofuJwGN9nKg2o6wWInjX6XmxRinn3AeJMK81ltw==" - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/emoticon": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-3.2.0.tgz", - "integrity": "sha512-SNujglcLTTg+lDAcApPNgEdudaqQFiAbJCqzjNxJkvN9vAwCGi0uu8IUVvx+f16h+V44KCY6Y2yboroc9pilHg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", - "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-module-lexer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz", - "integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==" - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eta": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/eta/-/eta-2.0.1.tgz", - "integrity": "sha512-46E2qDPDm7QA+usjffUWz9KfXsxVZclPOuKsXs4ZWZdI/X1wpDF7AO424pt7fdYohCzWsIkXAhNGXSlwo5naAg==", - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "url": "https://github.com/eta-dev/eta?sponsor=1" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eval": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.8.tgz", - "integrity": "sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==", - "dependencies": { - "@types/node": "*", - "require-like": ">= 0.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/execa/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "node_modules/express/node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/express/node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" - }, - "node_modules/express/node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fast-url-parser": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", - "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", - "dependencies": { - "punycode": "^1.3.2" - } - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/fbemitter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz", - "integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==", - "dependencies": { - "fbjs": "^3.0.0" - } - }, - "node_modules/fbjs": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz", - "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==", - "dependencies": { - "cross-fetch": "^3.1.5", - "fbjs-css-vars": "^1.0.0", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^1.0.35" - } - }, - "node_modules/fbjs-css-vars": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", - "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" - }, - "node_modules/feed": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", - "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", - "dependencies": { - "xml-js": "^1.6.11" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/file-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", - "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", - "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/file-loader/node_modules/schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/filesize": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", - "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flux": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.4.tgz", - "integrity": "sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw==", - "dependencies": { - "fbemitter": "^3.0.0", - "fbjs": "^3.0.1" - }, - "peerDependencies": { - "react": "^15.0.2 || ^16.0.0 || ^17.0.0" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/fork-ts-checker-webpack-plugin": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", - "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", - "dependencies": { - "@babel/code-frame": "^7.8.3", - "@types/json-schema": "^7.0.5", - "chalk": "^4.1.0", - "chokidar": "^3.4.2", - "cosmiconfig": "^6.0.0", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.0", - "glob": "^7.1.6", - "memfs": "^3.1.2", - "minimatch": "^3.0.4", - "schema-utils": "2.7.0", - "semver": "^7.3.2", - "tapable": "^1.0.0" - }, - "engines": { - "node": ">=10", - "yarn": ">=1.0.0" - }, - "peerDependencies": { - "eslint": ">= 6", - "typescript": ">= 2.7", - "vue-template-compiler": "*", - "webpack": ">= 4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - }, - "vue-template-compiler": { - "optional": true - } - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", - "dependencies": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fraction.js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://www.patreon.com/infusion" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/fs-monkey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", - "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==" - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" - }, - "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/github-slugger": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", - "integrity": "sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==" - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" - }, - "node_modules/global-dirs": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", - "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", - "dependencies": { - "ini": "2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/global-dirs/node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "dependencies": { - "global-prefix": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "dependencies": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dependencies": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" - }, - "node_modules/gray-matter": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", - "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", - "dependencies": { - "js-yaml": "^3.13.1", - "kind-of": "^6.0.2", - "section-matter": "^1.0.0", - "strip-bom-string": "^1.0.0" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/gray-matter/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/gray-matter/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/gzip-size": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", - "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", - "dependencies": { - "duplexer": "^0.1.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/hast-to-hyperscript": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz", - "integrity": "sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==", - "dependencies": { - "@types/unist": "^2.0.3", - "comma-separated-tokens": "^1.0.0", - "property-information": "^5.3.0", - "space-separated-tokens": "^1.0.0", - "style-to-object": "^0.3.0", - "unist-util-is": "^4.0.0", - "web-namespaces": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-from-parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz", - "integrity": "sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==", - "dependencies": { - "@types/parse5": "^5.0.0", - "hastscript": "^6.0.0", - "property-information": "^5.0.0", - "vfile": "^4.0.0", - "vfile-location": "^3.2.0", - "web-namespaces": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-parse-selector": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", - "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-raw": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-6.0.1.tgz", - "integrity": "sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==", - "dependencies": { - "@types/hast": "^2.0.0", - "hast-util-from-parse5": "^6.0.0", - "hast-util-to-parse5": "^6.0.0", - "html-void-elements": "^1.0.0", - "parse5": "^6.0.0", - "unist-util-position": "^3.0.0", - "vfile": "^4.0.0", - "web-namespaces": "^1.0.0", - "xtend": "^4.0.0", - "zwitch": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-raw/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - }, - "node_modules/hast-util-to-parse5": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz", - "integrity": "sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ==", - "dependencies": { - "hast-to-hyperscript": "^9.0.0", - "property-information": "^5.0.0", - "web-namespaces": "^1.0.0", - "xtend": "^4.0.0", - "zwitch": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hastscript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", - "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", - "dependencies": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^1.0.0", - "hast-util-parse-selector": "^2.0.0", - "property-information": "^5.0.0", - "space-separated-tokens": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "bin": { - "he": "bin/he" - } - }, - "node_modules/history": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", - "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", - "dependencies": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" - } - }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/hpack.js/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/hpack.js/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/html-entities": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", - "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==" - }, - "node_modules/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", - "dependencies": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - }, - "bin": { - "html-minifier-terser": "cli.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/html-minifier-terser/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "engines": { - "node": ">= 12" - } - }, - "node_modules/html-tags": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", - "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/html-void-elements": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz", - "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/html-webpack-plugin": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.1.tgz", - "integrity": "sha512-cTUzZ1+NqjGEKjmVgZKLMdiFg3m9MdRXkZW2OEe69WYVi5ONLMmlnSZdXzGGMOq0C8jGDrL6EWyEDDUioHO/pA==", - "dependencies": { - "@types/html-minifier-terser": "^6.0.0", - "html-minifier-terser": "^6.0.2", - "lodash": "^4.17.21", - "pretty-error": "^4.0.0", - "tapable": "^2.0.0" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/html-webpack-plugin" - }, - "peerDependencies": { - "webpack": "^5.20.0" - } - }, - "node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", - "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" - }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } - } - }, - "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/image-size": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz", - "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==", - "dependencies": { - "queue": "6.0.2" - }, - "bin": { - "image-size": "bin/image-size.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/immediate": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", - "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==" - }, - "node_modules/immer": { - "version": "9.0.21", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", - "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", - "engines": { - "node": ">=4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/infima": { - "version": "0.2.0-alpha.43", - "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.43.tgz", - "integrity": "sha512-2uw57LvUqW0rK/SWYnd/2rRfxNA5DDNOh33jxF7fy46VWoNhGxiUQyVZHbBMjQ33mQem0cjdDVwgWVAmlRfgyQ==", - "engines": { - "node": ">=12" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "node_modules/inline-style-parser": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", - "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" - }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, - "node_modules/ipaddr.js": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", - "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", - "engines": { - "node": ">= 10" - } - }, - "node_modules/is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "dependencies": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "engines": { - "node": ">=4" - } - }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dependencies": { - "ci-info": "^2.0.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-ci/node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" - }, - "node_modules/is-core-module": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", - "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-hexadecimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dependencies": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-root": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", - "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" - }, - "node_modules/is-whitespace-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", - "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-word-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", - "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" - }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", - "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", - "dependencies": { - "@types/node": "*", - "jest-util": "^29.5.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jiti": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", - "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==", - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/joi": { - "version": "17.9.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.9.1.tgz", - "integrity": "sha512-FariIi9j6QODKATGBrEX7HZcja8Bsh3rfdGYy/Sb65sGlZWK/QWesU1ghk7aJWDj95knjXlQfSmzFSPPkLVsfw==", - "dependencies": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.1", - "@sideway/pinpoint": "^2.0.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==" - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dependencies": { - "json-buffer": "3.0.0" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/klaw-sync": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", - "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", - "dependencies": { - "graceful-fs": "^4.1.11" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "engines": { - "node": ">=6" - } - }, - "node_modules/klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "dependencies": { - "package-json": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/launch-editor": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", - "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==", - "dependencies": { - "picocolors": "^1.0.0", - "shell-quote": "^1.7.3" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "engines": { - "node": ">=6" - } - }, - "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.curry": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", - "integrity": "sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" - }, - "node_modules/lodash.flow": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", - "integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==" - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dependencies": { - "tslib": "^2.0.3" - } - }, - "node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==" - }, - "node_modules/lunr-languages": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/lunr-languages/-/lunr-languages-1.12.0.tgz", - "integrity": "sha512-C2z02jt74ymrDocBwxYB4Cr1LNZj9rHGLTH/00+JuoT6eJOSSuPBzeqQG8kjnlPUQe+/PAWv1/KHbDT+YYYRnA==" - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "peer": true - }, - "node_modules/mark.js": { - "version": "8.11.1", - "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", - "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==" - }, - "node_modules/markdown-escapes": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz", - "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdast-squeeze-paragraphs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz", - "integrity": "sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==", - "dependencies": { - "unist-util-remove": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-definitions": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz", - "integrity": "sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==", - "dependencies": { - "unist-util-visit": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-hast": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz", - "integrity": "sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA==", - "dependencies": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "mdast-util-definitions": "^4.0.0", - "mdurl": "^1.0.0", - "unist-builder": "^2.0.0", - "unist-util-generated": "^1.0.0", - "unist-util-position": "^3.0.0", - "unist-util-visit": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", - "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" - }, - "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memfs": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.0.tgz", - "integrity": "sha512-yK6o8xVJlQerz57kvPROwTMgx5WtGwC2ZxDtOUsnGl49rHjYkfQoPNZPCKH73VdLE1BwBu/+Fx/NL8NYMUw2aA==", - "dependencies": { - "fs-monkey": "^1.0.3" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", - "dependencies": { - "mime-db": "~1.33.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/mini-css-extract-plugin": { - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.5.tgz", - "integrity": "sha512-9HaR++0mlgom81s95vvNjxkg52n2b5s//3ZTI1EtzFb98awsLSivs2LMsVqnQ3ay0PVhqWcGNyDaTE961FOcjQ==", - "dependencies": { - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/mini-css-extract-plugin/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.1.tgz", - "integrity": "sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ==", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mrmime": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", - "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", - "dependencies": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" - }, - "bin": { - "multicast-dns": "cli.js" - } - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" - }, - "node_modules/no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "node_modules/node-emoji": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", - "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", - "dependencies": { - "lodash": "^4.17.21" - } - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "engines": { - "node": ">= 6.13.0" - } - }, - "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nprogress": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", - "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==" - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/opener": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", - "bin": { - "opener": "bin/opener-bin.js" - } - }, - "node_modules/p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", - "dependencies": { - "@types/retry": "0.12.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", - "dependencies": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/package-json/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", - "dependencies": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse-numeric-range": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", - "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==" - }, - "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", - "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", - "dependencies": { - "domhandler": "^5.0.2", - "parse5": "^7.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==" - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dependencies": { - "isarray": "0.0.1" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-up": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-up/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-calc": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", - "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", - "dependencies": { - "postcss-selector-parser": "^6.0.9", - "postcss-value-parser": "^4.2.0" - }, - "peerDependencies": { - "postcss": "^8.2.2" - } - }, - "node_modules/postcss-colormin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", - "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-convert-values": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", - "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", - "dependencies": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-comments": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", - "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-duplicates": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", - "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-empty": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", - "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-overridden": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", - "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-unused": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-5.1.0.tgz", - "integrity": "sha512-KwLWymI9hbwXmJa0dkrzpRbSJEh0vVUd7r8t0yOGPcfKzyJJxFM8kLyC5Ev9avji6nY95pOp1W6HqIrfT+0VGw==", - "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", - "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", - "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^1.10.2" - }, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/postcss-loader": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.2.4.tgz", - "integrity": "sha512-F88rpxxNspo5hatIc+orYwZDtHFaVFOSIVAx+fBfJC1GmhWbVmPWtmg2gXKE1OxJbneOSGn8PWdIwsZFcruS+w==", - "dependencies": { - "cosmiconfig": "^8.1.3", - "cosmiconfig-typescript-loader": "^4.3.0", - "klona": "^2.0.6", - "semver": "^7.3.8" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "postcss": "^7.0.0 || ^8.0.1", - "ts-node": ">=10", - "typescript": ">=4", - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - }, - "typescript": { - "optional": true - } - } - }, - "node_modules/postcss-loader/node_modules/cosmiconfig": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", - "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", - "dependencies": { - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - } - }, - "node_modules/postcss-merge-idents": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-5.1.1.tgz", - "integrity": "sha512-pCijL1TREiCoog5nQp7wUe+TUonA2tC2sQ54UGeMmryK3UFGIYKqDyjnqd6RcuI4znFn9hWSLNN8xKE/vWcUQw==", - "dependencies": { - "cssnano-utils": "^3.1.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-merge-longhand": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", - "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", - "dependencies": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^5.1.1" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-merge-rules": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", - "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^3.1.0", - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-font-values": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", - "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-gradients": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", - "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", - "dependencies": { - "colord": "^2.9.1", - "cssnano-utils": "^3.1.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-params": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", - "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", - "dependencies": { - "browserslist": "^4.21.4", - "cssnano-utils": "^3.1.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-selectors": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", - "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", - "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", - "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", - "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dependencies": { - "icss-utils": "^5.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-nested": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz", - "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==", - "dependencies": { - "postcss-selector-parser": "^6.0.10" - }, - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-normalize-charset": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", - "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-display-values": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", - "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-positions": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", - "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-repeat-style": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", - "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-string": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", - "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-timing-functions": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", - "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-unicode": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", - "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", - "dependencies": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", - "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", - "dependencies": { - "normalize-url": "^6.0.1", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-whitespace": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", - "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-ordered-values": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", - "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", - "dependencies": { - "cssnano-utils": "^3.1.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-reduce-idents": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-5.2.0.tgz", - "integrity": "sha512-BTrLjICoSB6gxbc58D5mdBK8OhXRDqud/zodYfdSi52qvDHdMwk+9kB9xsM8yJThH/sZU5A6QVSmMmaN001gIg==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-reduce-initial": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", - "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-reduce-transforms": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", - "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", - "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-sort-media-queries": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.4.1.tgz", - "integrity": "sha512-QDESFzDDGKgpiIh4GYXsSy6sek2yAwQx1JASl5AxBtU1Lq2JfKBljIPNdil989NcSKRQX1ToiaKphImtBuhXWw==", - "dependencies": { - "sort-css-media-queries": "2.1.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "postcss": "^8.4.16" - } - }, - "node_modules/postcss-svgo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", - "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", - "dependencies": { - "postcss-value-parser": "^4.2.0", - "svgo": "^2.7.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-unique-selectors": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", - "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", - "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - }, - "node_modules/postcss-zindex": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-5.1.0.tgz", - "integrity": "sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A==", - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/pretty-error": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", - "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", - "dependencies": { - "lodash": "^4.17.20", - "renderkid": "^3.0.0" - } - }, - "node_modules/pretty-time": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", - "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/prism-react-renderer": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.3.5.tgz", - "integrity": "sha512-IJ+MSwBWKG+SM3b2SUfdrhC+gu01QkV2KmRQgREThBfSQRoufqRfxfHUxpG1WcaFjP+kojcFyO9Qqtpgt3qLCg==", - "peerDependencies": { - "react": ">=0.14.9" - } - }, - "node_modules/prismjs": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", - "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", - "engines": { - "node": ">=6" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "node_modules/promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "dependencies": { - "asap": "~2.0.3" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/property-information": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", - "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", - "dependencies": { - "xtend": "^4.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" - }, - "node_modules/pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "dependencies": { - "escape-goat": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pure-color": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz", - "integrity": "sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA==" - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", - "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", - "dependencies": { - "inherits": "~2.0.3" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-base16-styling": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.6.0.tgz", - "integrity": "sha512-yvh/7CArceR/jNATXOKDlvTnPKPmGZz7zsenQ3jUwLzHkNUR0CvY3yGYJbWJ/nnxsL8Sgmt5cO3/SILVuPO6TQ==", - "dependencies": { - "base16": "^1.0.0", - "lodash.curry": "^4.0.1", - "lodash.flow": "^3.3.0", - "pure-color": "^1.2.0" - } - }, - "node_modules/react-dev-utils": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", - "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", - "dependencies": { - "@babel/code-frame": "^7.16.0", - "address": "^1.1.2", - "browserslist": "^4.18.1", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", - "detect-port-alt": "^1.1.6", - "escape-string-regexp": "^4.0.0", - "filesize": "^8.0.6", - "find-up": "^5.0.0", - "fork-ts-checker-webpack-plugin": "^6.5.0", - "global-modules": "^2.0.0", - "globby": "^11.0.4", - "gzip-size": "^6.0.0", - "immer": "^9.0.7", - "is-root": "^2.1.0", - "loader-utils": "^3.2.0", - "open": "^8.4.0", - "pkg-up": "^3.1.0", - "prompts": "^2.4.2", - "react-error-overlay": "^6.0.11", - "recursive-readdir": "^2.2.2", - "shell-quote": "^1.7.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/react-dev-utils/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-dev-utils/node_modules/loader-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/react-dev-utils/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-dev-utils/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-dev-utils/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - }, - "peerDependencies": { - "react": "17.0.2" - } - }, - "node_modules/react-error-overlay": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", - "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" - }, - "node_modules/react-fast-compare": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.1.tgz", - "integrity": "sha512-xTYf9zFim2pEif/Fw16dBiXpe0hoy5PxcD8+OwBnTtNLfIm3g6WxhKNurY+6OmdH1u6Ta/W/Vl6vjbYP1MFnDg==" - }, - "node_modules/react-helmet-async": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.3.0.tgz", - "integrity": "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==", - "dependencies": { - "@babel/runtime": "^7.12.5", - "invariant": "^2.2.4", - "prop-types": "^15.7.2", - "react-fast-compare": "^3.2.0", - "shallowequal": "^1.1.0" - }, - "peerDependencies": { - "react": "^16.6.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/react-json-view": { - "version": "1.21.3", - "resolved": "https://registry.npmjs.org/react-json-view/-/react-json-view-1.21.3.tgz", - "integrity": "sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw==", - "dependencies": { - "flux": "^4.0.1", - "react-base16-styling": "^0.6.0", - "react-lifecycles-compat": "^3.0.4", - "react-textarea-autosize": "^8.3.2" - }, - "peerDependencies": { - "react": "^17.0.0 || ^16.3.0 || ^15.5.4", - "react-dom": "^17.0.0 || ^16.3.0 || ^15.5.4" - } - }, - "node_modules/react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" - }, - "node_modules/react-loadable": { - "name": "@docusaurus/react-loadable", - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", - "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", - "dependencies": { - "@types/react": "*", - "prop-types": "^15.6.2" - }, - "peerDependencies": { - "react": "*" - } - }, - "node_modules/react-loadable-ssr-addon-v5-slorber": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", - "integrity": "sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A==", - "dependencies": { - "@babel/runtime": "^7.10.3" - }, - "engines": { - "node": ">=10.13.0" - }, - "peerDependencies": { - "react-loadable": "*", - "webpack": ">=4.41.1 || 5.x" - } - }, - "node_modules/react-router": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", - "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", - "dependencies": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - }, - "peerDependencies": { - "react": ">=15" - } - }, - "node_modules/react-router-config": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", - "integrity": "sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==", - "dependencies": { - "@babel/runtime": "^7.1.2" - }, - "peerDependencies": { - "react": ">=15", - "react-router": ">=5" - } - }, - "node_modules/react-router-dom": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", - "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", - "dependencies": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.3.4", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - }, - "peerDependencies": { - "react": ">=15" - } - }, - "node_modules/react-textarea-autosize": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.5.3.tgz", - "integrity": "sha512-XT1024o2pqCuZSuBt9FwHlaDeNtVrtCXu0Rnz88t1jUGheCLa3PhjE1GH8Ctm2axEtvdCl5SUHYschyQ0L5QHQ==", - "dependencies": { - "@babel/runtime": "^7.20.13", - "use-composed-ref": "^1.3.0", - "use-latest": "^1.2.1" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/reading-time": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", - "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==" - }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/recursive-readdir": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", - "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", - "dependencies": { - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", - "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, - "node_modules/regenerator-transform": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", - "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "node_modules/regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", - "dependencies": { - "@babel/regjsgen": "^0.8.0", - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/registry-auth-token": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", - "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", - "dependencies": { - "rc": "1.2.8" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/remark-emoji": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-2.2.0.tgz", - "integrity": "sha512-P3cj9s5ggsUvWw5fS2uzCHJMGuXYRb0NnZqYlNecewXt8QBU9n5vW3DUUKOhepS8F9CwdMx9B8a3i7pqFWAI5w==", - "dependencies": { - "emoticon": "^3.2.0", - "node-emoji": "^1.10.0", - "unist-util-visit": "^2.0.3" - } - }, - "node_modules/remark-footnotes": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-2.0.0.tgz", - "integrity": "sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-mdx": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-1.6.22.tgz", - "integrity": "sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==", - "dependencies": { - "@babel/core": "7.12.9", - "@babel/helper-plugin-utils": "7.10.4", - "@babel/plugin-proposal-object-rest-spread": "7.12.1", - "@babel/plugin-syntax-jsx": "7.12.1", - "@mdx-js/util": "1.6.22", - "is-alphabetical": "1.0.4", - "remark-parse": "8.0.3", - "unified": "9.2.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-mdx/node_modules/@babel/core": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.7", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.9", - "@babel/types": "^7.12.7", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/remark-mdx/node_modules/@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - }, - "node_modules/remark-mdx/node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", - "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.12.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/remark-mdx/node_modules/@babel/plugin-syntax-jsx": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/remark-mdx/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/remark-mdx/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/remark-mdx/node_modules/unified": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", - "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", - "dependencies": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-parse": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz", - "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==", - "dependencies": { - "ccount": "^1.0.0", - "collapse-white-space": "^1.0.2", - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-whitespace-character": "^1.0.0", - "is-word-character": "^1.0.0", - "markdown-escapes": "^1.0.0", - "parse-entities": "^2.0.0", - "repeat-string": "^1.5.4", - "state-toggle": "^1.0.0", - "trim": "0.0.1", - "trim-trailing-lines": "^1.0.0", - "unherit": "^1.0.4", - "unist-util-remove-position": "^2.0.0", - "vfile-location": "^3.0.0", - "xtend": "^4.0.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-squeeze-paragraphs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz", - "integrity": "sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw==", - "dependencies": { - "mdast-squeeze-paragraphs": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/renderkid": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", - "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", - "dependencies": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^6.0.1" - } - }, - "node_modules/renderkid/node_modules/css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/renderkid/node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/renderkid/node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/renderkid/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/renderkid/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/renderkid/node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-like": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", - "integrity": "sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==", - "engines": { - "node": "*" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" - }, - "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "dependencies": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-pathname": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" - }, - "node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", - "dependencies": { - "lowercase-keys": "^1.0.0" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rtl-detect": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.0.4.tgz", - "integrity": "sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ==" - }, - "node_modules/rtlcss": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-3.5.0.tgz", - "integrity": "sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A==", - "dependencies": { - "find-up": "^5.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.3.11", - "strip-json-comments": "^3.1.1" - }, - "bin": { - "rtlcss": "bin/rtlcss.js" - } - }, - "node_modules/rtlcss/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/rtlcss/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/rtlcss/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/rtlcss/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", - "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "node_modules/schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", - "dependencies": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/search-insights": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.8.3.tgz", - "integrity": "sha512-W9rZfQ9XEfF0O6ntgQOTI7Txc8nkZrO4eJ/pTHK0Br6wWND2sPGPoWg+yGhdIW7wMbLqk8dc23IyEtLlNGpeNw==", - "peer": true - }, - "node_modules/section-matter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", - "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", - "dependencies": { - "extend-shallow": "^2.0.1", - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" - }, - "node_modules/selfsigned": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", - "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", - "dependencies": { - "node-forge": "^1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dependencies": { - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semver-diff/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/send/node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serve-handler": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", - "integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==", - "dependencies": { - "bytes": "3.0.0", - "content-disposition": "0.5.2", - "fast-url-parser": "1.1.3", - "mime-types": "2.1.18", - "minimatch": "3.1.2", - "path-is-inside": "1.0.2", - "path-to-regexp": "2.2.1", - "range-parser": "1.2.0" - } - }, - "node_modules/serve-handler/node_modules/path-to-regexp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", - "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==" - }, - "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", - "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-index/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/serve-index/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" - }, - "node_modules/serve-index/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - }, - "node_modules/serve-index/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "dependencies": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "node_modules/sirv": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", - "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==", - "dependencies": { - "@polka/url": "^1.0.0-next.20", - "mrmime": "^1.0.0", - "totalist": "^1.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" - }, - "node_modules/sitemap": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.1.tgz", - "integrity": "sha512-mK3aFtjz4VdJN0igpIJrinf3EO8U8mxOPsTBzSsy06UtjZQJ3YY3o3Xa7zSc5nMqcMrRwlChHZ18Kxg0caiPBg==", - "dependencies": { - "@types/node": "^17.0.5", - "@types/sax": "^1.2.1", - "arg": "^5.0.0", - "sax": "^1.2.4" - }, - "bin": { - "sitemap": "dist/cli.js" - }, - "engines": { - "node": ">=12.0.0", - "npm": ">=5.6.0" - } - }, - "node_modules/sitemap/node_modules/@types/node": { - "version": "17.0.45", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", - "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", - "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" - } - }, - "node_modules/sort-css-media-queries": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.1.0.tgz", - "integrity": "sha512-IeWvo8NkNiY2vVYdPa27MCQiR0MN0M80johAYFVxWWXQ44KU84WNxjslwBHmc/7ZL2ccwkM7/e6S5aiKZXm7jA==", - "engines": { - "node": ">= 6.3.0" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/space-separated-tokens": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", - "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" - }, - "node_modules/stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", - "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility" - }, - "node_modules/state-toggle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz", - "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/std-env": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.3.2.tgz", - "integrity": "sha512-uUZI65yrV2Qva5gqE0+A7uVAvO40iPo6jGhs7s8keRfHCmtg+uB2X6EiLGCI9IgL1J17xGhvoOqSz79lzICPTA==" - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "dependencies": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/style-to-object": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", - "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", - "dependencies": { - "inline-style-parser": "0.1.1" - } - }, - "node_modules/stylehacks": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", - "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", - "dependencies": { - "browserslist": "^4.21.4", - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/sucrase": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", - "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "7.1.6", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/sucrase/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/sucrase/node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/svg-parser": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" - }, - "node_modules/svgo": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", - "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", - "dependencies": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^4.1.3", - "css-tree": "^1.1.3", - "csso": "^4.2.0", - "picocolors": "^1.0.0", - "stable": "^0.1.8" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/svgo/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "engines": { - "node": ">= 10" - } - }, - "node_modules/svgo/node_modules/css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/svgo/node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/svgo/node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/svgo/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/svgo/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/tailwindcss": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.1.tgz", - "integrity": "sha512-Vkiouc41d4CEq0ujXl6oiGFQ7bA3WEhUZdTgXAhtKxSy49OmKs8rEfQmupsfF0IGW8fv2iQkp1EVUuapCFrZ9g==", - "dependencies": { - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "color-name": "^1.1.4", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.12", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.17.2", - "lilconfig": "^2.0.6", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.0.9", - "postcss-import": "^14.1.0", - "postcss-js": "^4.0.0", - "postcss-load-config": "^3.1.4", - "postcss-nested": "6.0.0", - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", - "quick-lru": "^5.1.1", - "resolve": "^1.22.1", - "sucrase": "^3.29.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=12.13.0" - }, - "peerDependencies": { - "postcss": "^8.0.9" - } - }, - "node_modules/tailwindcss/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/tailwindcss/node_modules/postcss-import": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", - "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/terser": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.1.tgz", - "integrity": "sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw==", - "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz", - "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.16.5" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser-webpack-plugin/node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/terser-webpack-plugin/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" - }, - "node_modules/tiny-invariant": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", - "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" - }, - "node_modules/tiny-warning": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "engines": { - "node": ">=4" - } - }, - "node_modules/to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "engines": { - "node": ">=6" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/totalist": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", - "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==", - "engines": { - "node": ">=6" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/trim": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", - "integrity": "sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ==", - "deprecated": "Use String.prototype.trim() instead" - }, - "node_modules/trim-trailing-lines": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz", - "integrity": "sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/trough": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", - "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" - }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "peer": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node/node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "peer": true - }, - "node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, - "node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/type-is/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/type-is/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=12.20" - } - }, - "node_modules/ua-parser-js": { - "version": "1.0.36", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.36.tgz", - "integrity": "sha512-znuyCIXzl8ciS3+y3fHJI/2OhQIXbXw9MWC/o3qwyR+RGppjZHrM27CGFSKCJXi2Kctiz537iOu2KnXs1lMQhw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/ua-parser-js" - }, - { - "type": "paypal", - "url": "https://paypal.me/faisalman" - }, - { - "type": "github", - "url": "https://github.com/sponsors/faisalman" - } - ], - "engines": { - "node": "*" - } - }, - "node_modules/unherit": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz", - "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==", - "dependencies": { - "inherits": "^2.0.0", - "xtend": "^4.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", - "engines": { - "node": ">=4" - } - }, - "node_modules/unified": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz", - "integrity": "sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==", - "dependencies": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dependencies": { - "crypto-random-string": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/unist-builder": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-2.0.3.tgz", - "integrity": "sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-generated": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.6.tgz", - "integrity": "sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-is": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", - "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-position": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.1.0.tgz", - "integrity": "sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-remove": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-2.1.0.tgz", - "integrity": "sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q==", - "dependencies": { - "unist-util-is": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-remove-position": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz", - "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==", - "dependencies": { - "unist-util-visit": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-stringify-position": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", - "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", - "dependencies": { - "@types/unist": "^2.0.2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", - "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0", - "unist-util-visit-parents": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit-parents": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", - "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/update-notifier": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", - "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", - "dependencies": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/yeoman/update-notifier?sponsor=1" - } - }, - "node_modules/update-notifier/node_modules/boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "dependencies": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/update-notifier/node_modules/cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/update-notifier/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/update-notifier/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/update-notifier/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/update-notifier/node_modules/widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dependencies": { - "string-width": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/update-notifier/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/uri-js/node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/url-loader": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", - "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", - "dependencies": { - "loader-utils": "^2.0.0", - "mime-types": "^2.1.27", - "schema-utils": "^3.0.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "file-loader": "*", - "webpack": "^4.0.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "file-loader": { - "optional": true - } - } - }, - "node_modules/url-loader/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/url-loader/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/url-loader/node_modules/schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", - "dependencies": { - "prepend-http": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/use-composed-ref": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.3.0.tgz", - "integrity": "sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/use-isomorphic-layout-effect": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", - "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/use-latest": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.1.tgz", - "integrity": "sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==", - "dependencies": { - "use-isomorphic-layout-effect": "^1.1.1" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" - }, - "node_modules/utility-types": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", - "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "peer": true - }, - "node_modules/value-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", - "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/vfile": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", - "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", - "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^2.0.0", - "vfile-message": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vfile-location": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.2.0.tgz", - "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vfile-message": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", - "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/wait-on": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz", - "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==", - "dependencies": { - "axios": "^0.25.0", - "joi": "^17.6.0", - "lodash": "^4.17.21", - "minimist": "^1.2.5", - "rxjs": "^7.5.4" - }, - "bin": { - "wait-on": "bin/wait-on" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dependencies": { - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/web-namespaces": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz", - "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/webpack": { - "version": "5.79.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.79.0.tgz", - "integrity": "sha512-3mN4rR2Xq+INd6NnYuL9RC9GAmc1ROPKJoHhrZ4pAjdMFEkJJWrsPw8o2JjCIyQyTu7rTXYn4VG6OpyB3CobZg==", - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-bundle-analyzer": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.8.0.tgz", - "integrity": "sha512-ZzoSBePshOKhr+hd8u6oCkZVwpVaXgpw23ScGLFpR6SjYI7+7iIWYarjN6OEYOfRt8o7ZyZZQk0DuMizJ+LEIg==", - "dependencies": { - "@discoveryjs/json-ext": "0.5.7", - "acorn": "^8.0.4", - "acorn-walk": "^8.0.0", - "chalk": "^4.1.0", - "commander": "^7.2.0", - "gzip-size": "^6.0.0", - "lodash": "^4.17.20", - "opener": "^1.5.2", - "sirv": "^1.0.7", - "ws": "^7.3.1" - }, - "bin": { - "webpack-bundle-analyzer": "lib/bin/analyzer.js" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/webpack-bundle-analyzer/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "engines": { - "node": ">= 10" - } - }, - "node_modules/webpack-dev-middleware": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", - "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", - "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.4.3", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/webpack-dev-middleware/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack-dev-middleware/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack-dev-middleware/node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.1.tgz", - "integrity": "sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ==", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/webpack-dev-server": { - "version": "4.13.3", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.13.3.tgz", - "integrity": "sha512-KqqzrzMRSRy5ePz10VhjyL27K2dxqwXQLP5rAKwRJBPUahe7Z2bBWzHw37jeb8GCPKxZRO79ZdQUAPesMh/Nug==", - "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/serve-static": "^1.13.10", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.1", - "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.0.11", - "chokidar": "^3.5.3", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^2.0.0", - "default-gateway": "^6.0.3", - "express": "^4.17.3", - "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.3", - "ipaddr.js": "^2.0.1", - "launch-editor": "^2.6.0", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "rimraf": "^3.0.2", - "schema-utils": "^4.0.0", - "selfsigned": "^2.1.1", - "serve-index": "^1.9.1", - "sockjs": "^0.3.24", - "spdy": "^4.0.2", - "webpack-dev-middleware": "^5.3.1", - "ws": "^8.13.0" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - }, - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-server/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/webpack-dev-server/node_modules/schema-utils": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.1.tgz", - "integrity": "sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ==", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", - "dependencies": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/webpackbar": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-5.0.2.tgz", - "integrity": "sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==", - "dependencies": { - "chalk": "^4.1.0", - "consola": "^2.15.3", - "pretty-time": "^1.1.0", - "std-env": "^3.0.1" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "webpack": "3 || 4 || 5" - } - }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/widest-line": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", - "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", - "dependencies": { - "string-width": "^5.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/wildcard": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/xml-js": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", - "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", - "dependencies": { - "sax": "^1.2.4" - }, - "bin": { - "xml-js": "bin/cli.js" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zwitch": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", - "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - } - }, - "dependencies": { - "@algolia/autocomplete-core": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.9.3.tgz", - "integrity": "sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==", - "requires": { - "@algolia/autocomplete-plugin-algolia-insights": "1.9.3", - "@algolia/autocomplete-shared": "1.9.3" - } - }, - "@algolia/autocomplete-plugin-algolia-insights": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.9.3.tgz", - "integrity": "sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==", - "requires": { - "@algolia/autocomplete-shared": "1.9.3" - } - }, - "@algolia/autocomplete-preset-algolia": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.9.3.tgz", - "integrity": "sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==", - "requires": { - "@algolia/autocomplete-shared": "1.9.3" - } - }, - "@algolia/autocomplete-shared": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.9.3.tgz", - "integrity": "sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==", - "requires": {} - }, - "@algolia/cache-browser-local-storage": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.20.0.tgz", - "integrity": "sha512-uujahcBt4DxduBTvYdwO3sBfHuJvJokiC3BP1+O70fglmE1ShkH8lpXqZBac1rrU3FnNYSUs4pL9lBdTKeRPOQ==", - "requires": { - "@algolia/cache-common": "4.20.0" - } - }, - "@algolia/cache-common": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.20.0.tgz", - "integrity": "sha512-vCfxauaZutL3NImzB2G9LjLt36vKAckc6DhMp05An14kVo8F1Yofb6SIl6U3SaEz8pG2QOB9ptwM5c+zGevwIQ==" - }, - "@algolia/cache-in-memory": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.20.0.tgz", - "integrity": "sha512-Wm9ak/IaacAZXS4mB3+qF/KCoVSBV6aLgIGFEtQtJwjv64g4ePMapORGmCyulCFwfePaRAtcaTbMcJF+voc/bg==", - "requires": { - "@algolia/cache-common": "4.20.0" - } - }, - "@algolia/client-account": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.20.0.tgz", - "integrity": "sha512-GGToLQvrwo7am4zVkZTnKa72pheQeez/16sURDWm7Seyz+HUxKi3BM6fthVVPUEBhtJ0reyVtuK9ArmnaKl10Q==", - "requires": { - "@algolia/client-common": "4.20.0", - "@algolia/client-search": "4.20.0", - "@algolia/transporter": "4.20.0" - } - }, - "@algolia/client-analytics": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.20.0.tgz", - "integrity": "sha512-EIr+PdFMOallRdBTHHdKI3CstslgLORQG7844Mq84ib5oVFRVASuuPmG4bXBgiDbcsMLUeOC6zRVJhv1KWI0ug==", - "requires": { - "@algolia/client-common": "4.20.0", - "@algolia/client-search": "4.20.0", - "@algolia/requester-common": "4.20.0", - "@algolia/transporter": "4.20.0" - } - }, - "@algolia/client-common": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.20.0.tgz", - "integrity": "sha512-P3WgMdEss915p+knMMSd/fwiHRHKvDu4DYRrCRaBrsfFw7EQHon+EbRSm4QisS9NYdxbS04kcvNoavVGthyfqQ==", - "requires": { - "@algolia/requester-common": "4.20.0", - "@algolia/transporter": "4.20.0" - } - }, - "@algolia/client-personalization": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.20.0.tgz", - "integrity": "sha512-N9+zx0tWOQsLc3K4PVRDV8GUeOLAY0i445En79Pr3zWB+m67V+n/8w4Kw1C5LlbHDDJcyhMMIlqezh6BEk7xAQ==", - "requires": { - "@algolia/client-common": "4.20.0", - "@algolia/requester-common": "4.20.0", - "@algolia/transporter": "4.20.0" - } - }, - "@algolia/client-search": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.20.0.tgz", - "integrity": "sha512-zgwqnMvhWLdpzKTpd3sGmMlr4c+iS7eyyLGiaO51zDZWGMkpgoNVmltkzdBwxOVXz0RsFMznIxB9zuarUv4TZg==", - "requires": { - "@algolia/client-common": "4.20.0", - "@algolia/requester-common": "4.20.0", - "@algolia/transporter": "4.20.0" - } - }, - "@algolia/events": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", - "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" - }, - "@algolia/logger-common": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.20.0.tgz", - "integrity": "sha512-xouigCMB5WJYEwvoWW5XDv7Z9f0A8VoXJc3VKwlHJw/je+3p2RcDXfksLI4G4lIVncFUYMZx30tP/rsdlvvzHQ==" - }, - "@algolia/logger-console": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.20.0.tgz", - "integrity": "sha512-THlIGG1g/FS63z0StQqDhT6bprUczBI8wnLT3JWvfAQDZX5P6fCg7dG+pIrUBpDIHGszgkqYEqECaKKsdNKOUA==", - "requires": { - "@algolia/logger-common": "4.20.0" - } - }, - "@algolia/requester-browser-xhr": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.20.0.tgz", - "integrity": "sha512-HbzoSjcjuUmYOkcHECkVTwAelmvTlgs48N6Owt4FnTOQdwn0b8pdht9eMgishvk8+F8bal354nhx/xOoTfwiAw==", - "requires": { - "@algolia/requester-common": "4.20.0" - } - }, - "@algolia/requester-common": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.20.0.tgz", - "integrity": "sha512-9h6ye6RY/BkfmeJp7Z8gyyeMrmmWsMOCRBXQDs4mZKKsyVlfIVICpcSibbeYcuUdurLhIlrOUkH3rQEgZzonng==" - }, - "@algolia/requester-node-http": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.20.0.tgz", - "integrity": "sha512-ocJ66L60ABSSTRFnCHIEZpNHv6qTxsBwJEPfYaSBsLQodm0F9ptvalFkHMpvj5DfE22oZrcrLbOYM2bdPJRHng==", - "requires": { - "@algolia/requester-common": "4.20.0" - } - }, - "@algolia/transporter": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.20.0.tgz", - "integrity": "sha512-Lsii1pGWOAISbzeyuf+r/GPhvHMPHSPrTDWNcIzOE1SG1inlJHICaVe2ikuoRjcpgxZNU54Jl+if15SUCsaTUg==", - "requires": { - "@algolia/cache-common": "4.20.0", - "@algolia/logger-common": "4.20.0", - "@algolia/requester-common": "4.20.0" - } - }, - "@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/compat-data": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz", - "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==" - }, - "@babel/core": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz", - "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==", - "requires": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-compilation-targets": "^7.21.4", - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.4", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.4", - "@babel/types": "^7.21.4", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - } - } - }, - "@babel/generator": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", - "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", - "requires": { - "@babel/types": "^7.21.4", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", - "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", - "requires": { - "@babel/helper-explode-assignable-expression": "^7.18.6", - "@babel/types": "^7.18.9" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz", - "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==", - "requires": { - "@babel/compat-data": "^7.21.4", - "@babel/helper-validator-option": "^7.21.0", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - } - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.21.4.tgz", - "integrity": "sha512-46QrX2CQlaFRF4TkwfTt6nJD7IHq8539cCL7SDpqWSDeJKY1xylKKY5F/33mJhLZ3mFvKv2gGrVS6NkyF6qs+Q==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-member-expression-to-functions": "^7.21.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-replace-supers": "^7.20.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/helper-split-export-declaration": "^7.18.6" - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.21.4.tgz", - "integrity": "sha512-M00OuhU+0GyZ5iBBN9czjugzWrEq2vDpf/zCYHxxf93ul/Q5rv+a5h+/+0WnI1AebHNVtl5bFV0qsJoH23DbfA==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "regexpu-core": "^5.3.1" - } - }, - "@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", - "requires": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", - "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", - "requires": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.21.0.tgz", - "integrity": "sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q==", - "requires": { - "@babel/types": "^7.21.0" - } - }, - "@babel/helper-module-imports": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", - "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", - "requires": { - "@babel/types": "^7.21.4" - } - }, - "@babel/helper-module-transforms": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", - "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.2", - "@babel/types": "^7.21.2" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", - "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==" - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", - "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-wrap-function": "^7.18.9", - "@babel/types": "^7.18.9" - } - }, - "@babel/helper-replace-supers": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz", - "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==", - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-member-expression-to-functions": "^7.20.7", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.7", - "@babel/types": "^7.20.7" - } - }, - "@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", - "requires": { - "@babel/types": "^7.20.2" - } - }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", - "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", - "requires": { - "@babel/types": "^7.20.0" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" - }, - "@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==" - }, - "@babel/helper-wrap-function": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", - "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", - "requires": { - "@babel/helper-function-name": "^7.19.0", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5" - } - }, - "@babel/helpers": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", - "requires": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" - } - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", - "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==" - }, - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", - "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz", - "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-proposal-optional-chaining": "^7.20.7" - } - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", - "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-proposal-class-static-block": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz", - "integrity": "sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", - "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - } - }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", - "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", - "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3" - } - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", - "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", - "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", - "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", - "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", - "requires": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.20.7" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", - "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", - "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", - "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0.tgz", - "integrity": "sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", - "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-import-assertions": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", - "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.19.0" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz", - "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", - "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz", - "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", - "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==", - "requires": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", - "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.21.0.tgz", - "integrity": "sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.21.0.tgz", - "integrity": "sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-replace-supers": "^7.20.7", - "@babel/helper-split-export-declaration": "^7.18.6", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz", - "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/template": "^7.20.7" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.21.3.tgz", - "integrity": "sha512-bp6hwMFzuiE4HqYEyoGJ/V2LeIWn+hLVKc4pnj++E5XQptwhtcGmSayM029d/j2X1bPKGTlsyPwAubuU22KhMA==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", - "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", - "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", - "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.21.0.tgz", - "integrity": "sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", - "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", - "requires": { - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", - "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", - "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz", - "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==", - "requires": { - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.21.2.tgz", - "integrity": "sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA==", - "requires": { - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-simple-access": "^7.20.2" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz", - "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==", - "requires": { - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-identifier": "^7.19.1" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", - "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", - "requires": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", - "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.20.5", - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", - "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", - "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.6" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.21.3.tgz", - "integrity": "sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", - "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-react-constant-elements": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.21.3.tgz", - "integrity": "sha512-4DVcFeWe/yDYBLp0kBmOGFJ6N2UYg7coGid1gdxb4co62dy/xISDMaYBXBVXEDhfgMk7qkbcYiGtwd5Q/hwDDQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-react-display-name": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz", - "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-react-jsx": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.21.0.tgz", - "integrity": "sha512-6OAWljMvQrZjR2DaNhVfRz6dkCAVV+ymcLUmaf8bccGOHn2v5rHJK3tTpij0BuhdYWP4LLaqj5lwcdlpAAPuvg==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-jsx": "^7.18.6", - "@babel/types": "^7.21.0" - } - }, - "@babel/plugin-transform-react-jsx-development": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz", - "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==", - "requires": { - "@babel/plugin-transform-react-jsx": "^7.18.6" - } - }, - "@babel/plugin-transform-react-pure-annotations": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz", - "integrity": "sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", - "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "regenerator-transform": "^0.15.1" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", - "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-runtime": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.21.4.tgz", - "integrity": "sha512-1J4dhrw1h1PqnNNpzwxQ2UBymJUF8KuPjAAnlLwZcGhHAIqUigFW7cdK6GHoB64ubY4qXQNYknoUeks4Wz7CUA==", - "requires": { - "@babel/helper-module-imports": "^7.21.4", - "@babel/helper-plugin-utils": "^7.20.2", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - } - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", - "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz", - "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", - "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", - "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", - "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-typescript": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.21.3.tgz", - "integrity": "sha512-RQxPz6Iqt8T0uw/WsJNReuBpWpBqs/n7mNo18sKLoTbMp+UrEekhH+pKSVC7gWz+DNjo9gryfV8YzCiT45RgMw==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-typescript": "^7.20.0" - } - }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", - "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", - "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/preset-env": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.21.4.tgz", - "integrity": "sha512-2W57zHs2yDLm6GD5ZpvNn71lZ0B/iypSdIeq25OurDKji6AdzV07qp4s3n1/x5BqtiGaTrPN3nerlSCaC5qNTw==", - "requires": { - "@babel/compat-data": "^7.21.4", - "@babel/helper-compilation-targets": "^7.21.4", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-option": "^7.21.0", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.20.7", - "@babel/plugin-proposal-async-generator-functions": "^7.20.7", - "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-class-static-block": "^7.21.0", - "@babel/plugin-proposal-dynamic-import": "^7.18.6", - "@babel/plugin-proposal-export-namespace-from": "^7.18.9", - "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.20.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", - "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.20.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.21.0", - "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.21.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.20.0", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.20.7", - "@babel/plugin-transform-async-to-generator": "^7.20.7", - "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.21.0", - "@babel/plugin-transform-classes": "^7.21.0", - "@babel/plugin-transform-computed-properties": "^7.20.7", - "@babel/plugin-transform-destructuring": "^7.21.3", - "@babel/plugin-transform-dotall-regex": "^7.18.6", - "@babel/plugin-transform-duplicate-keys": "^7.18.9", - "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.21.0", - "@babel/plugin-transform-function-name": "^7.18.9", - "@babel/plugin-transform-literals": "^7.18.9", - "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.20.11", - "@babel/plugin-transform-modules-commonjs": "^7.21.2", - "@babel/plugin-transform-modules-systemjs": "^7.20.11", - "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.20.5", - "@babel/plugin-transform-new-target": "^7.18.6", - "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.21.3", - "@babel/plugin-transform-property-literals": "^7.18.6", - "@babel/plugin-transform-regenerator": "^7.20.5", - "@babel/plugin-transform-reserved-words": "^7.18.6", - "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.20.7", - "@babel/plugin-transform-sticky-regex": "^7.18.6", - "@babel/plugin-transform-template-literals": "^7.18.9", - "@babel/plugin-transform-typeof-symbol": "^7.18.9", - "@babel/plugin-transform-unicode-escapes": "^7.18.10", - "@babel/plugin-transform-unicode-regex": "^7.18.6", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.21.4", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "core-js-compat": "^3.25.1", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - } - } - }, - "@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, - "@babel/preset-react": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.18.6.tgz", - "integrity": "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-transform-react-display-name": "^7.18.6", - "@babel/plugin-transform-react-jsx": "^7.18.6", - "@babel/plugin-transform-react-jsx-development": "^7.18.6", - "@babel/plugin-transform-react-pure-annotations": "^7.18.6" - } - }, - "@babel/preset-typescript": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.21.4.tgz", - "integrity": "sha512-sMLNWY37TCdRH/bJ6ZeeOH1nPuanED7Ai9Y/vH31IPqalioJ6ZNFUWONsakhv4r4n+I6gm5lmoE0olkgib/j/A==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-option": "^7.21.0", - "@babel/plugin-syntax-jsx": "^7.21.4", - "@babel/plugin-transform-modules-commonjs": "^7.21.2", - "@babel/plugin-transform-typescript": "^7.21.3" - } - }, - "@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" - }, - "@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", - "requires": { - "regenerator-runtime": "^0.13.11" - } - }, - "@babel/runtime-corejs3": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.21.0.tgz", - "integrity": "sha512-TDD4UJzos3JJtM+tHX+w2Uc+KWj7GV+VKKFdMVd2Rx8sdA19hcc3P3AHFYd5LVOw+pYuSd5lICC3gm52B6Rwxw==", - "requires": { - "core-js-pure": "^3.25.1", - "regenerator-runtime": "^0.13.11" - } - }, - "@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - } - }, - "@babel/traverse": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz", - "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", - "requires": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.4", - "@babel/types": "^7.21.4", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", - "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - }, - "@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "optional": true - }, - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "peer": true, - "requires": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "dependencies": { - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "peer": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - } - } - }, - "@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==" - }, - "@docsearch/css": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.5.2.tgz", - "integrity": "sha512-SPiDHaWKQZpwR2siD0KQUwlStvIAnEyK6tAE2h2Wuoq8ue9skzhlyVQ1ddzOxX6khULnAALDiR/isSF3bnuciA==" - }, - "@docsearch/react": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.5.2.tgz", - "integrity": "sha512-9Ahcrs5z2jq/DcAvYtvlqEBHImbm4YJI8M9y0x6Tqg598P40HTEkX7hsMcIuThI+hTFxRGZ9hll0Wygm2yEjng==", - "requires": { - "@algolia/autocomplete-core": "1.9.3", - "@algolia/autocomplete-preset-algolia": "1.9.3", - "@docsearch/css": "3.5.2", - "algoliasearch": "^4.19.1" - } - }, - "@docusaurus/core": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.4.3.tgz", - "integrity": "sha512-dWH5P7cgeNSIg9ufReX6gaCl/TmrGKD38Orbwuz05WPhAQtFXHd5B8Qym1TiXfvUNvwoYKkAJOJuGe8ou0Z7PA==", - "requires": { - "@babel/core": "^7.18.6", - "@babel/generator": "^7.18.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-transform-runtime": "^7.18.6", - "@babel/preset-env": "^7.18.6", - "@babel/preset-react": "^7.18.6", - "@babel/preset-typescript": "^7.18.6", - "@babel/runtime": "^7.18.6", - "@babel/runtime-corejs3": "^7.18.6", - "@babel/traverse": "^7.18.8", - "@docusaurus/cssnano-preset": "2.4.3", - "@docusaurus/logger": "2.4.3", - "@docusaurus/mdx-loader": "2.4.3", - "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/utils": "2.4.3", - "@docusaurus/utils-common": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "@slorber/static-site-generator-webpack-plugin": "^4.0.7", - "@svgr/webpack": "^6.2.1", - "autoprefixer": "^10.4.7", - "babel-loader": "^8.2.5", - "babel-plugin-dynamic-import-node": "^2.3.3", - "boxen": "^6.2.1", - "chalk": "^4.1.2", - "chokidar": "^3.5.3", - "clean-css": "^5.3.0", - "cli-table3": "^0.6.2", - "combine-promises": "^1.1.0", - "commander": "^5.1.0", - "copy-webpack-plugin": "^11.0.0", - "core-js": "^3.23.3", - "css-loader": "^6.7.1", - "css-minimizer-webpack-plugin": "^4.0.0", - "cssnano": "^5.1.12", - "del": "^6.1.1", - "detect-port": "^1.3.0", - "escape-html": "^1.0.3", - "eta": "^2.0.0", - "file-loader": "^6.2.0", - "fs-extra": "^10.1.0", - "html-minifier-terser": "^6.1.0", - "html-tags": "^3.2.0", - "html-webpack-plugin": "^5.5.0", - "import-fresh": "^3.3.0", - "leven": "^3.1.0", - "lodash": "^4.17.21", - "mini-css-extract-plugin": "^2.6.1", - "postcss": "^8.4.14", - "postcss-loader": "^7.0.0", - "prompts": "^2.4.2", - "react-dev-utils": "^12.0.1", - "react-helmet-async": "^1.3.0", - "react-loadable": "npm:@docusaurus/react-loadable@5.5.2", - "react-loadable-ssr-addon-v5-slorber": "^1.0.1", - "react-router": "^5.3.3", - "react-router-config": "^5.1.1", - "react-router-dom": "^5.3.3", - "rtl-detect": "^1.0.4", - "semver": "^7.3.7", - "serve-handler": "^6.1.3", - "shelljs": "^0.8.5", - "terser-webpack-plugin": "^5.3.3", - "tslib": "^2.4.0", - "update-notifier": "^5.1.0", - "url-loader": "^4.1.1", - "wait-on": "^6.0.1", - "webpack": "^5.73.0", - "webpack-bundle-analyzer": "^4.5.0", - "webpack-dev-server": "^4.9.3", - "webpack-merge": "^5.8.0", - "webpackbar": "^5.0.2" - } - }, - "@docusaurus/cssnano-preset": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.4.3.tgz", - "integrity": "sha512-ZvGSRCi7z9wLnZrXNPG6DmVPHdKGd8dIn9pYbEOFiYihfv4uDR3UtxogmKf+rT8ZlKFf5Lqne8E8nt08zNM8CA==", - "requires": { - "cssnano-preset-advanced": "^5.3.8", - "postcss": "^8.4.14", - "postcss-sort-media-queries": "^4.2.1", - "tslib": "^2.4.0" - } - }, - "@docusaurus/logger": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.4.3.tgz", - "integrity": "sha512-Zxws7r3yLufk9xM1zq9ged0YHs65mlRmtsobnFkdZTxWXdTYlWWLWdKyNKAsVC+D7zg+pv2fGbyabdOnyZOM3w==", - "requires": { - "chalk": "^4.1.2", - "tslib": "^2.4.0" - } - }, - "@docusaurus/mdx-loader": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.4.3.tgz", - "integrity": "sha512-b1+fDnWtl3GiqkL0BRjYtc94FZrcDDBV1j8446+4tptB9BAOlePwG2p/pK6vGvfL53lkOsszXMghr2g67M0vCw==", - "requires": { - "@babel/parser": "^7.18.8", - "@babel/traverse": "^7.18.8", - "@docusaurus/logger": "2.4.3", - "@docusaurus/utils": "2.4.3", - "@mdx-js/mdx": "^1.6.22", - "escape-html": "^1.0.3", - "file-loader": "^6.2.0", - "fs-extra": "^10.1.0", - "image-size": "^1.0.1", - "mdast-util-to-string": "^2.0.0", - "remark-emoji": "^2.2.0", - "stringify-object": "^3.3.0", - "tslib": "^2.4.0", - "unified": "^9.2.2", - "unist-util-visit": "^2.0.3", - "url-loader": "^4.1.1", - "webpack": "^5.73.0" - } - }, - "@docusaurus/module-type-aliases": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-2.4.3.tgz", - "integrity": "sha512-cwkBkt1UCiduuvEAo7XZY01dJfRn7UR/75mBgOdb1hKknhrabJZ8YH+7savd/y9kLExPyrhe0QwdS9GuzsRRIA==", - "requires": { - "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/types": "2.4.3", - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router-config": "*", - "@types/react-router-dom": "*", - "react-helmet-async": "*", - "react-loadable": "npm:@docusaurus/react-loadable@5.5.2" - } - }, - "@docusaurus/plugin-client-redirects": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-2.4.3.tgz", - "integrity": "sha512-iCwc/zH8X6eNtLYdyUJFY6+GbsbRgMgvAC/TmSmCYTmwnoN5Y1Bc5OwUkdtoch0XKizotJMRAmGIAhP8sAetdQ==", - "requires": { - "@docusaurus/core": "2.4.3", - "@docusaurus/logger": "2.4.3", - "@docusaurus/utils": "2.4.3", - "@docusaurus/utils-common": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "eta": "^2.0.0", - "fs-extra": "^10.1.0", - "lodash": "^4.17.21", - "tslib": "^2.4.0" - } - }, - "@docusaurus/plugin-content-blog": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.4.3.tgz", - "integrity": "sha512-PVhypqaA0t98zVDpOeTqWUTvRqCEjJubtfFUQ7zJNYdbYTbS/E/ytq6zbLVsN/dImvemtO/5JQgjLxsh8XLo8Q==", - "requires": { - "@docusaurus/core": "2.4.3", - "@docusaurus/logger": "2.4.3", - "@docusaurus/mdx-loader": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils": "2.4.3", - "@docusaurus/utils-common": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "cheerio": "^1.0.0-rc.12", - "feed": "^4.2.2", - "fs-extra": "^10.1.0", - "lodash": "^4.17.21", - "reading-time": "^1.5.0", - "tslib": "^2.4.0", - "unist-util-visit": "^2.0.3", - "utility-types": "^3.10.0", - "webpack": "^5.73.0" - } - }, - "@docusaurus/plugin-content-docs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.4.3.tgz", - "integrity": "sha512-N7Po2LSH6UejQhzTCsvuX5NOzlC+HiXOVvofnEPj0WhMu1etpLEXE6a4aTxrtg95lQ5kf0xUIdjX9sh3d3G76A==", - "requires": { - "@docusaurus/core": "2.4.3", - "@docusaurus/logger": "2.4.3", - "@docusaurus/mdx-loader": "2.4.3", - "@docusaurus/module-type-aliases": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "@types/react-router-config": "^5.0.6", - "combine-promises": "^1.1.0", - "fs-extra": "^10.1.0", - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "lodash": "^4.17.21", - "tslib": "^2.4.0", - "utility-types": "^3.10.0", - "webpack": "^5.73.0" - } - }, - "@docusaurus/plugin-content-pages": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.4.3.tgz", - "integrity": "sha512-txtDVz7y3zGk67q0HjG0gRttVPodkHqE0bpJ+7dOaTH40CQFLSh7+aBeGnPOTl+oCPG+hxkim4SndqPqXjQ8Bg==", - "requires": { - "@docusaurus/core": "2.4.3", - "@docusaurus/mdx-loader": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "fs-extra": "^10.1.0", - "tslib": "^2.4.0", - "webpack": "^5.73.0" - } - }, - "@docusaurus/plugin-debug": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.4.3.tgz", - "integrity": "sha512-LkUbuq3zCmINlFb+gAd4ZvYr+bPAzMC0hwND4F7V9bZ852dCX8YoWyovVUBKq4er1XsOwSQaHmNGtObtn8Av8Q==", - "requires": { - "@docusaurus/core": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils": "2.4.3", - "fs-extra": "^10.1.0", - "react-json-view": "^1.21.3", - "tslib": "^2.4.0" - } - }, - "@docusaurus/plugin-google-analytics": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.4.3.tgz", - "integrity": "sha512-KzBV3k8lDkWOhg/oYGxlK5o9bOwX7KpPc/FTWoB+SfKhlHfhq7qcQdMi1elAaVEIop8tgK6gD1E58Q+XC6otSQ==", - "requires": { - "@docusaurus/core": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "tslib": "^2.4.0" - } - }, - "@docusaurus/plugin-google-gtag": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.4.3.tgz", - "integrity": "sha512-5FMg0rT7sDy4i9AGsvJC71MQrqQZwgLNdDetLEGDHLfSHLvJhQbTCUGbGXknUgWXQJckcV/AILYeJy+HhxeIFA==", - "requires": { - "@docusaurus/core": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "tslib": "^2.4.0" - } - }, - "@docusaurus/plugin-google-tag-manager": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.4.3.tgz", - "integrity": "sha512-1jTzp71yDGuQiX9Bi0pVp3alArV0LSnHXempvQTxwCGAEzUWWaBg4d8pocAlTpbP9aULQQqhgzrs8hgTRPOM0A==", - "requires": { - "@docusaurus/core": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "tslib": "^2.4.0" - } - }, - "@docusaurus/plugin-sitemap": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.4.3.tgz", - "integrity": "sha512-LRQYrK1oH1rNfr4YvWBmRzTL0LN9UAPxBbghgeFRBm5yloF6P+zv1tm2pe2hQTX/QP5bSKdnajCvfnScgKXMZQ==", - "requires": { - "@docusaurus/core": "2.4.3", - "@docusaurus/logger": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils": "2.4.3", - "@docusaurus/utils-common": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "fs-extra": "^10.1.0", - "sitemap": "^7.1.1", - "tslib": "^2.4.0" - } - }, - "@docusaurus/preset-classic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.4.3.tgz", - "integrity": "sha512-tRyMliepY11Ym6hB1rAFSNGwQDpmszvWYJvlK1E+md4SW8i6ylNHtpZjaYFff9Mdk3i/Pg8ItQq9P0daOJAvQw==", - "requires": { - "@docusaurus/core": "2.4.3", - "@docusaurus/plugin-content-blog": "2.4.3", - "@docusaurus/plugin-content-docs": "2.4.3", - "@docusaurus/plugin-content-pages": "2.4.3", - "@docusaurus/plugin-debug": "2.4.3", - "@docusaurus/plugin-google-analytics": "2.4.3", - "@docusaurus/plugin-google-gtag": "2.4.3", - "@docusaurus/plugin-google-tag-manager": "2.4.3", - "@docusaurus/plugin-sitemap": "2.4.3", - "@docusaurus/theme-classic": "2.4.3", - "@docusaurus/theme-common": "2.4.3", - "@docusaurus/theme-search-algolia": "2.4.3", - "@docusaurus/types": "2.4.3" - } - }, - "@docusaurus/react-loadable": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", - "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", - "requires": { - "@types/react": "*", - "prop-types": "^15.6.2" - } - }, - "@docusaurus/theme-classic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.4.3.tgz", - "integrity": "sha512-QKRAJPSGPfDY2yCiPMIVyr+MqwZCIV2lxNzqbyUW0YkrlmdzzP3WuQJPMGLCjWgQp/5c9kpWMvMxjhpZx1R32Q==", - "requires": { - "@docusaurus/core": "2.4.3", - "@docusaurus/mdx-loader": "2.4.3", - "@docusaurus/module-type-aliases": "2.4.3", - "@docusaurus/plugin-content-blog": "2.4.3", - "@docusaurus/plugin-content-docs": "2.4.3", - "@docusaurus/plugin-content-pages": "2.4.3", - "@docusaurus/theme-common": "2.4.3", - "@docusaurus/theme-translations": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils": "2.4.3", - "@docusaurus/utils-common": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "@mdx-js/react": "^1.6.22", - "clsx": "^1.2.1", - "copy-text-to-clipboard": "^3.0.1", - "infima": "0.2.0-alpha.43", - "lodash": "^4.17.21", - "nprogress": "^0.2.0", - "postcss": "^8.4.14", - "prism-react-renderer": "^1.3.5", - "prismjs": "^1.28.0", - "react-router-dom": "^5.3.3", - "rtlcss": "^3.5.0", - "tslib": "^2.4.0", - "utility-types": "^3.10.0" - } - }, - "@docusaurus/theme-common": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.4.3.tgz", - "integrity": "sha512-7KaDJBXKBVGXw5WOVt84FtN8czGWhM0lbyWEZXGp8AFfL6sZQfRTluFp4QriR97qwzSyOfQb+nzcDZZU4tezUw==", - "requires": { - "@docusaurus/mdx-loader": "2.4.3", - "@docusaurus/module-type-aliases": "2.4.3", - "@docusaurus/plugin-content-blog": "2.4.3", - "@docusaurus/plugin-content-docs": "2.4.3", - "@docusaurus/plugin-content-pages": "2.4.3", - "@docusaurus/utils": "2.4.3", - "@docusaurus/utils-common": "2.4.3", - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router-config": "*", - "clsx": "^1.2.1", - "parse-numeric-range": "^1.3.0", - "prism-react-renderer": "^1.3.5", - "tslib": "^2.4.0", - "use-sync-external-store": "^1.2.0", - "utility-types": "^3.10.0" - } - }, - "@docusaurus/theme-search-algolia": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.3.tgz", - "integrity": "sha512-jziq4f6YVUB5hZOB85ELATwnxBz/RmSLD3ksGQOLDPKVzat4pmI8tddNWtriPpxR04BNT+ZfpPUMFkNFetSW1Q==", - "requires": { - "@docsearch/react": "^3.1.1", - "@docusaurus/core": "2.4.3", - "@docusaurus/logger": "2.4.3", - "@docusaurus/plugin-content-docs": "2.4.3", - "@docusaurus/theme-common": "2.4.3", - "@docusaurus/theme-translations": "2.4.3", - "@docusaurus/utils": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "algoliasearch": "^4.13.1", - "algoliasearch-helper": "^3.10.0", - "clsx": "^1.2.1", - "eta": "^2.0.0", - "fs-extra": "^10.1.0", - "lodash": "^4.17.21", - "tslib": "^2.4.0", - "utility-types": "^3.10.0" - } - }, - "@docusaurus/theme-translations": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.4.3.tgz", - "integrity": "sha512-H4D+lbZbjbKNS/Zw1Lel64PioUAIT3cLYYJLUf3KkuO/oc9e0QCVhIYVtUI2SfBCF2NNdlyhBDQEEMygsCedIg==", - "requires": { - "fs-extra": "^10.1.0", - "tslib": "^2.4.0" - } - }, - "@docusaurus/types": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.4.3.tgz", - "integrity": "sha512-W6zNLGQqfrp/EoPD0bhb9n7OobP+RHpmvVzpA+Z/IuU3Q63njJM24hmT0GYboovWcDtFmnIJC9wcyx4RVPQscw==", - "requires": { - "@types/history": "^4.7.11", - "@types/react": "*", - "commander": "^5.1.0", - "joi": "^17.6.0", - "react-helmet-async": "^1.3.0", - "utility-types": "^3.10.0", - "webpack": "^5.73.0", - "webpack-merge": "^5.8.0" - } - }, - "@docusaurus/utils": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.4.3.tgz", - "integrity": "sha512-fKcXsjrD86Smxv8Pt0TBFqYieZZCPh4cbf9oszUq/AMhZn3ujwpKaVYZACPX8mmjtYx0JOgNx52CREBfiGQB4A==", - "requires": { - "@docusaurus/logger": "2.4.3", - "@svgr/webpack": "^6.2.1", - "escape-string-regexp": "^4.0.0", - "file-loader": "^6.2.0", - "fs-extra": "^10.1.0", - "github-slugger": "^1.4.0", - "globby": "^11.1.0", - "gray-matter": "^4.0.3", - "js-yaml": "^4.1.0", - "lodash": "^4.17.21", - "micromatch": "^4.0.5", - "resolve-pathname": "^3.0.0", - "shelljs": "^0.8.5", - "tslib": "^2.4.0", - "url-loader": "^4.1.1", - "webpack": "^5.73.0" - } - }, - "@docusaurus/utils-common": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.4.3.tgz", - "integrity": "sha512-/jascp4GbLQCPVmcGkPzEQjNaAk3ADVfMtudk49Ggb+131B1WDD6HqlSmDf8MxGdy7Dja2gc+StHf01kiWoTDQ==", - "requires": { - "tslib": "^2.4.0" - } - }, - "@docusaurus/utils-validation": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.4.3.tgz", - "integrity": "sha512-G2+Vt3WR5E/9drAobP+hhZQMaswRwDlp6qOMi7o7ZypB+VO7N//DZWhZEwhcRGepMDJGQEwtPv7UxtYwPL9PBw==", - "requires": { - "@docusaurus/logger": "2.4.3", - "@docusaurus/utils": "2.4.3", - "joi": "^17.6.0", - "js-yaml": "^4.1.0", - "tslib": "^2.4.0" - } - }, - "@easyops-cn/autocomplete.js": { - "version": "0.38.1", - "resolved": "https://registry.npmjs.org/@easyops-cn/autocomplete.js/-/autocomplete.js-0.38.1.tgz", - "integrity": "sha512-drg76jS6syilOUmVNkyo1c7ZEBPcPuK+aJA7AksM5ZIIbV57DMHCywiCr+uHyv8BE5jUTU98j/H7gVrkHrWW3Q==", - "requires": { - "cssesc": "^3.0.0", - "immediate": "^3.2.3" - } - }, - "@easyops-cn/docusaurus-search-local": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@easyops-cn/docusaurus-search-local/-/docusaurus-search-local-0.36.0.tgz", - "integrity": "sha512-4R8tLYQc1aLTJcqIYHd7Np/wh6/psfHmGbNuJMwAFW7bJ6KyStlagBdXzv3k3SCqpo5emW2IUNYmHmN+8xvB6A==", - "requires": { - "@docusaurus/plugin-content-docs": "^2.0.0-rc.1", - "@docusaurus/theme-translations": "^2.0.0-rc.1", - "@docusaurus/utils": "^2.0.0-rc.1", - "@docusaurus/utils-common": "^2.0.0-rc.1", - "@docusaurus/utils-validation": "^2.0.0-rc.1", - "@easyops-cn/autocomplete.js": "^0.38.1", - "@node-rs/jieba": "^1.6.0", - "cheerio": "^1.0.0-rc.3", - "clsx": "^1.1.1", - "debug": "^4.2.0", - "fs-extra": "^10.0.0", - "klaw-sync": "^6.0.0", - "lunr": "^2.3.9", - "lunr-languages": "^1.4.0", - "mark.js": "^8.11.1", - "tslib": "^2.4.0" - } - }, - "@hapi/hoek": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" - }, - "@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "requires": { - "@hapi/hoek": "^9.0.0" - } - }, - "@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", - "requires": { - "@sinclair/typebox": "^0.25.16" - } - }, - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" - }, - "@jridgewell/source-map": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", - "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==", - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" - }, - "@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - }, - "dependencies": { - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - } - } - }, - "@leichtgewicht/ip-codec": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", - "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" - }, - "@mdx-js/mdx": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-1.6.22.tgz", - "integrity": "sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==", - "requires": { - "@babel/core": "7.12.9", - "@babel/plugin-syntax-jsx": "7.12.1", - "@babel/plugin-syntax-object-rest-spread": "7.8.3", - "@mdx-js/util": "1.6.22", - "babel-plugin-apply-mdx-type-prop": "1.6.22", - "babel-plugin-extract-import-names": "1.6.22", - "camelcase-css": "2.0.1", - "detab": "2.0.4", - "hast-util-raw": "6.0.1", - "lodash.uniq": "4.5.0", - "mdast-util-to-hast": "10.0.1", - "remark-footnotes": "2.0.0", - "remark-mdx": "1.6.22", - "remark-parse": "8.0.3", - "remark-squeeze-paragraphs": "4.0.0", - "style-to-object": "0.3.0", - "unified": "9.2.0", - "unist-builder": "2.0.3", - "unist-util-visit": "2.0.3" - }, - "dependencies": { - "@babel/core": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.7", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.9", - "@babel/types": "^7.12.7", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" - }, - "unified": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", - "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", - "requires": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" - } - } - } - }, - "@mdx-js/react": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-1.6.22.tgz", - "integrity": "sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==", - "requires": {} - }, - "@mdx-js/util": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz", - "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==" - }, - "@node-rs/jieba": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba/-/jieba-1.7.0.tgz", - "integrity": "sha512-Hm1JIlejxkWe1FSFZRns/g1j5hZmp357n+0n2BluABA4KLZ8EraHfPmPRmVMW6vbdMZObTYIVu5aVrPnUfBOxg==", - "requires": { - "@node-rs/jieba-android-arm-eabi": "1.7.0", - "@node-rs/jieba-android-arm64": "1.7.0", - "@node-rs/jieba-darwin-arm64": "1.7.0", - "@node-rs/jieba-darwin-x64": "1.7.0", - "@node-rs/jieba-freebsd-x64": "1.7.0", - "@node-rs/jieba-linux-arm-gnueabihf": "1.7.0", - "@node-rs/jieba-linux-arm64-gnu": "1.7.0", - "@node-rs/jieba-linux-arm64-musl": "1.7.0", - "@node-rs/jieba-linux-x64-gnu": "1.7.0", - "@node-rs/jieba-linux-x64-musl": "1.7.0", - "@node-rs/jieba-win32-arm64-msvc": "1.7.0", - "@node-rs/jieba-win32-ia32-msvc": "1.7.0", - "@node-rs/jieba-win32-x64-msvc": "1.7.0" - } - }, - "@node-rs/jieba-android-arm-eabi": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-android-arm-eabi/-/jieba-android-arm-eabi-1.7.0.tgz", - "integrity": "sha512-XF4OYcZCyDiBK+jm1Zmt2o+xEO7K2K5OvUC3MTc9jd3Lwvy3EdHp8tpGvEp8PxfVFe2/JxNzX4OQQQP3Dhmk9A==", - "optional": true - }, - "@node-rs/jieba-android-arm64": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-android-arm64/-/jieba-android-arm64-1.7.0.tgz", - "integrity": "sha512-9oWwFVr/37T89WC+jjiI9A6u0zUJNTJl5ZC4CMxX45MVMokWI7bBXU7t7qBmMdFBzj+OFwDd3sm1fh4vl7NSWA==", - "optional": true - }, - "@node-rs/jieba-darwin-arm64": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-darwin-arm64/-/jieba-darwin-arm64-1.7.0.tgz", - "integrity": "sha512-9gBuxJCNITNI/gU5l8eeVGQ9MAf0BV86lfeo9TeU61vJCy6sqyx26wFMLODQgLNdiMP+q/fZme/G0hfZUjfPVA==", - "optional": true - }, - "@node-rs/jieba-darwin-x64": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-darwin-x64/-/jieba-darwin-x64-1.7.0.tgz", - "integrity": "sha512-FFUSMY4tl0Prpxa1SHy7Yzze2KfV/bZzccpO5nd+a8zCKbiX6gVkJ89FfxSAD2QrXUGkZvJYiPmu5nkZItqRZQ==", - "optional": true - }, - "@node-rs/jieba-freebsd-x64": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-freebsd-x64/-/jieba-freebsd-x64-1.7.0.tgz", - "integrity": "sha512-QFz2pz0Br+621QbKkgQPqTn90j1kcCD9jaI++qTLNHJGlWLRn6sFoAjb+jQEQEy9aE7VqfIV56eaVcCoU5VO2w==", - "optional": true - }, - "@node-rs/jieba-linux-arm-gnueabihf": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm-gnueabihf/-/jieba-linux-arm-gnueabihf-1.7.0.tgz", - "integrity": "sha512-kHJxO2sd7gMKqI1YS5DjABEcRwRemaCtgbKSuUqEaHGmUz9nAaUF6FSY8U4rXwr7HXt+kQa4NgyYDjgz+Pscrw==", - "optional": true - }, - "@node-rs/jieba-linux-arm64-gnu": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm64-gnu/-/jieba-linux-arm64-gnu-1.7.0.tgz", - "integrity": "sha512-3qoCV9pF6llPBGDMu7K8JdHjI10WPkrq6P2gpZESqekcE4DatV6DcU9FWR+QL7MK/7meoE3/Zhjm7OK+qBd8gg==", - "optional": true - }, - "@node-rs/jieba-linux-arm64-musl": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm64-musl/-/jieba-linux-arm64-musl-1.7.0.tgz", - "integrity": "sha512-xv6hvzOV7iTCq7mM8SWhC3zEk6CqmBwhOSlfbb3gvPkc4U1UA1hmvcrD7oO5Qn+U+nuswysGCdVU6Z5AypLDfg==", - "optional": true - }, - "@node-rs/jieba-linux-x64-gnu": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-x64-gnu/-/jieba-linux-x64-gnu-1.7.0.tgz", - "integrity": "sha512-NpelWidMSNLoFTw+ov3y5jhJZjapHwEnh0Fyfm/7mvqkdwzVyedqNj22etRGum+nsAosMotCUWUznIMAD075gQ==", - "optional": true - }, - "@node-rs/jieba-linux-x64-musl": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-x64-musl/-/jieba-linux-x64-musl-1.7.0.tgz", - "integrity": "sha512-yG4F8sy+fW4RbhyKXmEMT/JGuQuKH0TGymCEGYgT0km2I60iys63jWf2VTzCtrx583wxN5XoHv5HN60nhtIBtw==", - "optional": true - }, - "@node-rs/jieba-win32-arm64-msvc": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-arm64-msvc/-/jieba-win32-arm64-msvc-1.7.0.tgz", - "integrity": "sha512-R6l/BSMs6R6BwpZS6DIDZuAEjUIPdAHgyi+xptP3mICjm6U+GMsvsRTeZkIJ7a/yzYUfqvz54VpQsfE5f0psBQ==", - "optional": true - }, - "@node-rs/jieba-win32-ia32-msvc": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-ia32-msvc/-/jieba-win32-ia32-msvc-1.7.0.tgz", - "integrity": "sha512-FwibbuizEjzom02K2JM2T8tL0VlxW5xGDDy3L3dgx46xIGE85PwGYjgju+eDt4UODgxDsxGC4DUMMZf3XvCc7A==", - "optional": true - }, - "@node-rs/jieba-win32-x64-msvc": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-x64-msvc/-/jieba-win32-x64-msvc-1.7.0.tgz", - "integrity": "sha512-pJv7nluB6azhsOWvJB86Dyfg/M7n9k49bs9Bwmsylz9uhdZX9QnEShDW934RdmnjPYQ5aPgsSFrY6NXP/aovUA==", - "optional": true - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@polka/url": { - "version": "1.0.0-next.21", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", - "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==" - }, - "@sideway/address": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", - "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", - "requires": { - "@hapi/hoek": "^9.0.0" - } - }, - "@sideway/formula": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" - }, - "@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" - }, - "@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==" - }, - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" - }, - "@slorber/static-site-generator-webpack-plugin": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.7.tgz", - "integrity": "sha512-Ug7x6z5lwrz0WqdnNFOMYrDQNTPAprvHLSh6+/fmml3qUiz6l5eq+2MzLKWtn/q5K5NpSiFsZTP/fck/3vjSxA==", - "requires": { - "eval": "^0.1.8", - "p-map": "^4.0.0", - "webpack-sources": "^3.2.2" - } - }, - "@svgr/babel-plugin-add-jsx-attribute": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.5.1.tgz", - "integrity": "sha512-9PYGcXrAxitycIjRmZB+Q0JaN07GZIWaTBIGQzfaZv+qr1n8X1XUEJ5rZ/vx6OVD9RRYlrNnXWExQXcmZeD/BQ==", - "requires": {} - }, - "@svgr/babel-plugin-remove-jsx-attribute": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-7.0.0.tgz", - "integrity": "sha512-iiZaIvb3H/c7d3TH2HBeK91uI2rMhZNwnsIrvd7ZwGLkFw6mmunOCoVnjdYua662MqGFxlN9xTq4fv9hgR4VXQ==", - "requires": {} - }, - "@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-7.0.0.tgz", - "integrity": "sha512-sQQmyo+qegBx8DfFc04PFmIO1FP1MHI1/QEpzcIcclo5OAISsOJPW76ZIs0bDyO/DBSJEa/tDa1W26pVtt0FRw==", - "requires": {} - }, - "@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.5.1.tgz", - "integrity": "sha512-8DPaVVE3fd5JKuIC29dqyMB54sA6mfgki2H2+swh+zNJoynC8pMPzOkidqHOSc6Wj032fhl8Z0TVn1GiPpAiJg==", - "requires": {} - }, - "@svgr/babel-plugin-svg-dynamic-title": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.5.1.tgz", - "integrity": "sha512-FwOEi0Il72iAzlkaHrlemVurgSQRDFbk0OC8dSvD5fSBPHltNh7JtLsxmZUhjYBZo2PpcU/RJvvi6Q0l7O7ogw==", - "requires": {} - }, - "@svgr/babel-plugin-svg-em-dimensions": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.5.1.tgz", - "integrity": "sha512-gWGsiwjb4tw+ITOJ86ndY/DZZ6cuXMNE/SjcDRg+HLuCmwpcjOktwRF9WgAiycTqJD/QXqL2f8IzE2Rzh7aVXA==", - "requires": {} - }, - "@svgr/babel-plugin-transform-react-native-svg": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.5.1.tgz", - "integrity": "sha512-2jT3nTayyYP7kI6aGutkyfJ7UMGtuguD72OjeGLwVNyfPRBD8zQthlvL+fAbAKk5n9ZNcvFkp/b1lZ7VsYqVJg==", - "requires": {} - }, - "@svgr/babel-plugin-transform-svg-component": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.5.1.tgz", - "integrity": "sha512-a1p6LF5Jt33O3rZoVRBqdxL350oge54iZWHNI6LJB5tQ7EelvD/Mb1mfBiZNAan0dt4i3VArkFRjA4iObuNykQ==", - "requires": {} - }, - "@svgr/babel-preset": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-6.5.1.tgz", - "integrity": "sha512-6127fvO/FF2oi5EzSQOAjo1LE3OtNVh11R+/8FXa+mHx1ptAaS4cknIjnUA7e6j6fwGGJ17NzaTJFUwOV2zwCw==", - "requires": { - "@svgr/babel-plugin-add-jsx-attribute": "^6.5.1", - "@svgr/babel-plugin-remove-jsx-attribute": "*", - "@svgr/babel-plugin-remove-jsx-empty-expression": "*", - "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.5.1", - "@svgr/babel-plugin-svg-dynamic-title": "^6.5.1", - "@svgr/babel-plugin-svg-em-dimensions": "^6.5.1", - "@svgr/babel-plugin-transform-react-native-svg": "^6.5.1", - "@svgr/babel-plugin-transform-svg-component": "^6.5.1" - } - }, - "@svgr/core": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.5.1.tgz", - "integrity": "sha512-/xdLSWxK5QkqG524ONSjvg3V/FkNyCv538OIBdQqPNaAta3AsXj/Bd2FbvR87yMbXO2hFSWiAe/Q6IkVPDw+mw==", - "requires": { - "@babel/core": "^7.19.6", - "@svgr/babel-preset": "^6.5.1", - "@svgr/plugin-jsx": "^6.5.1", - "camelcase": "^6.2.0", - "cosmiconfig": "^7.0.1" - } - }, - "@svgr/hast-util-to-babel-ast": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.5.1.tgz", - "integrity": "sha512-1hnUxxjd83EAxbL4a0JDJoD3Dao3hmjvyvyEV8PzWmLK3B9m9NPlW7GKjFyoWE8nM7HnXzPcmmSyOW8yOddSXw==", - "requires": { - "@babel/types": "^7.20.0", - "entities": "^4.4.0" - } - }, - "@svgr/plugin-jsx": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.5.1.tgz", - "integrity": "sha512-+UdQxI3jgtSjCykNSlEMuy1jSRQlGC7pqBCPvkG/2dATdWo082zHTTK3uhnAju2/6XpE6B5mZ3z4Z8Ns01S8Gw==", - "requires": { - "@babel/core": "^7.19.6", - "@svgr/babel-preset": "^6.5.1", - "@svgr/hast-util-to-babel-ast": "^6.5.1", - "svg-parser": "^2.0.4" - } - }, - "@svgr/plugin-svgo": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-6.5.1.tgz", - "integrity": "sha512-omvZKf8ixP9z6GWgwbtmP9qQMPX4ODXi+wzbVZgomNFsUIlHA1sf4fThdwTWSsZGgvGAG6yE+b/F5gWUkcZ/iQ==", - "requires": { - "cosmiconfig": "^7.0.1", - "deepmerge": "^4.2.2", - "svgo": "^2.8.0" - } - }, - "@svgr/webpack": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-6.5.1.tgz", - "integrity": "sha512-cQ/AsnBkXPkEK8cLbv4Dm7JGXq2XrumKnL1dRpJD9rIO2fTIlJI9a1uCciYG1F2aUsox/hJQyNGbt3soDxSRkA==", - "requires": { - "@babel/core": "^7.19.6", - "@babel/plugin-transform-react-constant-elements": "^7.18.12", - "@babel/preset-env": "^7.19.4", - "@babel/preset-react": "^7.18.6", - "@babel/preset-typescript": "^7.18.6", - "@svgr/core": "^6.5.1", - "@svgr/plugin-jsx": "^6.5.1", - "@svgr/plugin-svgo": "^6.5.1" - } - }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "requires": { - "defer-to-connect": "^1.0.1" - } - }, - "@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==" - }, - "@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "peer": true - }, - "@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "peer": true - }, - "@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "peer": true - }, - "@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "peer": true - }, - "@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/bonjour": { - "version": "3.5.10", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", - "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", - "requires": { - "@types/node": "*" - } - }, - "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "requires": { - "@types/node": "*" - } - }, - "@types/connect-history-api-fallback": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", - "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", - "requires": { - "@types/express-serve-static-core": "*", - "@types/node": "*" - } - }, - "@types/eslint": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz", - "integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==", - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" - }, - "@types/express": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", - "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.33", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", - "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "@types/hast": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", - "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", - "requires": { - "@types/unist": "*" - } - }, - "@types/history": { - "version": "4.7.11", - "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", - "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" - }, - "@types/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" - }, - "@types/http-proxy": { - "version": "1.17.10", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.10.tgz", - "integrity": "sha512-Qs5aULi+zV1bwKAg5z1PWnDXWmsn+LxIvUGv6E2+OOMYhclZMO+OXd9pYVf2gLykf2I7IV2u7oTHwChPNsvJ7g==", - "requires": { - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" - }, - "@types/mdast": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.11.tgz", - "integrity": "sha512-Y/uImid8aAwrEA24/1tcRZwpxX3pIFTSilcNDKSPn+Y2iDywSEachzRuvgAYYLR3wpGXAsMbv5lvKLDZLeYPAw==", - "requires": { - "@types/unist": "*" - } - }, - "@types/mime": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", - "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" - }, - "@types/node": { - "version": "18.15.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", - "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" - }, - "@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" - }, - "@types/parse5": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz", - "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==" - }, - "@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" - }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" - }, - "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" - }, - "@types/react": { - "version": "18.0.37", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.37.tgz", - "integrity": "sha512-4yaZZtkRN3ZIQD3KSEwkfcik8s0SWV+82dlJot1AbGYHCzJkWP3ENBY6wYeDRmKZ6HkrgoGAmR2HqdwYGp6OEw==", - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "@types/react-router": { - "version": "5.1.20", - "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", - "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", - "requires": { - "@types/history": "^4.7.11", - "@types/react": "*" - } - }, - "@types/react-router-config": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.7.tgz", - "integrity": "sha512-pFFVXUIydHlcJP6wJm7sDii5mD/bCmmAY0wQzq+M+uX7bqS95AQqHZWP1iNMKrWVQSuHIzj5qi9BvrtLX2/T4w==", - "requires": { - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router": "^5.1.0" - } - }, - "@types/react-router-dom": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", - "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", - "requires": { - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router": "*" - } - }, - "@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" - }, - "@types/sax": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.5.tgz", - "integrity": "sha512-9jWta97bBVC027/MShr3gLab8gPhKy4l6qpb+UJLF5pDm3501NvA7uvqVCW+REFtx00oTi6Cq9JzLwgq6evVgw==", - "requires": { - "@types/node": "*" - } - }, - "@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" - }, - "@types/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", - "requires": { - "@types/express": "*" - } - }, - "@types/serve-static": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", - "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", - "requires": { - "@types/mime": "*", - "@types/node": "*" - } - }, - "@types/sockjs": { - "version": "0.3.33", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", - "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", - "requires": { - "@types/node": "*" - } - }, - "@types/unist": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", - "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" - }, - "@types/ws": { - "version": "8.5.4", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", - "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", - "requires": { - "@types/node": "*" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" - }, - "@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==" - }, - "@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==" - }, - "@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==" - }, - "@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==" - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==" - }, - "@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" - }, - "@you54f/theme-github-codeblock": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@you54f/theme-github-codeblock/-/theme-github-codeblock-0.1.1.tgz", - "integrity": "sha512-SFbkHzwfsfShYd9yL818P9P7AlSBQgDC92pyQWZqJV/PMdgfCh5ZsK/pt/1s/jy0wvYi4pFTwOEQ0+vhdy324w==" - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "dependencies": { - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - } - } - }, - "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==" - }, - "acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "requires": {} - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" - }, - "address": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", - "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==" - }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "requires": { - "ajv": "^8.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - } - } - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "requires": {} - }, - "algoliasearch": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.20.0.tgz", - "integrity": "sha512-y+UHEjnOItoNy0bYO+WWmLWBlPwDjKHW6mNHrPi0NkuhpQOOEbrkwQH/wgKFDLh7qlKjzoKeiRtlpewDPDG23g==", - "requires": { - "@algolia/cache-browser-local-storage": "4.20.0", - "@algolia/cache-common": "4.20.0", - "@algolia/cache-in-memory": "4.20.0", - "@algolia/client-account": "4.20.0", - "@algolia/client-analytics": "4.20.0", - "@algolia/client-common": "4.20.0", - "@algolia/client-personalization": "4.20.0", - "@algolia/client-search": "4.20.0", - "@algolia/logger-common": "4.20.0", - "@algolia/logger-console": "4.20.0", - "@algolia/requester-browser-xhr": "4.20.0", - "@algolia/requester-common": "4.20.0", - "@algolia/requester-node-http": "4.20.0", - "@algolia/transporter": "4.20.0" - } - }, - "algoliasearch-helper": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.14.2.tgz", - "integrity": "sha512-FjDSrjvQvJT/SKMW74nPgFpsoPUwZCzGbCqbp8HhBFfSk/OvNFxzCaCmuO0p7AWeLy1gD+muFwQEkBwcl5H4pg==", - "requires": { - "@algolia/events": "^4.0.1" - } - }, - "ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "requires": { - "string-width": "^4.1.0" - }, - "dependencies": { - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - } - } - }, - "ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==" - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" - }, - "anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" - }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" - }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" - }, - "autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", - "requires": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", - "requires": { - "follow-redirects": "^1.14.7" - } - }, - "babel-loader": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz", - "integrity": "sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==", - "requires": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^2.0.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" - } - }, - "babel-plugin-apply-mdx-type-prop": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz", - "integrity": "sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==", - "requires": { - "@babel/helper-plugin-utils": "7.10.4", - "@mdx-js/util": "1.6.22" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - } - } - }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "requires": { - "object.assign": "^4.1.0" - } - }, - "babel-plugin-extract-import-names": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz", - "integrity": "sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==", - "requires": { - "@babel/helper-plugin-utils": "7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - } - } - }, - "babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", - "requires": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - } - } - }, - "babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.3", - "core-js-compat": "^3.25.1" - } - }, - "babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.3" - } - }, - "bail": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", - "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==" - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base16": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", - "integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==" - }, - "batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" - }, - "body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "dependencies": { - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "bonjour-service": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", - "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", - "requires": { - "array-flatten": "^2.1.2", - "dns-equal": "^1.0.0", - "fast-deep-equal": "^3.1.3", - "multicast-dns": "^7.2.5" - } - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - }, - "boxen": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", - "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", - "requires": { - "ansi-align": "^3.0.1", - "camelcase": "^6.2.0", - "chalk": "^4.1.2", - "cli-boxes": "^3.0.0", - "string-width": "^5.0.1", - "type-fest": "^2.5.0", - "widest-line": "^4.0.1", - "wrap-ansi": "^8.0.1" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "requires": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" - }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "requires": { - "pump": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" - }, - "normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==" - } - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" - }, - "camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "requires": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - } - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" - }, - "camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" - }, - "caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "requires": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "caniuse-lite": { - "version": "1.0.30001480", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001480.tgz", - "integrity": "sha512-q7cpoPPvZYgtyC4VaBSN0Bt+PJ4c4EYRf0DrduInOz2SkFpHD5p3LnvEpqBp7UnJn+8x1Ogl1s38saUxe+ihQQ==" - }, - "ccount": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", - "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==" - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==" - }, - "character-entities-legacy": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==" - }, - "character-reference-invalid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==" - }, - "cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", - "requires": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" - } - }, - "cheerio-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", - "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", - "requires": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" - }, - "ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==" - }, - "clean-css": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", - "integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==", - "requires": { - "source-map": "~0.6.0" - } - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" - }, - "cli-boxes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", - "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==" - }, - "cli-table3": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", - "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", - "requires": { - "@colors/colors": "1.5.0", - "string-width": "^4.2.0" - }, - "dependencies": { - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - } - } - }, - "clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "requires": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - } - }, - "clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "requires": { - "mimic-response": "^1.0.0" - } - }, - "clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" - }, - "collapse-white-space": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", - "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==" - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" - }, - "colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" - }, - "combine-promises": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/combine-promises/-/combine-promises-1.1.0.tgz", - "integrity": "sha512-ZI9jvcLDxqwaXEixOhArm3r7ReIivsXkpbyEWyeOhzz1QS0iSgBPnWvEqvIQtYyamGCYA88gFhmUrs9hrrQ0pg==" - }, - "comma-separated-tokens": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", - "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==" - }, - "commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==" - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" - }, - "compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "requires": { - "mime-db": ">= 1.43.0 < 2" - }, - "dependencies": { - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - } - } - }, - "compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "requires": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "requires": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - } - }, - "connect-history-api-fallback": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==" - }, - "consola": { - "version": "2.15.3", - "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", - "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" - }, - "content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==" - }, - "content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" - }, - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" - }, - "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "copy-text-to-clipboard": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz", - "integrity": "sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==" - }, - "copy-webpack-plugin": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", - "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", - "requires": { - "fast-glob": "^3.2.11", - "glob-parent": "^6.0.1", - "globby": "^13.1.1", - "normalize-path": "^3.0.0", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "requires": { - "is-glob": "^4.0.3" - } - }, - "globby": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", - "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", - "requires": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "schema-utils": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.1.tgz", - "integrity": "sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ==", - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - } - }, - "slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==" - } - } - }, - "core-js": { - "version": "3.30.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.30.1.tgz", - "integrity": "sha512-ZNS5nbiSwDTq4hFosEDqm65izl2CWmLz0hARJMyNQBgkUZMIF51cQiMvIQKA6hvuaeWxQDP3hEedM1JZIgTldQ==" - }, - "core-js-compat": { - "version": "3.30.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.30.1.tgz", - "integrity": "sha512-d690npR7MC6P0gq4npTl5n2VQeNAmUrJ90n+MHiKS7W2+xno4o3F5GDEuylSdi6EJ3VssibSGXOa1r3YXD3Mhw==", - "requires": { - "browserslist": "^4.21.5" - } - }, - "core-js-pure": { - "version": "3.30.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.30.1.tgz", - "integrity": "sha512-nXBEVpmUnNRhz83cHd9JRQC52cTMcuXAmR56+9dSMpRdpeA4I1PX6yjmhd71Eyc/wXNsdBdUDIj1QTIeZpU5Tg==" - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - } - }, - "cosmiconfig-typescript-loader": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.3.0.tgz", - "integrity": "sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q==", - "requires": {} - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "peer": true - }, - "cross-fetch": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", - "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", - "requires": { - "node-fetch": "^2.6.12" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" - }, - "css-declaration-sorter": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz", - "integrity": "sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew==", - "requires": {} - }, - "css-loader": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", - "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", - "requires": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.19", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.3.8" - } - }, - "css-minimizer-webpack-plugin": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-4.2.2.tgz", - "integrity": "sha512-s3Of/4jKfw1Hj9CxEO1E5oXhQAxlayuHO2y/ML+C6I9sQ7FdzfEV6QgMLN3vI+qFsjJGIAFLKtQK7t8BOXAIyA==", - "requires": { - "cssnano": "^5.1.8", - "jest-worker": "^29.1.2", - "postcss": "^8.4.17", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1" - }, - "dependencies": { - "ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "schema-utils": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.1.tgz", - "integrity": "sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ==", - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - } - } - } - }, - "css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "requires": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - } - }, - "css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "requires": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - } - }, - "css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" - }, - "cssnano": { - "version": "5.1.15", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", - "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", - "requires": { - "cssnano-preset-default": "^5.2.14", - "lilconfig": "^2.0.3", - "yaml": "^1.10.2" - } - }, - "cssnano-preset-advanced": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.10.tgz", - "integrity": "sha512-fnYJyCS9jgMU+cmHO1rPSPf9axbQyD7iUhLO5Df6O4G+fKIOMps+ZbU0PdGFejFBBZ3Pftf18fn1eG7MAPUSWQ==", - "requires": { - "autoprefixer": "^10.4.12", - "cssnano-preset-default": "^5.2.14", - "postcss-discard-unused": "^5.1.0", - "postcss-merge-idents": "^5.1.1", - "postcss-reduce-idents": "^5.2.0", - "postcss-zindex": "^5.1.0" - } - }, - "cssnano-preset-default": { - "version": "5.2.14", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", - "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", - "requires": { - "css-declaration-sorter": "^6.3.1", - "cssnano-utils": "^3.1.0", - "postcss-calc": "^8.2.3", - "postcss-colormin": "^5.3.1", - "postcss-convert-values": "^5.1.3", - "postcss-discard-comments": "^5.1.2", - "postcss-discard-duplicates": "^5.1.0", - "postcss-discard-empty": "^5.1.1", - "postcss-discard-overridden": "^5.1.0", - "postcss-merge-longhand": "^5.1.7", - "postcss-merge-rules": "^5.1.4", - "postcss-minify-font-values": "^5.1.0", - "postcss-minify-gradients": "^5.1.1", - "postcss-minify-params": "^5.1.4", - "postcss-minify-selectors": "^5.2.1", - "postcss-normalize-charset": "^5.1.0", - "postcss-normalize-display-values": "^5.1.0", - "postcss-normalize-positions": "^5.1.1", - "postcss-normalize-repeat-style": "^5.1.1", - "postcss-normalize-string": "^5.1.0", - "postcss-normalize-timing-functions": "^5.1.0", - "postcss-normalize-unicode": "^5.1.1", - "postcss-normalize-url": "^5.1.0", - "postcss-normalize-whitespace": "^5.1.1", - "postcss-ordered-values": "^5.1.3", - "postcss-reduce-initial": "^5.1.2", - "postcss-reduce-transforms": "^5.1.0", - "postcss-svgo": "^5.1.0", - "postcss-unique-selectors": "^5.1.1" - } - }, - "cssnano-utils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", - "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", - "requires": {} - }, - "csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", - "requires": { - "css-tree": "^1.1.2" - } - }, - "csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "requires": { - "mimic-response": "^1.0.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, - "deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==" - }, - "default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", - "requires": { - "execa": "^5.0.0" - } - }, - "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" - }, - "define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==" - }, - "define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "del": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", - "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", - "requires": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - } - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" - }, - "detab": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detab/-/detab-2.0.4.tgz", - "integrity": "sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==", - "requires": { - "repeat-string": "^1.5.4" - } - }, - "detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" - }, - "detect-port": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", - "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", - "requires": { - "address": "^1.0.1", - "debug": "4" - } - }, - "detect-port-alt": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", - "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", - "requires": { - "address": "^1.0.1", - "debug": "^2.6.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "peer": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "requires": { - "path-type": "^4.0.0" - } - }, - "dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" - }, - "dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" - }, - "dns-packet": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.0.tgz", - "integrity": "sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ==", - "requires": { - "@leichtgewicht/ip-codec": "^2.0.1" - } - }, - "dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "requires": { - "utila": "~0.4" - } - }, - "dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - } - }, - "domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" - }, - "domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "requires": { - "domelementtype": "^2.3.0" - } - }, - "domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "requires": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - } - }, - "dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "requires": { - "is-obj": "^2.0.0" - }, - "dependencies": { - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" - } - } - }, - "duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" - }, - "duplexer3": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", - "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==" - }, - "eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "electron-to-chromium": { - "version": "1.4.368", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.368.tgz", - "integrity": "sha512-e2aeCAixCj9M7nJxdB/wDjO6mbYX+lJJxSJCXDzlr5YPGYVofuJwGN9nKg2o6wWInjX6XmxRinn3AeJMK81ltw==" - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" - }, - "emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" - }, - "emoticon": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-3.2.0.tgz", - "integrity": "sha512-SNujglcLTTg+lDAcApPNgEdudaqQFiAbJCqzjNxJkvN9vAwCGi0uu8IUVvx+f16h+V44KCY6Y2yboroc9pilHg==" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "enhanced-resolve": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", - "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, - "entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-module-lexer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz", - "integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==" - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - }, - "escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==" - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - }, - "eta": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/eta/-/eta-2.0.1.tgz", - "integrity": "sha512-46E2qDPDm7QA+usjffUWz9KfXsxVZclPOuKsXs4ZWZdI/X1wpDF7AO424pt7fdYohCzWsIkXAhNGXSlwo5naAg==" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" - }, - "eval": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.8.tgz", - "integrity": "sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==", - "requires": { - "@types/node": "*", - "require-like": ">= 0.1.1" - } - }, - "eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" - }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "dependencies": { - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" - } - } - }, - "express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "requires": { - "safe-buffer": "5.2.1" - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "fast-url-parser": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", - "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", - "requires": { - "punycode": "^1.3.2" - } - }, - "fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "requires": { - "reusify": "^1.0.4" - } - }, - "faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "requires": { - "websocket-driver": ">=0.5.1" - } - }, - "fbemitter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz", - "integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==", - "requires": { - "fbjs": "^3.0.0" - } - }, - "fbjs": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz", - "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==", - "requires": { - "cross-fetch": "^3.1.5", - "fbjs-css-vars": "^1.0.0", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^1.0.35" - } - }, - "fbjs-css-vars": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", - "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" - }, - "feed": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", - "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", - "requires": { - "xml-js": "^1.6.11" - } - }, - "file-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", - "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", - "requires": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "dependencies": { - "schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - } - } - }, - "filesize": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", - "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==" - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "flux": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.4.tgz", - "integrity": "sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw==", - "requires": { - "fbemitter": "^3.0.0", - "fbjs": "^3.0.1" - } - }, - "follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" - }, - "fork-ts-checker-webpack-plugin": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", - "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", - "requires": { - "@babel/code-frame": "^7.8.3", - "@types/json-schema": "^7.0.5", - "chalk": "^4.1.0", - "chokidar": "^3.4.2", - "cosmiconfig": "^6.0.0", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.0", - "glob": "^7.1.6", - "memfs": "^3.1.2", - "minimatch": "^3.0.4", - "schema-utils": "2.7.0", - "semver": "^7.3.2", - "tapable": "^1.0.0" - }, - "dependencies": { - "cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - } - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", - "requires": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" - } - }, - "tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" - } - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "fraction.js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" - }, - "fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "fs-monkey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", - "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" - }, - "get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - } - }, - "get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "requires": { - "pump": "^3.0.0" - } - }, - "github-slugger": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", - "integrity": "sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==" - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "requires": { - "is-glob": "^4.0.1" - } - }, - "glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" - }, - "global-dirs": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", - "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", - "requires": { - "ini": "2.0.0" - }, - "dependencies": { - "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==" - } - } - }, - "global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "requires": { - "global-prefix": "^3.0.0" - } - }, - "global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "requires": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "dependencies": { - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" - }, - "gray-matter": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", - "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", - "requires": { - "js-yaml": "^3.13.1", - "kind-of": "^6.0.2", - "section-matter": "^1.0.0", - "strip-bom-string": "^1.0.0" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - } - } - }, - "gzip-size": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", - "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", - "requires": { - "duplexer": "^0.1.2" - } - }, - "handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==" - }, - "hast-to-hyperscript": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz", - "integrity": "sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==", - "requires": { - "@types/unist": "^2.0.3", - "comma-separated-tokens": "^1.0.0", - "property-information": "^5.3.0", - "space-separated-tokens": "^1.0.0", - "style-to-object": "^0.3.0", - "unist-util-is": "^4.0.0", - "web-namespaces": "^1.0.0" - } - }, - "hast-util-from-parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz", - "integrity": "sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==", - "requires": { - "@types/parse5": "^5.0.0", - "hastscript": "^6.0.0", - "property-information": "^5.0.0", - "vfile": "^4.0.0", - "vfile-location": "^3.2.0", - "web-namespaces": "^1.0.0" - } - }, - "hast-util-parse-selector": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", - "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==" - }, - "hast-util-raw": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-6.0.1.tgz", - "integrity": "sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==", - "requires": { - "@types/hast": "^2.0.0", - "hast-util-from-parse5": "^6.0.0", - "hast-util-to-parse5": "^6.0.0", - "html-void-elements": "^1.0.0", - "parse5": "^6.0.0", - "unist-util-position": "^3.0.0", - "vfile": "^4.0.0", - "web-namespaces": "^1.0.0", - "xtend": "^4.0.0", - "zwitch": "^1.0.0" - }, - "dependencies": { - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - } - } - }, - "hast-util-to-parse5": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz", - "integrity": "sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ==", - "requires": { - "hast-to-hyperscript": "^9.0.0", - "property-information": "^5.0.0", - "web-namespaces": "^1.0.0", - "xtend": "^4.0.0", - "zwitch": "^1.0.0" - } - }, - "hastscript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", - "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", - "requires": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^1.0.0", - "hast-util-parse-selector": "^2.0.0", - "property-information": "^5.0.0", - "space-separated-tokens": "^1.0.0" - } - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" - }, - "history": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", - "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", - "requires": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" - } - }, - "hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "requires": { - "react-is": "^16.7.0" - } - }, - "hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", - "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "html-entities": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", - "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==" - }, - "html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", - "requires": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - }, - "dependencies": { - "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" - } - } - }, - "html-tags": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", - "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==" - }, - "html-void-elements": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz", - "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==" - }, - "html-webpack-plugin": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.1.tgz", - "integrity": "sha512-cTUzZ1+NqjGEKjmVgZKLMdiFg3m9MdRXkZW2OEe69WYVi5ONLMmlnSZdXzGGMOq0C8jGDrL6EWyEDDUioHO/pA==", - "requires": { - "@types/html-minifier-terser": "^6.0.0", - "html-minifier-terser": "^6.0.2", - "lodash": "^4.17.21", - "pretty-error": "^4.0.0", - "tapable": "^2.0.0" - } - }, - "htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, - "http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" - }, - "http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" - }, - "http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - } - }, - "http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", - "requires": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "dependencies": { - "is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==" - } - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "requires": {} - }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==" - }, - "image-size": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz", - "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==", - "requires": { - "queue": "6.0.2" - } - }, - "immediate": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", - "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==" - }, - "immer": { - "version": "9.0.21", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", - "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==" - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==" - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" - }, - "infima": { - "version": "0.2.0-alpha.43", - "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.43.tgz", - "integrity": "sha512-2uw57LvUqW0rK/SWYnd/2rRfxNA5DDNOh33jxF7fy46VWoNhGxiUQyVZHbBMjQ33mQem0cjdDVwgWVAmlRfgyQ==" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "inline-style-parser": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", - "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" - }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "requires": { - "loose-envify": "^1.0.0" - } - }, - "ipaddr.js": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", - "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==" - }, - "is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==" - }, - "is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "requires": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "requires": { - "ci-info": "^2.0.0" - }, - "dependencies": { - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" - } - } - }, - "is-core-module": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", - "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", - "requires": { - "has": "^1.0.3" - } - }, - "is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==" - }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-hexadecimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==" - }, - "is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "requires": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - } - }, - "is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==" - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==" - }, - "is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==" - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" - }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "requires": { - "isobject": "^3.0.1" - } - }, - "is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==" - }, - "is-root": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", - "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==" - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" - }, - "is-whitespace-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", - "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==" - }, - "is-word-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", - "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==" - }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "requires": { - "is-docker": "^2.0.0" - } - }, - "is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" - }, - "jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "requires": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - } - }, - "jest-worker": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", - "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", - "requires": { - "@types/node": "*", - "jest-util": "^29.5.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jiti": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", - "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==" - }, - "joi": { - "version": "17.9.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.9.1.tgz", - "integrity": "sha512-FariIi9j6QODKATGBrEX7HZcja8Bsh3rfdGYy/Sb65sGlZWK/QWesU1ghk7aJWDj95knjXlQfSmzFSPPkLVsfw==", - "requires": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.1", - "@sideway/pinpoint": "^2.0.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "requires": { - "argparse": "^2.0.1" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" - }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==" - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "requires": { - "json-buffer": "3.0.0" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - }, - "klaw-sync": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", - "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", - "requires": { - "graceful-fs": "^4.1.11" - } - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" - }, - "klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==" - }, - "latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "requires": { - "package-json": "^6.3.0" - } - }, - "launch-editor": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", - "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==", - "requires": { - "picocolors": "^1.0.0", - "shell-quote": "^1.7.3" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" - }, - "lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==" - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==" - }, - "loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.curry": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", - "integrity": "sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==" - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" - }, - "lodash.flow": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", - "integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==" - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "requires": { - "tslib": "^2.0.3" - } - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "requires": { - "yallist": "^3.0.2" - } - }, - "lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==" - }, - "lunr-languages": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/lunr-languages/-/lunr-languages-1.12.0.tgz", - "integrity": "sha512-C2z02jt74ymrDocBwxYB4Cr1LNZj9rHGLTH/00+JuoT6eJOSSuPBzeqQG8kjnlPUQe+/PAWv1/KHbDT+YYYRnA==" - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - } - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "peer": true - }, - "mark.js": { - "version": "8.11.1", - "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", - "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==" - }, - "markdown-escapes": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz", - "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==" - }, - "mdast-squeeze-paragraphs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz", - "integrity": "sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==", - "requires": { - "unist-util-remove": "^2.0.0" - } - }, - "mdast-util-definitions": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz", - "integrity": "sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==", - "requires": { - "unist-util-visit": "^2.0.0" - } - }, - "mdast-util-to-hast": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz", - "integrity": "sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA==", - "requires": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "mdast-util-definitions": "^4.0.0", - "mdurl": "^1.0.0", - "unist-builder": "^2.0.0", - "unist-util-generated": "^1.0.0", - "unist-util-position": "^3.0.0", - "unist-util-visit": "^2.0.0" - } - }, - "mdast-util-to-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", - "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==" - }, - "mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" - }, - "memfs": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.0.tgz", - "integrity": "sha512-yK6o8xVJlQerz57kvPROwTMgx5WtGwC2ZxDtOUsnGl49rHjYkfQoPNZPCKH73VdLE1BwBu/+Fx/NL8NYMUw2aA==", - "requires": { - "fs-monkey": "^1.0.3" - } - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" - }, - "mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", - "requires": { - "mime-db": "~1.33.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" - }, - "mini-css-extract-plugin": { - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.5.tgz", - "integrity": "sha512-9HaR++0mlgom81s95vvNjxkg52n2b5s//3ZTI1EtzFb98awsLSivs2LMsVqnQ3ay0PVhqWcGNyDaTE961FOcjQ==", - "requires": { - "schema-utils": "^4.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "schema-utils": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.1.tgz", - "integrity": "sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ==", - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - } - } - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" - }, - "mrmime": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", - "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==" - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", - "requires": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" - } - }, - "mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "requires": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==" - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" - }, - "no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "requires": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "node-emoji": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", - "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", - "requires": { - "lodash": "^4.17.21" - } - }, - "node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" - }, - "node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==" - }, - "normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==" - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "requires": { - "path-key": "^3.0.0" - } - }, - "nprogress": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", - "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==" - }, - "nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "requires": { - "boolbase": "^1.0.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" - }, - "object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==" - }, - "object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - }, - "obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "requires": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - } - }, - "opener": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==" - }, - "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", - "requires": { - "@types/retry": "0.12.0", - "retry": "^0.13.1" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", - "requires": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - } - } - }, - "param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "requires": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", - "requires": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "parse-numeric-range": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", - "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==" - }, - "parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "requires": { - "entities": "^4.4.0" - } - }, - "parse5-htmlparser2-tree-adapter": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", - "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", - "requires": { - "domhandler": "^5.0.2", - "parse5": "^7.0.0" - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==" - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "requires": { - "isarray": "0.0.1" - } - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" - }, - "pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==" - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "requires": { - "find-up": "^4.0.0" - } - }, - "pkg-up": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", - "requires": { - "find-up": "^3.0.0" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==" - } - } - }, - "postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", - "requires": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "postcss-calc": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", - "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", - "requires": { - "postcss-selector-parser": "^6.0.9", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-colormin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", - "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-convert-values": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", - "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", - "requires": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-discard-comments": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", - "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", - "requires": {} - }, - "postcss-discard-duplicates": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", - "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", - "requires": {} - }, - "postcss-discard-empty": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", - "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", - "requires": {} - }, - "postcss-discard-overridden": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", - "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", - "requires": {} - }, - "postcss-discard-unused": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-5.1.0.tgz", - "integrity": "sha512-KwLWymI9hbwXmJa0dkrzpRbSJEh0vVUd7r8t0yOGPcfKzyJJxFM8kLyC5Ev9avji6nY95pOp1W6HqIrfT+0VGw==", - "requires": { - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "requires": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - } - }, - "postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "requires": { - "camelcase-css": "^2.0.1" - } - }, - "postcss-load-config": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", - "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", - "requires": { - "lilconfig": "^2.0.5", - "yaml": "^1.10.2" - } - }, - "postcss-loader": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.2.4.tgz", - "integrity": "sha512-F88rpxxNspo5hatIc+orYwZDtHFaVFOSIVAx+fBfJC1GmhWbVmPWtmg2gXKE1OxJbneOSGn8PWdIwsZFcruS+w==", - "requires": { - "cosmiconfig": "^8.1.3", - "cosmiconfig-typescript-loader": "^4.3.0", - "klona": "^2.0.6", - "semver": "^7.3.8" - }, - "dependencies": { - "cosmiconfig": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", - "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", - "requires": { - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" - } - } - } - }, - "postcss-merge-idents": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-5.1.1.tgz", - "integrity": "sha512-pCijL1TREiCoog5nQp7wUe+TUonA2tC2sQ54UGeMmryK3UFGIYKqDyjnqd6RcuI4znFn9hWSLNN8xKE/vWcUQw==", - "requires": { - "cssnano-utils": "^3.1.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-merge-longhand": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", - "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", - "requires": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^5.1.1" - } - }, - "postcss-merge-rules": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", - "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^3.1.0", - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-minify-font-values": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", - "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-gradients": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", - "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", - "requires": { - "colord": "^2.9.1", - "cssnano-utils": "^3.1.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-params": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", - "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", - "requires": { - "browserslist": "^4.21.4", - "cssnano-utils": "^3.1.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-selectors": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", - "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", - "requires": { - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "requires": {} - }, - "postcss-modules-local-by-default": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", - "requires": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", - "requires": { - "postcss-selector-parser": "^6.0.4" - } - }, - "postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "requires": { - "icss-utils": "^5.0.0" - } - }, - "postcss-nested": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz", - "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==", - "requires": { - "postcss-selector-parser": "^6.0.10" - } - }, - "postcss-normalize-charset": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", - "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", - "requires": {} - }, - "postcss-normalize-display-values": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", - "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-positions": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", - "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-repeat-style": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", - "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-string": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", - "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-timing-functions": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", - "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-unicode": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", - "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", - "requires": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", - "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", - "requires": { - "normalize-url": "^6.0.1", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-whitespace": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", - "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-ordered-values": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", - "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", - "requires": { - "cssnano-utils": "^3.1.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-reduce-idents": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-5.2.0.tgz", - "integrity": "sha512-BTrLjICoSB6gxbc58D5mdBK8OhXRDqud/zodYfdSi52qvDHdMwk+9kB9xsM8yJThH/sZU5A6QVSmMmaN001gIg==", - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-reduce-initial": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", - "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0" - } - }, - "postcss-reduce-transforms": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", - "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-selector-parser": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", - "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - }, - "postcss-sort-media-queries": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.4.1.tgz", - "integrity": "sha512-QDESFzDDGKgpiIh4GYXsSy6sek2yAwQx1JASl5AxBtU1Lq2JfKBljIPNdil989NcSKRQX1ToiaKphImtBuhXWw==", - "requires": { - "sort-css-media-queries": "2.1.0" - } - }, - "postcss-svgo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", - "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", - "requires": { - "postcss-value-parser": "^4.2.0", - "svgo": "^2.7.0" - } - }, - "postcss-unique-selectors": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", - "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", - "requires": { - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - }, - "postcss-zindex": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-5.1.0.tgz", - "integrity": "sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A==", - "requires": {} - }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==" - }, - "pretty-error": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", - "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", - "requires": { - "lodash": "^4.17.20", - "renderkid": "^3.0.0" - } - }, - "pretty-time": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", - "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==" - }, - "prism-react-renderer": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.3.5.tgz", - "integrity": "sha512-IJ+MSwBWKG+SM3b2SUfdrhC+gu01QkV2KmRQgREThBfSQRoufqRfxfHUxpG1WcaFjP+kojcFyO9Qqtpgt3qLCg==", - "requires": {} - }, - "prismjs": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", - "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==" - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "requires": { - "asap": "~2.0.3" - } - }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "property-information": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", - "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", - "requires": { - "xtend": "^4.0.0" - } - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "dependencies": { - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" - } - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" - }, - "pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "requires": { - "escape-goat": "^2.0.0" - } - }, - "pure-color": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz", - "integrity": "sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA==" - }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "requires": { - "side-channel": "^1.0.4" - } - }, - "queue": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", - "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", - "requires": { - "inherits": "~2.0.3" - } - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" - }, - "quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==" - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "range-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==" - }, - "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "dependencies": { - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - } - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" - } - } - }, - "react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "react-base16-styling": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.6.0.tgz", - "integrity": "sha512-yvh/7CArceR/jNATXOKDlvTnPKPmGZz7zsenQ3jUwLzHkNUR0CvY3yGYJbWJ/nnxsL8Sgmt5cO3/SILVuPO6TQ==", - "requires": { - "base16": "^1.0.0", - "lodash.curry": "^4.0.1", - "lodash.flow": "^3.3.0", - "pure-color": "^1.2.0" - } - }, - "react-dev-utils": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", - "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", - "requires": { - "@babel/code-frame": "^7.16.0", - "address": "^1.1.2", - "browserslist": "^4.18.1", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", - "detect-port-alt": "^1.1.6", - "escape-string-regexp": "^4.0.0", - "filesize": "^8.0.6", - "find-up": "^5.0.0", - "fork-ts-checker-webpack-plugin": "^6.5.0", - "global-modules": "^2.0.0", - "globby": "^11.0.4", - "gzip-size": "^6.0.0", - "immer": "^9.0.7", - "is-root": "^2.1.0", - "loader-utils": "^3.2.0", - "open": "^8.4.0", - "pkg-up": "^3.1.0", - "prompts": "^2.4.2", - "react-error-overlay": "^6.0.11", - "recursive-readdir": "^2.2.2", - "shell-quote": "^1.7.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "dependencies": { - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "loader-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==" - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "requires": { - "p-locate": "^5.0.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "requires": { - "p-limit": "^3.0.2" - } - } - } - }, - "react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - } - }, - "react-error-overlay": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", - "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" - }, - "react-fast-compare": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.1.tgz", - "integrity": "sha512-xTYf9zFim2pEif/Fw16dBiXpe0hoy5PxcD8+OwBnTtNLfIm3g6WxhKNurY+6OmdH1u6Ta/W/Vl6vjbYP1MFnDg==" - }, - "react-helmet-async": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.3.0.tgz", - "integrity": "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==", - "requires": { - "@babel/runtime": "^7.12.5", - "invariant": "^2.2.4", - "prop-types": "^15.7.2", - "react-fast-compare": "^3.2.0", - "shallowequal": "^1.1.0" - } - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "react-json-view": { - "version": "1.21.3", - "resolved": "https://registry.npmjs.org/react-json-view/-/react-json-view-1.21.3.tgz", - "integrity": "sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw==", - "requires": { - "flux": "^4.0.1", - "react-base16-styling": "^0.6.0", - "react-lifecycles-compat": "^3.0.4", - "react-textarea-autosize": "^8.3.2" - } - }, - "react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" - }, - "react-loadable": { - "version": "npm:@docusaurus/react-loadable@5.5.2", - "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", - "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", - "requires": { - "@types/react": "*", - "prop-types": "^15.6.2" - } - }, - "react-loadable-ssr-addon-v5-slorber": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", - "integrity": "sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A==", - "requires": { - "@babel/runtime": "^7.10.3" - } - }, - "react-router": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", - "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", - "requires": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - } - }, - "react-router-config": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", - "integrity": "sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==", - "requires": { - "@babel/runtime": "^7.1.2" - } - }, - "react-router-dom": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", - "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", - "requires": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.3.4", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - } - }, - "react-textarea-autosize": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.5.3.tgz", - "integrity": "sha512-XT1024o2pqCuZSuBt9FwHlaDeNtVrtCXu0Rnz88t1jUGheCLa3PhjE1GH8Ctm2axEtvdCl5SUHYschyQ0L5QHQ==", - "requires": { - "@babel/runtime": "^7.20.13", - "use-composed-ref": "^1.3.0", - "use-latest": "^1.2.1" - } - }, - "read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "requires": { - "pify": "^2.3.0" - } - }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "requires": { - "picomatch": "^2.2.1" - } - }, - "reading-time": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", - "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==" - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "requires": { - "resolve": "^1.1.6" - } - }, - "recursive-readdir": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", - "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", - "requires": { - "minimatch": "^3.0.5" - } - }, - "regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" - }, - "regenerate-unicode-properties": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", - "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", - "requires": { - "regenerate": "^1.4.2" - } - }, - "regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, - "regenerator-transform": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", - "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", - "requires": { - "@babel/runtime": "^7.8.4" - } - }, - "regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", - "requires": { - "@babel/regjsgen": "^0.8.0", - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" - } - }, - "registry-auth-token": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", - "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", - "requires": { - "rc": "1.2.8" - } - }, - "registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "requires": { - "rc": "^1.2.8" - } - }, - "regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" - } - } - }, - "relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==" - }, - "remark-emoji": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-2.2.0.tgz", - "integrity": "sha512-P3cj9s5ggsUvWw5fS2uzCHJMGuXYRb0NnZqYlNecewXt8QBU9n5vW3DUUKOhepS8F9CwdMx9B8a3i7pqFWAI5w==", - "requires": { - "emoticon": "^3.2.0", - "node-emoji": "^1.10.0", - "unist-util-visit": "^2.0.3" - } - }, - "remark-footnotes": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-2.0.0.tgz", - "integrity": "sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==" - }, - "remark-mdx": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-1.6.22.tgz", - "integrity": "sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==", - "requires": { - "@babel/core": "7.12.9", - "@babel/helper-plugin-utils": "7.10.4", - "@babel/plugin-proposal-object-rest-spread": "7.12.1", - "@babel/plugin-syntax-jsx": "7.12.1", - "@mdx-js/util": "1.6.22", - "is-alphabetical": "1.0.4", - "remark-parse": "8.0.3", - "unified": "9.2.0" - }, - "dependencies": { - "@babel/core": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.7", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.9", - "@babel/types": "^7.12.7", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", - "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.12.1" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" - }, - "unified": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", - "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", - "requires": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" - } - } - } - }, - "remark-parse": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz", - "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==", - "requires": { - "ccount": "^1.0.0", - "collapse-white-space": "^1.0.2", - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-whitespace-character": "^1.0.0", - "is-word-character": "^1.0.0", - "markdown-escapes": "^1.0.0", - "parse-entities": "^2.0.0", - "repeat-string": "^1.5.4", - "state-toggle": "^1.0.0", - "trim": "0.0.1", - "trim-trailing-lines": "^1.0.0", - "unherit": "^1.0.4", - "unist-util-remove-position": "^2.0.0", - "vfile-location": "^3.0.0", - "xtend": "^4.0.1" - } - }, - "remark-squeeze-paragraphs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz", - "integrity": "sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw==", - "requires": { - "mdast-squeeze-paragraphs": "^4.0.0" - } - }, - "renderkid": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", - "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", - "requires": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", - "requires": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - } - }, - "dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "requires": { - "domelementtype": "^2.2.0" - } - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - }, - "htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - } - } - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==" - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" - }, - "require-like": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", - "integrity": "sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==" - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" - }, - "resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "requires": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" - }, - "resolve-pathname": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" - }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", - "requires": { - "lowercase-keys": "^1.0.0" - } - }, - "retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" - } - }, - "rtl-detect": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.0.4.tgz", - "integrity": "sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ==" - }, - "rtlcss": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-3.5.0.tgz", - "integrity": "sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A==", - "requires": { - "find-up": "^5.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.3.11", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "requires": { - "p-locate": "^5.0.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "requires": { - "p-limit": "^3.0.2" - } - } - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "rxjs": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", - "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", - "requires": { - "tslib": "^2.1.0" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", - "requires": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" - } - }, - "search-insights": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.8.3.tgz", - "integrity": "sha512-W9rZfQ9XEfF0O6ntgQOTI7Txc8nkZrO4eJ/pTHK0Br6wWND2sPGPoWg+yGhdIW7wMbLqk8dc23IyEtLlNGpeNw==", - "peer": true - }, - "section-matter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", - "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", - "requires": { - "extend-shallow": "^2.0.1", - "kind-of": "^6.0.0" - } - }, - "select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" - }, - "selfsigned": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", - "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", - "requires": { - "node-forge": "^1" - } - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "requires": { - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - } - } - }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - } - } - }, - "serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", - "requires": { - "randombytes": "^2.1.0" - } - }, - "serve-handler": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", - "integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==", - "requires": { - "bytes": "3.0.0", - "content-disposition": "0.5.2", - "fast-url-parser": "1.1.3", - "mime-types": "2.1.18", - "minimatch": "3.1.2", - "path-is-inside": "1.0.2", - "path-to-regexp": "2.2.1", - "range-parser": "1.2.0" - }, - "dependencies": { - "path-to-regexp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", - "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==" - } - } - }, - "serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", - "requires": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" - } - } - }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "requires": { - "kind-of": "^6.0.2" - } - }, - "shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" - }, - "shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==" - }, - "shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "sirv": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", - "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==", - "requires": { - "@polka/url": "^1.0.0-next.20", - "mrmime": "^1.0.0", - "totalist": "^1.0.0" - } - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" - }, - "sitemap": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.1.tgz", - "integrity": "sha512-mK3aFtjz4VdJN0igpIJrinf3EO8U8mxOPsTBzSsy06UtjZQJ3YY3o3Xa7zSc5nMqcMrRwlChHZ18Kxg0caiPBg==", - "requires": { - "@types/node": "^17.0.5", - "@types/sax": "^1.2.1", - "arg": "^5.0.0", - "sax": "^1.2.4" - }, - "dependencies": { - "@types/node": { - "version": "17.0.45", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", - "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" - } - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" - }, - "sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", - "requires": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" - } - }, - "sort-css-media-queries": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.1.0.tgz", - "integrity": "sha512-IeWvo8NkNiY2vVYdPa27MCQiR0MN0M80johAYFVxWWXQ44KU84WNxjslwBHmc/7ZL2ccwkM7/e6S5aiKZXm7jA==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "space-separated-tokens": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", - "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==" - }, - "spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "requires": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - } - }, - "spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "requires": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" - }, - "stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" - }, - "state-toggle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz", - "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==" - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" - }, - "std-env": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.3.2.tgz", - "integrity": "sha512-uUZI65yrV2Qva5gqE0+A7uVAvO40iPo6jGhs7s8keRfHCmtg+uB2X6EiLGCI9IgL1J17xGhvoOqSz79lzICPTA==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "requires": { - "ansi-regex": "^6.0.1" - } - } - } - }, - "stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "requires": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==" - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" - }, - "style-to-object": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", - "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", - "requires": { - "inline-style-parser": "0.1.1" - } - }, - "stylehacks": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", - "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", - "requires": { - "browserslist": "^4.21.4", - "postcss-selector-parser": "^6.0.4" - } - }, - "sucrase": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", - "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", - "requires": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "7.1.6", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "dependencies": { - "commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" - }, - "svg-parser": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" - }, - "svgo": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", - "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", - "requires": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^4.1.3", - "css-tree": "^1.1.3", - "csso": "^4.2.0", - "picocolors": "^1.0.0", - "stable": "^0.1.8" - }, - "dependencies": { - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" - }, - "css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", - "requires": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - } - }, - "dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "requires": { - "domelementtype": "^2.2.0" - } - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - } - } - }, - "tailwindcss": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.1.tgz", - "integrity": "sha512-Vkiouc41d4CEq0ujXl6oiGFQ7bA3WEhUZdTgXAhtKxSy49OmKs8rEfQmupsfF0IGW8fv2iQkp1EVUuapCFrZ9g==", - "requires": { - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "color-name": "^1.1.4", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.12", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.17.2", - "lilconfig": "^2.0.6", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.0.9", - "postcss-import": "^14.1.0", - "postcss-js": "^4.0.0", - "postcss-load-config": "^3.1.4", - "postcss-nested": "6.0.0", - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", - "quick-lru": "^5.1.1", - "resolve": "^1.22.1", - "sucrase": "^3.29.0" - }, - "dependencies": { - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "requires": { - "is-glob": "^4.0.3" - } - }, - "postcss-import": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", - "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", - "requires": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - } - } - } - }, - "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" - }, - "terser": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.1.tgz", - "integrity": "sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw==", - "requires": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - } - } - }, - "terser-webpack-plugin": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz", - "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==", - "requires": { - "@jridgewell/trace-mapping": "^0.3.17", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.16.5" - }, - "dependencies": { - "jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" - }, - "thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "requires": { - "any-promise": "^1.0.0" - } - }, - "thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "requires": { - "thenify": ">= 3.1.0 < 4" - } - }, - "thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" - }, - "tiny-invariant": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", - "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" - }, - "tiny-warning": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" - }, - "to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { - "is-number": "^7.0.0" - } - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" - }, - "totalist": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", - "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==" - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "trim": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", - "integrity": "sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ==" - }, - "trim-trailing-lines": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz", - "integrity": "sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==" - }, - "trough": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", - "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==" - }, - "ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" - }, - "ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "peer": true, - "requires": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "dependencies": { - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "peer": true - } - } - }, - "tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, - "type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==" - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "dependencies": { - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - } - } - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", - "peer": true - }, - "ua-parser-js": { - "version": "1.0.36", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.36.tgz", - "integrity": "sha512-znuyCIXzl8ciS3+y3fHJI/2OhQIXbXw9MWC/o3qwyR+RGppjZHrM27CGFSKCJXi2Kctiz537iOu2KnXs1lMQhw==" - }, - "unherit": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz", - "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==", - "requires": { - "inherits": "^2.0.0", - "xtend": "^4.0.0" - } - }, - "unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==" - }, - "unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "requires": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==" - }, - "unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" - }, - "unified": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz", - "integrity": "sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==", - "requires": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" - } - }, - "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "requires": { - "crypto-random-string": "^2.0.0" - } - }, - "unist-builder": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-2.0.3.tgz", - "integrity": "sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==" - }, - "unist-util-generated": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.6.tgz", - "integrity": "sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg==" - }, - "unist-util-is": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", - "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==" - }, - "unist-util-position": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.1.0.tgz", - "integrity": "sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==" - }, - "unist-util-remove": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-2.1.0.tgz", - "integrity": "sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q==", - "requires": { - "unist-util-is": "^4.0.0" - } - }, - "unist-util-remove-position": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz", - "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==", - "requires": { - "unist-util-visit": "^2.0.0" - } - }, - "unist-util-stringify-position": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", - "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", - "requires": { - "@types/unist": "^2.0.2" - } - }, - "unist-util-visit": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", - "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0", - "unist-util-visit-parents": "^3.0.0" - } - }, - "unist-util-visit-parents": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", - "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" - }, - "update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "update-notifier": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", - "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", - "requires": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, - "dependencies": { - "boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "requires": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - } - }, - "cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==" - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" - }, - "widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "requires": { - "string-width": "^4.0.0" - } - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - } - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "requires": { - "punycode": "^2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" - } - } - }, - "url-loader": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", - "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", - "requires": { - "loader-utils": "^2.0.0", - "mime-types": "^2.1.27", - "schema-utils": "^3.0.0" - }, - "dependencies": { - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - } - } - }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", - "requires": { - "prepend-http": "^2.0.0" - } - }, - "use-composed-ref": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.3.0.tgz", - "integrity": "sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==", - "requires": {} - }, - "use-isomorphic-layout-effect": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", - "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", - "requires": {} - }, - "use-latest": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.1.tgz", - "integrity": "sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==", - "requires": { - "use-isomorphic-layout-effect": "^1.1.1" - } - }, - "use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "requires": {} - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" - }, - "utility-types": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", - "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "peer": true - }, - "value-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", - "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" - }, - "vfile": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", - "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", - "requires": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^2.0.0", - "vfile-message": "^2.0.0" - } - }, - "vfile-location": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.2.0.tgz", - "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==" - }, - "vfile-message": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", - "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", - "requires": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^2.0.0" - } - }, - "wait-on": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz", - "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==", - "requires": { - "axios": "^0.25.0", - "joi": "^17.6.0", - "lodash": "^4.17.21", - "minimist": "^1.2.5", - "rxjs": "^7.5.4" - } - }, - "watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "requires": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - } - }, - "wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "requires": { - "minimalistic-assert": "^1.0.0" - } - }, - "web-namespaces": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz", - "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==" - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "webpack": { - "version": "5.79.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.79.0.tgz", - "integrity": "sha512-3mN4rR2Xq+INd6NnYuL9RC9GAmc1ROPKJoHhrZ4pAjdMFEkJJWrsPw8o2JjCIyQyTu7rTXYn4VG6OpyB3CobZg==", - "requires": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "dependencies": { - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - } - } - }, - "webpack-bundle-analyzer": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.8.0.tgz", - "integrity": "sha512-ZzoSBePshOKhr+hd8u6oCkZVwpVaXgpw23ScGLFpR6SjYI7+7iIWYarjN6OEYOfRt8o7ZyZZQk0DuMizJ+LEIg==", - "requires": { - "@discoveryjs/json-ext": "0.5.7", - "acorn": "^8.0.4", - "acorn-walk": "^8.0.0", - "chalk": "^4.1.0", - "commander": "^7.2.0", - "gzip-size": "^6.0.0", - "lodash": "^4.17.20", - "opener": "^1.5.2", - "sirv": "^1.0.7", - "ws": "^7.3.1" - }, - "dependencies": { - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" - } - } - }, - "webpack-dev-middleware": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", - "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", - "requires": { - "colorette": "^2.0.10", - "memfs": "^3.4.3", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "schema-utils": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.1.tgz", - "integrity": "sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ==", - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - } - } - } - }, - "webpack-dev-server": { - "version": "4.13.3", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.13.3.tgz", - "integrity": "sha512-KqqzrzMRSRy5ePz10VhjyL27K2dxqwXQLP5rAKwRJBPUahe7Z2bBWzHw37jeb8GCPKxZRO79ZdQUAPesMh/Nug==", - "requires": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/serve-static": "^1.13.10", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.1", - "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.0.11", - "chokidar": "^3.5.3", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^2.0.0", - "default-gateway": "^6.0.3", - "express": "^4.17.3", - "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.3", - "ipaddr.js": "^2.0.1", - "launch-editor": "^2.6.0", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "rimraf": "^3.0.2", - "schema-utils": "^4.0.0", - "selfsigned": "^2.1.1", - "serve-index": "^1.9.1", - "sockjs": "^0.3.24", - "spdy": "^4.0.2", - "webpack-dev-middleware": "^5.3.1", - "ws": "^8.13.0" - }, - "dependencies": { - "ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "schema-utils": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.1.tgz", - "integrity": "sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ==", - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - } - }, - "ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "requires": {} - } - } - }, - "webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", - "requires": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" - } - }, - "webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==" - }, - "webpackbar": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-5.0.2.tgz", - "integrity": "sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==", - "requires": { - "chalk": "^4.1.0", - "consola": "^2.15.3", - "pretty-time": "^1.1.0", - "std-env": "^3.0.1" - } - }, - "websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "requires": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - } - }, - "websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "requires": { - "isexe": "^2.0.0" - } - }, - "widest-line": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", - "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", - "requires": { - "string-width": "^5.0.1" - } - }, - "wildcard": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" - }, - "wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "requires": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" - }, - "ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==" - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "requires": { - "ansi-regex": "^6.0.1" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "requires": {} - }, - "xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" - }, - "xml-js": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", - "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", - "requires": { - "sax": "^1.2.4" - } - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "peer": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" - }, - "zwitch": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", - "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==" - } - } -} diff --git a/docs/package.json b/docs/package.json deleted file mode 100644 index 7ea02c97cf6..00000000000 --- a/docs/package.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "name": "docs", - "version": "0.0.0", - "private": true, - "scripts": { - "docusaurus": "docusaurus", - "start": "docusaurus start", - "dev": "docusaurus start", - "build": "docusaurus build", - "swizzle": "docusaurus swizzle", - "deploy": "docusaurus deploy", - "clear": "docusaurus clear", - "serve": "docusaurus serve", - "write-translations": "docusaurus write-translations", - "write-heading-ids": "docusaurus write-heading-ids" - }, - "dependencies": { - "@docusaurus/core": "^2.4.3", - "@docusaurus/plugin-client-redirects": "^2.4.3", - "@docusaurus/plugin-content-docs": "^2.4.3", - "@docusaurus/preset-classic": "^2.4.3", - "@easyops-cn/docusaurus-search-local": "^0.36.0", - "@mdx-js/react": "^1.6.22", - "@you54f/theme-github-codeblock": "^0.1.1", - "autoprefixer": "^10.4.14", - "clsx": "^1.2.1", - "postcss": "^8.4.23", - "postcss-import": "^15.1.0", - "prism-react-renderer": "^1.3.5", - "react": "^17.0.2", - "react-dom": "^17.0.2", - "tailwindcss": "^3.3.1" - }, - "devDependencies": { - "@docusaurus/module-type-aliases": "^2.4.3" - }, - "browserslist": { - "production": [ - ">0.5%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - }, - "engines": { - "node": ">=16.14" - } -} diff --git a/docs/params/params.md b/docs/params/params.md deleted file mode 100644 index f588e09f413..00000000000 --- a/docs/params/params.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -slug: /params.md ---- - -# Parameters - -## 02-Client - -The 02-client submodule contains the following parameters: - -| Key | Type | Default Value | -| ---------------- | -------- | ------------------------------------------------- | -| `AllowedClients` | []string | `"06-solomachine","07-tendermint","09-localhost"` | - -### AllowedClients - -The allowed clients parameter defines an allowlist of client types supported by the chain. A client -that is not registered on this list will fail upon creation or on genesis validation. Note that, -since the client type is an arbitrary string, chains they must not register two light clients which -return the same value for the `ClientType()` function, otherwise the allowlist check can be -bypassed. diff --git a/docs/requirements/ics27-requirements.md b/docs/requirements/ics27-requirements.md deleted file mode 100644 index ad13a56f102..00000000000 --- a/docs/requirements/ics27-requirements.md +++ /dev/null @@ -1,118 +0,0 @@ -# Business requirements - -> **TL;DR**: Rather than creating an IBC application to expose cross-chain access to every module's features, the Interchain Accounts feature would allow to leverage the capabilities of an account to access a blockchain's application-specific features. - -## Problem - -Without Interchain Accounts, cross-chain access to chain-specific features (such as staking, sending, voting, etc) has to be built as separate applications on top of the IBC TAO (Transport, Authentication, Ordering) layer. Creating new IBC application standards and implementations for each application-specific feature requires considerable time and resources. Interchain Accounts will allow new chain-specific features to be immediately available over IBC. - -## Objectives - -Provide a way to programmatically create accounts on a destination blockchain (called the host) and control them via transactions over IBC. An IBC packet will take a message from the controller blockchain to the host blockchain where it will be executed. This will allow new features on a blockchain to be immediately supported as IBC transactions, since the (destination blockchain) native messages are encapsulated in an IBC packet in an agnostic way. This will allow all of the modules on a chain to take advantage of the network effects created by the IBC ecosystem. - -## Scope - -| Features | Release | -| --------- | ------- | -| Deterministically create a new interchain account over IBC on the host chain. | v3.0.0 | -| Send over IBC a packet that contains the message to be executed by the interchain account on the host. | v3.0.0 | - -# User requirements - -## Use cases - -### Injective <> Band Chain - -Currently, Injective sends an IBC transaction to Band Chain via their custom IBC oracle module, which is a data request. When this IBC packet is executed on Band Chain, validators on Band Chain fetch prices for 10 different markets. A random selection of validators will post this selection on-chain. Once a minimum quorum has been reached, an IBC packet is sent to Injective with the prices of markets. The roundtrip latency of this flow is around 30 seconds when things go well (no packet timeouts or delays in validation). - -However, Injective wants to minimise as much as possible the latency between real world price updates and price updates on Injective. They can simplify this two-transaction flow to a single transaction using Interchain Accounts: Injective opens an interchain account on Band Chain, which would be able to pay for a continuous set of update transactions and maintain a standing request for the prices of marke. This would simplify the transaction flow to a single transaction, and introduce a simple flow to update the standing request if necessary. - -### Umee <> Cosmos Hub - -Users on the Hub would send their ATOM to Umee. In return, the user gets equivalent amount of meTokens (this token would be a form of a liquid staking token), which could then be staked on the Hub, in some other liquidity pool, etc, in addition to other business logic which Umee could perform on behalf of the users in return for the ATOM. - -Umee then stakes these ATOM tokens on the Hub on behalf of Umee (ATOMs get inflation rewards, etc). Without Interchain Accounts, Umee would have to use validator controlled multisig, because for this flow Umee needs an account on the Hub which can be controlled externally in a decentralised way. With Interchain Accounts, Umee can register an interchain account on the Hub and then receive the staking rewards for the ATOM, figure out distribution back to Umee chain, and send back to the corresponding existing account on Umee. - -### Hub custodial services - -The problem the Cosmos ecosystem faces is fragmentation of services. When a new chain goes live, they need to talk to custodial solutions and exchanges to integrate. Many exchanges and custodial solutions don't want to integrate tens of chains unless paid in advance. - -An alternative is offering the custodial service through the Hub. When a new chain goes live, the tokens of the chain are transferred through IBC to the Hub. This means that the custodial service would just have to integrate with one chain (the Hub), rather with an arbitrary number of them. - -Using Interchain Accounts, a service could be built in which a user sends tokens to an interchain account address on chain `X`, which corresponds to the registered interchain account of chain `X` on the Hub. This account would handle the token transfer to the Hub and then further on to the custodial wallet. - -# Functional requirements - -## Assumptions - -1. Interchain account packets will rarely timeout with application-set values. -2. Cosmos-SDK modules deployed on a chain are not malicious. -3. Authentication modules may implement their own permissioning scheme. - -## Features - -### 1 - Configuration - -| ID | Description | Verification | Status | Release | -| --- | ----------- | ------------ | ------ | ------- | -| 1.01 | A chain shall have the ability to enable or disable Interchain Accounts controller functionality in the genesis state. | The controller parameters have a [flag](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/types/host.pb.go#L30) to enable/disable the controller submodule, and this flag [is stored during genesis initialization](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/params.go#L24). | `Verified` | v3.0.0 | -| 1.02 | A chain shall have the ability to export the Interchain Accounts controller genesis state. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go#L47) | `Verified` | v3.0.0 | -| 1.03 | A chain shall have the ability to initialize the Interchain Accounts controller genesis state. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go#L10) | `Verified` | v3.0.0 | -| 1.04 | A chain shall have the ability to set the Interchain Accounts controller parameters when upgrading or via proposal. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/module_test.go#L33) | `Verified` | v3.0.0 | -| 1.05 | A chain shall have the ability to enable or disable Interchain Accounts host functionality in the genesis state. | The host parameters have a [flag](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/types/host.pb.go#L30) to enable/disable the host submodule, and this flag [is stored during genesis initialization](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/params.go#L31) | `Verified` | v3.0.0 | -| 1.06 | A chain shall have the ability to export the Interchain Accounts host genesis state. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go#L46) | `Verified` | v3.0.0 | -| 1.07 | A chain shall have the ability to initialize the Interchain Accounts host genesis state. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go#L10) | `Verified` | v3.0.0 | -| 1.08 | A chain shall have the ability to set the Interchain Accounts host parameters when upgrading or via proposal. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/module_test.go#L33) | `Verified` | v3.0.0 | -| 1.09 | The host chain shall have the ability to whitelist what types of messages or transactions that it chooses to facilitate (e.g. it can decide that registered interchain accounts cannot execute staking messages). | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/params_test.go#L5) | `Verified` | v3.0.0 | - -### 2 - Registration - -| ID | Description | Verification | Status | Release | -| --- | ----------- | ------------ | ------ | ------- | -| 2.01 | The controller chain can programmatically create interchain accounts on the host chain that shall be controlled only by the owner account on the controller chain. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/account_test.go#L10) | `Verified` | v3.0.0 | -| 2.02 | An interchain account shall be created by any actor without the approval of a third party (e.g. chain governance). | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/account_test.go#L10) | `Verified` | v3.0.0 | - -### 3 - Control - -| ID | Description | Verification | Status | Release | -| --- | ----------- | ------------ | ------ | ------- | -| 3.01 | The controller chain can programmatically control the interchain account by submitting transactions to be executed on the host chain on the behalf of the interchain account. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go#L29) | `Verified` | v3.0.0 | -| 3.02 | Under no circumstances shall the owner account on the controller chain irretrievably lose control over the registered interchain account on the host chain. | If the channel between controller and host closes, then [a relayer can open a new channel on the existing controller port](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/account.go#L16-L17). | `Verified` | v3.0.0 | - -### 4 - Host execution - -| ID | Description | Verification | Status | Release | -| --- | ----------- | ------------ | ------ | ------- | -| 4.01 | Transactions shall be executed by an interchain account on the host chain in exactly the same order in which they are submitted by the controller chain. | IBC packets with SDK messages will be sent from the controller to the host over an [ordered channel](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/account.go#L60). | `Verified` | v3.0.0 | -| 4.02 | The host shall execute only messages in the allow list. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/relay_test.go#L340) | `Verified` | v3.0.0 | -| 4.03 | The controller chain shall know how the host chain will handle the transaction bytes in advance. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go#L109-L133) | `Verified` | v3.0.0 | -| 4.04 | Each transaction submitted by the controller chain shall be executed only once by the interchain account on the host chain. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/relay_test.go#L248) | `Verified` | v3.0.0 | - -# Non-functional requirements - -## 5 - Security - -| ID | Description | Verification | Status | Release | -| -- | ----------- | ------------ | ------ | ------- | -| 5.01 | There shall be no means for the interchain account to execute transactions that have not been submitted first by the respective owner account on the controller chain. |[Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/relay_test.go#L361) | `Verified` | v3.0.0 | -| 5.02 | Every interchain account on the host chain shall have one and only one respective owner account on the controller chain. | The interchain account on the host [is generated using the host connection ID and the address of the owner on the controller](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/handshake.go#L73-L76). | `Verified` | v3.0.0 | -| 5.03 | The owner account on a controller chain shall not be able to control interchain accounts registered by other owner accounts on the same controller chain. | Before the host logic executes the received messages, it [retrieves the interchain account associated with the port ID](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/relay.go#L94) over which it received the message. For owner address B to be able to execute a message with the interchain account registered with owner address A, it would need to send the messages over a channel that binds to a port ID that contains the owner address A, and since we have assumption number 3, this should not be allowed by applications. | `Verified` | v3.0.0 | -| 5.04 | A controller chain shall not be able to control interchain accounts registered by owner accounts on different controller chains. | Same as 5.03. | `Verified` | v3.0.0 | -| 5.05 | Each interchain account on the host chain is owned by a single owner account on the controller chain. It shall not be possible to register a second interchain account with the same owner account on the controller chain. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/account_test.go#L42) | `Verified` | v3.0.0 | - -# External interface requirements - -## 6 - CLI - -| ID | Description | Verification | Status | Release | -| -- | ----------- | ------------ | ------ | ------- | -| 6.01 | There shall be a CLI command available to query the host parameters. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/client/cli/query.go#L22) | `Verified` | v3.0.0 | -| 6.02 | There shall be a CLI command available to query the receive packet events on the host chain to check the result of the execution of the message on the host. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/client/cli/query.go#L51) | `Verified` | v3.0.0 | -| 6.03 | There shall be a CLI command available to query the controller parameters. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/client/cli/query.go#L15) | `Verified` | v3.0.0 | - -## 7 - Application developers - -| ID | Description | Verification | Status | Release | -| -- | ----------- | ------------ | ------ | ------- | -| 7.01 | An IBC application developer shall be able to develop an Interchain Accounts authentication module that can register interchain accounts. | The [`RegisterInterchainAccount` function](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/account.go#L18) is the entry point to registering an interchain account. | `Verified` | v3.0.0 | -| 7.02 | An IBC application developer shall be able to develop an Interchain Accounts authentication module that can send messages from the controller to the host. | The [`SendTx` function](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/relay.go#L18) takes pre-built packet data containing messages to be executed on the host chain from an authentication module and attempts to send the packet. | `Verified` | v3.0.0 | diff --git a/docs/requirements/ics27-v2-requirements.md b/docs/requirements/ics27-v2-requirements.md deleted file mode 100644 index d3acdc5fd60..00000000000 --- a/docs/requirements/ics27-v2-requirements.md +++ /dev/null @@ -1,87 +0,0 @@ -# Business requirements - -> **TL;DR**: The lack of a default underlying app (previously called the *authentication module*), and the need to separate application and authentication concerns were recognised as primary reasons for the slow adoption of ICS 27 Interchain Accounts (ICA). - -## Problem - -We believe that the lack of controller chains so far have been because: - -- We did not develop a standardized authentication module, which created a bottleneck for chains looking to integrate the controller submodule. -- We did not have a clear understanding of all the use cases ICA would facilitate. -- We expected more chains to want to design custom authentication for ICA. -- Coupling ICA authentication and application logic was a misdesign. - -## Objectives - -- Make controller functionality integration in a chain easier. -- Introduce a message server in the controller submodule that exposes APIs for interchain account registration and control. -- Once application callbacks are implemented (via ADR 008) deprecate the APIs introduced in ibc-go v3.0.0. - -## Scope - -| Features | Release | -| --------- | ------- | -| Register interchain accounts and send transactions to host chain via message passing. | v6.0.0 | -| Support application callbacks with message server in controller submodule (requires ADR 008). | N/A | - -# User requirements - -## Use cases - -### Custom authentication module needs to access IBC packet callbacks - -Application developers of custom authentication modules that wish to consume IBC packet callbacks and react upon packet acknowledgements or timeouts must continue using the controller submodule's legacy APIs. - -### Custom authentication module does not need access to IBC packet callbacks - -The authentication module should interact with the controller submodule via the message server for registering interchain accounts and sending messages to it. - -### No need for custom authentication module - -Chains not only want individual accounts to be able to use Interchain Accounts, but also for generic Cosmos SDK authentication modules such as `x/gov` and `x/group` to be able to register an interchain account and send messages. An example use case with `x/gov`: the Cosmos Hub (controller), upon governance authorization, sends some of its inflationary rewards to Osmosis (host) to provide liquidity and purchase ATOM GAMM shares, which are then sent back to the Hub in one flow. - -# Functional requirements - -## Assumptions - -No further assumptions besides the ones listed in the v1 requirements document. - -## Known limitations - -1. Custom authentication modules that wish to consume IBC packet callbacks need to use the legacy APIs until ADR 008 is implemented. - -## Terminology - -See section [Definitions](https://github.com/cosmos/ibc/blob/main/spec/app/ics-027-interchain-accounts/README.md#definitions) in ICS 27 spec. - -## Features - -### 1 - Registration - -| ID | Description | Verification | Status | Release | -| --- | ----------- | ------------ | ------ | ------- | -| 1.01 | An application shall have the ability to use an RPC endpoint to create interchain accounts on the host chain. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v6.0.0/modules/apps/27-interchain-accounts/controller/keeper/msg_server_test.go#L31) | `Verified` | v6.0.0 | - -### 2 - Control - -| ID | Description | Verification | Status | Release | -| --- | ----------- | ------------ | ------ | ------- | -| 2.01 | An application shall have the ability to use an RPC endpoint to submit transactions to be executed on the host chain on the behalf of the interchain account. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v6.0.0/modules/apps/27-interchain-accounts/controller/keeper/msg_server_test.go#L31) | `Verified` | v6.0.0 | - -# Non-functional requirements - -## 3 - Migration - -| ID | Description | Verification | Status | Release | -| -- | ----------- | ------------ | ------ | ------- | -| 3.01 | Chains shall be able to run a migration to assign ownership of the channel capability of a custom authentication module to the ICS 27 controller submodule. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v6.0.0/modules/apps/27-interchain-accounts/controller/migrations/v6/migrations_test.go#L89) | `Verified` | v6.0.0 | - -# External interface requirements - -## 4 - CLI - -### Transaction - -| ID | Description | Verification | Status | Release | -| -- | ----------- | ------------ | ------ | ------- | -| 4.01 | There shall be a CLI command available to generate the Interchain Accounts packet data required to send. | [CLI](https://github.com/cosmos/ibc-go/blob/v6.0.0/modules/apps/27-interchain-accounts/host/client/cli/tx.go#L21) | `Verified` | v6.0.0 | diff --git a/docs/requirements/ics29-v1-requirements.md b/docs/requirements/ics29-v1-requirements.md deleted file mode 100644 index 65c76dc4cc9..00000000000 --- a/docs/requirements/ics29-v1-requirements.md +++ /dev/null @@ -1,177 +0,0 @@ -# Business requirements - -> **TL;DR**: There is no general incentivization mechanism to reward relayers for their service ensuring Interchain liveness. - -## Problem - -The Interchain dream will never scale unless there is a clear way to incentivize relayers. An interface that can be easily adopted by any applications is needed, without precluding chains that do not use tokens. - -Though IBC does not depend on relayer operators for transaction verification, the relayer infrastructure ensures liveness of the Interchain network — operators listen for packets sent through channels opened between chains, and perform the vital service of ferrying these packets (and proof of the transaction on the sending chain/receipt on the receiving chain) to the clients on each side of the channel. Though relaying is permissionless and completely decentralized and accessible, it does come with operational costs. Running full nodes to query transaction proofs and paying for transaction fees associated with IBC packets are two of the primary cost burdens which have driven the overall discussion on a general incentivization mechanism for relayers. - -## Objectives - -Provide a general fee payment design that can be adopted by any ICS application protocol as middleware. - -## Scope - -| Features | Release | -| --------- | ------- | -| Incentivize timely delivery of a packet (successfully submit `MsgRecvPacket`). | v1 | -| Incentivize relaying acknowledgement for a packet (successfully submit `MsgAcknowledgement`). | v1 | -| Incentivize relaying timeout for a packet when the timeout has expired before packet is delivered (successfully submit `MsgTimeout`). | v1 | -| Enable permissionless or permissioned relaying. | v1 | -| Allow opt-in for chains (an application with fee support on chain A could connect to the couterparty application without fee support on chain B). | v1 | - -# User requirements - -## Use cases - -- A packet already sent may be incentivized for one or more of the messages `MsgRecvPacket`, `MsgAcknowledgement`, `MsgTimeout`. -- The next packet to be sent may be incentivized for one or more of the messages `MsgRecvPacket`, `MsgAcknowledgement`, `MsgTimeout`. - -# Functional requirements - -## Assumptions - -1. Relayer addresses should not be forgeable. - -## Known limitations - -1. Without channel upgradability it is not possible to use fee incentivization on an existing channel. - -## Terminology - -See section [Definitions](https://github.com/cosmos/ibc/tree/main/spec/app/ics-029-fee-payment#definitions) in ICS 29 spec. - -## Features - -### 1 - Configuration - -| ID | Description | Verification | Status | -| --- | ----------- | ------------ | ------ | -| 1.02 | A chain shall have the ability to export the fee middleware genesis state. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/genesis_test.go#L69) | `Verified` | -| 1.03 | A chain shall have the ability to initialize the fee middleware genesis state. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/genesis_test.go#L9) | `Verified` | - -### 2 - Payee registration - -| ID | Description | Verification | Status | -| --- | ----------- | ------------ | ------ | -| 2.01 | A relayer shall have the ability to register for a channel an optional payee address to which fees shall be distributed for successful relaying `MsgAcknowledgement` and `MsgTimeout`. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L23) | `Verified` | -| 2.02 | The payee address shall only be registered if the channel exist. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L28) | `Verified` | -| 2.03 | The payee address shall only be registered if the channel is fee enabled. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L35) | `Verified` | -| 2.04 | The payee address shall only be registered if the address is a valid `Bech32` address. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L42) | `Verified` | -| 2.05 | The payee address shall only be registered if the address is not blocked. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L49) | `Verified` | - -### 3 - Counterparty payee registration - -| ID | Description | Verification | Status | -| --- | ----------- | ------------ | ------ | -| 3.01 | A relayer shall have the ability to register a counterparty payee to which fees shall be distributed for successful relaying of `MsgRecvPacket`. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L102) | `Verified` | -| 3.02 | The counterparty payee address shall only be registered if the channel exists. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L115) | `Verified` | -| 3.03 | The counterparty payee address shall only be registered if the channel is fee enabled. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L122) | `Verified` | -| 3.04 | The counterparty payee address may be an arbitrary string (since the counterparty chain may not be Cosmos-SDK based). | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L42) | `Verified` | - -### 4 - Fee incentivization - -#### Synchronously - -| ID | Description | Verification | Status | -| --- | ----------- | ------------ | ------ | -| 4.01 | If a channel is fee-enabled, the next sequence packet may be incentivized. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L178) | `Verified` | -| 4.02 | If the fee module is not locked, the next sequence packet may be incentivized. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L210) | `Verified` | -| 4.03 | The next sequence packet may be incentivized for some or all of `MsgRecvPacket`, `MsgAcknowledgement`, `MsgTimeout`. | Fees for any of the messages may be zero, but [not all of them](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/types/fee.go#L87). | `Verified` | -| 4.04 | A blocked account address shall not be allowed to incentivize the next sequence packet. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L239) | `Verified` | -| 4.05 | A non-valid `Bech32` account address shall not be allowed to incentivize the next sequence packet. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L225) | `Verified` | -| 4.06 | The next sequence packet may be incentivized by multiple account addresses. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L183) | `Verified` | -| 4.07 | The next sequence packet shall only be incentivized with valid coin denominations. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L246-L266) | `Verified` | - -#### Aynchronously - -| ID | Description | Verification | Status | -| --- | ----------- | ------------ | ------ | -| 4.08 | Only packets that have been sent may be incentivized. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L376) | `Verified` | -| 4.09 | A packet sent may be incentivized for some or all of `MsgRecvPacket`, `MsgAcknowledgement`, `MsgTimeout`. | Fees for any of the messages may be zero, but [not all of them](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/types/fee.go#L87). | `Verified` | -| 4.10 | Only packets that have not gone through the packet life cycle (i.e. have not been acknowledged or timed out yet) may be incentivized. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L382-L410) | `Verified` | -| 4.11 | If a channel exists, a packet sent may be incentivized. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L365) | -| 4.12 | If a channel is fee-enabled, a packet sent may be incentivized. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L357) | `Verified` | -| 4.13 | If the fee module is not locked, a packet sent may be incentivized. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L350) | `Verified` | -| 4.14 | A non-valid `Bech32` account address shall not be allowed to incentivize a packet sent. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L412) | `Verified` | -| 4.15 | An account that does not exist shall not be allowed to incentivize a packet sent. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L419) | `Verified` | -| 4.16 | A blocked account shall not be allowed to incentivize a packet sent. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/msg_server_test.go#L426) | `Verified` | - -### 5 - Fee distribution - -| ID | Description | Verification | Status | -| --- | ----------- | ------------ | ------ | -| 5.01 | Fee distribution shall occurr on the source chain from which packets originate. | Either in [`OnAcknowledgementPacket`](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/ibc_middleware.go#L288) or in [`OnTimeoutPacket`](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/ibc_middleware.go#L330). | `Verified` | - -#### `OnAcknowledgementPacket` - -| ID | Description | Verification | Status | -| --- | ----------- | ------------ | ------ | -| 5.02 | Fees for successful relaying of `MsgAcknowledgement` shall be distributed to the relayer address (or its associated payee address if one has been registered). | If a payee address exists for the relayer address, then [fees are distributed to the payee address](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/ibc_middleware.go#L288); otherwise [fees are distributed to the relayer address](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/ibc_middleware.go#L277). | `Verified` | -| 5.03 | Fees for successful relaying of `MsgRecvPacket` shall be distributed to the payee address of the relayer address. | [Fees are distributed to the payee address registered on the counterparty chain](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/escrow.go#L93) if it is a valid `Bech32` address and is not a blocked address. | `Verified` | - -#### `OnTimeoutPacket` - -| ID | Description | Verification | Status | -| --- | ----------- | ------------ | ------ | -| 5.05 | Fees for successful relaying of `MsgTimeout` shall be distributed to the relayer address (or its associated payee address if one has been registered). | If a payee address exists for the relayer address, then [fees are distributed to the payee address](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/ibc_middleware.go#L330); otherwise [fees are distributed to the relayer address](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/ibc_middleware.go#L319). | `Verified` | - -### 6 - Fee refunding - -#### `OnAcknowledgementPacket` - -| ID | Description | Verification | Status | -| --- | ----------- | ------------ | ------ | -| 6.01 | On successful processing of `MsgAcknowledgement`, fees for successful relay of `MsgTimeout` shall be refunded. | [Fees are refunded is the refund address is a valid `Bech32` address](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/escrow.go#L103). | `Verified` | -| 6.02 | On successful processing of `MsgAcknowledgement`, if fees for successful relay of `MsgRecvPacket` cannot be distributed, then they should be refunded. | [Fees are refunded](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/escrow.go#L96) if the payee address registered on the counterparty chain for the relayer is either [invalid](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/escrow_test.go#L105) or a [blocked address](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/escrow_test.go#L120). | `Verified` | - -#### `OnTimeoutPacket` - -| ID | Description | Verification | Status | -| --- | ----------- | ------------ | ------ | -| 6.03 | On successful processing of `MsgTimeout`, fees for successful relay of `MsgRecvPacket` shall be refunded. | [Fees are refunded is the refund address is a valid `Bech32` address](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/escrow.go#L146). | `Verified` | -| 6.04 | On successful processing of `MsgTimeout`, fees for successful relay of `MsgAcknowledgement` shall be refunded. | [Fees are refunded is the refund address is a valid `Bech32` address](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/escrow.go#L149). | `Verified` | - -#### Channel closure - -| ID | Description | Verification | Status | -| --- | ----------- | ------------ | ------ | -| 6.04 | Packet fees are refunded on channel closure. | Both on [`OnChanCloseInit`](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/ibc_middleware.go#L182) and [`OnChanCloseConfirm`](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/ibc_middleware.go#L207). | `Verified` | - -# Non-functional requirements - -## 7 - Security - -| ID | Description | Verification | Status | -| -- | ----------- | ------------ | ------ | -| 7.01 | If the escrow account does not have sufficient funds while distributing fees in `OnAcknowledgementPacket`, the fee module shall become locked. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/escrow_test.go#L85) | `Verified` | -| 7.02 | If the escrow account does not have sufficient funds while distributing fees in `OnTimeoutPacket`, the fee module shall become locked. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/escrow_test.go#L236) | `Verified` | -| 7.03 | If the escrow account does not have sufficient funds while refunding fees in channel closure, the fee module shall become locked. | [Acceptance test](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/keeper/escrow_test.go#L377) | `Verified` | - -# External interface requirements - -## 8 - CLI - -### Query - -| ID | Description | Verification | Status | -| -- | ----------- | ------------ | ------ | -| 8.01 | There shall be a CLI command available to query for the incentivization of an unrelayed packet by port ID, channel ID and packet sequence. | [CLI](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/client/cli/query.go#L64) | `Verified` | -| 8.02 | There shall be a CLI command to query for the incentivization of all unrelayed packets on all open channels. | [CLI](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/client/cli/query.go#L64) | `Verified` | -| 8.03 | There shall be a CLI command available to query for the total fees for `MsgRecvPacket` for a given port ID, channel ID and packet sequence. | [CLI](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/client/cli/query.go#L105) | `Verified` | -| 8.04 | There shall be a CLI command available to query for the total fees for `MsgAcknowledgement` for a given port ID, channel ID and packet sequence. | [CLI](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/client/cli/query.go#L151) | `Verified` | -| 8.05 | There shall be a CLI command available to query for the total fees for `MsgTimeout` for a given port ID, channel ID and packet sequence. | [CLI](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/client/cli/query.go#L197) | `Verified` | -| 8.06 | There shall be a CLI command available to query for the payee address registered for a relayer for a specific channel ID. | [CLI](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/client/cli/query.go#243) | `Verified` | -| 8.07 | There shall be a CLI command available to query for the counterparty payee address registered for a relayer for a specific channel ID. | [CLI](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/client/cli/query.go#282) | `Verified` | -| 8.08 | There shall be a CLI command available to query if a channel is fee-enabled for a port ID and channel ID. | [CLI](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/client/cli/query.go#L362) | `Verified` | -| 8.09 | There shall be a CLI command available to query for all the unrelayed incentivized packets in a channel by a port ID and channel ID. | [CLI](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/client/cli/query.go#L397) | `Verified` | - -### Transaction - -| ID | Description | Verification | Status | -| -- | ----------- | ------------ | ------ | -| 8.10 | There shall be a CLI command available to register a payee address for a channel by port ID and channel ID. | [CLI](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/client/cli/tx.go#L26) | `Verified` | -| 8.11 | There shall be a CLI command available to register a counterparty payee address for a channel by port ID and channel ID. | [CLI](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/client/cli/tx.go#L51) | `Verified` | -| 8.12 | There shall be a CLI command available to incentivize a packet by port ID, channel ID and packet sequence. | [CLI](https://github.com/cosmos/ibc-go/blob/v4.0.0/modules/apps/29-fee/client/cli/tx.go#L76) | `Verified` | diff --git a/docs/requirements/localhost-requirements.md b/docs/requirements/localhost-requirements.md deleted file mode 100644 index f467099ab09..00000000000 --- a/docs/requirements/localhost-requirements.md +++ /dev/null @@ -1,69 +0,0 @@ - - -# Business requirements - -The localhost client provides a unified interface to interact with different applications on a single chain. - -## Problem - -Currently applications, or smart contracts, on a single chain cannot communicate through a single interface. This means a user must interact with each application or smart contract directly which can be cumbersome, especially when a user wants to interact with many applications on one chain. - -## Objectives - -To provide a single interface in line with IBC application layer semantics, that enables a user to interact with multiple different applications or smart contracts remotely on a given blockchain. - -## Scope - -| Features | Release | -| --------- | ------- | -| To interface with applications or smart contracts on a blockchain through the IBC application layer | v7.1.0 | -| To use the localhost client without requiring third party relayer infrastructure | N/A | - -# User requirements - -## Use cases - -### Interacting with Smart Contracts - -Many IBC connected blockchains utilise smart contracts, these could be written in rust, solidity or javascript depending on the smart contract platform being used. Through the localhost client, a user can interact with and call into smart contracts by sending ibc messages from the localhost client to the smart contract. - -On Agoric, a planned use case is for managing delegations and staking with smart contracts on a given chain. MsgDelegate, MsgUndelegate, MsgBeginRedelegate messages would be sent using the localhost client to the staking module. The same interface could be used to manage staking cross chain, sending the same messages through IBC to an interchain account. - -### Interoperability Infrastructure - -Polymer plans to leverage the localhost client with multiple connections as part of their architecture to connect chains not using Tendermint or the Cosmos SDK to IBC enabled chains. Polymer will act as a hub connecting multiple blockchains together. - -# Functional requirements - -## Assumptions and dependencies - -1. Chains utilising the localhost client must be using an ibc-go release in the v7 line. -2. The channel behaviour of a localhost client will be as ICS 04 specifies. - -## Features - -### 1 - Configuration - -| ID | Description | Verification | Status | Release | -| -- | ----------- | ------------ | ------ | ------- | -| 1.01 | The localhost client shall have a client ID of the string `09-localhost`. | [Localhost client is created with client ID `09-localhost`](https://github.com/cosmos/ibc-go/blob/release/v7.1.x/modules/core/02-client/keeper/keeper.go#L60). | `Verified` | v7.1.0 | -| 1.02 | The localhost client shall have a sentinel connection ID of the string `connection-localhost`. | [Creation of sentinel connection with ID `connection-localhost`](https://github.com/cosmos/ibc-go/blob/release/v7.1.x/modules/core/03-connection/keeper/keeper.go#L200). | `Verified` | v7.1.0 | -| 1.03 | Only 1 localhost connection is required | Localhost connection handshakes are forbidden in [Init](https://github.com/cosmos/ibc-go/blob/release/v7.1.x/modules/core/03-connection/types/msgs.go#L47) and [Try](https://github.com/cosmos/ibc-go/blob/release/v7.1.x/modules/core/03-connection/types/msgs.go#L110). | `Verified` | v7.1.0 | -| 1.04 | When the localhost client is initialised the consensus state must be `nil`. | [Error is returned if consensus state is not `nil`](https://github.com/cosmos/ibc-go/blob/release/v7.1.x/modules/light-clients/09-localhost/client_state.go#L57). | `Verified` | v7.1.0 | -| 1.05 | The localhost client can be added to a chain through an upgrade. | [Automatic migration handler configured in core IBC module to set the localhost `ClientState` and sentinel `ConnectionEnd` in state.](https://github.com/cosmos/ibc-go/blob/release/v7.1.x/modules/core/module.go#L132-L145). | `Verified` | v7.1.0 | -| 1.06 | A chain can enable the localhost client by initialising the client in the genesis state. | [`InitGenesis` handler in 02-client](https://github.com/cosmos/ibc-go/blob/release/v7.1.x/modules/core/02-client/genesis.go#L52) and [`InitGenesis` handler in 03-connection](https://github.com/cosmos/ibc-go/blob/release/v7.1.x/modules/core/03-connection/genesis.go#L23). | `Verified` | v7.1.0 | - -### 2 - Operation - -| ID | Description | Verification | Status | Release | -| -- | ----------- | ------------ | ------ | ------- | -| 2.01 | A user of the localhost client can send IBC messages to an application on the same chain. | [e2e test with transfer](https://github.com/cosmos/ibc-go/blob/main/e2e/tests/transfer/localhost_test.go#L32). | `Verified`| v7.1.0 | -| 2.02 | A user can use the localhost client through the existing IBC application module interfaces. | [e2e test with transfer](https://github.com/cosmos/ibc-go/blob/main/e2e/tests/transfer/localhost_test.go#L32). | `Verified` | v7.1.0 | - -# External interface requirements - -## 3 - CLI - -| ID | Description | Verification | Status | Release | -| -- | ----------- | ------------ | ------ | ------- | -| 3.01 | Existing CLI interfaces used with IBC application modules shall be useable with the localhost client. | Manual test | `Verified` | v7.1.0 | diff --git a/docs/requirements/requirements-template.md b/docs/requirements/requirements-template.md deleted file mode 100644 index 6afd9961bf8..00000000000 --- a/docs/requirements/requirements-template.md +++ /dev/null @@ -1,53 +0,0 @@ - - -# Business requirements - - - - - -## Problem - - - -## Objectives - - - -## Scope - - - - - -# User requirements - -## Use cases - - - -# Functional requirements - - - -## Assumptions and dependencies - - - -## Features - - - -# External interface requirements - - - -# Non-functional requirements - - \ No newline at end of file diff --git a/docs/sidebars.js b/docs/sidebars.js deleted file mode 100644 index 7d1ce520638..00000000000 --- a/docs/sidebars.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Creating a sidebar enables you to: - - create an ordered group of docs - - render a sidebar for each doc of that group - - provide next/previous navigation - - The sidebars can be generated from the filesystem, or explicitly defined here. - - Create as many sidebars as you want. - */ - -// @ts-check - -/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ -const sidebars = { - // By default, Docusaurus generates a sidebar from the docs folder structure - defaultSidebar: [ - { type: "autogenerated", dirName: "." }, - { - type: "category", - label: "Resources", - collapsed: false, - items: [ - { - type: "link", - label: "IBC Specification", - href: "https://github.com/cosmos/ibc", - }, - { - type: "link", - label: "Protobuf Documentation", - href: "https://buf.build/cosmos/ibc/docs/main", - }, - { - type: "link", - label: "Tutorials", - href: "https://tutorials.cosmos.network", - }, - { - type: "link", - label: "Awesome Cosmos", - href: "https://github.com/cosmos/awesome-cosmos", - }, - { - type: "link", - label: "ibc-rs", - href: "https://github.com/cosmos/ibc-rs", - }, - ], - }, - ], - - // But you can create a sidebar manually - /* - tutorialSidebar: [ - 'intro', - 'hello', - { - type: 'category', - label: 'Tutorial', - items: ['tutorial-basics/create-a-document'], - }, - ], - */ -}; - -module.exports = sidebars; diff --git a/docs/src/css/base.css b/docs/src/css/base.css deleted file mode 100644 index e6d485266f8..00000000000 --- a/docs/src/css/base.css +++ /dev/null @@ -1,32 +0,0 @@ -/* - Copied from https://github.com/ignite/cli/blob/develop/docs/src/css/base.css -*/ - -@layer base { - html { - @apply font-inter; - font-feature-settings: 'kern', 'liga', 'calt', 'zero' 0; - -webkit-font-feature-settings: 'kern', 'liga', 'calt', 'zero' 0; - text-size-adjust: 100%; - -moz-osx-font-smoothing: grayscale; - font-smoothing: antialiased; - font-variant-ligatures: contextual common-ligatures; - font-kerning: normal; - text-rendering: optimizeLegibility; - - @supports (font-variation-settings: normal) { - @apply font-intervar - } - } - - *, - *::before, - *::after { - box-sizing: border-box; - margin: 0; - } - - svg { display: inline; } - - ::selection{} -} \ No newline at end of file diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css deleted file mode 100644 index b7fab70954b..00000000000 --- a/docs/src/css/custom.css +++ /dev/null @@ -1,524 +0,0 @@ -/* - Slighlty modified version of https://github.com/ignite/cli/blob/develop/docs/src/css/custom.css -*/ - -@import "tailwindcss/base"; -@import "./fonts.css"; -@import "./base.css"; -@import "tailwindcss/components"; -@import "tailwindcss/utilities"; - -/* You can override the default Infima variables here. */ -:root { - --ifm-color-primary: #5064fb; - --ifm-color-primary-dark: theme(colors.gray.1000); - --ifm-color-primary-darker: theme(colors.gray.1000); - --ifm-color-primary-darkest: theme(colors.gray.1000); - --ifm-color-primary-light: theme(colors.gray.1000); - --ifm-color-primary-lighter: theme(colors.gray.1000); - --ifm-color-primary-lightest: theme(colors.gray.1000); - --ifm-code-font-size: 95%; - --ifm-breadcrumb-item-background-active: transparent; - --ifm-breadcrumb-padding-horizontal: 0; - --ifm-list-paragraph-margin: 0; - --ifm-spacing-horizontal: theme(spacing.7); - --ifm-blockquote-border-color: theme(colors.gray.1000); - --ifm-menu-link-padding-vertical: 0.6rem; - --ifm-background-color: theme(colors.gray.0); - --ifm-footer-link-color: var(--ifm-font-color-base); - --ifm-menu-link-sublist-icon: url("~/img/ico-chevron.svg"); - --docsearch-searchbox-background: #f7f7f7; - --docsearch-modal-background: theme(colors.card) !important; - --ifm-navbar-height: 5.563rem; - --ifm-navbar-sidebar-width: 100vw; - --docsearch-highlight-color: theme(colors.fg) !important; - --docsearch-searchbox-shadow: inset 0 0 0 1px var(--docsearch-primary-color); - - /* temp: local search bar */ - --aa-primary-color-rgb: 0, 0, 0; - - @media screen and (prefers-reduced-motion) { - transition: ; - } - --ifm-menu-color-background-active: none; - --ifm-menu-color-background-hover: none; - --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); -} - -/* For readability concerns, you should choose a lighter palette in dark mode. */ -html[data-theme="dark"] { - --ifm-color-primary: theme(colors.gray.0); - --ifm-color-primary-dark: #e6e6e6; - --ifm-color-primary-darker: #d9d9d9; - --ifm-color-primary-darkest: #b3b3b3; - --ifm-color-primary-light: theme(colors.gray.0); - --ifm-color-primary-lighter: theme(colors.gray.0); - --ifm-color-primary-lightest: theme(colors.gray.0); - --ifm-background-color: theme(colors.gray.1000); - --docusaurus-highlighted-code-line-bg: theme(colors.inactive); - --docsearch-modal-background: theme(colors.gray.1000) !important; - --docsearch-highlight-color: theme(colors.inactiveLight) !important; - --docsearch-hit-background: theme(colors.lightfg) !important; - --docsearch-searchbox-shadow: inset 0 0 0 1px var(--docsearch-primary-color); - --docsearch-key-gradient: linear-gradient( - -26.5deg, - #5d5d5d, - #3c3c3c - ) !important; - --docsearch-key-shadow: inset 0 -2px 0 0 #353535, inset 0 0 1px 1px #7a7a7b, - 0 2px 2px 0 rgba(45, 45, 45, 0.3) !important; -} - -/* Custom colors for links embedded into markdown files in dark mode */ -html[data-theme="dark"] .markdown a { - color: #85c1e9; /* Choose the color you prefer */ -} - -/* Custom highlight color for @easyops-cn/docusaurus-search-local in dark mode */ -html[data-theme="dark"] { - --search-local-highlight-color: #d23669; -} - -html { - @apply bg-docusaurusBgColor; - /* Banner */ - - #__docusaurus > div[role="banner"] { - @apply bg-gray-30 text-gray-1000 font-normal; - a { - @apply no-underline w-full text-2; - } - } - - /* MAINNAV */ - .navbar { - @apply py-2 h-auto border-b border-b-docusaurusColorBorder shadow-none bg-docusaurusBgColor; - &__toggle { - @apply bg-card rounded-s h-8 w-8 flex justify-center items-center; - @media (min-width: 997px) { - @apply hidden; - } - } - &__brand { - & + * { - @apply ml-auto; - } - } - &__link--active { - @apply text-muted; - } - &__items:not(:last-child) { - @apply justify-between; - @media (min-width: 997px) { - @apply justify-start px-3; - } - button { - @apply order-2 mr-0; - } - } - &__items--right > :last-child { - @apply right-8.5; - } - } - &[data-theme="dark"] .navbar__item { - @apply text-mutedLight; - } - &[data-theme="dark"] .navbar__toggle { - @apply bg-fg; - } - - .github-icon { - @apply hover:opacity-50; - } - - /* SEARCHBAR */ - /* algolia */ - .DocSearch { - &-Hits mark { - @apply text-docusaurusColorBase; - } - &-Button { - @apply text-inactive rounded-sm h-8 w-8 bg-card justify-center mr-3; - @media (min-width: 997px) { - @apply w-auto justify-between; - } - .DocSearch-Search-Icon { - @apply text-docusaurusColorBase; - } - .DocSearch-Button-Keys { - @apply hidden; - } - .DocSearch-Button-Placeholder { - @apply pr-10; - } - } - - &-Logo path { - @apply fill-docusaurusColorBase; - } - } - - .navbar-sidebar { - @apply w-full; - &__brand { - @apply px-6 h-auto; - } - &__item { - @apply px-6 w-full; - } - &__back { - @apply px-0 hidden; - } - &__close { - @apply bg-gray-1000 rounded-s h-8 w-8 flex justify-center items-center ml-0; - & > svg > g { - @apply stroke-gray-0; - } - } - } - &[data-theme="dark"] .navbar-sidebar { - @apply bg-gray-1000; - &__brand { - @apply shadow-none relative; - &::after { - content: ""; - @apply absolute block h-px bg-linkHover bottom-0 right-3 left-0 mx-6; - } - } - &__close { - @apply bg-gray-0; - & > svg > g { - @apply stroke-gray-1000; - } - } - } - &[data-theme="dark"] .DocSearch-Modal { - @apply bg-gray-1000; - } - &[data-theme="dark"] .DocSearch-Footer { - @apply bg-gray-1000; - } - &[data-theme="dark"] .DocSearch-Button { - @apply bg-fg text-inactiveLight; - } - &[data-theme="dark"] .DocSearch-Button-Key { - @apply text-inactiveLight border-inactiveLight; - } - - /* BREADCRUMBS */ - .breadcrumbs__item { - &:first-child { - & > a { - &::after { - content: "Docs"; - } - & > svg { - @apply hidden; - } - } - } - &:not(:last-child)::after { - content: ">"; - @apply bg-none; - } - } - .theme-doc-breadcrumbs { - @media (min-width: 997px) { - @apply pt-[calc(theme(spacing.7)-1rem)]; - } - } - .theme-doc-toc-mobile { - @apply bg-card px-6 py-5.5 pb-0 rounded; - & > button { - @apply p-0 pb-5.5 flex justify-between; - &::after { - @apply order-last ml-5; - background-image: var(--ifm-menu-link-sublist-icon); - background-size: 70%; - } - } - & ul li { - @apply my-5 mx-0; - } - } - &[data-theme="dark"] .theme-doc-toc-mobile { - @apply bg-fg; - } - - /* SIDEBAR */ - .theme-doc-sidebar-container { - @media (min-width: 997px) { - @apply ml-4 border-r border-r-docusaurusColorBorder; - } - & > div:first-child > a { - @apply m-0; - } - } - - &[data-theme="dark"] .theme-doc-sidebar-menu .menu__list::before { - @apply bg-inactiveLight; - } - .theme-doc-sidebar-menu { - @apply font-normal; - - .menu__list { - @apply relative pl-0; - &::before { - content: ""; - @apply absolute block left-3 top-0 h-full w-[2px] bg-border; - } - ul::before { - @apply hidden; - } - } - - .menu__link { - @apply pl-0 pr-5; - &--active:not(.menu__link--sublist) { - @apply text-docusaurusColorBase font-medium; - } - } - - li li { - @apply pl-7; - .menu__link--active:not(.menu__link--sublist) { - @apply relative text-docusaurusColorBase font-medium; - &::before { - content: ""; - @apply absolute block left-0 top-0 h-full w-[2px] bg-docusaurusColorBase; - @apply -left-[calc(theme(space.7)-theme(space.3))]; - } - } - } - li li li { - @apply pl-5; - } - li li li .menu__link--active:not(.menu__link--sublist)::before { - @apply -left-[calc(theme(space.5)*1+theme(space.7)-theme(space.3))]; - } - li li li li .menu__link--active:not(.menu__link--sublist)::before { - @apply -left-[calc(theme(space.5)*2+theme(space.7)-theme(space.3))]; - } - li li li li li .menu__link--active:not(.menu__link--sublist)::before { - @apply -left-[calc(theme(space.5)*3+theme(space.7)-theme(space.3))]; - } - li li li li li li .menu__link--active:not(.menu__link--sublist)::before { - @apply -left-[calc(theme(space.5)*4+theme(space.7)-theme(space.3))]; - } - li li li li li li li .menu__link--active:not(.menu__link--sublist)::before { - @apply -left-[calc(theme(space.5)*5+theme(space.7)-theme(space.3))]; - } - } - - &[data-theme="dark"] .menu__link { - @apply text-mutedLight; - } - .theme-doc-sidebar-item-link .menu__link[target="_blank"] { - &::after { - content: "\2197"; - @apply ml-1; - } - } - .menu__link { - @apply text-muted; - &:hover { - text-shadow: 0.1px 0.1px 0 var(--ifm-font-color-base), - -0.1px -0.1px 0 var(--ifm-font-color-base), - 0.1px -0.1px 0 var(--ifm-font-color-base), - -0.1px 0.1px 0 var(--ifm-font-color-base), - -0.1px 0 0 var(--ifm-font-color-base), - 0.1px 0 0 var(--ifm-font-color-base), - 0 0.1px 0 var(--ifm-font-color-base), - 0 -0.1px 0 var(--ifm-font-color-base); - @apply text-docusaurusColorBase; - } - - & > svg { - @apply hidden; - } - } - - .menu__link--sublist-caret { - @apply flex; - &::after { - background-size: 16px; - background-repeat: no-repeat; - @apply order-first ml-0 mr-4; - } - } - .menu__list-item--collapsed .menu__link--sublist:after, - .menu__list-item--collapsed .menu__caret:before { - transform: rotateZ(0); - } - .menu__caret, - li li .menu__link--sublist-caret::after { - @apply hidden; - } - - /* TOC */ - .table-of-contents__link:hover, - .table-of-contents__link--active { - text-shadow: 0.1px 0.1px 0 var(--ifm-font-color-base), - -0.1px -0.1px 0 var(--ifm-font-color-base), - 0.1px -0.1px 0 var(--ifm-font-color-base), - -0.1px 0.1px 0 var(--ifm-font-color-base), - -0.1px 0 0 var(--ifm-font-color-base), - 0.1px 0 0 var(--ifm-font-color-base), 0 0.1px 0 var(--ifm-font-color-base), - 0 -0.1px 0 var(--ifm-font-color-base); - } - - /* RELATED ARTICLES */ - &[data-theme="dark"] .pagination-nav > a { - @apply bg-fg; - } - .pagination-nav { - @apply pb-7 mt-9; - & > a { - box-shadow: 0px 0px 80px rgba(0, 0, 0, 0.07); - @apply border-transparent rounded pb-8.5 col-span-2 pt-6 px-6 hover:shadow-none; - - @media (min-width: 997px) { - @apply col-span-1; - } - } - - .pagination-nav { - &__link--next { - @apply text-left; - @media (min-width: 997px) { - @apply text-right; - } - } - &__sublabel { - @apply mb-3.5 text-gray-1000 dark:text-docusaurusColorBase text-3; - } - &__label { - @apply text-4 font-semibold; - } - } - } - - /* FOOTER */ - .footer { - background-color: var(--ifm-background-color); - @apply border-t border-t-docusaurusColorBorder pt-10 mb-10; - &__link-item { - @apply hover:underline; - } - &__bottom { - margin: 0 calc(var(--ifm-spacing-horizontal) * -1); - } - &__copyright { - @apply text-center mt-9 text-2; - } - } - .footer__col:not(:first-child) { - @apply basis-1/2; - @media (min-width: 997px) { - @apply basis-0; - } - } - .footer__col:first-child .footer__title { - @apply hidden; - } - .footer__link-item { - & > svg { - @apply hidden; - } - } - - .theme-back-to-top-button { - @apply rotate-180; - &::after { - @apply w-1/2; - } - } - - /* MARKDOWN */ - .theme-code-block { - @apply font-jetbrain mt-3; - } - - .markdown { - --ifm-heading-vertical-rhythm-bottom: 1; - --ifm-h1-vertical-rhythm-bottom: 1; - } - .theme-doc-markdown { - @apply mt-7 pb-8 border-b border-b-border; - - h1 { - @apply text-7 font-bold leading-10 tracking-tight; - } - h2 { - @apply text-6 font-bold leading-9 tracking-tight; - } - h3 { - @apply text-4 font-semibold leading-8 tracking-tight; - } - h4 { - @apply text-3 font-semibold leading-7 tracking-tight; - } - h5 { - @apply text-3 font-semibold leading-6 tracking-wide; - } - p { - @apply leading-relaxed; - } - p, - ul, - ol, - blockquote { - @apply text-[1rem]; - } - code { - @apply border-0 px-3; - } - blockquote { - @apply my-7; - } - a { - @apply no-underline hover:underline; - color: var(--ifm-color-primary); - } - ol, - ul { - @apply my-6; - } - ul li { - @apply relative pl-6 mb-4 before:absolute before:block before:w-[4px] before:h-[4px] before:bg-current before:left-0 before:top-[calc(1em/2)]; - } - ul li li { - @apply last:mb-6 before:border before:border-current before:bg-transparent; - } - li:last-child li { - @apply last:mb-0; - } - ol { - list-style-type: none; - counter-reset: item; - & > li { - @apply relative pl-8 mb-5.5; - &::before { - counter-increment: item; - content: counters(item, ".", decimal-leading-zero) "."; - @apply absolute flex left-0 top-[.2rem] text-3 font-semibold tracking-tight; - } - } - } - ol ol { - counter-reset: subitem; - & > li { - &::before { - counter-increment: subitem; - content: counters(subitem, ".", decimal-leading-zero) "."; - } - } - } - li { - & > ul, - & > ol { - @apply my-5; - } - } - } -} diff --git a/docs/src/css/fonts.css b/docs/src/css/fonts.css deleted file mode 100644 index 9b98510d61f..00000000000 --- a/docs/src/css/fonts.css +++ /dev/null @@ -1,64 +0,0 @@ -/* - - FONT FAMILY GROUPS - -*/ - -/* - Copied from https://github.com/ignite/cli/blob/develop/docs/src/css/fonts.css -*/ - -/* Inter */ -@font-face { - font-family: "Inter"; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url("~/static/fonts/inter/Inter-Regular.woff2?v=3.19") format("woff2"), - url("~/static/fonts/inter/Inter-Regular.woff?v=3.19") format("woff"); -} - -@font-face { - font-family: "Inter"; - font-style: normal; - font-weight: 500; - font-display: swap; - src: url("~/static/fonts/inter/Inter-Medium.woff2?v=3.19") format("woff2"), - url("~/static/fonts/inter/Inter-Medium.woff?v=3.19") format("woff"); -} - -@font-face { - font-family: "Inter"; - font-style: normal; - font-weight: 700; - font-display: swap; - src: url("~/static/fonts/inter/Inter-Bold.woff2?v=3.19") format("woff2"), - url("~/static/fonts/inter/Inter-Bold.woff?v=3.19") format("woff"); -} - -@font-face { - font-family: "Inter"; - font-style: normal; - font-weight: 900; - font-display: swap; - src: url("~/static/fonts/inter/Inter-Black.woff2?v=3.19") format("woff2"), - url("~/static/fonts/inter/Inter-Black.woff?v=3.19") format("woff"); -} - -/* Inter var */ -@font-face { - font-family: "Inter var"; - font-weight: 100 900; - font-display: swap; - font-style: oblique 0deg 10deg; - src: url("~/static/fonts/intervar/Inter.var.woff2?v=3.19") format("woff2"); -} - -/* JetBrains Mono */ -@font-face { - font-family: "JetBrains Mono"; - font-weight: normal; - font-style: normal; - src: url("~/static/fonts/jetbrainsmono/JetBrainsMono-Regular.woff2") - format("woff2"); -} diff --git a/docs/static/.nojekyll b/docs/static/.nojekyll deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/docs/static/CNAME b/docs/static/CNAME deleted file mode 100644 index 45012264180..00000000000 --- a/docs/static/CNAME +++ /dev/null @@ -1 +0,0 @@ -ibc.cosmos.network diff --git a/docs/static/fonts/inter/Inter-Black.woff b/docs/static/fonts/inter/Inter-Black.woff deleted file mode 100644 index a18593a096e..00000000000 Binary files a/docs/static/fonts/inter/Inter-Black.woff and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-Black.woff2 b/docs/static/fonts/inter/Inter-Black.woff2 deleted file mode 100644 index 68f64c9ed98..00000000000 Binary files a/docs/static/fonts/inter/Inter-Black.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-BlackItalic.woff b/docs/static/fonts/inter/Inter-BlackItalic.woff deleted file mode 100644 index b6b01943d9f..00000000000 Binary files a/docs/static/fonts/inter/Inter-BlackItalic.woff and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-BlackItalic.woff2 b/docs/static/fonts/inter/Inter-BlackItalic.woff2 deleted file mode 100644 index 1c9c7ca8b04..00000000000 Binary files a/docs/static/fonts/inter/Inter-BlackItalic.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-Bold.woff b/docs/static/fonts/inter/Inter-Bold.woff deleted file mode 100644 index eaf3d4bfd7d..00000000000 Binary files a/docs/static/fonts/inter/Inter-Bold.woff and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-Bold.woff2 b/docs/static/fonts/inter/Inter-Bold.woff2 deleted file mode 100644 index 2846f29cc8a..00000000000 Binary files a/docs/static/fonts/inter/Inter-Bold.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-BoldItalic.woff b/docs/static/fonts/inter/Inter-BoldItalic.woff deleted file mode 100644 index 32750761640..00000000000 Binary files a/docs/static/fonts/inter/Inter-BoldItalic.woff and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-BoldItalic.woff2 b/docs/static/fonts/inter/Inter-BoldItalic.woff2 deleted file mode 100644 index 0b1fe8e1255..00000000000 Binary files a/docs/static/fonts/inter/Inter-BoldItalic.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-ExtraBold.woff b/docs/static/fonts/inter/Inter-ExtraBold.woff deleted file mode 100644 index c2c17edead6..00000000000 Binary files a/docs/static/fonts/inter/Inter-ExtraBold.woff and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-ExtraBold.woff2 b/docs/static/fonts/inter/Inter-ExtraBold.woff2 deleted file mode 100644 index c24c2bdc2f0..00000000000 Binary files a/docs/static/fonts/inter/Inter-ExtraBold.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-ExtraBoldItalic.woff b/docs/static/fonts/inter/Inter-ExtraBoldItalic.woff deleted file mode 100644 index c42f70526c8..00000000000 Binary files a/docs/static/fonts/inter/Inter-ExtraBoldItalic.woff and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-ExtraBoldItalic.woff2 b/docs/static/fonts/inter/Inter-ExtraBoldItalic.woff2 deleted file mode 100644 index 4a81dc79826..00000000000 Binary files a/docs/static/fonts/inter/Inter-ExtraBoldItalic.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-ExtraLight.woff b/docs/static/fonts/inter/Inter-ExtraLight.woff deleted file mode 100644 index d0de5f3973e..00000000000 Binary files a/docs/static/fonts/inter/Inter-ExtraLight.woff and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-ExtraLight.woff2 b/docs/static/fonts/inter/Inter-ExtraLight.woff2 deleted file mode 100644 index f2ea706fafa..00000000000 Binary files a/docs/static/fonts/inter/Inter-ExtraLight.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-ExtraLightItalic.woff b/docs/static/fonts/inter/Inter-ExtraLightItalic.woff deleted file mode 100644 index 81f1a28ef55..00000000000 Binary files a/docs/static/fonts/inter/Inter-ExtraLightItalic.woff and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-ExtraLightItalic.woff2 b/docs/static/fonts/inter/Inter-ExtraLightItalic.woff2 deleted file mode 100644 index 9af717ba91b..00000000000 Binary files a/docs/static/fonts/inter/Inter-ExtraLightItalic.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-Italic.woff b/docs/static/fonts/inter/Inter-Italic.woff deleted file mode 100644 index a806b382012..00000000000 Binary files a/docs/static/fonts/inter/Inter-Italic.woff and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-Italic.woff2 b/docs/static/fonts/inter/Inter-Italic.woff2 deleted file mode 100644 index a619fc54861..00000000000 Binary files a/docs/static/fonts/inter/Inter-Italic.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-Light.woff b/docs/static/fonts/inter/Inter-Light.woff deleted file mode 100644 index c496464d02d..00000000000 Binary files a/docs/static/fonts/inter/Inter-Light.woff and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-Light.woff2 b/docs/static/fonts/inter/Inter-Light.woff2 deleted file mode 100644 index bc4be6658b0..00000000000 Binary files a/docs/static/fonts/inter/Inter-Light.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-LightItalic.woff b/docs/static/fonts/inter/Inter-LightItalic.woff deleted file mode 100644 index f84a9de35e8..00000000000 Binary files a/docs/static/fonts/inter/Inter-LightItalic.woff and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-LightItalic.woff2 b/docs/static/fonts/inter/Inter-LightItalic.woff2 deleted file mode 100644 index 842b2dfcb77..00000000000 Binary files a/docs/static/fonts/inter/Inter-LightItalic.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-Medium.woff b/docs/static/fonts/inter/Inter-Medium.woff deleted file mode 100644 index d546843f283..00000000000 Binary files a/docs/static/fonts/inter/Inter-Medium.woff and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-Medium.woff2 b/docs/static/fonts/inter/Inter-Medium.woff2 deleted file mode 100644 index f92498a2ecf..00000000000 Binary files a/docs/static/fonts/inter/Inter-Medium.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-MediumItalic.woff b/docs/static/fonts/inter/Inter-MediumItalic.woff deleted file mode 100644 index 459a6568898..00000000000 Binary files a/docs/static/fonts/inter/Inter-MediumItalic.woff and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-MediumItalic.woff2 b/docs/static/fonts/inter/Inter-MediumItalic.woff2 deleted file mode 100644 index 0e3019f4ae7..00000000000 Binary files a/docs/static/fonts/inter/Inter-MediumItalic.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-Regular.woff b/docs/static/fonts/inter/Inter-Regular.woff deleted file mode 100644 index 62d3a618710..00000000000 Binary files a/docs/static/fonts/inter/Inter-Regular.woff and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-Regular.woff2 b/docs/static/fonts/inter/Inter-Regular.woff2 deleted file mode 100644 index 6c2b6893d59..00000000000 Binary files a/docs/static/fonts/inter/Inter-Regular.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-SemiBold.woff b/docs/static/fonts/inter/Inter-SemiBold.woff deleted file mode 100644 index a815f43a91f..00000000000 Binary files a/docs/static/fonts/inter/Inter-SemiBold.woff and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-SemiBold.woff2 b/docs/static/fonts/inter/Inter-SemiBold.woff2 deleted file mode 100644 index 611e90c958f..00000000000 Binary files a/docs/static/fonts/inter/Inter-SemiBold.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-SemiBoldItalic.woff b/docs/static/fonts/inter/Inter-SemiBoldItalic.woff deleted file mode 100644 index 909e43a97d8..00000000000 Binary files a/docs/static/fonts/inter/Inter-SemiBoldItalic.woff and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-SemiBoldItalic.woff2 b/docs/static/fonts/inter/Inter-SemiBoldItalic.woff2 deleted file mode 100644 index 545685bd2c6..00000000000 Binary files a/docs/static/fonts/inter/Inter-SemiBoldItalic.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-Thin.woff b/docs/static/fonts/inter/Inter-Thin.woff deleted file mode 100644 index 62bc58cd141..00000000000 Binary files a/docs/static/fonts/inter/Inter-Thin.woff and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-Thin.woff2 b/docs/static/fonts/inter/Inter-Thin.woff2 deleted file mode 100644 index abbc3a5c962..00000000000 Binary files a/docs/static/fonts/inter/Inter-Thin.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-ThinItalic.woff b/docs/static/fonts/inter/Inter-ThinItalic.woff deleted file mode 100644 index 700a7f069b9..00000000000 Binary files a/docs/static/fonts/inter/Inter-ThinItalic.woff and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-ThinItalic.woff2 b/docs/static/fonts/inter/Inter-ThinItalic.woff2 deleted file mode 100644 index ab0b2002a3a..00000000000 Binary files a/docs/static/fonts/inter/Inter-ThinItalic.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-italic.var.woff2 b/docs/static/fonts/inter/Inter-italic.var.woff2 deleted file mode 100644 index b826d5af84b..00000000000 Binary files a/docs/static/fonts/inter/Inter-italic.var.woff2 and /dev/null differ diff --git a/docs/static/fonts/inter/Inter-roman.var.woff2 b/docs/static/fonts/inter/Inter-roman.var.woff2 deleted file mode 100644 index 6a256a068f0..00000000000 Binary files a/docs/static/fonts/inter/Inter-roman.var.woff2 and /dev/null differ diff --git a/docs/static/fonts/intervar/Inter.var.woff2 b/docs/static/fonts/intervar/Inter.var.woff2 deleted file mode 100644 index 365eedc50cd..00000000000 Binary files a/docs/static/fonts/intervar/Inter.var.woff2 and /dev/null differ diff --git a/docs/static/fonts/jetbrainsmono/JetBrainsMono-Bold.woff2 b/docs/static/fonts/jetbrainsmono/JetBrainsMono-Bold.woff2 deleted file mode 100644 index 023512c051e..00000000000 Binary files a/docs/static/fonts/jetbrainsmono/JetBrainsMono-Bold.woff2 and /dev/null differ diff --git a/docs/static/fonts/jetbrainsmono/JetBrainsMono-BoldItalic.woff2 b/docs/static/fonts/jetbrainsmono/JetBrainsMono-BoldItalic.woff2 deleted file mode 100644 index f3e87a35abb..00000000000 Binary files a/docs/static/fonts/jetbrainsmono/JetBrainsMono-BoldItalic.woff2 and /dev/null differ diff --git a/docs/static/fonts/jetbrainsmono/JetBrainsMono-ExtraBold.woff2 b/docs/static/fonts/jetbrainsmono/JetBrainsMono-ExtraBold.woff2 deleted file mode 100644 index a8b78a9c176..00000000000 Binary files a/docs/static/fonts/jetbrainsmono/JetBrainsMono-ExtraBold.woff2 and /dev/null differ diff --git a/docs/static/fonts/jetbrainsmono/JetBrainsMono-ExtraBoldItalic.woff2 b/docs/static/fonts/jetbrainsmono/JetBrainsMono-ExtraBoldItalic.woff2 deleted file mode 100644 index b54a2d5beba..00000000000 Binary files a/docs/static/fonts/jetbrainsmono/JetBrainsMono-ExtraBoldItalic.woff2 and /dev/null differ diff --git a/docs/static/fonts/jetbrainsmono/JetBrainsMono-ExtraLight.woff2 b/docs/static/fonts/jetbrainsmono/JetBrainsMono-ExtraLight.woff2 deleted file mode 100644 index edd6a68c06d..00000000000 Binary files a/docs/static/fonts/jetbrainsmono/JetBrainsMono-ExtraLight.woff2 and /dev/null differ diff --git a/docs/static/fonts/jetbrainsmono/JetBrainsMono-ExtraLightItalic.woff2 b/docs/static/fonts/jetbrainsmono/JetBrainsMono-ExtraLightItalic.woff2 deleted file mode 100644 index 2a02a18e64c..00000000000 Binary files a/docs/static/fonts/jetbrainsmono/JetBrainsMono-ExtraLightItalic.woff2 and /dev/null differ diff --git a/docs/static/fonts/jetbrainsmono/JetBrainsMono-Italic.woff2 b/docs/static/fonts/jetbrainsmono/JetBrainsMono-Italic.woff2 deleted file mode 100644 index e8eeb4b8e85..00000000000 Binary files a/docs/static/fonts/jetbrainsmono/JetBrainsMono-Italic.woff2 and /dev/null differ diff --git a/docs/static/fonts/jetbrainsmono/JetBrainsMono-Light.woff2 b/docs/static/fonts/jetbrainsmono/JetBrainsMono-Light.woff2 deleted file mode 100644 index 459bacf4989..00000000000 Binary files a/docs/static/fonts/jetbrainsmono/JetBrainsMono-Light.woff2 and /dev/null differ diff --git a/docs/static/fonts/jetbrainsmono/JetBrainsMono-LightItalic.woff2 b/docs/static/fonts/jetbrainsmono/JetBrainsMono-LightItalic.woff2 deleted file mode 100644 index 352f5d95a6a..00000000000 Binary files a/docs/static/fonts/jetbrainsmono/JetBrainsMono-LightItalic.woff2 and /dev/null differ diff --git a/docs/static/fonts/jetbrainsmono/JetBrainsMono-Medium.woff2 b/docs/static/fonts/jetbrainsmono/JetBrainsMono-Medium.woff2 deleted file mode 100644 index 484c9e64152..00000000000 Binary files a/docs/static/fonts/jetbrainsmono/JetBrainsMono-Medium.woff2 and /dev/null differ diff --git a/docs/static/fonts/jetbrainsmono/JetBrainsMono-MediumItalic.woff2 b/docs/static/fonts/jetbrainsmono/JetBrainsMono-MediumItalic.woff2 deleted file mode 100644 index e1279949e07..00000000000 Binary files a/docs/static/fonts/jetbrainsmono/JetBrainsMono-MediumItalic.woff2 and /dev/null differ diff --git a/docs/static/fonts/jetbrainsmono/JetBrainsMono-Regular.woff2 b/docs/static/fonts/jetbrainsmono/JetBrainsMono-Regular.woff2 deleted file mode 100644 index 8c862e334da..00000000000 Binary files a/docs/static/fonts/jetbrainsmono/JetBrainsMono-Regular.woff2 and /dev/null differ diff --git a/docs/static/fonts/jetbrainsmono/JetBrainsMono-SemiBold.woff2 b/docs/static/fonts/jetbrainsmono/JetBrainsMono-SemiBold.woff2 deleted file mode 100644 index fce8cd8053c..00000000000 Binary files a/docs/static/fonts/jetbrainsmono/JetBrainsMono-SemiBold.woff2 and /dev/null differ diff --git a/docs/static/fonts/jetbrainsmono/JetBrainsMono-SemiBoldItalic.woff2 b/docs/static/fonts/jetbrainsmono/JetBrainsMono-SemiBoldItalic.woff2 deleted file mode 100644 index a14851f6bbe..00000000000 Binary files a/docs/static/fonts/jetbrainsmono/JetBrainsMono-SemiBoldItalic.woff2 and /dev/null differ diff --git a/docs/static/fonts/jetbrainsmono/JetBrainsMono-Thin.woff2 b/docs/static/fonts/jetbrainsmono/JetBrainsMono-Thin.woff2 deleted file mode 100644 index 7c6127875f5..00000000000 Binary files a/docs/static/fonts/jetbrainsmono/JetBrainsMono-Thin.woff2 and /dev/null differ diff --git a/docs/static/fonts/jetbrainsmono/JetBrainsMono-ThinItalic.woff2 b/docs/static/fonts/jetbrainsmono/JetBrainsMono-ThinItalic.woff2 deleted file mode 100644 index 0676ba8a56a..00000000000 Binary files a/docs/static/fonts/jetbrainsmono/JetBrainsMono-ThinItalic.woff2 and /dev/null differ diff --git a/docs/static/img/black-ibc-logo.svg b/docs/static/img/black-ibc-logo.svg deleted file mode 100644 index 71afdd3a515..00000000000 --- a/docs/static/img/black-ibc-logo.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/docs/static/img/black-large-ibc-logo.svg b/docs/static/img/black-large-ibc-logo.svg deleted file mode 100644 index 2902c0cef78..00000000000 --- a/docs/static/img/black-large-ibc-logo.svg +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/static/img/cosmos-logo-bw.svg b/docs/static/img/cosmos-logo-bw.svg deleted file mode 100644 index f2575260a76..00000000000 --- a/docs/static/img/cosmos-logo-bw.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/docs/static/img/ibc-go-image.png b/docs/static/img/ibc-go-image.png deleted file mode 100644 index 70d8aa20205..00000000000 Binary files a/docs/static/img/ibc-go-image.png and /dev/null differ diff --git a/docs/static/img/ico-chevron.svg b/docs/static/img/ico-chevron.svg deleted file mode 100644 index 3f8e8fac11a..00000000000 --- a/docs/static/img/ico-chevron.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/docs/static/img/white-cosmos-icon.svg b/docs/static/img/white-cosmos-icon.svg deleted file mode 100644 index 4e59ad83e63..00000000000 --- a/docs/static/img/white-cosmos-icon.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/docs/static/img/white-ibc-logo.svg b/docs/static/img/white-ibc-logo.svg deleted file mode 100644 index c4ac0cbd75a..00000000000 --- a/docs/static/img/white-ibc-logo.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/docs/static/img/white-large-ibc-logo.svg b/docs/static/img/white-large-ibc-logo.svg deleted file mode 100644 index 7f349eada71..00000000000 --- a/docs/static/img/white-large-ibc-logo.svg +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/tailwind.config.js b/docs/tailwind.config.js deleted file mode 100644 index d48e14f851c..00000000000 --- a/docs/tailwind.config.js +++ /dev/null @@ -1,104 +0,0 @@ -const defaultTheme = require("tailwindcss/defaultTheme"); - -// Px to REM function (static base of 16) -const pxToRem = (dest) => 1 / (16 / dest); - -// Config -module.exports = { - content: ["./src/**/*.{js,jsx,ts,tsx}"], - corePlugins: { - // preflight: false, // avoid reset all docusaurus css - }, - theme: { - borderRadius: { - none: "0", - xs: `${pxToRem(4)}rem`, - s: `${pxToRem(8)}rem`, - sm: `${pxToRem(10)}rem`, - DEFAULT: `${pxToRem(16)}rem`, - md: `${pxToRem(20)}rem`, - lg: `${pxToRem(100)}rem`, - circle: "100%", - }, - fontFamily: { - intervar: ['"Inter var"', defaultTheme.fontFamily.sans], - inter: ["Inter", defaultTheme.fontFamily.sans], - jetbrain: ["JetBrains Mono", defaultTheme.fontFamily.mono], - }, - fontSize: { - 0: "0", - 1: [`${pxToRem(10)}rem`], - 2: [`${pxToRem(13)}rem`], - 3: [`${pxToRem(16)}rem`], - 4: [`${pxToRem(21)}rem`], - 5: [`${pxToRem(28)}rem`], - 6: [`${pxToRem(32)}rem`], - 7: [`${pxToRem(38)}rem`], - 8: [`${pxToRem(51)}rem`], - 9: [`${pxToRem(56)}rem`], - 10: [`${pxToRem(76)}rem`], - }, - spacing: { - inherit: "inherit", - auto: "auto", - full: "100%", - px: "1px", - "1/2": "50%", - "1/3": "33.333%", - "2/3": "66.666%", - "1/4": "25%", - "3/4": "75%", - "1/5": "20%", - "2/5": "40%", - "3/5": "60%", - "4/5": "80%", - 0: "0", - 1: ".25rem", - 2: `${pxToRem(6)}rem`, - 3: `${pxToRem(8)}rem`, - 3.5: `${pxToRem(10)}rem`, - 4: `${pxToRem(12)}rem`, - 5: `${pxToRem(16)}rem`, - 5.5: `${pxToRem(20)}rem`, - 6: `${pxToRem(24)}rem`, - 7: `${pxToRem(32)}rem`, - 7.5: `${pxToRem(40)}rem`, - 8: `${pxToRem(48)}rem`, - 8.5: `${pxToRem(52)}rem`, - 9: `${pxToRem(64)}rem`, - 9.5: "5rem", - 9.75: `${pxToRem(84)}rem`, - 10: `${pxToRem(96)}rem`, - 11: `${pxToRem(128)}rem`, - 12: `${pxToRem(144)}rem`, - 13: `${pxToRem(160)}rem`, - 14: `${pxToRem(192)}rem`, - 15: `${pxToRem(208)}rem`, - }, - colors: { - transparent: "transparent", - current: "currentColor", - inherit: "inherit", - gray: { - 0: "#FFFFFF", - 30: "rgba(0, 0, 0, 0.03)", - 1000: "#000000", - }, - card: "#F7F7F7", - border: "rgba(0, 0, 0, 0.07)", - inactive: "rgba(0, 0, 0, 0.33)", - inactiveLight: "rgba(255, 255, 255, 0.44)", - muted: "#555555", - mutedLight: "rgba(255, 255, 255, 0.67)", - fg: "rgba(24, 24, 24, 0.67)", - lightfg: "rgba(24, 24, 24, 0.67)", - link: "#000000", - linkHover: "#555555", - docusaurusColorBase: "var(--ifm-font-color-base)", - docusaurusBgColor: "var(--ifm-background-color)", - docusaurusColorBorder: "var(--ifm-color-emphasis-200)", - }, - extend: {}, - }, - plugins: [], -}; diff --git a/docs/versioned_docs/version-v4.4.x/00-intro.md b/docs/versioned_docs/version-v4.4.x/00-intro.md deleted file mode 100644 index c842dac0022..00000000000 --- a/docs/versioned_docs/version-v4.4.x/00-intro.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -slug: / -sidebar_position: 0 ---- - -# IBC-Go Documentation - -Welcome to the IBC-Go documentation! - -The Inter-Blockchain Communication protocol (IBC) is an end-to-end, connection-oriented, stateful protocol for reliable, ordered, and authenticated communication between heterogeneous blockchains arranged in an unknown and dynamic topology. - -IBC is a protocol that allows blockchains to talk to each other. - -The protocol realizes this interoperability by specifying a set of data structures, abstractions, and semantics that can be implemented by any distributed ledger that satisfies a small set of requirements. - -IBC can be used to build a wide range of cross-chain applications that include token transfers, atomic swaps, multi-chain smart contracts (with or without mutually comprehensible VMs), and data and code sharding of various kinds. diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/01-overview.md b/docs/versioned_docs/version-v4.4.x/01-ibc/01-overview.md deleted file mode 100644 index e8767d36cdb..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/01-overview.md +++ /dev/null @@ -1,297 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /ibc/overview ---- - - -# Overview - -:::note Synopsis -Learn about IBC, its components, and IBC use cases. -::: - -## What is the Interblockchain Communication Protocol (IBC)? - -This document serves as a guide for developers who want to write their own Inter-Blockchain -Communication protocol (IBC) applications for custom use cases. - -> IBC applications must be written as self-contained modules. - -Due to the modular design of the IBC protocol, IBC -application developers do not need to be concerned with the low-level details of clients, -connections, and proof verification. - -This brief explanation of the lower levels of the -stack gives application developers a broad understanding of the IBC -protocol. Abstraction layer details for channels and ports are most relevant for application developers and describe how to define custom packets and `IBCModule` callbacks. - -The requirements to have your module interact over IBC are: - -- Bind to a port or ports. -- Define your packet data. -- Use the default acknowledgment struct provided by core IBC or optionally define a custom acknowledgment struct. -- Standardize an encoding of the packet data. -- Implement the `IBCModule` interface. - -Read on for a detailed explanation of how to write a self-contained IBC application module. - -## Components Overview - -### [Clients](https://github.com/cosmos/ibc-go/blob/main/modules/core/02-client) - -IBC clients are on-chain light clients. Each light client is identified by a unique client-id. -IBC clients track the consensus states of other blockchains, along with the proof spec necessary to -properly verify proofs against the client's consensus state. A client can be associated with any number -of connections to the counterparty chain. The client identifier is auto generated using the client type -and the global client counter appended in the format: `{client-type}-{N}`. - -A `ClientState` should contain chain specific and light client specific information necessary for verifying updates -and upgrades to the IBC client. The `ClientState` may contain information such as chain-id, latest height, proof specs, -unbonding periods or the status of the light client. The `ClientState` should not contain information that -is specific to a given block at a certain height, this is the function of the `ConsensusState`. Each `ConsensusState` -should be associated with a unique block and should be referenced using a height. IBC clients are given a -client identifier prefixed store to store their associated client state and consensus states along with -any metadata associated with the consensus states. Consensus states are stored using their associated height. - -The supported IBC clients are: - -- [Solo Machine light client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/06-solomachine): Devices such as phones, browsers, or laptops. -- [Tendermint light client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/07-tendermint): The default for Cosmos SDK-based chains. -- [Localhost (loopback) client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/09-localhost): Useful for -testing, simulation, and relaying packets to modules on the same application. - -### IBC Client Heights - -IBC Client Heights are represented by the struct: - -```go -type Height struct { - RevisionNumber uint64 - RevisionHeight uint64 -} -``` - -The `RevisionNumber` represents the revision of the chain that the height is representing. -A revision typically represents a continuous, monotonically increasing range of block-heights. -The `RevisionHeight` represents the height of the chain within the given revision. - -On any reset of the `RevisionHeight`—for example, when hard-forking a Tendermint chain— -the `RevisionNumber` will get incremented. This allows IBC clients to distinguish between a -block-height `n` of a previous revision of the chain (at revision `p`) and block-height `n` of the current -revision of the chain (at revision `e`). - -`Height`s that share the same revision number can be compared by simply comparing their respective `RevisionHeight`s. -`Height`s that do not share the same revision number will only be compared using their respective `RevisionNumber`s. -Thus a height `h` with revision number `e+1` will always be greater than a height `g` with revision number `e`, -**REGARDLESS** of the difference in revision heights. - -Ex: - -```go -Height{RevisionNumber: 3, RevisionHeight: 0} > Height{RevisionNumber: 2, RevisionHeight: 100000000000} -``` - -When a Tendermint chain is running a particular revision, relayers can simply submit headers and proofs with the revision number -given by the chain's `chainID`, and the revision height given by the Tendermint block height. When a chain updates using a hard-fork -and resets its block-height, it is responsible for updating its `chainID` to increment the revision number. -IBC Tendermint clients then verifies the revision number against their `chainID` and treat the `RevisionHeight` as the Tendermint block-height. - -Tendermint chains wishing to use revisions to maintain persistent IBC connections even across height-resetting upgrades must format their `chainID`s -in the following manner: `{chainID}-{revision_number}`. On any height-resetting upgrade, the `chainID` **MUST** be updated with a higher revision number -than the previous value. - -Ex: - -- Before upgrade `chainID`: `gaiamainnet-3` -- After upgrade `chainID`: `gaiamainnet-4` - -Clients that do not require revisions, such as the solo-machine client, simply hardcode `0` into the revision number whenever they -need to return an IBC height when implementing IBC interfaces and use the `RevisionHeight` exclusively. - -Other client-types can implement their own logic to verify the IBC heights that relayers provide in their `Update`, `Misbehavior`, and -`Verify` functions respectively. - -The IBC interfaces expect an `ibcexported.Height` interface, however all clients must use the concrete implementation provided in -`02-client/types` and reproduced above. - -### [Connections](https://github.com/cosmos/ibc-go/blob/main/modules/core/03-connection) - -Connections encapsulate two `ConnectionEnd` objects on two separate blockchains. Each -`ConnectionEnd` is associated with a client of the other blockchain (for example, the counterparty blockchain). -The connection handshake is responsible for verifying that the light clients on each chain are -correct for their respective counterparties. Connections, once established, are responsible for -facilitating all cross-chain verifications of IBC state. A connection can be associated with any -number of channels. - -### [Proofs](https://github.com/cosmos/ibc-go/blob/main/modules/core/23-commitment) and [Paths](https://github.com/cosmos/ibc-go/blob/main/modules/core/24-host) - -In IBC, blockchains do not directly pass messages to each other over the network. Instead, to -communicate, a blockchain commits some state to a specifically defined path that is reserved for a -specific message type and a specific counterparty. For example, for storing a specific connectionEnd as part -of a handshake or a packet intended to be relayed to a module on the counterparty chain. A relayer -process monitors for updates to these paths and relays messages by submitting the data stored -under the path and a proof to the counterparty chain. - -Proofs are passed from core IBC to light-clients as bytes. It is up to light client implementation to interpret these bytes appropriately. - -- The paths that all IBC implementations must use for committing IBC messages is defined in -[ICS-24 Host State Machine Requirements](https://github.com/cosmos/ics/tree/master/spec/core/ics-024-host-requirements). -- The proof format that all implementations must be able to produce and verify is defined in [ICS-23 Proofs](https://github.com/confio/ics23) implementation. - -### [Capabilities](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/advanced/10-ocap.md) - -IBC is intended to work in execution environments where modules do not necessarily trust each -other. Thus, IBC must authenticate module actions on ports and channels so that only modules with the -appropriate permissions can use them. - -This module authentication is accomplished using a [dynamic -capability store](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-003-dynamic-capability-store.md). Upon binding to a port or -creating a channel for a module, IBC returns a dynamic capability that the module must claim in -order to use that port or channel. The dynamic capability module prevents other modules from using that port or channel since -they do not own the appropriate capability. - -While this background information is useful, IBC modules do not need to interact at all with -these lower-level abstractions. The relevant abstraction layer for IBC application developers is -that of channels and ports. IBC applications must be written as self-contained **modules**. - -A module on one blockchain can communicate with other modules on other blockchains by sending, -receiving, and acknowledging packets through channels that are uniquely identified by the -`(channelID, portID)` tuple. - -A useful analogy is to consider IBC modules as internet applications on -a computer. A channel can then be conceptualized as an IP connection, with the IBC portID being -analogous to an IP port and the IBC channelID being analogous to an IP address. Thus, a single -instance of an IBC module can communicate on the same port with any number of other modules and -IBC correctly routes all packets to the relevant module using the (channelID, portID tuple). An -IBC module can also communicate with another IBC module over multiple ports, with each -`(portID<->portID)` packet stream being sent on a different unique channel. - -### [Ports](https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port) - -An IBC module can bind to any number of ports. Each port must be identified by a unique `portID`. -Since IBC is designed to be secure with mutually distrusted modules operating on the same ledger, -binding a port returns a dynamic object capability. In order to take action on a particular port -(for example, an open channel with its portID), a module must provide the dynamic object capability to the IBC -handler. This requirement prevents a malicious module from opening channels with ports it does not own. Thus, -IBC modules are responsible for claiming the capability that is returned on `BindPort`. - -### [Channels](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -An IBC channel can be established between two IBC ports. Currently, a port is exclusively owned by a -single module. IBC packets are sent over channels. Just as IP packets contain the destination IP -address and IP port, and the source IP address and source IP port, IBC packets contain -the destination portID and channelID, and the source portID and channelID. This packet structure enables IBC to -correctly route packets to the destination module while allowing modules receiving packets to -know the sender module. - -A channel can be `ORDERED`, where packets from a sending module must be processed by the -receiving module in the order they were sent. Or a channel can be `UNORDERED`, where packets -from a sending module are processed in the order they arrive (might be in a different order than they were sent). - -Modules can choose which channels they wish to communicate over with, thus IBC expects modules to -implement callbacks that are called during the channel handshake. These callbacks can do custom -channel initialization logic. If any callback returns an error, the channel handshake fails. Thus, by -returning errors on callbacks, modules can programmatically reject and accept channels. - -The channel handshake is a 4-step handshake. Briefly, if a given chain A wants to open a channel with -chain B using an already established connection: - -1. chain A sends a `ChanOpenInit` message to signal a channel initialization attempt with chain B. -2. chain B sends a `ChanOpenTry` message to try opening the channel on chain A. -3. chain A sends a `ChanOpenAck` message to mark its channel end status as open. -4. chain B sends a `ChanOpenConfirm` message to mark its channel end status as open. - -If all handshake steps are successful, the channel is opened on both sides. At each step in the handshake, the module -associated with the `ChannelEnd` executes its callback. So -on `ChanOpenInit`, the module on chain A executes its callback `OnChanOpenInit`. - -The channel identifier is auto derived in the format: `channel-{N}` where N is the next sequence to be used. - -Just as ports came with dynamic capabilities, channel initialization returns a dynamic capability -that the module **must** claim so that they can pass in a capability to authenticate channel actions -like sending packets. The channel capability is passed into the callback on the first parts of the -handshake; either `OnChanOpenInit` on the initializing chain or `OnChanOpenTry` on the other chain. - -#### Closing channels - -Closing a channel occurs in 2 handshake steps as defined in [ICS 04](https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics). - -`ChanCloseInit` closes a channel on the executing chain if the channel exists, it is not -already closed and the connection it exists upon is OPEN. Channels can only be closed by a -calling module or in the case of a packet timeout on an ORDERED channel. - -`ChanCloseConfirm` is a response to a counterparty channel executing `ChanCloseInit`. The channel -on the executing chain closes if the channel exists, the channel is not already closed, -the connection the channel exists upon is OPEN and the executing chain successfully verifies -that the counterparty channel has been closed. - -### [Packets](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -Modules communicate with each other by sending packets over IBC channels. All -IBC packets contain the destination `portID` and `channelID` along with the source `portID` and -`channelID`. This packet structure allows modules to know the sender module of a given packet. IBC packets -contain a sequence to optionally enforce ordering. - -IBC packets also contain a `TimeoutHeight` and a `TimeoutTimestamp` that determine the deadline before the receiving module must process a packet. - -Modules send custom application data to each other inside the `Data []byte` field of the IBC packet. -Thus, packet data is opaque to IBC handlers. It is incumbent on a sender module to encode -their application-specific packet information into the `Data` field of packets. The receiver -module must decode that `Data` back to the original application data. - -### [Receipts and Timeouts](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -Since IBC works over a distributed network and relies on potentially faulty relayers to relay messages between ledgers, -IBC must handle the case where a packet does not get sent to its destination in a timely manner or at all. Packets must -specify a non-zero value for timeout height (`TimeoutHeight`) or timeout timestamp (`TimeoutTimestamp` ) after which a packet can no longer be successfully received on the destination chain. - -- The `timeoutHeight` indicates a consensus height on the destination chain after which the packet is no longer be processed, and instead counts as having timed-out. -- The `timeoutTimestamp` indicates a timestamp on the destination chain after which the packet is no longer be processed, and instead counts as having timed-out. - -If the timeout passes without the packet being successfully received, the packet can no longer be -received on the destination chain. The sending module can timeout the packet and take appropriate actions. - -If the timeout is reached, then a proof of packet timeout can be submitted to the original chain. The original chain can then perform -application-specific logic to timeout the packet, perhaps by rolling back the packet send changes (refunding senders any locked funds, etc.). - -- In ORDERED channels, a timeout of a single packet in the channel causes the channel to close. - - - If packet sequence `n` times out, then a packet at sequence `k > n` cannot be received without violating the contract of ORDERED channels that packets are processed in the order that they are sent. - - Since ORDERED channels enforce this invariant, a proof that sequence `n` has not been received on the destination chain by the specified timeout of packet `n` is sufficient to timeout packet `n` and close the channel. - -- In UNORDERED channels, the application-specific timeout logic for that packet is applied and the channel is not closed. - - - Packets can be received in any order. - - - IBC writes a packet receipt for each sequence receives in the UNORDERED channel. This receipt does not contain information; it is simply a marker intended to signify that the UNORDERED channel has received a packet at the specified sequence. - - - To timeout a packet on an UNORDERED channel, a proof is required that a packet receipt **does not exist** for the packet's sequence by the specified timeout. - -For this reason, most modules should use UNORDERED channels as they require fewer liveness guarantees to function effectively for users of that channel. - -### [Acknowledgments](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -Modules can also choose to write application-specific acknowledgments upon processing a packet. Acknowledgments can be done: - -- Synchronously on `OnRecvPacket` if the module processes packets as soon as they are received from IBC module. -- Asynchronously if module processes packets at some later point after receiving the packet. - -This acknowledgment data is opaque to IBC much like the packet `Data` and is treated by IBC as a simple byte string `[]byte`. Receiver modules must encode their acknowledgment so that the sender module can decode it correctly. The encoding must be negotiated between the two parties during version negotiation in the channel handshake. - -The acknowledgment can encode whether the packet processing succeeded or failed, along with additional information that allows the sender module to take appropriate action. - -After the acknowledgment has been written by the receiving chain, a relayer relays the acknowledgment back to the original sender module. - -The original sender module then executes application-specific acknowledgment logic using the contents of the acknowledgment. - -- After an acknowledgement fails, packet-send changes can be rolled back (for example, refunding senders in ICS20). - -- After an acknowledgment is received successfully on the original sender on the chain, the corresponding packet commitment is deleted since it is no longer needed. - -## Further Readings and Specs - -If you want to learn more about IBC, check the following specifications: - -- [IBC specification overview](https://github.com/cosmos/ibc/blob/master/README.md) diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/02-integration.md b/docs/versioned_docs/version-v4.4.x/01-ibc/02-integration.md deleted file mode 100644 index 60bedf7e216..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/02-integration.md +++ /dev/null @@ -1,222 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 2 -slug: /ibc/integration ---- - -# Integration - -:::note Synopsis -Learn how to integrate IBC to your application and send data packets to other chains. -::: - -This document outlines the required steps to integrate and configure the [IBC -module](https://github.com/cosmos/ibc-go/tree/main/modules/core) to your Cosmos SDK application and -send fungible token transfers to other chains. - -## Integrating the IBC module - -Integrating the IBC module to your SDK-based application is straighforward. The general changes can be summarized in the following steps: - -- Add required modules to the `module.BasicManager` -- Define additional `Keeper` fields for the new modules on the `App` type -- Add the module's `StoreKeys` and initialize their `Keepers` -- Set up corresponding routers and routes for the `ibc` module -- Add the modules to the module `Manager` -- Add modules to `Begin/EndBlockers` and `InitGenesis` -- Update the module `SimulationManager` to enable simulations - -### Module `BasicManager` and `ModuleAccount` permissions - -The first step is to add the following modules to the `BasicManager`: `x/capability`, `x/ibc`, -and `x/ibc-transfer`. After that, we need to grant `Minter` and `Burner` permissions to -the `ibc-transfer` `ModuleAccount` to mint and burn relayed tokens. - -```go -// app.go -var ( - - ModuleBasics = module.NewBasicManager( - // ... - capability.AppModuleBasic{}, - ibc.AppModuleBasic{}, - transfer.AppModuleBasic{}, // i.e ibc-transfer module - ) - - // module account permissions - maccPerms = map[string][]string{ - // other module accounts permissions - // ... - ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, -) -``` - -### Application fields - -Then, we need to register the `Keepers` as follows: - -```go -// app.go -type App struct { - // baseapp, keys and subspaces definitions - - // other keepers - // ... - IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly - TransferKeeper ibctransferkeeper.Keeper // for cross-chain fungible token transfers - - // make scoped keepers public for test purposes - ScopedIBCKeeper capabilitykeeper.ScopedKeeper - ScopedTransferKeeper capabilitykeeper.ScopedKeeper - - /// ... - /// module and simulation manager definitions -} -``` - -### Configure the `Keepers` - -During initialization, besides initializing the IBC `Keepers` (for the `x/ibc`, and -`x/ibc-transfer` modules), we need to grant specific capabilities through the capability module -`ScopedKeepers` so that we can authenticate the object-capability permissions for each of the IBC -channels. - -```go -func NewApp(...args) *App { - // define codecs and baseapp - - // add capability keeper and ScopeToModule for ibc module - app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey]) - - // grant capabilities for the ibc and ibc-transfer modules - scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName) - scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) - - // ... other modules keepers - - // Create IBC Keeper - app.IBCKeeper = ibckeeper.NewKeeper( - appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper, - ) - - // Create Transfer Keepers - app.TransferKeeper = ibctransferkeeper.NewKeeper( - appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName), - app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, app.BankKeeper, scopedTransferKeeper, - ) - transferModule := transfer.NewAppModule(app.TransferKeeper) - - // .. continues -} -``` - -### Register `Routers` - -IBC needs to know which module is bound to which port so that it can route packets to the -appropriate module and call the appropriate callbacks. The port to module name mapping is handled by -IBC's port `Keeper`. However, the mapping from module name to the relevant callbacks is accomplished -by the port -[`Router`](https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port/types/router.go) on the -IBC module. - -Adding the module routes allows the IBC handler to call the appropriate callback when processing a -channel handshake or a packet. - -Currently, a `Router` is static so it must be initialized and set correctly on app initialization. -Once the `Router` has been set, no new routes can be added. - -```go -// app.go -func NewApp(...args) *App { - // .. continuation from above - - // Create static IBC router, add ibc-tranfer module route, then set and seal it - ibcRouter := port.NewRouter() - ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule) - // Setting Router will finalize all routes by sealing router - // No more routes can be added - app.IBCKeeper.SetRouter(ibcRouter) - - // .. continues -``` - -### Module Managers - -In order to use IBC, we need to add the new modules to the module `Manager` and to the `SimulationManager` in case your application supports [simulations](https://github.com/cosmos/cosmos-sdk/blob/main/docs/build/building-modules/14-simulator.md). - -```go -// app.go -func NewApp(...args) *App { - // .. continuation from above - - app.mm = module.NewManager( - // other modules - // ... - capability.NewAppModule(appCodec, *app.CapabilityKeeper), - ibc.NewAppModule(app.IBCKeeper), - transferModule, - ) - - // ... - - app.sm = module.NewSimulationManager( - // other modules - // ... - capability.NewAppModule(appCodec, *app.CapabilityKeeper), - ibc.NewAppModule(app.IBCKeeper), - transferModule, - ) - - // .. continues -``` - -### Application ABCI Ordering - -One addition from IBC is the concept of `HistoricalEntries` which are stored on the staking module. -Each entry contains the historical information for the `Header` and `ValidatorSet` of this chain which is stored -at each height during the `BeginBlock` call. The historical info is required to introspect the -past historical info at any given height in order to verify the light client `ConsensusState` during the -connection handhake. - -The IBC module also has -[`BeginBlock`](https://github.com/cosmos/ibc-go/blob/main/modules/core/02-client/abci.go) logic as well. This is optional as it is only required if your application uses the localhost client to connect two different modules from the same chain. - -:::tip -Only register the ibc module to the `SetOrderBeginBlockers` if your application will use the -localhost (*aka* loopback) client. -::: - -```go -// app.go -func NewApp(...args) *App { - // .. continuation from above - - // add staking and ibc modules to BeginBlockers - app.mm.SetOrderBeginBlockers( - // other modules ... - stakingtypes.ModuleName, ibchost.ModuleName, - ) - - // ... - - // 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. - app.mm.SetOrderInitGenesis( - capabilitytypes.ModuleName, - // other modules ... - ibchost.ModuleName, ibctransfertypes.ModuleName, - ) - - // .. continues -``` - -:::warning -**IMPORTANT**: The capability module **must** be declared first in `SetOrderInitGenesis` -::: - -That's it! You have now wired up the IBC module and are now able to send fungible tokens across -different chains. If you want to have a broader view of the changes take a look into the SDK's -[`SimApp`](https://github.com/cosmos/ibc-go/blob/main/testing/simapp/app.go). diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/01-apps.md b/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/01-apps.md deleted file mode 100644 index 58a1bb63045..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/01-apps.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: IBC Applications -sidebar_label: IBC Applications -sidebar_position: 1 -slug: /ibc/apps/apps ---- - -# IBC Applications - -:::note Synopsis -Learn how to build custom IBC application modules that enable packets to be sent to and received from other IBC-enabled chains. -::: - -This document serves as a guide for developers who want to write their own Inter-blockchain Communication Protocol (IBC) applications for custom use cases. - -Due to the modular design of the IBC protocol, IBC application developers do not need to concern themselves with the low-level details of clients, connections, and proof verification. Nevertheless, an overview of these low-level concepts can be found in [the Overview section](../01-overview.md). -The document goes into detail on the abstraction layer most relevant for application developers (channels and ports), and describes how to define your own custom packets, `IBCModule` callbacks and more to make an application module IBC ready. - -**To have your module interact over IBC you must:** - -- implement the `IBCModule` interface, i.e.: - - channel (opening) handshake callbacks - - channel closing handshake callbacks - - packet callbacks -- bind to a port(s) -- add keeper methods -- define your own packet data and acknowledgement structs as well as how to encode/decode them -- add a route to the IBC router - -The following sections provide a more detailed explanation of how to write an IBC application -module correctly corresponding to the listed steps. - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: - -## Working example - -For a real working example of an IBC application, you can look through the `ibc-transfer` module -which implements everything discussed in this section. - -Here are the useful parts of the module to look at: - -[Binding to transfer -port](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/genesis.go) - -[Sending transfer -packets](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/relay.go) - -[Implementing IBC -callbacks](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/ibc_module.go) diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/02-ibcmodule.md b/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/02-ibcmodule.md deleted file mode 100644 index ce96fbe4778..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/02-ibcmodule.md +++ /dev/null @@ -1,351 +0,0 @@ ---- -title: Implement `IBCModule` interface and callbacks -sidebar_label: Implement `IBCModule` interface and callbacks -sidebar_position: 2 -slug: /ibc/apps/ibcmodule ---- - -# Implement `IBCModule` interface and callbacks - -:::note Synopsis -Learn how to implement the `IBCModule` interface and all of the callbacks it requires. -::: - -The Cosmos SDK expects all IBC modules to implement the [`IBCModule` -interface](https://github.com/cosmos/ibc-go/tree/main/modules/core/05-port/types/module.go). This interface contains all of the callbacks IBC expects modules to implement. They include callbacks related to channel handshake, closing and packet callbacks (`OnRecvPacket`, `OnAcknowledgementPacket` and `OnTimeoutPacket`). - -```go -// IBCModule implements the ICS26 interface for given the keeper. -// The implementation of the IBCModule interface could for example be in a file called ibc_module.go, -// but ultimately file structure is up to the developer -type IBCModule struct { - keeper keeper.Keeper -} -``` - -Additionally, in the `module.go` file, add the following line: - -```go -var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} - // Add this line - _ porttypes.IBCModule = IBCModule{} -) -``` - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: - -## Channel handshake callbacks - -This section will describe the callbacks that are called during channel handshake execution. Among other things, it will claim channel capabilities passed on from core IBC. For a refresher on capabilities, check [the Overview section](../01-overview.md#capabilities). - -Here are the channel handshake callbacks that modules are expected to implement: - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `checkArguments` and `negotiateAppVersion` functions. - -```go -// Called by IBC Handler on MsgOpenInit -func (im IBCModule) OnChanOpenInit(ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) (string, error) { - // ... do custom initialization logic - - // Use above arguments to determine if we want to abort handshake - // Examples: - // - Abort if order == UNORDERED, - // - Abort if version is unsupported - if err := checkArguments(args); err != nil { - return "", err - } - - // OpenInit must claim the channelCapability that IBC passes into the callback - if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return "", err - } - - return version, nil -} - -// Called by IBC Handler on MsgOpenTry -func (im IBCModule) OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (string, error) { - // ... do custom initialization logic - - // Use above arguments to determine if we want to abort handshake - if err := checkArguments(args); err != nil { - return "", err - } - - // OpenTry must claim the channelCapability that IBC passes into the callback - if err := im.keeper.scopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return err - } - - // Construct application version - // IBC applications must return the appropriate application version - // This can be a simple string or it can be a complex version constructed - // from the counterpartyVersion and other arguments. - // The version returned will be the channel version used for both channel ends. - appVersion := negotiateAppVersion(counterpartyVersion, args) - - return appVersion, nil -} - -// Called by IBC Handler on MsgOpenAck -func (im IBCModule) OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyVersion string, -) error { - if counterpartyVersion != types.Version { - return sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: %s, expected %s", counterpartyVersion, types.Version) - } - - // do custom logic - - return nil -} - -// Called by IBC Handler on MsgOpenConfirm -func (im IBCModule) OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // do custom logic - - return nil -} -``` - -The channel closing handshake will also invoke module callbacks that can return errors to abort the closing handshake. Closing a channel is a 2-step handshake, the initiating chain calls `ChanCloseInit` and the finalizing chain calls `ChanCloseConfirm`. - -```go -// Called by IBC Handler on MsgCloseInit -func (im IBCModule) OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - // ... do custom finalization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} - -// Called by IBC Handler on MsgCloseConfirm -func (im IBCModule) OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // ... do custom finalization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} -``` - -### Channel handshake version negotiation - -Application modules are expected to verify versioning used during the channel handshake procedure. - -- `OnChanOpenInit` will verify that the relayer-chosen parameters - are valid and perform any custom `INIT` logic. - It may return an error if the chosen parameters are invalid - in which case the handshake is aborted. - If the provided version string is non-empty, `OnChanOpenInit` should return - the version string if valid or an error if the provided version is invalid. - **If the version string is empty, `OnChanOpenInit` is expected to - return a default version string representing the version(s) - it supports.** - If there is no default version string for the application, - it should return an error if the provided version is an empty string. -- `OnChanOpenTry` will verify the relayer-chosen parameters along with the - counterparty-chosen version string and perform custom `TRY` logic. - If the relayer-chosen parameters - are invalid, the callback must return an error to abort the handshake. - If the counterparty-chosen version is not compatible with this module's - supported versions, the callback must return an error to abort the handshake. - If the versions are compatible, the try callback must select the final version - string and return it to core IBC. - `OnChanOpenTry` may also perform custom initialization logic. -- `OnChanOpenAck` will error if the counterparty selected version string - is invalid and abort the handshake. It may also perform custom ACK logic. - -Versions must be strings but can implement any versioning structure. If your application plans to -have linear releases then semantic versioning is recommended. If your application plans to release -various features in between major releases then it is advised to use the same versioning scheme -as IBC. This versioning scheme specifies a version identifier and compatible feature set with -that identifier. Valid version selection includes selecting a compatible version identifier with -a subset of features supported by your application for that version. The struct used for this -scheme can be found in [03-connection/types](https://github.com/cosmos/ibc-go/blob/main/modules/core/03-connection/types/version.go#L16). - -Since the version type is a string, applications have the ability to do simple version verification -via string matching or they can use the already impelemented versioning system and pass the proto -encoded version into each handhshake call as necessary. - -ICS20 currently implements basic string matching with a single supported version. - -## Packet callbacks - -Just as IBC expects modules to implement callbacks for channel handshakes, it also expects modules to implement callbacks for handling the packet flow through a channel, as defined in the `IBCModule` interface. - -Once a module A and module B are connected to each other, relayers can start relaying packets and acknowledgements back and forth on the channel. - -![IBC packet flow diagram](./images/packet_flow.png) - -Briefly, a successful packet flow works as follows: - -1. module A sends a packet through the IBC module -2. the packet is received by module B -3. if module B writes an acknowledgement of the packet then module A will process the - acknowledgement -4. if the packet is not successfully received before the timeout, then module A processes the - packet's timeout. - -### Sending packets - -Modules **do not send packets through callbacks**, since the modules initiate the action of sending packets to the IBC module, as opposed to other parts of the packet flow where messages sent to the IBC -module must trigger execution on the port-bound module through the use of callbacks. Thus, to send a packet a module simply needs to call `SendPacket` on the `IBCChannelKeeper`. - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `EncodePacketData(customPacketData)` function. - -```go -// retrieve the dynamic capability for this channel -channelCap := scopedKeeper.GetCapability(ctx, channelCapName) -// Sending custom application packet data -data := EncodePacketData(customPacketData) -packet.Data = data -// Send packet to IBC, authenticating with channelCap -IBCChannelKeeper.SendPacket(ctx, channelCap, packet) -``` - -:::warning -In order to prevent modules from sending packets on channels they do not own, IBC expects -modules to pass in the correct channel capability for the packet's source channel. -::: - -### Receiving packets - -To handle receiving packets, the module must implement the `OnRecvPacket` callback. This gets -invoked by the IBC module after the packet has been proved valid and correctly processed by the IBC -keepers. Thus, the `OnRecvPacket` callback only needs to worry about making the appropriate state -changes given the packet data without worrying about whether the packet is valid or not. - -Modules may return to the IBC handler an acknowledgement which implements the `Acknowledgement` interface. -The IBC handler will then commit this acknowledgement of the packet so that a relayer may relay the -acknowledgement back to the sender module. - -The state changes that occurred during this callback will only be written if: - -- the acknowledgement was successful as indicated by the `Success()` function of the acknowledgement -- if the acknowledgement returned is nil indicating that an asynchronous process is occurring - -NOTE: Applications which process asynchronous acknowledgements must handle reverting state changes -when appropriate. Any state changes that occurred during the `OnRecvPacket` callback will be written -for asynchronous acknowledgements. - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `DecodePacketData(packet.Data)` function. - -```go -func (im IBCModule) OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, -) ibcexported.Acknowledgement { - // Decode the packet data - packetData := DecodePacketData(packet.Data) - - // do application state changes based on packet data and return the acknowledgement - // NOTE: The acknowledgement will indicate to the IBC handler if the application - // state changes should be written via the `Success()` function. Application state - // changes are only written if the acknowledgement is successful or the acknowledgement - // returned is nil indicating that an asynchronous acknowledgement will occur. - ack := processPacket(ctx, packet, packetData) - - return ack -} -``` - -Reminder, the `Acknowledgement` interface: - -```go -// Acknowledgement defines the interface used to return -// acknowledgements in the OnRecvPacket callback. -type Acknowledgement interface { - Success() bool - Acknowledgement() []byte -} -``` - -### Acknowledging packets - -After a module writes an acknowledgement, a relayer can relay back the acknowledgement to the sender module. The sender module can -then process the acknowledgement using the `OnAcknowledgementPacket` callback. The contents of the -acknowledgement is entirely up to the modules on the channel (just like the packet data); however, it -may often contain information on whether the packet was successfully processed along -with some additional data that could be useful for remediation if the packet processing failed. - -Since the modules are responsible for agreeing on an encoding/decoding standard for packet data and -acknowledgements, IBC will pass in the acknowledgements as `[]byte` to this callback. The callback -is responsible for decoding the acknowledgement and processing it. - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `DecodeAcknowledgement(acknowledgments)` and `processAck(ack)` functions. - -```go -func (im IBCModule) OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, -) (*sdk.Result, error) { - // Decode acknowledgement - ack := DecodeAcknowledgement(acknowledgement) - - // process ack - res, err := processAck(ack) - return res, err -} -``` - -### Timeout packets - -If the timeout for a packet is reached before the packet is successfully received or the -counterparty channel end is closed before the packet is successfully received, then the receiving -chain can no longer process it. Thus, the sending chain must process the timeout using -`OnTimeoutPacket` to handle this situation. Again the IBC module will verify that the timeout is -indeed valid, so our module only needs to implement the state machine logic for what to do once a -timeout is reached and the packet can no longer be received. - -```go -func (im IBCModule) OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, -) (*sdk.Result, error) { - // do custom timeout logic -} -``` diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/03-bindports.md b/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/03-bindports.md deleted file mode 100644 index a57ec4c6000..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/03-bindports.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -title: Bind ports -sidebar_label: Bind ports -sidebar_position: 3 -slug: /ibc/apps/bindports ---- - -# Bind ports - -:::note Synopsis -Learn what changes to make to bind modules to their ports on initialization. -::: - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: -Currently, ports must be bound on app initialization. In order to bind modules to their respective ports on initialization, the following needs to be implemented: - -> Note that `portID` does not refer to a certain numerical ID, like `localhost:8080` with a `portID` 8080. Rather it refers to the application module the port binds. For IBC Modules built with the Cosmos SDK, it defaults to the module's name and for Cosmwasm contracts it defaults to the contract address. - -1. Add port ID to the `GenesisState` proto definition: - - ```protobuf - message GenesisState { - string port_id = 1; - // other fields - } - ``` - -1. Add port ID as a key to the module store: - - ```go - // x//types/keys.go - const ( - // ModuleName defines the IBC Module name - ModuleName = "moduleName" - - // Version defines the current version the IBC - // module supports - Version = "moduleVersion-1" - - // PortID is the default port id that module binds to - PortID = "portID" - - // ... - ) - ``` - -1. Add port ID to `x//types/genesis.go`: - - ```go - // in x//types/genesis.go - - // DefaultGenesisState returns a GenesisState with "transfer" as the default PortID. - func DefaultGenesisState() *GenesisState { - return &GenesisState{ - PortId: PortID, - // additional k-v fields - } - } - - // Validate performs basic genesis state validation returning an error upon any - // failure. - func (gs GenesisState) Validate() error { - if err := host.PortIdentifierValidator(gs.PortId); err != nil { - return err - } - //addtional validations - - return gs.Params.Validate() - } - ``` - -1. Bind to port(s) in the module keeper's `InitGenesis`: - - ```go - // InitGenesis initializes the ibc-module state and binds to PortID. - func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) { - k.SetPort(ctx, state.PortId) - - // ... - - // Only try to bind to port if it is not already bound, since we may already own - // port capability from capability InitGenesis - if !k.IsBound(ctx, state.PortId) { - // transfer module binds to the transfer port on InitChain - // and claims the returned capability - err := k.BindPort(ctx, state.PortId) - if err != nil { - panic(fmt.Sprintf("could not claim port capability: %v", err)) - } - } - - // ... - } - ``` - - With: - - ```go - // IsBound checks if the module is already bound to the desired port - func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { - _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) - return ok - } - - // BindPort defines a wrapper function for the port Keeper's function in - // order to expose it to module's InitGenesis function - func (k Keeper) BindPort(ctx sdk.Context, portID string) error { - cap := k.portKeeper.BindPort(ctx, portID) - return k.ClaimCapability(ctx, cap, host.PortPath(portID)) - } - ``` - - The module binds to the desired port(s) and returns the capabilities. - - In the above we find reference to keeper methods that wrap other keeper functionality, in the next section the keeper methods that need to be implemented will be defined. diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/04-keeper.md b/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/04-keeper.md deleted file mode 100644 index e359e014f2c..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/04-keeper.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: Keeper -sidebar_label: Keeper -sidebar_position: 4 -slug: /ibc/apps/keeper ---- - -# Keeper - -:::note Synopsis -Learn how to implement the IBC Module keeper. -::: - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: -In the previous sections, on channel handshake callbacks and port binding in `InitGenesis`, a reference was made to keeper methods that need to be implemented when creating a custom IBC module. Below is an overview of how to define an IBC module's keeper. - -> Note that some code has been left out for clarity, to get a full code overview, please refer to [the transfer module's keeper in the ibc-go repo](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/keeper.go). - -```go -// Keeper defines the IBC app module keeper -type Keeper struct { - storeKey sdk.StoreKey - cdc codec.BinaryCodec - paramSpace paramtypes.Subspace - - channelKeeper types.ChannelKeeper - portKeeper types.PortKeeper - scopedKeeper capabilitykeeper.ScopedKeeper - - // ... additional according to custom logic -} - -// NewKeeper creates a new IBC app module Keeper instance -func NewKeeper( - // args -) Keeper { - // ... - - return Keeper{ - cdc: cdc, - storeKey: key, - paramSpace: paramSpace, - - channelKeeper: channelKeeper, - portKeeper: portKeeper, - scopedKeeper: scopedKeeper, - - // ... additional according to custom logic - } -} - -// IsBound checks if the IBC app module is already bound to the desired port -func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { - _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) - return ok -} - -// BindPort defines a wrapper function for the port Keeper's function in -// order to expose it to module's InitGenesis function -func (k Keeper) BindPort(ctx sdk.Context, portID string) error { - cap := k.portKeeper.BindPort(ctx, portID) - return k.ClaimCapability(ctx, cap, host.PortPath(portID)) -} - -// GetPort returns the portID for the IBC app module. Used in ExportGenesis -func (k Keeper) GetPort(ctx sdk.Context) string { - store := ctx.KVStore(k.storeKey) - return string(store.Get(types.PortKey)) -} - -// SetPort sets the portID for the IBC app module. Used in InitGenesis -func (k Keeper) SetPort(ctx sdk.Context, portID string) { - store := ctx.KVStore(k.storeKey) - store.Set(types.PortKey, []byte(portID)) -} - -// AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function -func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool { - return k.scopedKeeper.AuthenticateCapability(ctx, cap, name) -} - -// ClaimCapability allows the IBC app module to claim a capability that core IBC -// passes to it -func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { - return k.scopedKeeper.ClaimCapability(ctx, cap, name) -} - -// ... additional according to custom logic -``` diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/05-packets_acks.md b/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/05-packets_acks.md deleted file mode 100644 index 95bec486255..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/05-packets_acks.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -title: Define packets and acks -sidebar_label: Define packets and acks -sidebar_position: 5 -slug: /ibc/apps/packets_acks ---- - -# Define packets and acks - -:::note Synopsis -Learn how to define custom packet and acknowledgement structs and how to encode and decode them. -::: - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: - -## Custom packets - -Modules connected by a channel must agree on what application data they are sending over the -channel, as well as how they will encode/decode it. This process is not specified by IBC as it is up -to each application module to determine how to implement this agreement. However, for most -applications this will happen as a version negotiation during the channel handshake. While more -complex version negotiation is possible to implement inside the channel opening handshake, a very -simple version negotation is implemented in the [ibc-transfer module](https://github.com/cosmos/ibc-go/tree/main/modules/apps/transfer/module.go). - -Thus, a module must define its custom packet data structure, along with a well-defined way to -encode and decode it to and from `[]byte`. - -```go -// Custom packet data defined in application module -type CustomPacketData struct { - // Custom fields ... -} - -EncodePacketData(packetData CustomPacketData) []byte { - // encode packetData to bytes -} - -DecodePacketData(encoded []byte) (CustomPacketData) { - // decode from bytes to packet data -} -``` - -> Note that the `CustomPacketData` struct is defined in the proto definition and then compiled by the protobuf compiler. - -Then a module must encode its packet data before sending it through IBC. - -```go -// Sending custom application packet data -data := EncodePacketData(customPacketData) -packet.Data = data -IBCChannelKeeper.SendPacket(ctx, packet) -``` - -A module receiving a packet must decode the `PacketData` into a structure it expects so that it can -act on it. - -```go -// Receiving custom application packet data (in OnRecvPacket) -packetData := DecodePacketData(packet.Data) -// handle received custom packet data -``` - -## Acknowledgements - -Modules may commit an acknowledgement upon receiving and processing a packet in the case of synchronous packet processing. -In the case where a packet is processed at some later point after the packet has been received (asynchronous execution), the acknowledgement -will be written once the packet has been processed by the application which may be well after the packet receipt. - -NOTE: Most blockchain modules will want to use the synchronous execution model in which the module processes and writes the acknowledgement -for a packet as soon as it has been received from the IBC module. - -This acknowledgement can then be relayed back to the original sender chain, which can take action -depending on the contents of the acknowledgement. - -Just as packet data was opaque to IBC, acknowledgements are similarly opaque. Modules must pass and -receive acknowledegments with the IBC modules as byte strings. - -Thus, modules must agree on how to encode/decode acknowledgements. The process of creating an -acknowledgement struct along with encoding and decoding it, is very similar to the packet data -example above. [ICS 04](https://github.com/cosmos/ibc/blob/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope) -specifies a recommended format for acknowledgements. This acknowledgement type can be imported from -[channel types](https://github.com/cosmos/ibc-go/tree/main/modules/core/04-channel/types). - -While modules may choose arbitrary acknowledgement structs, a default acknowledgement types is provided by IBC [here](https://github.com/cosmos/ibc-go/blob/main/proto/ibc/core/channel/v1/channel.proto): - -```protobuf -// Acknowledgement is the recommended acknowledgement format to be used by -// app-specific protocols. -// NOTE: The field numbers 21 and 22 were explicitly chosen to avoid accidental -// conflicts with other protobuf message formats used for acknowledgements. -// The first byte of any message with this format will be the non-ASCII values -// `0xaa` (result) or `0xb2` (error). Implemented as defined by ICS: -// https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope -message Acknowledgement { - // response contains either a result or an error and must be non-empty - oneof response { - bytes result = 21; - string error = 22; - } -} -``` diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/06-routing.md b/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/06-routing.md deleted file mode 100644 index e11b3182e7f..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/06-routing.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Routing -sidebar_label: Routing -sidebar_position: 6 -slug: /ibc/apps/routing ---- - -# Routing - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: -:::note Synopsis -Learn how to hook a route to the IBC router for the custom IBC module. -::: - -As mentioned above, modules must implement the `IBCModule` interface (which contains both channel -handshake callbacks and packet handling callbacks). The concrete implementation of this interface -must be registered with the module name as a route on the IBC `Router`. - -```go -// app.go -func NewApp(...args) *App { -// ... - -// Create static IBC router, add module routes, then set and seal it -ibcRouter := port.NewRouter() - -ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule) -// Note: moduleCallbacks must implement IBCModule interface -ibcRouter.AddRoute(moduleName, moduleCallbacks) - -// Setting Router will finalize all routes by sealing router -// No more routes can be added -app.IBCKeeper.SetRouter(ibcRouter) - -// ... -} -``` diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/_category_.json b/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/_category_.json deleted file mode 100644 index 4561a95b84c..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Applications", - "position": 3, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/images/packet_flow.png b/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/images/packet_flow.png deleted file mode 100644 index db2d1d314b8..00000000000 Binary files a/docs/versioned_docs/version-v4.4.x/01-ibc/03-apps/images/packet_flow.png and /dev/null differ diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/04-middleware/01-develop.md b/docs/versioned_docs/version-v4.4.x/01-ibc/04-middleware/01-develop.md deleted file mode 100644 index 27304558b5f..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/04-middleware/01-develop.md +++ /dev/null @@ -1,422 +0,0 @@ ---- -title: IBC middleware -sidebar_label: IBC middleware -sidebar_position: 1 -slug: /ibc/middleware/develop ---- - -# IBC middleware - -:::note Synopsis -Learn how to write your own custom middleware to wrap an IBC application, and understand how to hook different middleware to IBC base applications to form different IBC application stacks -:::. - -This document serves as a guide for middleware developers who want to write their own middleware and for chain developers who want to use IBC middleware on their chains. - -IBC applications are designed to be self-contained modules that implement their own application-specific logic through a set of interfaces with the core IBC handlers. These core IBC handlers, in turn, are designed to enforce the correctness properties of IBC (transport, authentication, ordering) while delegating all application-specific handling to the IBC application modules. However, there are cases where some functionality may be desired by many applications, yet not appropriate to place in core IBC. - -Middleware allows developers to define the extensions as separate modules that can wrap over the base application. This middleware can thus perform its own custom logic, and pass data into the application so that it may run its logic without being aware of the middleware's existence. This allows both the application and the middleware to implement its own isolated logic while still being able to run as part of a single packet flow. - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC Integration](../02-integration.md) -- [IBC Application Developer Guide](../03-apps/01-apps.md) - -::: - -## Definitions - -`Middleware`: A self-contained module that sits between core IBC and an underlying IBC application during packet execution. All messages between core IBC and underlying application must flow through middleware, which may perform its own custom logic. - -`Underlying Application`: An underlying application is the application that is directly connected to the middleware in question. This underlying application may itself be middleware that is chained to a base application. - -`Base Application`: A base application is an IBC application that does not contain any middleware. It may be nested by 0 or multiple middleware to form an application stack. - -`Application Stack (or stack)`: A stack is the complete set of application logic (middleware(s) + base application) that gets connected to core IBC. A stack may be just a base application, or it may be a series of middlewares that nest a base application. - -## Create a custom IBC middleware - -IBC middleware will wrap over an underlying IBC application and sits between core IBC and the application. It has complete control in modifying any message coming from IBC to the application, and any message coming from the application to core IBC. Thus, middleware must be completely trusted by chain developers who wish to integrate them, however this gives them complete flexibility in modifying the application(s) they wrap. - -### Interfaces - -```go -// Middleware implements the ICS26 Module interface -type Middleware interface { - porttypes.IBCModule // middleware has acccess to an underlying application which may be wrapped by more middleware - ics4Wrapper: ICS4Wrapper // middleware has access to ICS4Wrapper which may be core IBC Channel Handler or a higher-level middleware that wraps this middleware. -} -``` - -```typescript -// This is implemented by ICS4 and all middleware that are wrapping base application. -// The base application will call `sendPacket` or `writeAcknowledgement` of the middleware directly above them -// which will call the next middleware until it reaches the core IBC handler. -type ICS4Wrapper interface { - SendPacket(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet exported.Packet) error - WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet exported.Packet, ack exported.Acknowledgement) error - GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) -} -``` - -### Implement `IBCModule` interface and callbacks - -The `IBCModule` is a struct that implements the [ICS-26 interface (`porttypes.IBCModule`)](https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port/types/module.go#L11-L106). It is recommended to separate these callbacks into a separate file `ibc_module.go`. As will be mentioned in the [integration section](02-integration.md), this struct should be different than the struct that implements `AppModule` in case the middleware maintains its own internal state and processes separate SDK messages. - -The middleware must have access to the underlying application, and be called before during all ICS-26 callbacks. It may execute custom logic during these callbacks, and then call the underlying application's callback. Middleware **may** choose not to call the underlying application's callback at all. Though these should generally be limited to error cases. - -In the case where the IBC middleware expects to speak to a compatible IBC middleware on the counterparty chain, they must use the channel handshake to negotiate the middleware version without interfering in the version negotiation of the underlying application. - -Middleware accomplishes this by formatting the version in a JSON-encoded string containing the middleware version and the application version. The application version may as well be a JSON-encoded string, possibly including further middleware and app versions, if the application stack consists of multiple milddlewares wrapping a base application. The format of the version is specified in ICS-30 as the following: - -```json -{ - "": "", - "app_version": "" -} -``` - -The `` key in the JSON struct should be replaced by the actual name of the key for the corresponding middleware (e.g. `fee_version`). - -During the handshake callbacks, the middleware can unmarshal the version string and retrieve the middleware and application versions. It can do its negotiation logic on ``, and pass the `` to the underlying application. - -The middleware should simply pass the capability in the callback arguments along to the underlying application so that it may be claimed by the base application. The base application will then pass the capability up the stack in order to authenticate an outgoing packet/acknowledgement. - -In the case where the middleware wishes to send a packet or acknowledgment without the involvement of the underlying application, it should be given access to the same `scopedKeeper` as the base application so that it can retrieve the capabilities by itself. - -### Handshake callbacks - -#### `OnChanOpenInit` - -```go -func (im IBCModule) OnChanOpenInit( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) (string, error) { - if version != "" { - // try to unmarshal JSON-encoded version string and pass - // the app-specific version to app callback. - // otherwise, pass version directly to app callback. - metadata, err := Unmarshal(version) - if err != nil { - // Since it is valid for fee version to not be specified, - // the above middleware version may be for another middleware. - // Pass the entire version string onto the underlying application. - return im.app.OnChanOpenInit( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - version, - ) - } - else { - metadata = { - // set middleware version to default value - MiddlewareVersion: defaultMiddlewareVersion, - // allow application to return its default version - AppVersion: "", - } - } - - doCustomLogic() - - // if the version string is empty, OnChanOpenInit is expected to return - // a default version string representing the version(s) it supports - appVersion, err := im.app.OnChanOpenInit( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - metadata.AppVersion, // note we only pass app version here - ) - if err != nil { - return "", err - } - - version := constructVersion(metadata.MiddlewareVersion, appVersion) - - return version, nil -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L34-L82) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnChanOpenTry` - -```go -func OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (string, error) { - // try to unmarshal JSON-encoded version string and pass - // the app-specific version to app callback. - // otherwise, pass version directly to app callback. - cpMetadata, err := Unmarshal(counterpartyVersion) - if err != nil { - return app.OnChanOpenTry( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - counterpartyVersion, - ) - } - - doCustomLogic() - - // Call the underlying application's OnChanOpenTry callback. - // The try callback must select the final app-specific version string and return it. - appVersion, err := app.OnChanOpenTry( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - cpMetadata.AppVersion, // note we only pass counterparty app version here - ) - if err != nil { - return "", err - } - - // negotiate final middleware version - middlewareVersion := negotiateMiddlewareVersion(cpMetadata.MiddlewareVersion) - version := constructVersion(middlewareVersion, appVersion) - - return version, nil -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L84-L124) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnChanOpenAck` - -```go -func OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyChannelID string, - counterpartyVersion string, -) error { - // try to unmarshal JSON-encoded version string and pass - // the app-specific version to app callback. - // otherwise, pass version directly to app callback. - cpMetadata, err = UnmarshalJSON(counterpartyVersion) - if err != nil { - return app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) - } - - if !isCompatible(cpMetadata.MiddlewareVersion) { - return error - } - doCustomLogic() - - // call the underlying application's OnChanOpenTry callback - return app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, cpMetadata.AppVersion) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L126-L152) an example implementation of this callback for the ICS29 Fee Middleware module. - -### `OnChanOpenConfirm` - -```go -func OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - doCustomLogic() - - return app.OnChanOpenConfirm(ctx, portID, channelID) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L154-L162) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnChanCloseInit` - -```go -func OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - doCustomLogic() - - return app.OnChanCloseInit(ctx, portID, channelID) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L164-L187) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnChanCloseConfirm` - -```go -func OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - doCustomLogic() - - return app.OnChanCloseConfirm(ctx, portID, channelID) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L189-L212) an example implementation of this callback for the ICS29 Fee Middleware module. - -**NOTE**: Middleware that does not need to negotiate with a counterparty middleware on the remote stack will not implement the version unmarshalling and negotiation, and will simply perform its own custom logic on the callbacks without relying on the counterparty behaving similarly. - -### Packet callbacks - -The packet callbacks just like the handshake callbacks wrap the application's packet callbacks. The packet callbacks are where the middleware performs most of its custom logic. The middleware may read the packet flow data and perform some additional packet handling, or it may modify the incoming data before it reaches the underlying application. This enables a wide degree of usecases, as a simple base application like token-transfer can be transformed for a variety of usecases by combining it with custom middleware. - -#### `OnRecvPacket` - -```go -func OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) ibcexported.Acknowledgement { - doCustomLogic(packet) - - ack := app.OnRecvPacket(ctx, packet, relayer) - - doCustomLogic(ack) // middleware may modify outgoing ack - return ack -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L214-L237) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnAcknowledgementPacket` - -```go -func OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - relayer sdk.AccAddress, -) error { - doCustomLogic(packet, ack) - - return app.OnAcknowledgementPacket(ctx, packet, ack, relayer) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L239-L292) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnTimeoutPacket` - -```go -func OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) error { - doCustomLogic(packet) - - return app.OnTimeoutPacket(ctx, packet, relayer) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L294-L334) an example implementation of this callback for the ICS29 Fee Middleware module. - -### ICS-4 wrappers - -Middleware must also wrap ICS-4 so that any communication from the application to the `channelKeeper` goes through the middleware first. Similar to the packet callbacks, the middleware may modify outgoing acknowledgements and packets in any way it wishes. - -#### `SendPacket` - -```go -func SendPacket( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - appPacket exported.PacketI, -) { - // middleware may modify packet - packet = doCustomLogic(appPacket) - - return ics4Keeper.SendPacket(ctx, chanCap, packet) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L336-L343) an example implementation of this function for the ICS29 Fee Middleware module. - -#### `WriteAcknowledgement` - -```go -// only called for async acks -func WriteAcknowledgement( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - packet exported.PacketI, - ack exported.Acknowledgement, -) { - // middleware may modify acknowledgement - ack_bytes = doCustomLogic(ack) - - return ics4Keeper.WriteAcknowledgement(packet, ack_bytes) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L345-L353) an example implementation of this function for the ICS29 Fee Middleware module. - -#### `GetAppVersion` - -```go -// middleware must return the underlying application version -func GetAppVersion( - ctx sdk.Context, - portID, - channelID string, -) (string, bool) { - version, found := ics4Keeper.GetAppVersion(ctx, portID, channelID) - if !found { - return "", false - } - - if !MiddlewareEnabled { - return version, true - } - - // unwrap channel version - metadata, err := Unmarshal(version) - if err != nil { - panic(fmt.Errof("unable to unmarshal version: %w", err)) - } - - return metadata.AppVersion, true -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L355-L358) an example implementation of this function for the ICS29 Fee Middleware module. diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/04-middleware/02-integration.md b/docs/versioned_docs/version-v4.4.x/01-ibc/04-middleware/02-integration.md deleted file mode 100644 index 7bda98b5f88..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/04-middleware/02-integration.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: Integrating IBC middleware into a chain -sidebar_label: Integrating IBC middleware into a chain -sidebar_position: 2 -slug: /ibc/middleware/integration ---- - - -# Integrating IBC middleware into a chain - -Learn how to integrate IBC middleware(s) with a base application to your chain. The following document only applies for Cosmos SDK chains. - -If the middleware is maintaining its own state and/or processing SDK messages, then it should create and register its SDK module **only once** with the module manager in `app.go`. - -All middleware must be connected to the IBC router and wrap over an underlying base IBC application. An IBC application may be wrapped by many layers of middleware, only the top layer middleware should be hooked to the IBC router, with all underlying middlewares and application getting wrapped by it. - -The order of middleware **matters**, function calls from IBC to the application travel from top-level middleware to the bottom middleware and then to the application. Function calls from the application to IBC goes through the bottom middleware in order to the top middleware and then to core IBC handlers. Thus the same set of middleware put in different orders may produce different effects. - -## Example integration - -```go -// app.go - -// middleware 1 and middleware 3 are stateful middleware, -// perhaps implementing separate sdk.Msg and Handlers -mw1Keeper := mw1.NewKeeper(storeKey1) -mw3Keeper := mw3.NewKeeper(storeKey3) - -// Only create App Module **once** and register in app module -// if the module maintains independent state and/or processes sdk.Msgs -app.moduleManager = module.NewManager( - ... - mw1.NewAppModule(mw1Keeper), - mw3.NewAppModule(mw3Keeper), - transfer.NewAppModule(transferKeeper), - custom.NewAppModule(customKeeper) -) - -mw1IBCModule := mw1.NewIBCModule(mw1Keeper) -mw2IBCModule := mw2.NewIBCModule() // middleware2 is stateless middleware -mw3IBCModule := mw3.NewIBCModule(mw3Keeper) - -scopedKeeperTransfer := capabilityKeeper.NewScopedKeeper("transfer") -scopedKeeperCustom1 := capabilityKeeper.NewScopedKeeper("custom1") -scopedKeeperCustom2 := capabilityKeeper.NewScopedKeeper("custom2") - -// NOTE: IBC Modules may be initialized any number of times provided they use a separate -// scopedKeeper and underlying port. - -// initialize base IBC applications -// if you want to create two different stacks with the same base application, -// they must be given different scopedKeepers and assigned different ports. -transferIBCModule := transfer.NewIBCModule(transferKeeper) -customIBCModule1 := custom.NewIBCModule(customKeeper, "portCustom1") -customIBCModule2 := custom.NewIBCModule(customKeeper, "portCustom2") - -// create IBC stacks by combining middleware with base application -// NOTE: since middleware2 is stateless it does not require a Keeper -// stack 1 contains mw1 -> mw3 -> transfer -stack1 := mw1.NewIBCMiddleware(mw3.NewIBCMiddleware(transferIBCModule, mw3Keeper), mw1Keeper) -// stack 2 contains mw3 -> mw2 -> custom1 -stack2 := mw3.NewIBCMiddleware(mw2.NewIBCMiddleware(customIBCModule1), mw3Keeper) -// stack 3 contains mw2 -> mw1 -> custom2 -stack3 := mw2.NewIBCMiddleware(mw1.NewIBCMiddleware(customIBCModule2, mw1Keeper)) - -// associate each stack with the moduleName provided by the underlying scopedKeeper -ibcRouter := porttypes.NewRouter() -ibcRouter.AddRoute("transfer", stack1) -ibcRouter.AddRoute("custom1", stack2) -ibcRouter.AddRoute("custom2", stack3) -app.IBCKeeper.SetRouter(ibcRouter) -``` diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/04-middleware/_category_.json b/docs/versioned_docs/version-v4.4.x/01-ibc/04-middleware/_category_.json deleted file mode 100644 index 6596fe16c13..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/04-middleware/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Middleware", - "position": 4, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/05-upgrades/00-intro.md b/docs/versioned_docs/version-v4.4.x/01-ibc/05-upgrades/00-intro.md deleted file mode 100644 index 3ff92aba64f..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/05-upgrades/00-intro.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: Upgrading IBC Chains Overview -sidebar_label: Overview -sidebar_position: 0 -slug: /ibc/upgrades/intro ---- - -### Upgrading IBC Chains Overview - -This directory contains information on how to upgrade an IBC chain without breaking counterparty clients and connections. - -IBC-connnected chains must be able to upgrade without breaking connections to other chains. Otherwise there would be a massive disincentive towards upgrading and disrupting high-value IBC connections, thus preventing chains in the IBC ecosystem from evolving and improving. Many chain upgrades may be irrelevant to IBC, however some upgrades could potentially break counterparty clients if not handled correctly. Thus, any IBC chain that wishes to perform a IBC-client-breaking upgrade must perform an IBC upgrade in order to allow counterparty clients to securely upgrade to the new light client. - -1. The [quick-guide](./01-quick-guide.md) describes how IBC-connected chains can perform client-breaking upgrades and how relayers can securely upgrade counterparty clients using the SDK. -2. The [developer-guide](./02-developer-guide.md) is a guide for developers intending to develop IBC client implementations with upgrade functionality. diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/05-upgrades/01-quick-guide.md b/docs/versioned_docs/version-v4.4.x/01-ibc/05-upgrades/01-quick-guide.md deleted file mode 100644 index dc240e36f59..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/05-upgrades/01-quick-guide.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: How to Upgrade IBC Chains and their Clients -sidebar_label: How to Upgrade IBC Chains and their Clients -sidebar_position: 1 -slug: /ibc/upgrades/quick-guide ---- - - -# How to Upgrade IBC Chains and their Clients - -:::note Synopsis -Learn how to upgrade your chain and counterparty clients. -::: - -The information in this doc for upgrading chains is relevant to SDK chains. However, the guide for counterparty clients is relevant to any Tendermint client that enables upgrades. - -## IBC Client Breaking Upgrades - -IBC-connected chains must perform an IBC upgrade if their upgrade will break counterparty IBC clients. The current IBC protocol supports upgrading tendermint chains for a specific subset of IBC-client-breaking upgrades. Here is the exhaustive list of IBC client-breaking upgrades and whether the IBC protocol currently supports such upgrades. - -IBC currently does **NOT** support unplanned upgrades. All of the following upgrades must be planned and committed to in advance by the upgrading chain, in order for counterparty clients to maintain their connections securely. - -Note: Since upgrades are only implemented for Tendermint clients, this doc only discusses upgrades on Tendermint chains that would break counterparty IBC Tendermint Clients. - -1. Changing the Chain-ID: **Supported** -2. Changing the UnbondingPeriod: **Partially Supported**, chains may increase the unbonding period with no issues. However, decreasing the unbonding period may irreversibly break some counterparty clients. Thus, it is **not recommended** that chains reduce the unbonding period. -3. Changing the height (resetting to 0): **Supported**, so long as chains remember to increment the revision number in their chain-id. -4. Changing the ProofSpecs: **Supported**, this should be changed if the proof structure needed to verify IBC proofs is changed across the upgrade. Ex: Switching from an IAVL store, to a SimpleTree Store -5. Changing the UpgradePath: **Supported**, this might involve changing the key under which upgraded clients and consensus states are stored in the upgrade store, or even migrating the upgrade store itself. -6. Migrating the IBC store: **Unsupported**, as the IBC store location is negotiated by the connection. -7. Upgrading to a backwards compatible version of IBC: Supported -8. Upgrading to a non-backwards compatible version of IBC: **Unsupported**, as IBC version is negotiated on connection handshake. -9. Changing the Tendermint LightClient algorithm: **Partially Supported**. Changes to the light client algorithm that do not change the ClientState or ConsensusState struct may be supported, provided that the counterparty is also upgraded to support the new light client algorithm. Changes that require updating the ClientState and ConsensusState structs themselves are theoretically possible by providing a path to translate an older ClientState struct into the new ClientState struct; however this is not currently implemented. - -### Step-by-Step Upgrade Process for SDK chains - -If the IBC-connected chain is conducting an upgrade that will break counterparty clients, it must ensure that the upgrade is first supported by IBC using the list above and then execute the upgrade process described below in order to prevent counterparty clients from breaking. - -1. Create a 02-client [`UpgradeProposal`](https://github.com/cosmos/ibc-go/blob/v4.4.2/proto/ibc/core/client/v1/client.proto#L58-L77) with an `UpgradePlan` and a new IBC ClientState in the `UpgradedClientState` field. Note that the `UpgradePlan` must specify an upgrade height **only** (no upgrade time), and the `ClientState` should only include the fields common to all valid clients and zero out any client-customizable fields (such as TrustingPeriod). -2. Vote on and pass the `UpgradeProposal` - -Upon the `UpgradeProposal` passing, the upgrade module will commit the UpgradedClient under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedClient`. On the block right before the upgrade height, the upgrade module will also commit an initial consensus state for the next chain under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedConsState`. - -Once the chain reaches the upgrade height and halts, a relayer can upgrade the counterparty clients to the last block of the old chain. They can then submit the proofs of the `UpgradedClient` and `UpgradedConsensusState` against this last block and upgrade the counterparty client. - -### Step-by-Step Upgrade Process for Relayers Upgrading Counterparty Clients - -Once the upgrading chain has committed to upgrading, relayers must wait till the chain halts at the upgrade height before upgrading counterparty clients. This is because chains may reschedule or cancel upgrade plans before they occur. Thus, relayers must wait till the chain reaches the upgrade height and halts before they can be sure the upgrade will take place. - -Thus, the upgrade process for relayers trying to upgrade the counterparty clients is as follows: - -1. Wait for the upgrading chain to reach the upgrade height and halt -2. Query a full node for the proofs of `UpgradedClient` and `UpgradedConsensusState` at the last height of the old chain. -3. Update the counterparty client to the last height of the old chain using the `UpdateClient` msg. -4. Submit an `UpgradeClient` msg to the counterparty chain with the `UpgradedClient`, `UpgradedConsensusState` and their respective proofs. -5. Submit an `UpdateClient` msg to the counterparty chain with a header from the new upgraded chain. - -The Tendermint client on the counterparty chain will verify that the upgrading chain did indeed commit to the upgraded client and upgraded consensus state at the upgrade height (since the upgrade height is included in the key). If the proofs are verified against the upgrade height, then the client will upgrade to the new client while retaining all of its client-customized fields. Thus, it will retain its old TrustingPeriod, TrustLevel, MaxClockDrift, etc; while adopting the new chain-specified fields such as UnbondingPeriod, ChainId, UpgradePath, etc. Note, this can lead to an invalid client since the old client-chosen fields may no longer be valid given the new chain-chosen fields. Upgrading chains should try to avoid these situations by not altering parameters that can break old clients. For an example, see the UnbondingPeriod example in the supported upgrades section. - -The upgraded consensus state will serve purely as a basis of trust for future `UpdateClientMsgs` and will not contain a consensus root to perform proof verification against. Thus, relayers must submit an `UpdateClientMsg` with a header from the new chain so that the connection can be used for proof verification again. diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/05-upgrades/02-developer-guide.md b/docs/versioned_docs/version-v4.4.x/01-ibc/05-upgrades/02-developer-guide.md deleted file mode 100644 index 0321bdbe594..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/05-upgrades/02-developer-guide.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: IBC Client Developer Guide to Upgrades -sidebar_label: IBC Client Developer Guide to Upgrades -sidebar_position: 2 -slug: /ibc/upgrades/developer-guide ---- - - -# IBC Client Developer Guide to Upgrades - -:::note Synopsis -Learn how to implement upgrade functionality for your custom IBC client. -::: - -As mentioned in the [README](./00-intro.md), it is vital that high-value IBC clients can upgrade along with their underlying chains to avoid disruption to the IBC ecosystem. Thus, IBC client developers will want to implement upgrade functionality to enable clients to maintain connections and channels even across chain upgrades. - -The IBC protocol allows client implementations to provide a path to upgrading clients given the upgraded client state, upgraded consensus state and proofs for each. - -```go -// Upgrade functions -// NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last -// height committed by the current revision. Clients are responsible for ensuring that the planned last -// height of the current revision is somehow encoded in the proof verification process. -// This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty -// may be cancelled or modified before the last planned height. -VerifyUpgradeAndUpdateState( - ctx sdk.Context, - cdc codec.BinaryCodec, - store sdk.KVStore, - newClient ClientState, - newConsState ConsensusState, - proofUpgradeClient, - proofUpgradeConsState []byte, -) (upgradedClient ClientState, upgradedConsensus ConsensusState, err error) -``` - -Note that the clients should have prior knowledge of the merkle path that the upgraded client and upgraded consensus states will use. The height at which the upgrade has occurred should also be encoded in the proof. The Tendermint client implementation accomplishes this by including an `UpgradePath` in the ClientState itself, which is used along with the upgrade height to construct the merkle path under which the client state and consensus state are committed. - -Developers must ensure that the `UpgradeClientMsg` does not pass until the last height of the old chain has been committed, and after the chain upgrades, the `UpgradeClientMsg` should pass once and only once on all counterparty clients. - -Developers must ensure that the new client adopts all of the new Client parameters that must be uniform across every valid light client of a chain (chain-chosen parameters), while maintaining the Client parameters that are customizable by each individual client (client-chosen parameters) from the previous version of the client. - -Upgrades must adhere to the IBC Security Model. IBC does not rely on the assumption of honest relayers for correctness. Thus users should not have to rely on relayers to maintain client correctness and security (though honest relayers must exist to maintain relayer liveness). While relayers may choose any set of client parameters while creating a new `ClientState`, this still holds under the security model since users can always choose a relayer-created client that suits their security and correctness needs or create a Client with their desired parameters if no such client exists. - -However, when upgrading an existing client, one must keep in mind that there are already many users who depend on this client's particular parameters. We cannot give the upgrading relayer free choice over these parameters once they have already been chosen. This would violate the security model since users who rely on the client would have to rely on the upgrading relayer to maintain the same level of security. Thus, developers must make sure that their upgrade mechanism allows clients to upgrade the chain-specified parameters whenever a chain upgrade changes these parameters (examples in the Tendermint client include `UnbondingPeriod`, `TrustingPeriod`, `ChainID`, `UpgradePath`, etc.), while ensuring that the relayer submitting the `UpgradeClientMsg` cannot alter the client-chosen parameters that the users are relying upon (examples in Tendermint client include `TrustLevel`, `MaxClockDrift`, etc). - -Developers should maintain the distinction between Client parameters that are uniform across every valid light client of a chain (chain-chosen parameters), and Client parameters that are customizable by each individual client (client-chosen parameters); since this distinction is necessary to implement the `ZeroCustomFields` method in the `ClientState` interface: - -```go -// Utility function that zeroes out any client customizable fields in client state -// Ledger enforced fields are maintained while all custom fields are zero values -// Used to verify upgrades -ZeroCustomFields() ClientState -``` - -Counterparty clients can upgrade securely by using all of the chain-chosen parameters from the chain-committed `UpgradedClient` and preserving all of the old client-chosen parameters. This enables chains to securely upgrade without relying on an honest relayer, however it can in some cases lead to an invalid final `ClientState` if the new chain-chosen parameters clash with the old client-chosen parameter. This can happen in the Tendermint client case if the upgrading chain lowers the `UnbondingPeriod` (chain-chosen) to a duration below that of a counterparty client's `TrustingPeriod` (client-chosen). Such cases should be clearly documented by developers, so that chains know which upgrades should be avoided to prevent this problem. The final upgraded client should also be validated in `VerifyUpgradeAndUpdateState` before returning to ensure that the client does not upgrade to an invalid `ClientState`. diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/05-upgrades/03-genesis-restart.md b/docs/versioned_docs/version-v4.4.x/01-ibc/05-upgrades/03-genesis-restart.md deleted file mode 100644 index 48766e8f5b8..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/05-upgrades/03-genesis-restart.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: Genesis Restart Upgrades -sidebar_label: Genesis Restart Upgrades -sidebar_position: 3 -slug: /ibc/upgrades/genesis-restart ---- - - -# Genesis Restart Upgrades - -:::note Synopsis -Learn how to upgrade your chain and counterparty clients using genesis restarts. -::: - -**NOTE**: Regular genesis restarts are currently unsupported by relayers! - -## IBC Client Breaking Upgrades - -IBC client breaking upgrades are possible using genesis restarts. -It is highly recommended to use the in-place migrations instead of a genesis restart. -Genesis restarts should be used sparingly and as backup plans. - -Genesis restarts still require the usage of an IBC upgrade proposal in order to correctly upgrade counterparty clients. - -### Step-by-Step Upgrade Process for SDK Chains - -If the IBC-connected chain is conducting an upgrade that will break counterparty clients, it must ensure that the upgrade is first supported by IBC using the [IBC Client Breaking Upgrade List](./01-quick-guide.md#ibc-client-breaking-upgrades) and then execute the upgrade process described below in order to prevent counterparty clients from breaking. - -1. Create a 02-client [`UpgradeProposal`](https://github.com/cosmos/ibc-go/blob/v4.4.2/proto/ibc/core/client/v1/client.proto#L58-L77) with an `UpgradePlan` and a new IBC ClientState in the `UpgradedClientState` field. Note that the `UpgradePlan` must specify an upgrade height **only** (no upgrade time), and the `ClientState` should only include the fields common to all valid clients and zero out any client-customizable fields (such as TrustingPeriod). -2. Vote on and pass the `UpgradeProposal` -3. Halt the node after successful upgrade. -4. Export the genesis file. -5. Swap to the new binary. -6. Run migrations on the genesis file. -7. Remove the `UpgradeProposal` plan from the genesis file. This may be done by migrations. -8. Change desired chain-specific fields (chain id, unbonding period, etc). This may be done by migrations. -8. Reset the node's data. -9. Start the chain. - -Upon the `UpgradeProposal` passing, the upgrade module will commit the UpgradedClient under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedClient`. On the block right before the upgrade height, the upgrade module will also commit an initial consensus state for the next chain under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedConsState`. - -Once the chain reaches the upgrade height and halts, a relayer can upgrade the counterparty clients to the last block of the old chain. They can then submit the proofs of the `UpgradedClient` and `UpgradedConsensusState` against this last block and upgrade the counterparty client. - -#### Step-by-Step Upgrade Process for Relayers Upgrading Counterparty Clients - -These steps are identical to the regular [IBC client breaking upgrade process](./01-quick-guide.md#step-by-step-upgrade-process-for-relayers-upgrading-counterparty-clients). - -### Non-IBC Client Breaking Upgrades - -While ibc-go supports genesis restarts which do not break IBC clients, relayers do not support this upgrade path. -Here is a tracking issue on [Hermes](https://github.com/informalsystems/ibc-rs/issues/1152). -Please do not attempt a regular genesis restarts unless you have a tool to update counterparty clients correctly. diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/05-upgrades/_category_.json b/docs/versioned_docs/version-v4.4.x/01-ibc/05-upgrades/_category_.json deleted file mode 100644 index 7c3191d2ce9..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/05-upgrades/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Upgrades", - "position": 5, - "link": { "type": "doc", "id": "intro" } -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/06-proposals.md b/docs/versioned_docs/version-v4.4.x/01-ibc/06-proposals.md deleted file mode 100644 index feb942144c8..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/06-proposals.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -title: Governance Proposals -sidebar_label: Governance Proposals -sidebar_position: 6 -slug: /ibc/proposals ---- - -# Governance Proposals - -In uncommon situations, a highly valued client may become frozen due to uncontrollable -circumstances. A highly valued client might have hundreds of channels being actively used. -Some of those channels might have a significant amount of locked tokens used for ICS 20. - -If the one third of the validator set of the chain the client represents decides to collude, -they can sign off on two valid but conflicting headers each signed by the other one third -of the honest validator set. The light client can now be updated with two valid, but conflicting -headers at the same height. The light client cannot know which header is trustworthy and therefore -evidence of such misbehaviour is likely to be submitted resulting in a frozen light client. - -Frozen light clients cannot be updated under any circumstance except via a governance proposal. -Since a quorum of validators can sign arbitrary state roots which may not be valid executions -of the state machine, a governance proposal has been added to ease the complexity of unfreezing -or updating clients which have become "stuck". Without this mechanism, validator sets would need -to construct a state root to unfreeze the client. Unfreezing clients, re-enables all of the channels -built upon that client. This may result in recovery of otherwise lost funds. - -Tendermint light clients may become expired if the trusting period has passed since their -last update. This may occur if relayers stop submitting headers to update the clients. - -An unplanned upgrade by the counterparty chain may also result in expired clients. If the counterparty -chain undergoes an unplanned upgrade, there may be no commitment to that upgrade signed by the validator -set before the chain-id changes. In this situation, the validator set of the last valid update for the -light client is never expected to produce another valid header since the chain-id has changed, which will -ultimately lead the on-chain light client to become expired. - -In the case that a highly valued light client is frozen, expired, or rendered non-updateable, a -governance proposal may be submitted to update this client, known as the subject client. The -proposal includes the client identifier for the subject and the client identifier for a substitute -client. Light client implementations may implement custom updating logic, but in most cases, -the subject will be updated to the latest consensus state of the substitute client, if the proposal passes. -The substitute client is used as a "stand in" while the subject is on trial. It is best practice to create -a substitute client *after* the subject has become frozen to avoid the substitute from also becoming frozen. -An active substitute client allows headers to be submitted during the voting period to prevent accidental expiry -once the proposal passes. - -## How to recover an expired client with a governance proposal - -See also the relevant documentation: [ADR-026, IBC client recovery mechanisms](/architecture/adr-026-ibc-client-recovery-mechanisms) - -### Preconditions - -- The chain is updated with ibc-go >= v1.1.0. -- The client identifier of an active client for the same counterparty chain. -- The governance deposit. - -## Steps - -### Step 1 - -Check if the client is attached to the expected `chain-id`. For example, for an expired Tendermint client representing the Akash chain the client state looks like this on querying the client state: - -```text -{ - client_id: 07-tendermint-146 - client_state: - '@type': /ibc.lightclients.tendermint.v1.ClientState - allow_update_after_expiry: true - allow_update_after_misbehaviour: true - chain_id: akashnet-2 -} -``` - -The client is attached to the expected Akash `chain-id`. Note that although the parameters (`allow_update_after_expiry` and `allow_update_after_misbehaviour`) exist to signal intent, these parameters have been deprecated and will not enforce any checks on the revival of client. See ADR-026 for more context on this deprecation. - -### Step 2 - -If the chain has been updated to ibc-go >= v1.1.0, anyone can submit the governance proposal to recover the client by executing this via cli: - -```bash - tx gov submit-proposal update-client -``` - -The `` should be a client identifier on the same chain as the expired or frozen client. This client identifier should connect to the same chain as the expired or frozen client. This means: use the active client that is currently being used to relay packets between the two chains as the replacement client. - -After this, it is just a question of who funds the governance deposit and if the chain in question votes yes. - -## Important considerations - -Please note that from v1.0.0 of ibc-go it will not be allowed for transactions to go to expired clients anymore, so please update to at least this version to prevent similar issues in the future. - -Please also note that if the client on the other end of the transaction is also expired, that client will also need to update. This process updates only one client. diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/07-relayer.md b/docs/versioned_docs/version-v4.4.x/01-ibc/07-relayer.md deleted file mode 100644 index f40e9e671a3..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/07-relayer.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: Relayer -sidebar_label: Relayer -sidebar_position: 7 -slug: /ibc/relayer ---- - -# Relayer - -:::note - -## Pre-requisite readings - -- [IBC Overview](01-overview.md) -- [Events](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/advanced/08-events.md) - -::: - -## Events - -Events are emitted for every transaction processed by the base application to indicate the execution -of some logic clients may want to be aware of. This is extremely useful when relaying IBC packets. -Any message that uses IBC will emit events for the corresponding TAO logic executed as defined in -the [IBC events document](/events/events). - -In the SDK, it can be assumed that for every message there is an event emitted with the type `message`, -attribute key `action`, and an attribute value representing the type of message sent -(`channel_open_init` would be the attribute value for `MsgChannelOpenInit`). If a relayer queries -for transaction events, it can split message events using this event Type/Attribute Key pair. - -The Event Type `message` with the Attribute Key `module` may be emitted multiple times for a single -message due to application callbacks. It can be assumed that any TAO logic executed will result in -a module event emission with the attribute value `ibc_` (02-client emits `ibc_client`). - -### Subscribing with Tendermint - -Calling the Tendermint RPC method `Subscribe` via [Tendermint's Websocket](https://docs.tendermint.com/main/rpc/) will return events using -Tendermint's internal representation of them. Instead of receiving back a list of events as they -were emitted, Tendermint will return the type `map[string][]string` which maps a string in the -form `.` to `attribute_value`. This causes extraction of the event -ordering to be non-trivial, but still possible. - -A relayer should use the `message.action` key to extract the number of messages in the transaction -and the type of IBC transactions sent. For every IBC transaction within the string array for -`message.action`, the necessary information should be extracted from the other event fields. If -`send_packet` appears at index 2 in the value for `message.action`, a relayer will need to use the -value at index 2 of the key `send_packet.packet_sequence`. This process should be repeated for each -piece of information needed to relay a packet. - -## Example Implementations - -- [Golang Relayer](https://github.com/cosmos/relayer) -- [Hermes](https://github.com/informalsystems/ibc-rs/tree/master/crates/relayer) diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/08-proto-docs.md b/docs/versioned_docs/version-v4.4.x/01-ibc/08-proto-docs.md deleted file mode 100644 index 3e72876cac1..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/08-proto-docs.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: Protobuf Documentation -sidebar_label: Protobuf Documentation -sidebar_position: 8 -slug: /ibc/proto-docs ---- - -# Protobuf documentation - -See [ibc-go v4.4.x Buf Protobuf documentation](https://github.com/cosmos/ibc-go/blob/release/v4.4.x/docs/ibc/proto-docs.md). diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/09-roadmap.md b/docs/versioned_docs/version-v4.4.x/01-ibc/09-roadmap.md deleted file mode 100644 index d6c56680f91..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/09-roadmap.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -title: Roadmap -sidebar_label: Roadmap -sidebar_position: 9 -slug: /roadmap/roadmap ---- - -# Roadmap ibc-go - -*Lastest update: March 31, 2022* - -This document endeavours to inform the wider IBC community about plans and priorities for work on ibc-go by the team at Interchain GmbH. It is intended to broadly inform all users of ibc-go, including developers and operators of IBC, relayer, chain and wallet applications. - -This roadmap should be read as a high-level guide, rather than a commitment to schedules and deliverables. The degree of specificity is inversely proportional to the timeline. We will update this document periodically to reflect the status and plans. - -## Q2 - 2022 - -At a high level we will focus on: - -- Finishing the implementation of [relayer incentivisation](https://github.com/orgs/cosmos/projects/7/views/8). -- Finishing the [refactoring of 02-client](https://github.com/cosmos/ibc-go/milestone/16). -- Finishing the upgrade to Cosmos SDK v0.46 and Tendermint v0.35. -- Implementing and testing the changes needed to support the [transtion to SMT storage](https://github.com/cosmos/ibc-go/milestone/21) in the Cosmos SDK. -- Desiging the implementation and scoping the engineering work for [channel upgradability](https://github.com/cosmos/ibc/blob/master/spec/core/ics-004-channel-and-packet-semantics/UPGRADES.md). -- Improving the project's documentation and writing guides for [light client](https://github.com/cosmos/ibc-go/issues/59) and middleware implementation. -- Working on [core backlog issues](https://github.com/cosmos/ibc-go/milestone/8). -- Spending time on expanding and deepening our knowledge of IBC, but also other parts of the Cosmos stack. -- And last, but not least, onboarding new members to the team. - -For a detail view of each iteration's planned work, please check out our [project board](https://github.com/orgs/cosmos/projects/7). - -### Release schedule - -#### **April** - -In the first half of the month we will probably cut: - -- Alpha/beta pre-releases with the upgrade to SDK 0.46 and Tendermint v0.35. -- [Alpha](https://github.com/cosmos/ibc-go/milestone/5) pre-release with the implementation of relayer incentivisation. - -In the second half, and depending on the date of the final release of Cosmos SDK 0.46, we will probably cut the final release with the upgrade to SDK 0.46 and Tendermint v0.35, and also a [beta](https://github.com/cosmos/ibc-go/milestone/23) pre-release with the implementation of relayer incentivisation. - -In the second half of the month we also plan to do a second internal audit of the implementation of relayer incentivisation, and issues will most likely will be created from the audit. Depending on the nature and type of the issues we create, those would be released in a second beta pre-release or in a [release candidate](https://github.com/cosmos/ibc-go/milestone/24). - -#### **May** - -In the first half we will probably start cutting release candidates with relayer incentivisation and the 02-client refactor. Final release would most likely come out at the end of the month or beginning of June. - -#### **June** - -We will probably cut at the end of the month or beginning of Q3 patch or minor releases on all the supported release lines with the [small features and core improvements](https://github.com/cosmos/ibc-go/milestone/8) that we work on during the quarter. - -## Q3 - 2022 - -We will most likely start the implementation of [channel upgradability](https://github.com/cosmos/ibc/blob/master/spec/core/ics-004-channel-and-packet-semantics/UPGRADES.md). At the end of Q2 or maybe beginning of Q3 we might also work on designing the implementation and scoping the engineering work to add support for [ordered channels that can timeout](https://github.com/cosmos/ibc/pull/636), and we could potentially work on this feature also in Q3. - -We will also probably do an audit of the implementation of the [CCV application](https://github.com/cosmos/interchain-security/tree/main/x/ccv) for Interchain Security. - -### Release schedule - -In this quarter we will make the final release to support the migration to SMT storage. diff --git a/docs/versioned_docs/version-v4.4.x/01-ibc/_category_.json b/docs/versioned_docs/version-v4.4.x/01-ibc/_category_.json deleted file mode 100644 index 066f3af93b1..00000000000 --- a/docs/versioned_docs/version-v4.4.x/01-ibc/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Using IBC-Go", - "position": 1, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/01-overview.md b/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/01-overview.md deleted file mode 100644 index 7e257d1e805..00000000000 --- a/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/01-overview.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /apps/transfer/overview ---- - -# Overview - -:::note Synopsis -Learn about what the token Transfer module is -::: - -## What is the Transfer module? - -Transfer is the Cosmos SDK implementation of the [ICS-20](https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer) protocol, which enables cross-chain fungible token transfers. - -## Concepts - -### Acknowledgements - -ICS20 uses the recommended acknowledgement format as specified by [ICS 04](https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope). - -A successful receive of a transfer packet will result in a Result Acknowledgement being written -with the value `[]byte{byte(1)}` in the `Response` field. - -An unsuccessful receive of a transfer packet will result in an Error Acknowledgement being written -with the error message in the `Response` field. - -### Denomination trace - -The denomination trace corresponds to the information that allows a token to be traced back to its -origin chain. It contains a sequence of port and channel identifiers ordered from the most recent to -the oldest in the timeline of transfers. - -This information is included on the token denomination field in the form of a hash to prevent an -unbounded denomination length. For example, the token `transfer/channelToA/uatom` will be displayed -as `ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2`. - -Each send to any chain other than the one it was previously received from is a movement forwards in -the token's timeline. This causes trace to be added to the token's history and the destination port -and destination channel to be prefixed to the denomination. In these instances the sender chain is -acting as the "source zone". When the token is sent back to the chain it previously received from, the -prefix is removed. This is a backwards movement in the token's timeline and the sender chain is -acting as the "sink zone". - -It is strongly recommended to read the full details of [ADR 001: Coin Source Tracing](/architecture/adr-001-coin-source-tracing) to understand the implications and context of the IBC token representations. - -## UX suggestions for clients - -For clients (wallets, exchanges, applications, block explorers, etc) that want to display the source of the token, it is recommended to use the following alternatives for each of the cases below: - -### Direct connection - -If the denomination trace contains a single identifier prefix pair (as in the example above), then -the easiest way to retrieve the chain and light client identifier is to map the trace information -directly. In summary, this requires querying the channel from the denomination trace identifiers, -and then the counterparty client state using the counterparty port and channel identifiers from the -retrieved channel. - -A general pseudo algorithm would look like the following: - -1. Query the full denomination trace. -2. Query the channel with the `portID/channelID` pair, which corresponds to the first destination of the - token. -3. Query the client state using the identifiers pair. Note that this query will return a `"Not -Found"` response if the current chain is not connected to this channel. -4. Retrieve the client identifier or chain identifier from the client state (eg: on - Tendermint clients) and store it locally. - -Using the gRPC gateway client service the steps above would be, with a given IBC token `ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2` stored on `chainB`: - -1. `GET /ibc/apps/transfer/v1/denom_traces/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2` -> `{"path": "transfer/channelToA", "base_denom": "uatom"}` -2. `GET /ibc/apps/transfer/v1/channels/channelToA/ports/transfer/client_state"` -> `{"client_id": "clientA", "chain-id": "chainA", ...}` -3. `GET /ibc/apps/transfer/v1/channels/channelToA/ports/transfer"` -> `{"channel_id": "channelToA", port_id": "transfer", counterparty: {"channel_id": "channelToB", port_id": "transfer"}, ...}` -4. `GET /ibc/apps/transfer/v1/channels/channelToB/ports/transfer/client_state" -> {"client_id": "clientB", "chain-id": "chainB", ...}` - -Then, the token transfer chain path for the `uatom` denomination would be: `chainA` -> `chainB`. - -### Multiple hops - -The multiple channel hops case applies when the token has passed through multiple chains between the original source and final destination chains. - -The IBC protocol doesn't know the topology of the overall network (i.e connections between chains and identifier names between them). For this reason, in the multiple hops case, a particular chain in the timeline of the individual transfers can't query the chain and client identifiers of the other chains. - -Take for example the following sequence of transfers `A -> B -> C` for an IBC token, with a final prefix path (trace info) of `transfer/channelChainC/transfer/channelChainB`. What the paragraph above means is that even in the case that chain `C` is directly connected to chain `A`, querying the port and channel identifiers that chain `B` uses to connect to chain `A` (eg: `transfer/channelChainA`) can be completely different from the one that chain `C` uses to connect to chain `A` (eg: `transfer/channelToChainA`). - -Thus the proposed solution for clients that the IBC team recommends are the following: - -- **Connect to all chains**: Connecting to all the chains in the timeline would allow clients to - perform the queries outlined in the [direct connection](#direct-connection) section to each - relevant chain. By repeatedly following the port and channel denomination trace transfer timeline, - clients should always be able to find all the relevant identifiers. This comes at the tradeoff - that the client must connect to nodes on each of the chains in order to perform the queries. -- **Relayer as a Service (RaaS)**: A longer term solution is to use/create a relayer service that - could map the denomination trace to the chain path timeline for each token (i.e `origin chain -> -chain #1 -> ... -> chain #(n-1) -> final chain`). These services could provide merkle proofs in - order to allow clients to optionally verify the path timeline correctness for themselves by - running light clients. If the proofs are not verified, they should be considered as trusted third - parties services. Additionally, client would be advised in the future to use RaaS that support the - largest number of connections between chains in the ecosystem. Unfortunately, none of the existing - public relayers (in [Golang](https://github.com/cosmos/relayer) and - [Rust](https://github.com/informalsystems/ibc-rs)), provide this service to clients. - -:::tip -The only viable alternative for clients (at the time of writing) to tokens with multiple connection hops, is to connect to all chains directly and perform relevant queries to each of them in the sequence. -::: - -## Locked funds - -In some [exceptional cases](/architecture/adr-026-ibc-client-recovery-mechanisms#exceptional-cases), a client state associated with a given channel cannot be updated. This causes that funds from fungible tokens in that channel will be permanently locked and thus can no longer be transferred. - -To mitigate this, a client update governance proposal can be submitted to update the frozen client -with a new valid header. Once the proposal passes the client state will be unfrozen and the funds -from the associated channels will then be unlocked. This mechanism only applies to clients that -allow updates via governance, such as Tendermint clients. - -In addition to this, it's important to mention that a token must be sent back along the exact route -that it took originally in order to return it to its original form on the source chain (eg: the -Cosmos Hub for the `uatom`). Sending a token back to the same chain across a different channel will -**not** move the token back across its timeline. If a channel in the chain history closes before the -token can be sent back across that channel, then the token will not be returnable to its original -form. - -## Security considerations - -For safety, no other module must be capable of minting tokens with the `ibc/` prefix. The IBC -transfer module needs a subset of the denomination space that only it can create tokens in. diff --git a/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/02-state.md b/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/02-state.md deleted file mode 100644 index 916e99b46c3..00000000000 --- a/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/02-state.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: State -sidebar_label: State -sidebar_position: 2 -slug: /apps/transfer/state ---- - -# State - -The IBC transfer application module keeps state of the port to which the module is binded and the denomination trace information as outlined in [ADR 001](/architecture/adr-001-coin-source-tracing). - -- `Port`: `0x01 -> ProtocolBuffer(string)` -- `DenomTrace`: `0x02 | []bytes(traceHash) -> ProtocolBuffer(DenomTrace)` diff --git a/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/03-state-transitions.md b/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/03-state-transitions.md deleted file mode 100644 index 7c73b8da21c..00000000000 --- a/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/03-state-transitions.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: State Transitions -sidebar_label: State Transitions -sidebar_position: 3 -slug: /apps/transfer/state-transitions ---- - -# State transitions - -## Send fungible tokens - -A successful fungible token send has two state transitions depending if the transfer is a movement forward or backwards in the token's timeline: - -1. Sender chain is the source chain, *i.e* a transfer to any chain other than the one it was previously received from is a movement forwards in the token's timeline. This results in the following state transitions: - - - The coins are transferred to an escrow address (i.e locked) on the sender chain. - - The coins are transferred to the receiving chain through IBC TAO logic. - -2. Sender chain is the sink chain, *i.e* the token is sent back to the chain it previously received from. This is a backwards movement in the token's timeline. This results in the following state transitions: - - - The coins (vouchers) are burned on the sender chain. - - The coins are transferred to the receiving chain through IBC TAO logic. - -## Receive fungible tokens - -A successful fungible token receive has two state transitions depending if the transfer is a movement forward or backwards in the token's timeline: - -1. Receiver chain is the source chain. This is a backwards movement in the token's timeline. This results in the following state transitions: - - - The leftmost port and channel identifier pair is removed from the token denomination prefix. - - The tokens are unescrowed and sent to the receiving address. - -2. Receiver chain is the sink chain. This is a movement forwards in the token's timeline. This results in the following state transitions: - - - Token vouchers are minted by prefixing the destination port and channel identifiers to the trace information. - - The receiving chain stores the new trace information in the store (if not set already). - - The vouchers are sent to the receiving address. diff --git a/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/04-messages.md b/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/04-messages.md deleted file mode 100644 index 7eb46cd32a1..00000000000 --- a/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/04-messages.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: Messages -sidebar_label: Messages -sidebar_position: 4 -slug: /apps/transfer/messages ---- - -# Messages - -## `MsgTransfer` - -A fungible token cross chain transfer is achieved by using the `MsgTransfer`: - -```go -type MsgTransfer struct { - SourcePort string - SourceChannel string - Token sdk.Coin - Sender string - Receiver string - TimeoutHeight ibcexported.Height - TimeoutTimestamp uint64 - Memo string -} -``` - -This message is expected to fail if: - -- `SourcePort` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). -- `SourceChannel` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -- `Token` is invalid (denom is invalid or amount is negative) - - `Token.Amount` is not positive. - - `Token.Denom` is not a valid IBC denomination as per [ADR 001 - Coin Source Tracing](/architecture/adr-001-coin-source-tracing). -- `Sender` is empty. -- `Receiver` is empty. -- `TimeoutHeight` and `TimeoutTimestamp` are both zero. - -This message will send a fungible token to the counterparty chain represented by the counterparty Channel End connected to the Channel End with the identifiers `SourcePort` and `SourceChannel`. - -The denomination provided for transfer should correspond to the same denomination represented on this chain. The prefixes will be added as necessary upon by the receiving chain. - -### Memo - -The memo field was added to allow applications and users to attach metadata to transfer packets. The field is optional and may be left empty. When it is used to attach metadata for a particular middleware, the memo field should be represented as a json object where different middlewares use different json keys. - -You can find more information about applications that use the memo field in the [chain registry](https://github.com/cosmos/chain-registry/blob/master/_memo_keys/ICS20_memo_keys.json). diff --git a/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/05-events.md b/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/05-events.md deleted file mode 100644 index 888b26a959a..00000000000 --- a/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/05-events.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Events -sidebar_label: Events -sidebar_position: 5 -slug: /apps/transfer/events ---- - - -# Events - -## `MsgTransfer` - -| Type | Attribute Key | Attribute Value | -|--------------|---------------|-----------------| -| ibc_transfer | sender | {sender} | -| ibc_transfer | receiver | {receiver} | -| message | action | transfer | -| message | module | transfer | - -## `OnRecvPacket` callback - -| Type | Attribute Key | Attribute Value | -|-----------------------|---------------|-----------------| -| fungible_token_packet | module | transfer | -| fungible_token_packet | sender | {sender} | -| fungible_token_packet | receiver | {receiver} | -| fungible_token_packet | denom | {denom} | -| fungible_token_packet | amount | {amount} | -| fungible_token_packet | success | {ackSuccess} | -| fungible_token_packet | memo | {memo} | -| denomination_trace | trace_hash | {hex_hash} | - -## `OnAcknowledgePacket` callback - -| Type | Attribute Key | Attribute Value | -|-----------------------|-----------------|-------------------| -| fungible_token_packet | module | transfer | -| fungible_token_packet | sender | {sender} | -| fungible_token_packet | receiver | {receiver} | -| fungible_token_packet | denom | {denom} | -| fungible_token_packet | amount | {amount} | -| fungible_token_packet | memo | {memo} | -| fungible_token_packet | acknowledgement | {ack.String()} | -| fungible_token_packet | success | error | {ack.Response} | - -## `OnTimeoutPacket` callback - -| Type | Attribute Key | Attribute Value | -|-----------------------|-----------------|-----------------| -| fungible_token_packet | module | transfer | -| fungible_token_packet | refund_receiver | {receiver} | -| fungible_token_packet | denom | {denom} | -| fungible_token_packet | amount | {amount} | -| fungible_token_packet | memo | {memo} | diff --git a/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/06-metrics.md b/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/06-metrics.md deleted file mode 100644 index 104e5b4d3bc..00000000000 --- a/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/06-metrics.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: Metrics -sidebar_label: Metrics -sidebar_position: 6 -slug: /apps/transfer/metrics ---- - - -# Metrics - -The IBC transfer application module exposes the following set of [metrics](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/advanced/09-telemetry.md). - -| Metric | Description | Unit | Type | -|:--------------------------------|:------------------------------------------------------------------------------------------|:----------------|:--------| -| `tx_msg_ibc_transfer` | The total amount of tokens transferred via IBC in a `MsgTransfer` (source or sink chain) | token | gauge | -| `ibc_transfer_packet_receive` | The total amount of tokens received in a `FungibleTokenPacketData` (source or sink chain) | token | gauge | -| `ibc_transfer_send` | Total number of IBC transfers sent from a chain (source or sink) | transfer | counter | -| `ibc_transfer_receive` | Total number of IBC transfers received to a chain (source or sink) | transfer | counter | diff --git a/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/07-params.md b/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/07-params.md deleted file mode 100644 index f3d55f7388f..00000000000 --- a/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/07-params.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: Params -sidebar_label: Params -sidebar_position: 7 -slug: /apps/transfer/params ---- - - -# Parameters - -The IBC transfer application module contains the following parameters: - -| Key | Type | Default Value | -|------------------|------|---------------| -| `SendEnabled` | bool | `true` | -| `ReceiveEnabled` | bool | `true` | - -## `SendEnabled` - -The transfers enabled parameter controls send cross-chain transfer capabilities for all fungible tokens. - -To prevent a single token from being transferred from the chain, set the `SendEnabled` parameter to `true` and then, depending on the Cosmos SDK version, do one of the following: - -- For Cosmos SDK v0.46.x or earlier, set the bank module's [`SendEnabled` parameter](https://github.com/cosmos/cosmos-sdk/blob/release/v0.46.x/x/bank/spec/05_params.md#sendenabled) for the denomination to `false`. -- For Cosmos SDK versions above v0.46.x, set the bank module's `SendEnabled` entry for the denomination to `false` using `MsgSetSendEnabled` as a governance proposal. - -## `ReceiveEnabled` - -The transfers enabled parameter controls receive cross-chain transfer capabilities for all fungible tokens. - -To prevent a single token from being transferred to the chain, set the `ReceiveEnabled` parameter to `true` and then, depending on the Cosmos SDK version, do one of the following: - -- For Cosmos SDK v0.46.x or earlier, set the bank module's [`SendEnabled` parameter](https://github.com/cosmos/cosmos-sdk/blob/release/v0.46.x/x/bank/spec/05_params.md#sendenabled) for the denomination to `false`. -- For Cosmos SDK versions above v0.46.x, set the bank module's `SendEnabled` entry for the denomination to `false` using `MsgSetSendEnabled` as a governance proposal. diff --git a/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/_category_.json b/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/_category_.json deleted file mode 100644 index d643a498cdf..00000000000 --- a/docs/versioned_docs/version-v4.4.x/02-apps/01-transfer/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Transfer", - "position": 1, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/01-overview.md b/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/01-overview.md deleted file mode 100644 index 52a5123198a..00000000000 --- a/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/01-overview.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /apps/interchain-accounts/overview ---- - - -# Overview - -:::note Synopsis -Learn about what the Interchain Accounts module is, and how to build custom modules that utilize Interchain Accounts functionality -::: - -## What is the Interchain Accounts module? - -Interchain Accounts is the Cosmos SDK implementation of the ICS-27 protocol, which enables cross-chain account management built upon IBC. Chains using the Interchain Accounts module can programmatically create accounts on other chains and control these accounts via IBC transactions. - -Interchain Accounts exposes a simple-to-use API which means IBC application developers do not require an in-depth knowledge of the underlying low-level details of IBC or the ICS-27 protocol. - -Developers looking to build upon Interchain Accounts must write custom logic in their own IBC application module, called authentication modules. - -- How is an interchain account different than a regular account? - -Regular accounts use a private key to sign transactions on-chain. Interchain Accounts are instead controlled programmatically by separate chains via IBC transactions. Interchain Accounts are implemented as sub-accounts of the interchain accounts module account. - -## Concepts - -`Host Chain`: The chain where the interchain account is registered. The host chain listens for IBC packets from a controller chain which should contain instructions (e.g. cosmos SDK messages) for which the interchain account will execute. - -`Controller Chain`: The chain registering and controlling an account on a host chain. The controller chain sends IBC packets to the host chain to control the account. A controller chain must have at least one interchain accounts authentication module in order to act as a controller chain. - -`Authentication Module`: A custom IBC application module on the controller chain that uses the Interchain Accounts module API to build custom logic for the creation & management of interchain accounts. For a controller chain to utilize the interchain accounts module functionality, an authentication module is required. - -`Interchain Account`: An account on a host chain. An interchain account has all the capabilities of a normal account. However, rather than signing transactions with a private key, a controller chain's authentication module will send IBC packets to the host chain which signals what transactions the interchain account should execute. - -## SDK Security Model - -SDK modules on a chain are assumed to be trustworthy. For example, there are no checks to prevent an untrustworthy module from accessing the bank keeper. - -The implementation of ICS27 on ibc-go uses this assumption in its security considerations. The implementation assumes the authentication module will not try to open channels on owner addresses it does not control. - -The implementation assumes other IBC application modules will not bind to ports within the ICS27 namespace. - -## Known Bugs - -- Fee-enabled Interchain Accounts channels cannot be reopened in case of closure due to packet timeout. Regular channels (non fee-enabled) can be reopened. A fix for this bug has been implemented, but, since it is API breaking, it is only available from v5.x. See [this PR](https://github.com/cosmos/ibc-go/pull/2302) for more details. diff --git a/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/02-auth-modules.md b/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/02-auth-modules.md deleted file mode 100644 index 26014bc286a..00000000000 --- a/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/02-auth-modules.md +++ /dev/null @@ -1,402 +0,0 @@ ---- -title: Authentication Modules -sidebar_label: Authentication Modules -sidebar_position: 2 -slug: /apps/interchain-accounts/auth-modules ---- - - -# Building an authentication module - -:::note Synopsis -Authentication modules play the role of the `Base Application` as described in [ICS30 IBC Middleware](https://github.com/cosmos/ibc/tree/master/spec/app/ics-030-middleware), and enable application developers to perform custom logic when working with the Interchain Accounts controller API. -::: - -The controller submodule is used for account registration and packet sending. -It executes only logic required of all controllers of interchain accounts. -The type of authentication used to manage the interchain accounts remains unspecified. -There may exist many different types of authentication which are desirable for different use cases. -Thus the purpose of the authentication module is to wrap the controller module with custom authentication logic. - -In ibc-go, authentication modules are connected to the controller chain via a middleware stack. -The controller module is implemented as [middleware](https://github.com/cosmos/ibc/tree/master/spec/app/ics-030-middleware) and the authentication module is connected to the controller module as the base application of the middleware stack. -To implement an authentication module, the `IBCModule` interface must be fulfilled. -By implementing the controller module as middleware, any amount of authentication modules can be created and connected to the controller module without writing redundant code. - -The authentication module must: - -- Authenticate interchain account owners -- Track the associated interchain account address for an owner -- Claim the channel capability in `OnChanOpenInit` -- Send packets on behalf of an owner (after authentication) - -## IBCModule implementation - -The following `IBCModule` callbacks must be implemented with appropriate custom logic: - -```go -// OnChanOpenInit implements the IBCModule interface -func (im IBCModule) OnChanOpenInit( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) (string, error) { - // the authentication module *must* claim the channel capability on OnChanOpenInit - if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return version, err - } - - // perform custom logic - - return version, nil -} - -// OnChanOpenAck implements the IBCModule interface -func (im IBCModule) OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyVersion string, -) error { - // perform custom logic - - return nil -} - -// OnChanCloseConfirm implements the IBCModule interface -func (im IBCModule) OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // perform custom logic - - return nil -} - -// OnAcknowledgementPacket implements the IBCModule interface -func (im IBCModule) OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - relayer sdk.AccAddress, -) error { - // perform custom logic - - return nil -} - -// OnTimeoutPacket implements the IBCModule interface. -func (im IBCModule) OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) error { - // perform custom logic - - return nil -} -``` - -**Note**: The channel capability must be claimed by the authentication module in `OnChanOpenInit` otherwise the authentication module will not be able to send packets on the channel created for the associated interchain account. - -The following functions must be defined to fulfill the `IBCModule` interface, but they will never be called by the controller module so they may error or panic. - -```go -// OnChanOpenTry implements the IBCModule interface -func (im IBCModule) OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (string, error) { - panic("UNIMPLEMENTED") -} - -// OnChanOpenConfirm implements the IBCModule interface -func (im IBCModule) OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - panic("UNIMPLEMENTED") -} - -// OnChanCloseInit implements the IBCModule interface -func (im IBCModule) OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - panic("UNIMPLEMENTED") -} - -// OnRecvPacket implements the IBCModule interface. A successful acknowledgement -// is returned if the packet data is succesfully decoded and the receive application -// logic returns without error. -func (im IBCModule) OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) ibcexported.Acknowledgement { - panic("UNIMPLEMENTED") -} -``` - -## `RegisterInterchainAccount` - -The authentication module can begin registering interchain accounts by calling `RegisterInterchainAccount`: - -```go -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, connectionID, owner.String(), version); err != nil { - return err -} - -return nil -``` - -The `version` argument is used to support ICS29 fee middleware for relayer incentivization of ICS27 packets. Consumers of the `RegisterInterchainAccount` are expected to build the appropriate JSON encoded version string themselves and pass it accordingly. If an empty string is passed in the `version` argument, then the version will be initialized to a default value in the `OnChanOpenInit` callback of the controller's handler, so that channel handshake can proceed. - -The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, controllerConnectionID, owner.String(), string(appVersion)); err != nil { - return err -} -``` - -Similarly, if the application stack is configured to route through ICS29 fee middleware and a fee enabled channel is desired, construct the appropriate ICS29 `Metadata` type: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -feeMetadata := feetypes.Metadata{ - AppVersion: string(appVersion), - FeeVersion: feetypes.Version, -} - -feeEnabledVersion, err := feetypes.ModuleCdc.MarshalJSON(&feeMetadata) -if err != nil { - return err -} - -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, controllerConnectionID, owner.String(), string(feeEnabledVersion)); err != nil { - return err -} -``` - -## `SendTx` - -The authentication module can attempt to send a packet by calling `SendTx`: - -```go - -// Authenticate owner -// perform custom logic - -// Construct controller portID based on interchain account owner address -portID, err := icatypes.NewControllerPortID(owner.String()) -if err != nil { - return err -} - -channelID, found := keeper.icaControllerKeeper.GetActiveChannelID(ctx, portID) -if !found { - return sdkerrors.Wrapf(icatypes.ErrActiveChannelNotFound, "failed to retrieve active channel for port %s", portID) -} - -// Obtain the channel capability, claimed in OnChanOpenInit -chanCap, found := keeper.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(portID, channelID)) -if !found { - return sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") -} - -// Obtain data to be sent to the host chain. -// In this example, the owner of the interchain account would like to send a bank MsgSend to the host chain. -// The appropriate serialization function should be called. The host chain must be able to deserialize the transaction. -// If the host chain is using the ibc-go host module, `SerializeCosmosTx` should be used. -msg := &banktypes.MsgSend{FromAddress: fromAddr, ToAddress: toAddr, Amount: amt} -data, err := icatypes.SerializeCosmosTx(keeper.cdc, []sdk.Msg{msg}) -if err != nil { - return err -} - -// Construct packet data -packetData := icatypes.InterchainAccountPacketData{ - Type: icatypes.EXECUTE_TX, - Data: data, -} - -// Obtain timeout timestamp -// An appropriate timeout timestamp must be determined based on the usage of the interchain account. -// If the packet times out, the channel will be closed requiring a new channel to be created -timeoutTimestamp := obtainTimeoutTimestamp() - -// Send the interchain accounts packet, returning the packet sequence -seq, err = keeper.icaControllerKeeper.SendTx(ctx, chanCap, portID, packetData, timeoutTimestamp) -``` - -The data within an `InterchainAccountPacketData` must be serialized using a format supported by the host chain. -If the host chain is using the ibc-go host chain submodule, `SerializeCosmosTx` should be used. If the `InterchainAccountPacketData.Data` is serialized using a format not support by the host chain, the packet will not be successfully received. - -## `OnAcknowledgementPacket` - -Controller chains will be able to access the acknowledgement written into the host chain state once a relayer relays the acknowledgement. -The acknowledgement bytes will be passed to the auth module via the `OnAcknowledgementPacket` callback. -Auth modules are expected to know how to decode the acknowledgement. - -If the controller chain is connected to a host chain using the host module on ibc-go, it may interpret the acknowledgement bytes as follows: - -Begin by unmarshaling the acknowledgement into sdk.TxMsgData: - -```go -var ack channeltypes.Acknowledgement -if err := channeltypes.SubModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { - return err -} - -txMsgData := &sdk.TxMsgData{} -if err := proto.Unmarshal(ack.GetResult(), txMsgData); err != nil { - return err -} -``` - -If the txMsgData.Data field is non nil, the host chain is using SDK version <= v0.45. -The auth module should interpret the txMsgData.Data as follows: - -```go -switch len(txMsgData.Data) { -case 0: - // see documentation below for SDK 0.46.x or greater -default: - for _, msgData := range txMsgData.Data { - if err := handler(msgData); err != nil { - return err - } - } -... -} -``` - -A handler will be needed to interpret what actions to perform based on the message type sent. -A router could be used, or more simply a switch statement. - -```go -func handler(msgData sdk.MsgData) error { -switch msgData.MsgType { -case sdk.MsgTypeURL(&banktypes.MsgSend{}): - msgResponse := &banktypes.MsgSendResponse{} - if err := proto.Unmarshal(msgData.Data, msgResponse}; err != nil { - return err - } - - handleBankSendMsg(msgResponse) - -case sdk.MsgTypeURL(&stakingtypes.MsgDelegate{}): - msgResponse := &stakingtypes.MsgDelegateResponse{} - if err := proto.Unmarshal(msgData.Data, msgResponse}; err != nil { - return err - } - - handleStakingDelegateMsg(msgResponse) - -case sdk.MsgTypeURL(&transfertypes.MsgTransfer{}): - msgResponse := &transfertypes.MsgTransferResponse{} - if err := proto.Unmarshal(msgData.Data, msgResponse}; err != nil { - return err - } - - handleIBCTransferMsg(msgResponse) - -default: - return -} -``` - -If the txMsgData.Data is empty, the host chain is using SDK version > v0.45. -The auth module should interpret the txMsgData.Responses as follows: - -```go -... -// switch statement from above -case 0: - for _, any := range txMsgData.MsgResponses { - if err := handleAny(any); err != nil { - return err - } - } -} -``` - -A handler will be needed to interpret what actions to perform based on the type url of the Any. -A router could be used, or more simply a switch statement. -It may be possible to deduplicate logic between `handler` and `handleAny`. - -```go -func handleAny(any *codectypes.Any) error { -switch any.TypeURL { -case banktypes.MsgSend: - msgResponse, err := unpackBankMsgSendResponse(any) - if err != nil { - return err - } - - handleBankSendMsg(msgResponse) - -case stakingtypes.MsgDelegate: - msgResponse, err := unpackStakingDelegateResponse(any) - if err != nil { - return err - } - - handleStakingDelegateMsg(msgResponse) - - case transfertypes.MsgTransfer: - msgResponse, err := unpackIBCTransferMsgResponse(any) - if err != nil { - return err - } - - handleIBCTransferMsg(msgResponse) - -default: - return -} -``` - -### Integration into `app.go` file - -To integrate the authentication module into your chain, please follow the steps outlined above in [app.go integration](04-integration.md#example-integration). diff --git a/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/03-active-channels.md b/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/03-active-channels.md deleted file mode 100644 index 6727055cb18..00000000000 --- a/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/03-active-channels.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: Active Channels -sidebar_label: Active Channels -sidebar_position: 3 -slug: /apps/interchain-accounts/active-channels ---- - - -# Understanding Active Channels - -The Interchain Accounts module uses [ORDERED channels](https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#ordering) to maintain the order of transactions when sending packets from a controller to a host chain. A limitation when using ORDERED channels is that when a packet times out the channel will be closed. - -In the case of a channel closing, a controller chain needs to be able to regain access to the interchain account registered on this channel. `Active Channels` enable this functionality. Future versions of the ICS-27 protocol and the Interchain Accounts module will likely use a new -channel type that provides ordering of packets without the channel closing on timing out, thus removing the need for `Active Channels` entirely. - -When an Interchain Account is registered using the `RegisterInterchainAccount` API, a new channel is created on a particular port. During the `OnChanOpenAck` and `OnChanOpenConfirm` steps (controller & host chain) the `Active Channel` for this interchain account -is stored in state. - -It is possible to create a new channel using the same controller chain portID if the previously set `Active Channel` is now in a `CLOSED` state. This channel creation can be initialized programatically by sending a new `MsgChannelOpenInit` message like so: - -```go -msg := channeltypes.NewMsgChannelOpenInit(portID, string(versionBytes), channeltypes.ORDERED, []string{connectionID}, icatypes.PortID, icatypes.ModuleName) -handler := k.msgRouter.Handler(msg) -``` - -Alternatively, any relayer operator may initiate a new channel handshake for this interchain account once the previously set `Active Channel` is in a `CLOSED` state. This is done by initiating the channel handshake on the controller chain using the same portID associated with the interchain account in question. - -It is important to note that once a channel has been opened for a given Interchain Account, new channels can not be opened for this account until the currently set `Active Channel` is set to `CLOSED`. diff --git a/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/04-integration.md b/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/04-integration.md deleted file mode 100644 index bb1725b9b87..00000000000 --- a/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/04-integration.md +++ /dev/null @@ -1,193 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 4 -slug: /apps/interchain-accounts/integration ---- - - -# Integration - -:::note Synopsis -Learn how to integrate Interchain Accounts host and controller functionality to your chain. The following document only applies for Cosmos SDK chains. -::: - -The Interchain Accounts module contains two submodules. Each submodule has its own IBC application. The Interchain Accounts module should be registered as an `AppModule` in the same way all SDK modules are registered on a chain, but each submodule should create its own `IBCModule` as necessary. A route should be added to the IBC router for each submodule which will be used. - -Chains who wish to support ICS27 may elect to act as a host chain, a controller chain or both. Disabling host or controller functionality may be done statically by excluding the host or controller module entirely from the `app.go` file or it may be done dynamically by taking advantage of the on-chain parameters which enable or disable the host or controller submodules. - -Interchain Account authentication modules are the base application of a middleware stack. The controller submodule is the middleware in this stack. - -## Example integration - -```go -// app.go - -// Register the AppModule for the Interchain Accounts module and the authentication module -// Note: No `icaauth` exists, this must be substituted with an actual Interchain Accounts authentication module -ModuleBasics = module.NewBasicManager( - ... - ica.AppModuleBasic{}, - icaauth.AppModuleBasic{}, - ... -) - -... - -// Add module account permissions for the Interchain Accounts module -// Only necessary for host chain functionality -// Each Interchain Account created on the host chain is derived from the module account created -maccPerms = map[string][]string{ - ... - icatypes.ModuleName: nil, -} - -... - -// Add Interchain Accounts Keepers for each submodule used and the authentication module -// If a submodule is being statically disabled, the associated Keeper does not need to be added. -type App struct { - ... - - ICAControllerKeeper icacontrollerkeeper.Keeper - ICAHostKeeper icahostkeeper.Keeper - ICAAuthKeeper icaauthkeeper.Keeper - - ... -} - -... - -// Create store keys for each submodule Keeper and the authentication module -keys := sdk.NewKVStoreKeys( - ... - icacontrollertypes.StoreKey, - icahosttypes.StoreKey, - icaauthtypes.StoreKey, - ... -) - -... - -// Create the scoped keepers for each submodule keeper and authentication keeper -scopedICAControllerKeeper := app.CapabilityKeeper.ScopeToModule(icacontrollertypes.SubModuleName) -scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icahosttypes.SubModuleName) -scopedICAAuthKeeper := app.CapabilityKeeper.ScopeToModule(icaauthtypes.ModuleName) - -... - -// Create the Keeper for each submodule -app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( - appCodec, keys[icacontrollertypes.StoreKey], app.GetSubspace(icacontrollertypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - scopedICAControllerKeeper, app.MsgServiceRouter(), -) -app.ICAHostKeeper = icahostkeeper.NewKeeper( - appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), -) - -// Create Interchain Accounts AppModule -icaModule := ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper) - -// Create your Interchain Accounts authentication module -app.ICAAuthKeeper = icaauthkeeper.NewKeeper(appCodec, keys[icaauthtypes.StoreKey], app.ICAControllerKeeper, scopedICAAuthKeeper) - -// ICA auth AppModule -icaAuthModule := icaauth.NewAppModule(appCodec, app.ICAAuthKeeper) - -// ICA auth IBC Module -icaAuthIBCModule := icaauth.NewIBCModule(app.ICAAuthKeeper) - -// Create controller IBC application stack and host IBC module as desired -icaControllerStack := icacontroller.NewIBCMiddleware(icaAuthIBCModule, app.ICAControllerKeeper) -icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - -// Register host and authentication routes -ibcRouter. - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icahosttypes.SubModuleName, icaHostIBCModule). - AddRoute(icaauthtypes.ModuleName, icaControllerStack) // Note, the authentication module is routed to the top level of the middleware stack - -... - -// Register Interchain Accounts and authentication module AppModule's -app.moduleManager = module.NewManager( - ... - icaModule, - icaAuthModule, -) - -... - -// Add fee middleware to begin blocker logic -app.moduleManager.SetOrderBeginBlockers( - ... - icatypes.ModuleName, - ... -) - -// Add fee middleware to end blocker logic -app.moduleManager.SetOrderEndBlockers( - ... - icatypes.ModuleName, - ... -) - -// Add Interchain Accounts module InitGenesis logic -app.moduleManager.SetOrderInitGenesis( - ... - icatypes.ModuleName, - ... -) - -// initParamsKeeper init params keeper and its subspaces -func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) paramskeeper.Keeper { - ... - paramsKeeper.Subspace(icahosttypes.SubModuleName) - paramsKeeper.Subspace(icacontrollertypes.SubModuleName) - ... -``` - -### Using submodules exclusively - -As described above, the Interchain Accounts application module is structured to support the ability of exclusively enabling controller or host functionality. -This can be achieved by simply omitting either controller or host `Keeper` from the Interchain Accounts `NewAppModule` constructor function, and mounting only the desired submodule via the `IBCRouter`. -Alternatively, submodules can be enabled and disabled dynamically using [on-chain parameters](05-parameters.md). - -The following snippets show basic examples of statically disabling submodules using `app.go`. - -#### Disabling controller chain functionality - -```go -// Create Interchain Accounts AppModule omitting the controller keeper -icaModule := ica.NewAppModule(nil, &app.ICAHostKeeper) - -// Create host IBC Module -icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - -// Register host route -ibcRouter.AddRoute(icahosttypes.SubModuleName, icaHostIBCModule) -``` - -#### Disabling host chain functionality - -```go -// Create Interchain Accounts AppModule omitting the host keeper -icaModule := ica.NewAppModule(&app.ICAControllerKeeper, nil) - -// Create your Interchain Accounts authentication module, setting up the Keeper, AppModule and IBCModule appropriately -app.ICAAuthKeeper = icaauthkeeper.NewKeeper(appCodec, keys[icaauthtypes.StoreKey], app.ICAControllerKeeper, scopedICAAuthKeeper) -icaAuthModule := icaauth.NewAppModule(appCodec, app.ICAAuthKeeper) -icaAuthIBCModule := icaauth.NewIBCModule(app.ICAAuthKeeper) - -// Create controller IBC application stack -icaControllerStack := icacontroller.NewIBCMiddleware(icaAuthIBCModule, app.ICAControllerKeeper) - -// Register controller and authentication routes -ibcRouter. - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icaauthtypes.ModuleName, icaControllerStack) // Note, the authentication module is routed to the top level of the middleware stack -``` diff --git a/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/05-parameters.md b/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/05-parameters.md deleted file mode 100644 index 15e827fda87..00000000000 --- a/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/05-parameters.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -title: Parameters -sidebar_label: Parameters -sidebar_position: 5 -slug: /apps/interchain-accounts/parameters ---- - - -# Parameters - -The Interchain Accounts module contains the following on-chain parameters, logically separated for each distinct submodule: - -## Controller Submodule Parameters - -| Key | Type | Default Value | -|------------------------|------|---------------| -| `ControllerEnabled` | bool | `true` | - -### ControllerEnabled - -The `ControllerEnabled` parameter controls a chains ability to service ICS-27 controller specific logic. This includes the sending of Interchain Accounts packet data as well as the following ICS-26 callback handlers: - -- `OnChanOpenInit` -- `OnChanOpenAck` -- `OnChanCloseConfirm` -- `OnAcknowledgementPacket` -- `OnTimeoutPacket` - -## Host Submodule Parameters - -| Key | Type | Default Value | -|------------------------|----------|---------------| -| `HostEnabled` | bool | `true` | -| `AllowMessages` | []string | `[]` | - -### HostEnabled - -The `HostEnabled` parameter controls a chains ability to service ICS27 host specific logic. This includes the following ICS-26 callback handlers: - -- `OnChanOpenTry` -- `OnChanOpenConfirm` -- `OnChanCloseConfirm` -- `OnRecvPacket` - -### AllowMessages - -The `AllowMessages` parameter provides the ability for a chain to limit the types of messages or transactions that hosted interchain accounts are authorized to execute by defining an allowlist using the Protobuf message TypeURL format. - -For example, a Cosmos SDK based chain that elects to provide hosted Interchain Accounts with the ability of governance voting and staking delegations will define its parameters as follows: - -```json -"params": { - "host_enabled": true, - "allow_messages": ["/cosmos.staking.v1beta1.MsgDelegate", "/cosmos.gov.v1beta1.MsgVote"] -} -``` - -There is also a special wildcard `"*"` message type which allows any type of message to be executed by the interchain account. This must be the only message in the `allow_messages` array. - -```json -"params": { - "host_enabled": true, - "allow_messages": ["*"] -} -``` diff --git a/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/06-transactions.md b/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/06-transactions.md deleted file mode 100644 index 394d374989f..00000000000 --- a/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/06-transactions.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: Transactions -sidebar_label: Transactions -sidebar_position: 6 -slug: /apps/interchain-accounts/transactions ---- - - -# Transactions - -:::note Synopsis -Learn about Interchain Accounts transaction execution -::: - -## Executing a transaction - -As described in [Authentication Modules](02-auth-modules.md#trysendtx) transactions are executed using the interchain accounts controller API and require a `Base Application` as outlined in [ICS30 IBC Middleware](https://github.com/cosmos/ibc/tree/master/spec/app/ics-030-middleware) to facilitate authentication. The method of authentication remains unspecified to provide flexibility for the authentication module developer. - -Transactions are executed via the ICS27 [`SendTx` API](02-auth-modules.md#trysendtx). This must be invoked through an Interchain Accounts authentication module and follows the outlined path of execution below. Packet relaying semantics provided by the IBC core transport, authentication, and ordering (IBC/TAO) layer are omitted for brevity. - -![send-interchain-tx.png](./images/send-interchain-tx.png) - -## Atomicity - -As the Interchain Accounts module supports the execution of multiple transactions using the Cosmos SDK `Msg` interface, it provides the same atomicity guarantees as Cosmos SDK-based applications, leveraging the [`CacheMultiStore`](https://docs.cosmos.network/main/learn/advanced/store#cachemultistore) architecture provided by the [`Context`](https://docs.cosmos.network/main/learn/advanced/context.html) type. - -This provides atomic execution of transactions when using Interchain Accounts, where state changes are only committed if all `Msg`s succeed. diff --git a/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/_category_.json b/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/_category_.json deleted file mode 100644 index 5ac86ce8ff6..00000000000 --- a/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Interchain Accounts", - "position": 2, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/images/send-interchain-tx.png b/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/images/send-interchain-tx.png deleted file mode 100644 index ecaaa98157e..00000000000 Binary files a/docs/versioned_docs/version-v4.4.x/02-apps/02-interchain-accounts/images/send-interchain-tx.png and /dev/null differ diff --git a/docs/versioned_docs/version-v4.4.x/02-apps/_category_.json b/docs/versioned_docs/version-v4.4.x/02-apps/_category_.json deleted file mode 100644 index fa5fbf0ac9a..00000000000 --- a/docs/versioned_docs/version-v4.4.x/02-apps/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "IBC Application Modules", - "position": 2, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/01-overview.md b/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/01-overview.md deleted file mode 100644 index b1e85bfb9eb..00000000000 --- a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/01-overview.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /middleware/ics29-fee/overview ---- - -# Overview - -:::note Synopsis -Learn about what the Fee Middleware module is, and how to build custom modules that utilize the Fee Middleware functionality -::: - -## What is the Fee Middleware module? - -IBC does not depend on relayer operators for transaction verification. However, the relayer infrastructure ensures liveness of the Interchain network — operators listen for packets sent through channels opened between chains, and perform the vital service of ferrying these packets (and proof of the transaction on the sending chain/receipt on the receiving chain) to the clients on each side of the channel. - -Though relaying is permissionless and completely decentralized and accessible, it does come with operational costs. Running full nodes to query transaction proofs and paying for transaction fees associated with IBC packets are two of the primary cost burdens which have driven the overall discussion on **a general, in-protocol incentivization mechanism for relayers**. - -Initially, a [simple proposal](https://github.com/cosmos/ibc/pull/577/files) was created to incentivize relaying on ICS20 token transfers on the destination chain. However, the proposal was specific to ICS20 token transfers and would have to be reimplemented in this format on every other IBC application module. - -After much discussion, the proposal was expanded to a [general incentivisation design](https://github.com/cosmos/ibc/tree/master/spec/app/ics-029-fee-payment) that can be adopted by any ICS application protocol as [middleware](../../01-ibc/04-middleware/01-develop.md). - -## Concepts - -ICS29 fee payments in this middleware design are built on the assumption that sender chains are the source of incentives — the chain on which packets are incentivized is the chain that distributes fees to relayer operators. However, as part of the IBC packet flow, messages have to be submitted on both sender and destination chains. This introduces the requirement of a mapping of relayer operator's addresses on both chains. - -To achieve the stated requirements, the **fee middleware module has two main groups of functionality**: - -- Registering of relayer addresses associated with each party involved in relaying the packet on the source chain. This registration process can be automated on start up of relayer infrastructure and happens only once, not every packet flow. - - This is described in the [Fee distribution section](04-fee-distribution.md). - -- Escrowing fees by any party which will be paid out to each rightful party on completion of the packet lifecycle. - - This is described in the [Fee messages section](03-msgs.md). - -We complete the introduction by giving a list of definitions of relevant terminolgy. - -`Forward relayer`: The relayer that submits the `MsgRecvPacket` message for a given packet (on the destination chain). - -`Reverse relayer`: The relayer that submits the `MsgAcknowledgement` message for a given packet (on the source chain). - -`Timeout relayer`: The relayer that submits the `MsgTimeout` or `MsgTimeoutOnClose` messages for a given packet (on the source chain). - -`Payee`: The account address on the source chain to be paid on completion of the packet lifecycle. The packet lifecycle on the source chain completes with the receipt of a `MsgTimeout`/`MsgTimeoutOnClose` or a `MsgAcknowledgement`. - -`Counterparty payee`: The account address to be paid on completion of the packet lifecycle on the destination chain. The package lifecycle on the destination chain completes with a successful `MsgRecvPacket`. - -`Refund address`: The address of the account paying for the incentivization of packet relaying. The account is refunded timeout fees upon successful acknowledgement. In the event of a packet timeout, both acknowledgement and receive fees are refunded. - -## Known Limitations - -The first version of fee payments middleware will only support incentivisation of new channels, however, channel upgradeability will enable incentivisation of all existing channels. diff --git a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/02-integration.md b/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/02-integration.md deleted file mode 100644 index 4fa2909e316..00000000000 --- a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/02-integration.md +++ /dev/null @@ -1,174 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 2 -slug: /middleware/ics29-fee/integration ---- - - -# Integration - -:::note Synopsis -Learn how to configure the Fee Middleware module with IBC applications. The following document is intended for developers building on top of the Cosmos SDK and only applies for Cosmos SDK chains. -::: - -## Pre-requisite Readings - -- [IBC middleware development](../../01-ibc/04-middleware/01-develop.md) -- [IBC middleware integration](../../01-ibc/04-middleware/02-integration.md) - -The Fee Middleware module, as the name suggests, plays the role of an IBC middleware and as such must be configured by chain developers to route and handle IBC messages correctly. -For Cosmos SDK chains this setup is done via the `app/app.go` file, where modules are constructed and configured in order to bootstrap the blockchain application. - -## Example integration of the Fee Middleware module - -```go -// app.go - -// Register the AppModule for the fee middleware module -ModuleBasics = module.NewBasicManager( - ... - ibcfee.AppModuleBasic{}, - ... -) - -... - -// Add module account permissions for the fee middleware module -maccPerms = map[string][]string{ - ... - ibcfeetypes.ModuleName: nil, -} - -... - -// Add fee middleware Keeper -type App struct { - ... - - IBCFeeKeeper ibcfeekeeper.Keeper - - ... -} - -... - -// Create store keys -keys := sdk.NewKVStoreKeys( - ... - ibcfeetypes.StoreKey, - ... -) - -... - -app.IBCFeeKeeper = ibcfeekeeper.NewKeeper( - appCodec, keys[ibcfeetypes.StoreKey], - app.IBCKeeper.ChannelKeeper, // may be replaced with IBC middleware - app.IBCKeeper.ChannelKeeper, - &app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, -) - - -// See the section below for configuring an application stack with the fee middleware module - -... - -// Register fee middleware AppModule -app.moduleManager = module.NewManager( - ... - ibcfee.NewAppModule(app.IBCFeeKeeper), -) - -... - -// Add fee middleware to begin blocker logic -app.moduleManager.SetOrderBeginBlockers( - ... - ibcfeetypes.ModuleName, - ... -) - -// Add fee middleware to end blocker logic -app.moduleManager.SetOrderEndBlockers( - ... - ibcfeetypes.ModuleName, - ... -) - -// Add fee middleware to init genesis logic -app.moduleManager.SetOrderInitGenesis( - ... - ibcfeetypes.ModuleName, - ... -) -``` - -## Configuring an application stack with Fee Middleware - -As mentioned in [IBC middleware development](../../01-ibc/04-middleware/01-develop.md) an application stack may be composed of many or no middlewares that nest a base application. -These layers form the complete set of application logic that enable developers to build composable and flexible IBC application stacks. -For example, an application stack may be just a single base application like `transfer`, however, the same application stack composed with `29-fee` will nest the `transfer` base application -by wrapping it with the Fee Middleware module. - -### Transfer - -See below for an example of how to create an application stack using `transfer` and `29-fee`. -The following `transferStack` is configured in `app/app.go` and added to the IBC `Router`. -The in-line comments describe the execution flow of packets between the application stack and IBC core. - -```go -// Create Transfer Stack -// SendPacket, since it is originating from the application to core IBC: -// transferKeeper.SendPacket -> fee.SendPacket -> channel.SendPacket - -// RecvPacket, message that originates from core IBC and goes down to app, the flow is the other way -// channel.RecvPacket -> fee.OnRecvPacket -> transfer.OnRecvPacket - -// transfer stack contains (from top to bottom): -// - IBC Fee Middleware -// - Transfer - -// create IBC module from bottom to top of stack -var transferStack porttypes.IBCModule -transferStack = transfer.NewIBCModule(app.TransferKeeper) -transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) - -// Add transfer stack to IBC Router -ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) -``` - -### Interchain Accounts - -See below for an example of how to create an application stack using `27-interchain-accounts` and `29-fee`. -The following `icaControllerStack` and `icaHostStack` are configured in `app/app.go` and added to the IBC `Router` with the associated authentication module. -The in-line comments describe the execution flow of packets between the application stack and IBC core. - -```go -// Create Interchain Accounts Stack -// SendPacket, since it is originating from the application to core IBC: -// icaAuthModuleKeeper.SendTx -> icaController.SendPacket -> fee.SendPacket -> channel.SendPacket - -// initialize ICA module with mock module as the authentication module on the controller side -var icaControllerStack porttypes.IBCModule -icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp("", scopedICAMockKeeper)) -app.ICAAuthModule = icaControllerStack.(ibcmock.IBCModule) -icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) -icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) - -// RecvPacket, message that originates from core IBC and goes down to app, the flow is: -// channel.RecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket - -var icaHostStack porttypes.IBCModule -icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) -icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) - -// Add authentication module, controller and host to IBC router -ibcRouter. - // the ICA Controller middleware needs to be explicitly added to the IBC Router because the - // ICA controller module owns the port capability for ICA. The ICA authentication module - // owns the channel capability. - AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack) - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icahosttypes.SubModuleName, icaHostStack). -``` diff --git a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/03-msgs.md b/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/03-msgs.md deleted file mode 100644 index 02d648c27f1..00000000000 --- a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/03-msgs.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: Fee Messages -sidebar_label: Fee Messages -sidebar_position: 3 -slug: /middleware/ics29-fee/msgs ---- - -# Fee messages - -:::note Synopsis -Learn about the different ways to pay for fees, how the fees are paid out and what happens when not enough escrowed fees are available for payout -::: - -## Escrowing fees - -The fee middleware module exposes two different ways to pay fees for relaying IBC packets: - -1. `MsgPayPacketFee`, which enables the escrowing of fees for a packet at the next sequence send and should be combined into one `MultiMsgTx` with the message that will be paid for. - - Note that the `Relayers` field has been set up to allow for an optional whitelist of relayers permitted to receive this fee, however, this feature has not yet been enabled at this time. - - ```go - type MsgPayPacketFee struct{ - // fee encapsulates the recv, ack and timeout fees associated with an IBC packet - Fee Fee - // the source port unique identifier - SourcePortId string - // the source channel unique identifer - SourceChannelId string - // account address to refund fee if necessary - Signer string - // optional list of relayers permitted to the receive packet fee - Relayers []string - } - ``` - - The `Fee` message contained in this synchronous fee payment method configures different fees which will be paid out for `MsgRecvPacket`, `MsgAcknowledgement`, and `MsgTimeout`/`MsgTimeoutOnClose`. - - ```go - type Fee struct { - RecvFee types.Coins - AckFee types.Coins - TimeoutFee types.Coins - } - ``` - - The diagram below shows the `MultiMsgTx` with the `MsgTransfer` coming from a token transfer message, along with `MsgPayPacketFee`. - - ![msgpaypacket.png](./images/msgpaypacket.png) - -2. `MsgPayPacketFeeAsync`, which enables the asynchronous escrowing of fees for a specified packet: - - Note that a packet can be 'topped up' multiple times with additional fees of any coin denomination by broadcasting multiple `MsgPayPacketFeeAsync` messages. - - ```go - type MsgPayPacketFeeAsync struct { - // unique packet identifier comprised of the channel ID, port ID and sequence - PacketId channeltypes.PacketId - // the packet fee associated with a particular IBC packet - PacketFee PacketFee - } - ``` - - where the `PacketFee` also specifies the `Fee` to be paid as well as the refund address for fees which are not paid out - - ```go - type PacketFee struct { - Fee Fee - RefundAddress string - Relayers []string - } - ``` - -The diagram below shows how multiple `MsgPayPacketFeeAsync` can be broadcasted asynchronously. Escrowing of the fee associated with a packet can be carried out by any party because ICS-29 does not dictate a particular fee payer. In fact, chains can choose to simply not expose this fee payment to end users at all and rely on a different module account or even the community pool as the source of relayer incentives. - -![paypacketfeeasync.png](./images/paypacketfeeasync.png) - -Please see our [wiki](https://github.com/cosmos/ibc-go/wiki/Fee-enabled-fungible-token-transfers) for example flows on how to use these messages to incentivise a token transfer channel using a CLI. - -## Paying out the escrowed fees - -Following diagram takes a look at the packet flow for an incentivized token transfer and investigates the several scenario's for paying out the escrowed fees. We assume that the relayers have registered their counterparty address, detailed in the [Fee distribution section](04-fee-distribution.md). - -![feeflow.png](./images/feeflow.png) - -- In the case of a successful transaction, `RecvFee` will be paid out to the designated counterparty payee address which has been registered on the receiver chain and sent back with the `MsgAcknowledgement`, `AckFee` will be paid out to the relayer address which has submitted the `MsgAcknowledgement` on the sending chain (or the registered payee in case one has been registered for the relayer address), and `TimeoutFee` will be reimbursed to the account which escrowed the fee. -- In case of a timeout transaction, `RecvFee` and `AckFee` will be reimbursed. The `TimeoutFee` will be paid to the `Timeout Relayer` (who submits the timeout message to the source chain). - -> Please note that fee payments are built on the assumption that sender chains are the source of incentives — the chain that sends the packets is the same chain where fee payments will occur -- please see the [Fee distribution section](04-fee-distribution.md) to understand the flow for registering payee and counterparty payee (fee receiving) addresses. - -## A locked fee middleware module - -The fee middleware module can become locked if the situation arises that the escrow account for the fees does not have sufficient funds to pay out the fees which have been escrowed for each packet. *This situation indicates a severe bug.* In this case, the fee module will be locked until manual intervention fixes the issue. - -> A locked fee module will simply skip fee logic and continue on to the underlying packet flow. A channel with a locked fee module will temporarily function as a fee disabled channel, and the locking of a fee module will not affect the continued flow of packets over the channel. diff --git a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/04-fee-distribution.md b/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/04-fee-distribution.md deleted file mode 100644 index 9cfd4f3e5a6..00000000000 --- a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/04-fee-distribution.md +++ /dev/null @@ -1,114 +0,0 @@ ---- -title: Fee Distribution -sidebar_label: Fee Distribution -sidebar_position: 4 -slug: /middleware/ics29-fee/fee-distribution ---- - - -# Fee distribution - -:::note Synopsis -Learn about payee registration for the distribution of packet fees. The following document is intended for relayer operators. -::: - -## Pre-requisite readings - -- [Fee Middleware](01-overview.md) - -Packet fees are divided into 3 distinct amounts in order to compensate relayer operators for packet relaying on fee enabled IBC channels. - -- `RecvFee`: The sum of all packet receive fees distributed to a payee for successful execution of `MsgRecvPacket`. -- `AckFee`: The sum of all packet acknowledgement fees distributed to a payee for successful execution of `MsgAcknowledgement`. -- `TimeoutFee`: The sum of all packet timeout fees distributed to a payee for successful execution of `MsgTimeout`. - -## Register a counterparty payee address for forward relaying - -As mentioned in [ICS29 Concepts](01-overview.md#concepts), the forward relayer describes the actor who performs the submission of `MsgRecvPacket` on the destination chain. -Fee distribution for incentivized packet relays takes place on the packet source chain. - -> Relayer operators are expected to register a counterparty payee address, in order to be compensated accordingly with `RecvFee`s upon completion of a packet lifecycle. - -The counterparty payee address registered on the destination chain is encoded into the packet acknowledgement and communicated as such to the source chain for fee distribution. -**If a counterparty payee is not registered for the forward relayer on the destination chain, the escrowed fees will be refunded upon fee distribution.** - -### Relayer operator actions? - -A transaction must be submitted **to the destination chain** including a `CounterpartyPayee` address of an account on the source chain. -The transaction must be signed by the `Relayer`. - -Note: If a module account address is used as the `CounterpartyPayee` but the module has been set as a blocked address in the `BankKeeper`, the refunding to the module account will fail. This is because many modules use invariants to compare internal tracking of module account balances against the actual balance of the account stored in the `BankKeeper`. If a token transfer to the module account occurs without going through this module and updating the account balance of the module on the `BankKeeper`, then invariants may break and unknown behaviour could occur depending on the module implementation. Therefore, if it is desirable to use a module account that is currently blocked, the module developers should be consulted to gauge to possibility of removing the module account from the blocked list. - -```go -type MsgRegisterCounterpartyPayee struct { - // unique port identifier - PortId string - // unique channel identifier - ChannelId string - // the relayer address - Relayer string - // the counterparty payee address - CounterpartyPayee string -} -``` - -> This message is expected to fail if: -> -> - `PortId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). -> - `ChannelId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -> - `Relayer` is an invalid address (see [Cosmos SDK Addresses](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/beginner/03-accounts.md#addresses)). -> - `CounterpartyPayee` is empty. - -See below for an example CLI command: - -```bash -simd tx ibc-fee register-counterparty-payee transfer channel-0 \ -cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh \ -osmo1v5y0tz01llxzf4c2afml8s3awue0ymju22wxx2 \ ---from cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh -``` - -## Register an alternative payee address for reverse and timeout relaying - -As mentioned in [ICS29 Concepts](01-overview.md#concepts), the reverse relayer describes the actor who performs the submission of `MsgAcknowledgement` on the source chain. -Similarly the timeout relayer describes the actor who performs the submission of `MsgTimeout` (or `MsgTimeoutOnClose`) on the source chain. - -> Relayer operators **may choose** to register an optional payee address, in order to be compensated accordingly with `AckFee`s and `TimeoutFee`s upon completion of a packet life cycle. - -If a payee is not registered for the reverse or timeout relayer on the source chain, then fee distribution assumes the default behaviour, where fees are paid out to the relayer account which delivers `MsgAcknowledgement` or `MsgTimeout`/`MsgTimeoutOnClose`. - -### Relayer operator actions - -A transaction must be submitted **to the source chain** including a `Payee` address of an account on the source chain. -The transaction must be signed by the `Relayer`. - -Note: If a module account address is used as the `Payee` it is recommended to [turn off invariant checks](https://github.com/cosmos/ibc-go/blob/71d7480c923f4227453e8a80f51be01ae7ee845e/testing/simapp/app.go#L659) for that module. - -```go -type MsgRegisterPayee struct { - // unique port identifier - PortId string - // unique channel identifier - ChannelId string - // the relayer address - Relayer string - // the payee address - Payee string -} -``` - -> This message is expected to fail if: -> -> - `PortId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). -> - `ChannelId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -> - `Relayer` is an invalid address (see [Cosmos SDK Addresses](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/beginner/03-accounts.md#addresses)). -> - `Payee` is an invalid address (see [Cosmos SDK Addresses](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/beginner/03-accounts.md#addresses)). - -See below for an example CLI command: - -```bash -simd tx ibc-fee register-payee transfer channel-0 \ -cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh \ -cosmos153lf4zntqt33a4v0sm5cytrxyqn78q7kz8j8x5 \ ---from cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh -``` diff --git a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/05-events.md b/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/05-events.md deleted file mode 100644 index eddb296b70c..00000000000 --- a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/05-events.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: Events -sidebar_label: Events -sidebar_position: 5 -slug: /middleware/ics29-fee/events ---- - - -# Events - -:::note Synopsis -An overview of all events related to ICS-29 -::: - -## `MsgPayPacketFee`, `MsgPayPacketFeeAsync` - -| Type | Attribute Key | Attribute Value | -| ----------------------- | --------------- | --------------- | -| incentivized_ibc_packet | port_id | {portID} | -| incentivized_ibc_packet | channel_id | {channelID} | -| incentivized_ibc_packet | packet_sequence | {sequence} | -| incentivized_ibc_packet | recv_fee | {recvFee} | -| incentivized_ibc_packet | ack_fee | {ackFee} | -| incentivized_ibc_packet | timeout_fee | {timeoutFee} | -| message | module | fee-ibc | - -## `RegisterPayee` - -| Type | Attribute Key | Attribute Value | -| -------------- | ------------- | --------------- | -| register_payee | relayer | {relayer} | -| register_payee | payee | {payee} | -| register_payee | channel_id | {channelID} | -| message | module | fee-ibc | - -## `RegisterCounterpartyPayee` - -| Type | Attribute Key | Attribute Value | -| --------------------------- | ------------------ | ------------------- | -| register_counterparty_payee | relayer | {relayer} | -| register_counterparty_payee | counterparty_payee | {counterpartyPayee} | -| register_counterparty_payee | channel_id | {channelID} | -| message | module | fee-ibc | diff --git a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/06-end-users.md b/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/06-end-users.md deleted file mode 100644 index fbea38d0ded..00000000000 --- a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/06-end-users.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: End Users -sidebar_label: End Users -sidebar_position: 6 -slug: /middleware/ics29-fee/end-users ---- - - -# For end users - -:::note Synopsis -Learn how to incentivize IBC packets using the ICS29 Fee Middleware module. -::: - -## Pre-requisite readings - -- [Fee Middleware](01-overview.md) - -## Summary - -Different types of end users: - -- CLI users who want to manually incentivize IBC packets -- Client developers - -The Fee Middleware module allows end users to add a 'tip' to each IBC packet which will incentivize relayer operators to relay packets between chains. gRPC endpoints are exposed for client developers as well as a simple CLI for manually incentivizing IBC packets. - -## CLI Users - -For an in depth guide on how to use the ICS29 Fee Middleware module using the CLI please take a look at the [wiki](https://github.com/cosmos/ibc-go/wiki/Fee-enabled-fungible-token-transfers#asynchronous-incentivization-of-a-fungible-token-transfer) on the `ibc-go` repo. - -## Client developers - -Client developers can read more about the relevant ICS29 message types in the [Fee messages section](03-msgs.md). - -[CosmJS](https://github.com/cosmos/cosmjs) is a useful client library for signing and broadcasting Cosmos SDK messages. diff --git a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/_category_.json b/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/_category_.json deleted file mode 100644 index ddca8d29da6..00000000000 --- a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Fee Middleware", - "position": 1, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/images/feeflow.png b/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/images/feeflow.png deleted file mode 100644 index ba02071f4d8..00000000000 Binary files a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/images/feeflow.png and /dev/null differ diff --git a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/images/msgpaypacket.png b/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/images/msgpaypacket.png deleted file mode 100644 index 1bd5deb01fd..00000000000 Binary files a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/images/msgpaypacket.png and /dev/null differ diff --git a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/images/paypacketfeeasync.png b/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/images/paypacketfeeasync.png deleted file mode 100644 index 27c486a6f82..00000000000 Binary files a/docs/versioned_docs/version-v4.4.x/03-middleware/01-ics29-fee/images/paypacketfeeasync.png and /dev/null differ diff --git a/docs/versioned_docs/version-v4.4.x/03-middleware/_category_.json b/docs/versioned_docs/version-v4.4.x/03-middleware/_category_.json deleted file mode 100644 index 886249e8634..00000000000 --- a/docs/versioned_docs/version-v4.4.x/03-middleware/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "IBC Middleware Modules", - "position": 3, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v4.4.x/04-migrations/01-support-denoms-with-slashes.md b/docs/versioned_docs/version-v4.4.x/04-migrations/01-support-denoms-with-slashes.md deleted file mode 100644 index 5dc6b10d04e..00000000000 --- a/docs/versioned_docs/version-v4.4.x/04-migrations/01-support-denoms-with-slashes.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: Support transfer of coins whose base denom contains slashes -sidebar_label: Support transfer of coins whose base denom contains slashes -sidebar_position: 1 -slug: /migrations/support-denoms-with-slashes ---- -# Migrating from not supporing base denoms with slashes to supporting base denoms with slashes - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -This document is necessary when chains are upgrading from a version that does not support base denoms with slashes (e.g. v3.0.0) to a version that does (e.g. v3.2.0). All versions of ibc-go smaller than v1.5.0 for the v1.x release line, v2.3.0 for the v2.x release line, and v3.1.0 for the v3.x release line do **NOT** support IBC token transfers of coins whose base denoms contain slashes. Therefore the in-place of genesis migration described in this document are required when upgrading. - -If a chain receives coins of a base denom with slashes before it upgrades to supporting it, the receive may pass however the trace information will be incorrect. - -E.g. If a base denom of `testcoin/testcoin/testcoin` is sent to a chain that does not support slashes in the base denom, the receive will be successful. However, the trace information stored on the receiving chain will be: `Trace: "transfer/{channel-id}/testcoin/testcoin", BaseDenom: "testcoin"`. - -This incorrect trace information must be corrected when the chain does upgrade to fully supporting denominations with slashes. - -To do so, chain binaries should include a migration script that will run when the chain upgrades from not supporting base denominations with slashes to supporting base denominations with slashes. - -## Chains - -### ICS20 - Transfer - -The transfer module will now support slashes in base denoms, so we must iterate over current traces to check if any of them are incorrectly formed and correct the trace information. - -### Upgrade Proposal - -```go -app.UpgradeKeeper.SetUpgradeHandler("MigrateTraces", - func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - // transfer module consensus version has been bumped to 2 - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) - -``` - -This is only necessary if there are denom traces in the store with incorrect trace information from previously received coins that had a slash in the base denom. However, it is recommended that any chain upgrading to support base denominations with slashes runs this code for safety. - -For a more detailed sample, please check out the code changes in [this pull request](https://github.com/cosmos/ibc-go/pull/1680). - -### Genesis Migration - -If the chain chooses to add support for slashes in base denoms via genesis export, then the trace information must be corrected during genesis migration. - -The migration code required may look like: - -```go -func migrateGenesisSlashedDenomsUpgrade(appState genutiltypes.AppMap, clientCtx client.Context, genDoc *tmtypes.GenesisDoc) (genutiltypes.AppMap, error) { - if appState[ibctransfertypes.ModuleName] != nil { - transferGenState := &ibctransfertypes.GenesisState{} - clientCtx.Codec.MustUnmarshalJSON(appState[ibctransfertypes.ModuleName], transferGenState) - - substituteTraces := make([]ibctransfertypes.DenomTrace, len(transferGenState.DenomTraces)) - for i, dt := range transferGenState.DenomTraces { - // replace all previous traces with the latest trace if validation passes - // note most traces will have same value - newTrace := ibctransfertypes.ParseDenomTrace(dt.GetFullDenomPath()) - - if err := newTrace.Validate(); err != nil { - substituteTraces[i] = dt - } else { - substituteTraces[i] = newTrace - } - } - - transferGenState.DenomTraces = substituteTraces - - // delete old genesis state - delete(appState, ibctransfertypes.ModuleName) - - // set new ibc transfer genesis state - appState[ibctransfertypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(transferGenState) - } - - return appState, nil -} -``` - -For a more detailed sample, please check out the code changes in [this pull request](https://github.com/cosmos/ibc-go/pull/1528). diff --git a/docs/versioned_docs/version-v4.4.x/04-migrations/02-sdk-to-v1.md b/docs/versioned_docs/version-v4.4.x/04-migrations/02-sdk-to-v1.md deleted file mode 100644 index f979034e272..00000000000 --- a/docs/versioned_docs/version-v4.4.x/04-migrations/02-sdk-to-v1.md +++ /dev/null @@ -1,195 +0,0 @@ ---- -title: SDK v0.43 to IBC-Go v1 -sidebar_label: SDK v0.43 to IBC-Go v1 -sidebar_position: 2 -slug: /migrations/sdk-to-v1 ---- -# Migrating to ibc-go - -This file contains information on how to migrate from the IBC module contained in the SDK 0.41.x and 0.42.x lines to the IBC module in the ibc-go repository based on the 0.44 SDK version. - -## Import Changes - -The most obvious changes is import name changes. We need to change: - -- applications -> apps -- cosmos-sdk/x/ibc -> ibc-go - -On my GNU/Linux based machine I used the following commands, executed in order: - -```bash -grep -RiIl 'cosmos-sdk\/x\/ibc\/applications' | xargs sed -i 's/cosmos-sdk\/x\/ibc\/applications/ibc-go\/modules\/apps/g' -``` - -```bash -grep -RiIl 'cosmos-sdk\/x\/ibc' | xargs sed -i 's/cosmos-sdk\/x\/ibc/ibc-go\/modules/g' -``` - -ref: [explanation of the above commands](https://www.internalpointers.com/post/linux-find-and-replace-text-multiple-files) - -Executing these commands out of order will cause issues. - -Feel free to use your own method for modifying import names. - -NOTE: Updating to the `v0.44.0` SDK release and then running `go mod tidy` will cause a downgrade to `v0.42.0` in order to support the old IBC import paths. -Update the import paths before running `go mod tidy`. - -## Chain Upgrades - -Chains may choose to upgrade via an upgrade proposal or genesis upgrades. Both in-place store migrations and genesis migrations are supported. - -**WARNING**: Please read at least the quick guide for [IBC client upgrades](../01-ibc/05-upgrades/00-intro.md) before upgrading your chain. It is highly recommended you do not change the chain-ID during an upgrade, otherwise you must follow the IBC client upgrade instructions. - -Both in-place store migrations and genesis migrations will: - -- migrate the solo machine client state from v1 to v2 protobuf definitions -- prune all solo machine consensus states -- prune all expired tendermint consensus states - -Chains must set a new connection parameter during either in place store migrations or genesis migration. The new parameter, max expected block time, is used to enforce packet processing delays on the receiving end of an IBC packet flow. Checkout the [docs](https://github.com/cosmos/ibc-go/blob/release/v1.0.x/docs/ibc/proto-docs.md#params-2) for more information. - -### In-Place Store Migrations - -The new chain binary will need to run migrations in the upgrade handler. The fromVM (previous module version) for the IBC module should be 1. This will allow migrations to be run for IBC updating the version from 1 to 2. - -Ex: - -```go -app.UpgradeKeeper.SetUpgradeHandler("my-upgrade-proposal", - func(ctx sdk.Context, _ upgradetypes.Plan, _ module.VersionMap) (module.VersionMap, error) { - // set max expected block time parameter. Replace the default with your expected value - // https://github.com/cosmos/ibc-go/blob/release/v1.0.x/docs/ibc/proto-docs.md#params-2 - app.IBCKeeper.ConnectionKeeper.SetParams(ctx, ibcconnectiontypes.DefaultParams()) - - fromVM := map[string]uint64{ - ... // other modules - "ibc": 1, - ... - } - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) - -``` - -### Genesis Migrations - -To perform genesis migrations, the following code must be added to your existing migration code. - -```go -// add imports as necessary -import ( - ibcv100 "github.com/cosmos/ibc-go/modules/core/legacy/v100" - ibchost "github.com/cosmos/ibc-go/modules/core/24-host" -) - -... - -// add in migrate cmd function -// expectedTimePerBlock is a new connection parameter -// https://github.com/cosmos/ibc-go/blob/release/v1.0.x/docs/ibc/proto-docs.md#params-2 -newGenState, err = ibcv100.MigrateGenesis(newGenState, clientCtx, *genDoc, expectedTimePerBlock) -if err != nil { - return err -} -``` - -**NOTE:** The genesis chain-id, time and height MUST be updated before migrating IBC, otherwise the tendermint consensus state will not be pruned. - -## IBC Keeper Changes - -The IBC Keeper now takes in the Upgrade Keeper. Please add the chains' Upgrade Keeper after the Staking Keeper: - -```diff - // Create IBC Keeper - app.IBCKeeper = ibckeeper.NewKeeper( -- appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, scopedIBCKeeper, -+ appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper, - ) - -``` - -## Proposals - -### UpdateClientProposal - -The `UpdateClient` has been modified to take in two client-identifiers and one initial height. Please see the [documentation](../01-ibc/06-proposals.md) for more information. - -### UpgradeProposal - -A new IBC proposal type has been added, `UpgradeProposal`. This handles an IBC (breaking) Upgrade. -The previous `UpgradedClientState` field in an Upgrade `Plan` has been deprecated in favor of this new proposal type. - -### Proposal Handler Registration - -The `ClientUpdateProposalHandler` has been renamed to `ClientProposalHandler`. -It handles both `UpdateClientProposal`s and `UpgradeProposal`s. - -Add this import: - -```diff -+ ibcclienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" -``` - -Please ensure the governance module adds the correct route: - -```diff -- AddRoute(ibchost.RouterKey, ibcclient.NewClientUpdateProposalHandler(app.IBCKeeper.ClientKeeper)) -+ AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)) -``` - -NOTE: Simapp registration was incorrect in the 0.41.x releases. The `UpdateClient` proposal handler should be registered with the router key belonging to `ibc-go/core/02-client/types` -as shown in the diffs above. - -### Proposal CLI Registration - -Please ensure both proposal type CLI commands are registered on the governance module by adding the following arguments to `gov.NewAppModuleBasic()`: - -Add the following import: - -```diff -+ ibcclientclient "github.com/cosmos/ibc-go/modules/core/02-client/client" -``` - -Register the cli commands: - -```diff - gov.NewAppModuleBasic( - paramsclient.ProposalHandler, distrclient.ProposalHandler, upgradeclient.ProposalHandler, upgradeclient.CancelProposalHandler, -+ ibcclientclient.UpdateClientProposalHandler, ibcclientclient.UpgradeProposalHandler, - ), -``` - -REST routes are not supported for these proposals. - -## Proto file changes - -The gRPC querier service endpoints have changed slightly. The previous files used `v1beta1` gRPC route, this has been updated to `v1`. - -The solo machine has replaced the FrozenSequence uint64 field with a IsFrozen boolean field. The package has been bumped from `v1` to `v2` - -## IBC callback changes - -### OnRecvPacket - -Application developers need to update their `OnRecvPacket` callback logic. - -The `OnRecvPacket` callback has been modified to only return the acknowledgement. The acknowledgement returned must implement the `Acknowledgement` interface. The acknowledgement should indicate if it represents a successful processing of a packet by returning true on `Success()` and false in all other cases. A return value of false on `Success()` will result in all state changes which occurred in the callback being discarded. More information can be found in the [documentation](../01-ibc/03-apps/02-ibcmodule.md#receiving-packets). - -The `OnRecvPacket`, `OnAcknowledgementPacket`, and `OnTimeoutPacket` callbacks are now passed the `sdk.AccAddress` of the relayer who relayed the IBC packet. Applications may use or ignore this information. - -## IBC Event changes - -The `packet_data` attribute has been deprecated in favor of `packet_data_hex`, in order to provide standardized encoding/decoding of packet data in events. While the `packet_data` event still exists, all relayers and IBC Event consumers are strongly encouraged to switch over to using `packet_data_hex` as soon as possible. - -The `packet_ack` attribute has also been deprecated in favor of `packet_ack_hex` for the same reason stated above. All relayers and IBC Event consumers are strongly encouraged to switch over to using `packet_ack_hex` as soon as possible. - -The `consensus_height` attribute has been removed in the Misbehaviour event emitted. IBC clients no longer have a frozen height and misbehaviour does not necessarily have an associated height. - -## Relevant SDK changes - -- (codec) [\#9226](https://github.com/cosmos/cosmos-sdk/pull/9226) Rename codec interfaces and methods, to follow a general Go interfaces: - - `codec.Marshaler` → `codec.Codec` (this defines objects which serialize other objects) - - `codec.BinaryMarshaler` → `codec.BinaryCodec` - - `codec.JSONMarshaler` → `codec.JSONCodec` - - Removed `BinaryBare` suffix from `BinaryCodec` methods (`MarshalBinaryBare`, `UnmarshalBinaryBare`, ...) - - Removed `Binary` infix from `BinaryCodec` methods (`MarshalBinaryLengthPrefixed`, `UnmarshalBinaryLengthPrefixed`, ...) diff --git a/docs/versioned_docs/version-v4.4.x/04-migrations/03-v1-to-v2.md b/docs/versioned_docs/version-v4.4.x/04-migrations/03-v1-to-v2.md deleted file mode 100644 index 577ddf995bf..00000000000 --- a/docs/versioned_docs/version-v4.4.x/04-migrations/03-v1-to-v2.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: IBC-Go v1 to v2 -sidebar_label: IBC-Go v1 to v2 -sidebar_position: 3 -slug: /migrations/v1-to-v2 ---- -# Migrating from ibc-go v1 to v2 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -```go -github.com/cosmos/ibc-go -> github.com/cosmos/ibc-go/v2 -``` - -## Chains - -- No relevant changes were made in this release. - -## IBC Apps - -A new function has been added to the app module interface: - -```go -// NegotiateAppVersion performs application version negotiation given the provided channel ordering, connectionID, portID, counterparty and proposed version. - // An error is returned if version negotiation cannot be performed. For example, an application module implementing this interface - // may decide to return an error in the event of the proposed version being incompatible with it's own - NegotiateAppVersion( - ctx sdk.Context, - order channeltypes.Order, - connectionID string, - portID string, - counterparty channeltypes.Counterparty, - proposedVersion string, - ) (version string, err error) -} -``` - -This function should perform application version negotiation and return the negotiated version. If the version cannot be negotiated, an error should be returned. This function is only used on the client side. - -### sdk.Result removed - -sdk.Result has been removed as a return value in the application callbacks. Previously it was being discarded by core IBC and was thus unused. - -## Relayers - -A new gRPC has been added to 05-port, `AppVersion`. It returns the negotiated app version. This function should be used for the `ChanOpenTry` channel handshake step to decide upon the application version which should be set in the channel. - -## IBC Light Clients - -- No relevant changes were made in this release. diff --git a/docs/versioned_docs/version-v4.4.x/04-migrations/04-v2-to-v3.md b/docs/versioned_docs/version-v4.4.x/04-migrations/04-v2-to-v3.md deleted file mode 100644 index fca445b0554..00000000000 --- a/docs/versioned_docs/version-v4.4.x/04-migrations/04-v2-to-v3.md +++ /dev/null @@ -1,186 +0,0 @@ ---- -title: IBC-Go v2 to v3 -sidebar_label: IBC-Go v2 to v3 -sidebar_position: 4 -slug: /migrations/v2-to-v3 ---- -# Migrating from ibc-go v2 to v3 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -```go -github.com/cosmos/ibc-go/v2 -> github.com/cosmos/ibc-go/v3 -``` - -No genesis or in-place migrations are required when upgrading from v1 or v2 of ibc-go. - -## Chains - -### ICS20 - -The `transferkeeper.NewKeeper(...)` now takes in an ICS4Wrapper. -The ICS4Wrapper should be the IBC Channel Keeper unless ICS 20 is being connected to a middleware application. - -### ICS27 - -ICS27 Interchain Accounts has been added as a supported IBC application of ibc-go. -Please see the [ICS27 documentation](../02-apps/02-interchain-accounts/01-overview.md) for more information. - -### Upgrade Proposal - -If the chain will adopt ICS27, it must set the appropriate params during the execution of the upgrade handler in `app.go`: - -```go -app.UpgradeKeeper.SetUpgradeHandler("v3", - func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - // set the ICS27 consensus version so InitGenesis is not run - fromVM[icatypes.ModuleName] = icamodule.ConsensusVersion() - - // create ICS27 Controller submodule params - controllerParams := icacontrollertypes.Params{ - ControllerEnabled: true, - } - - // create ICS27 Host submodule params - hostParams := icahosttypes.Params{ - HostEnabled: true, - AllowMessages: []string{"/cosmos.bank.v1beta1.MsgSend", ...}, - } - - // initialize ICS27 module - icamodule.InitModule(ctx, controllerParams, hostParams) - - ... - - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) - -``` - -The host and controller submodule params only need to be set if the chain integrates those submodules. -For example, if a chain chooses not to integrate a controller submodule, it may pass empty params into `InitModule`. - -#### Add `StoreUpgrades` for ICS27 module - -For ICS27 it is also necessary to [manually add store upgrades](https://docs.cosmos.network/main/learn/advanced/upgrade#add-storeupgrades-for-new-modules) for the new ICS27 module and then configure the store loader to apply those upgrades in `app.go`: - -```go -if upgradeInfo.Name == "v3" && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { - storeUpgrades := store.StoreUpgrades{ - Added: []string{icacontrollertypes.StoreKey, icahosttypes.StoreKey}, - } - - app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) -} -``` - -This ensures that the new module's stores are added to the multistore before the migrations begin. -The host and controller submodule keys only need to be added if the chain integrates those submodules. -For example, if a chain chooses not to integrate a controller submodule, it does not need to add the controller key to the `Added` field. - -### Genesis migrations - -If the chain will adopt ICS27 and chooses to upgrade via a genesis export, then the ICS27 parameters must be set during genesis migration. - -The migration code required may look like: - -```go - controllerGenesisState := icatypes.DefaultControllerGenesis() - // overwrite parameters as desired - controllerGenesisState.Params = icacontrollertypes.Params{ - ControllerEnabled: true, - } - - hostGenesisState := icatypes.DefaultHostGenesis() - // overwrite parameters as desired - hostGenesisState.Params = icahosttypes.Params{ - HostEnabled: true, - AllowMessages: []string{"/cosmos.bank.v1beta1.MsgSend", ...}, - } - - icaGenesisState := icatypes.NewGenesisState(controllerGenesisState, hostGenesisState) - - // set new ics27 genesis state - appState[icatypes.ModuleName] = clientCtx.JSONCodec.MustMarshalJSON(icaGenesisState) -``` - -### Ante decorator - -The field of type `channelkeeper.Keeper` in the `AnteDecorator` structure has been replaced with a field of type `*keeper.Keeper`: - -```diff -type AnteDecorator struct { -- k channelkeeper.Keeper -+ k *keeper.Keeper -} - -- func NewAnteDecorator(k channelkeeper.Keeper) AnteDecorator { -+ func NewAnteDecorator(k *keeper.Keeper) AnteDecorator { - return AnteDecorator{k: k} -} -``` - -## IBC Apps - -### `OnChanOpenTry` must return negotiated application version - -The `OnChanOpenTry` application callback has been modified. -The return signature now includes the application version. -IBC applications must perform application version negoitation in `OnChanOpenTry` using the counterparty version. -The negotiated application version then must be returned in `OnChanOpenTry` to core IBC. -Core IBC will set this version in the TRYOPEN channel. - -### `OnChanOpenAck` will take additional `counterpartyChannelID` argument - -The `OnChanOpenAck` application callback has been modified. -The arguments now include the counterparty channel id. - -### `NegotiateAppVersion` removed from `IBCModule` interface - -Previously this logic was handled by the `NegotiateAppVersion` function. -Relayers would query this function before calling `ChanOpenTry`. -Applications would then need to verify that the passed in version was correct. -Now applications will perform this version negotiation during the channel handshake, thus removing the need for `NegotiateAppVersion`. - -### Channel state will not be set before application callback - -The channel handshake logic has been reorganized within core IBC. -Channel state will not be set in state after the application callback is performed. -Applications must rely only on the passed in channel parameters instead of querying the channel keeper for channel state. - -### IBC application callbacks moved from `AppModule` to `IBCModule` - -Previously, IBC module callbacks were apart of the `AppModule` type. -The recommended approach is to create an `IBCModule` type and move the IBC module callbacks from `AppModule` to `IBCModule` in a separate file `ibc_module.go`. - -The mock module go API has been broken in this release by applying the above format. -The IBC module callbacks have been moved from the mock modules `AppModule` into a new type `IBCModule`. - -As apart of this release, the mock module now supports middleware testing. Please see the [README](https://github.com/cosmos/ibc-go/blob/v4.4.0/testing/README.md#middleware-testing) for more information. - -Please review the [mock](https://github.com/cosmos/ibc-go/blob/v4.4.0/testing/mock/ibc_module.go) and [transfer](https://github.com/cosmos/ibc-go/blob/v4.4.0/modules/apps/transfer/ibc_module.go) modules as examples. Additionally, [simapp](https://github.com/cosmos/ibc-go/blob/v4.4.0/testing/simapp/app.go) provides an example of how `IBCModule` types should now be added to the IBC router in favour of `AppModule`. - -### IBC testing package - -`TestChain`s are now created with chainID's beginning from an index of 1. Any calls to `GetChainID(0)` will now fail. Please increment all calls to `GetChainID` by 1. - -## Relayers - -`AppVersion` gRPC has been removed. -The `version` string in `MsgChanOpenTry` has been deprecated and will be ignored by core IBC. -Relayers no longer need to determine the version to use on the `ChanOpenTry` step. -IBC applications will determine the correct version using the counterparty version. - -## IBC Light Clients - -The `GetProofSpecs` function has been removed from the `ClientState` interface. This function was previously unused by core IBC. Light clients which don't use this function may remove it. diff --git a/docs/versioned_docs/version-v4.4.x/04-migrations/05-v3-to-v4.md b/docs/versioned_docs/version-v4.4.x/04-migrations/05-v3-to-v4.md deleted file mode 100644 index 067d8738e68..00000000000 --- a/docs/versioned_docs/version-v4.4.x/04-migrations/05-v3-to-v4.md +++ /dev/null @@ -1,160 +0,0 @@ ---- -title: IBC-Go v3 to v4 -sidebar_label: IBC-Go v3 to v4 -sidebar_position: 5 -slug: /migrations/v3-to-v4 ---- -# Migrating from ibc-go v3 to v4 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -```go -github.com/cosmos/ibc-go/v3 -> github.com/cosmos/ibc-go/v4 -``` - -No genesis or in-place migrations required when upgrading from v1 or v2 of ibc-go. - -## Chains - -### ICS27 - Interchain Accounts - -The controller submodule implements now the 05-port `Middleware` interface instead of the 05-port `IBCModule` interface. Chains that integrate the controller submodule, need to create it with the `NewIBCMiddleware` constructor function. For example: - -```diff -- icacontroller.NewIBCModule(app.ICAControllerKeeper, icaAuthIBCModule) -+ icacontroller.NewIBCMiddleware(icaAuthIBCModule, app.ICAControllerKeeper) -``` - -where `icaAuthIBCModule` is the Interchain Accounts authentication IBC Module. - -### ICS29 - Fee Middleware - -The Fee Middleware module, as the name suggests, plays the role of an IBC middleware and as such must be configured by chain developers to route and handle IBC messages correctly. - -Please read the Fee Middleware [integration documentation](https://ibc.cosmos.network/main/middleware/ics29-fee/integration.html) for an in depth guide on how to congfigure the module correctly in order to incentivize IBC packets. - -Take a look at the following diff for an [example setup](https://github.com/cosmos/ibc-go/pull/1432/files#diff-d18972debee5e64f16e40807b2ae112ddbe609504a93ea5e1c80a5d489c3a08aL366) of how to incentivize ics27 channels. - -### Migration to fix support for base denoms with slashes - -As part of [v1.5.0](https://github.com/cosmos/ibc-go/releases/tag/v1.5.0), [v2.3.0](https://github.com/cosmos/ibc-go/releases/tag/v2.3.0) and [v3.1.0](https://github.com/cosmos/ibc-go/releases/tag/v3.1.0) some [migration handler code sample was documented](./01-support-denoms-with-slashes.md#upgrade-proposal) that needs to run in order to correct the trace information of coins transferred using ICS20 whose base denom contains slashes. - -Based on feedback from the community we add now an improved solution to run the same migration that does not require copying a large piece of code over from the migration document, but instead requires only adding a one-line upgrade handler. - -If the chain will migrate to supporting base denoms with slashes, it must set the appropriate params during the execution of the upgrade handler in `app.go`: - -```go -app.UpgradeKeeper.SetUpgradeHandler("MigrateTraces", - func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - // transfer module consensus version has been bumped to 2 - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) - -``` - -If a chain receives coins of a base denom with slashes before it upgrades to supporting it, the receive may pass however the trace information will be incorrect. - -E.g. If a base denom of `testcoin/testcoin/testcoin` is sent to a chain that does not support slashes in the base denom, the receive will be successful. However, the trace information stored on the receiving chain will be: `Trace: "transfer/{channel-id}/testcoin/testcoin", BaseDenom: "testcoin"`. - -This incorrect trace information must be corrected when the chain does upgrade to fully supporting denominations with slashes. - -## IBC Apps - -### ICS03 - Connection - -Crossing hellos have been removed from 03-connection handshake negotiation. -`PreviousConnectionId` in `MsgConnectionOpenTry` has been deprecated and is no longer used by core IBC. - -`NewMsgConnectionOpenTry` no longer takes in the `PreviousConnectionId` as crossing hellos are no longer supported. A non-empty `PreviousConnectionId` will fail basic validation for this message. - -### ICS04 - Channel - -The `WriteAcknowledgement` API now takes the `exported.Acknowledgement` type instead of passing in the acknowledgement byte array directly. -This is an API breaking change and as such IBC application developers will have to update any calls to `WriteAcknowledgement`. - -The `OnChanOpenInit` application callback has been modified. -The return signature now includes the application version as detailed in the latest IBC [spec changes](https://github.com/cosmos/ibc/pull/629). - -The `NewErrorAcknowledgement` method signature has changed. -It now accepts an `error` rather than a `string`. This was done in order to prevent accidental state changes. -All error acknowledgements now contain a deterministic ABCI code and error message. It is the responsibility of the application developer to emit error details in events. - -Crossing hellos have been removed from 04-channel handshake negotiation. -IBC Applications no longer need to account from already claimed capabilities in the `OnChanOpenTry` callback. The capability provided by core IBC must be able to be claimed with error. -`PreviousChannelId` in `MsgChannelOpenTry` has been deprecated and is no longer used by core IBC. - -`NewMsgChannelOpenTry` no longer takes in the `PreviousChannelId` as crossing hellos are no longer supported. A non-empty `PreviousChannelId` will fail basic validation for this message. - -### ICS27 - Interchain Accounts - -The `RegisterInterchainAccount` API has been modified to include an additional `version` argument. This change has been made in order to support ICS29 fee middleware, for relayer incentivization of ICS27 packets. -Consumers of the `RegisterInterchainAccount` are now expected to build the appropriate JSON encoded version string themselves and pass it accordingly. -This should be constructed within the interchain accounts authentication module which leverages the APIs exposed via the interchain accounts `controllerKeeper`. If an empty string is passed in the `version` argument, then the version will be initialized to a default value in the `OnChanOpenInit` callback of the controller's handler, so that channel handshake can proceed. - -The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, msg.Owner, string(appVersion)); err != nil { - return err -} -``` - -Similarly, if the application stack is configured to route through ICS29 fee middleware and a fee enabled channel is desired, construct the appropriate ICS29 `Metadata` type: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -feeMetadata := feetypes.Metadata{ - AppVersion: string(appVersion), - FeeVersion: feetypes.Version, -} - -feeEnabledVersion, err := feetypes.ModuleCdc.MarshalJSON(&feeMetadata) -if err != nil { - return err -} - -if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, msg.Owner, string(feeEnabledVersion)); err != nil { - return err -} -``` - -## Relayers - -When using the `DenomTrace` gRPC, the full IBC denomination with the `ibc/` prefix may now be passed in. - -Crossing hellos are no longer supported by core IBC for 03-connection and 04-channel. The handshake should be completed in the logical 4 step process (INIT, TRY, ACK, CONFIRM). diff --git a/docs/versioned_docs/version-v4.4.x/04-migrations/_category_.json b/docs/versioned_docs/version-v4.4.x/04-migrations/_category_.json deleted file mode 100644 index 95db8e5579e..00000000000 --- a/docs/versioned_docs/version-v4.4.x/04-migrations/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Migrations", - "position": 4, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v5.3.x/00-intro.md b/docs/versioned_docs/version-v5.3.x/00-intro.md deleted file mode 100644 index c842dac0022..00000000000 --- a/docs/versioned_docs/version-v5.3.x/00-intro.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -slug: / -sidebar_position: 0 ---- - -# IBC-Go Documentation - -Welcome to the IBC-Go documentation! - -The Inter-Blockchain Communication protocol (IBC) is an end-to-end, connection-oriented, stateful protocol for reliable, ordered, and authenticated communication between heterogeneous blockchains arranged in an unknown and dynamic topology. - -IBC is a protocol that allows blockchains to talk to each other. - -The protocol realizes this interoperability by specifying a set of data structures, abstractions, and semantics that can be implemented by any distributed ledger that satisfies a small set of requirements. - -IBC can be used to build a wide range of cross-chain applications that include token transfers, atomic swaps, multi-chain smart contracts (with or without mutually comprehensible VMs), and data and code sharding of various kinds. diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/01-overview.md b/docs/versioned_docs/version-v5.3.x/01-ibc/01-overview.md deleted file mode 100644 index e8767d36cdb..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/01-overview.md +++ /dev/null @@ -1,297 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /ibc/overview ---- - - -# Overview - -:::note Synopsis -Learn about IBC, its components, and IBC use cases. -::: - -## What is the Interblockchain Communication Protocol (IBC)? - -This document serves as a guide for developers who want to write their own Inter-Blockchain -Communication protocol (IBC) applications for custom use cases. - -> IBC applications must be written as self-contained modules. - -Due to the modular design of the IBC protocol, IBC -application developers do not need to be concerned with the low-level details of clients, -connections, and proof verification. - -This brief explanation of the lower levels of the -stack gives application developers a broad understanding of the IBC -protocol. Abstraction layer details for channels and ports are most relevant for application developers and describe how to define custom packets and `IBCModule` callbacks. - -The requirements to have your module interact over IBC are: - -- Bind to a port or ports. -- Define your packet data. -- Use the default acknowledgment struct provided by core IBC or optionally define a custom acknowledgment struct. -- Standardize an encoding of the packet data. -- Implement the `IBCModule` interface. - -Read on for a detailed explanation of how to write a self-contained IBC application module. - -## Components Overview - -### [Clients](https://github.com/cosmos/ibc-go/blob/main/modules/core/02-client) - -IBC clients are on-chain light clients. Each light client is identified by a unique client-id. -IBC clients track the consensus states of other blockchains, along with the proof spec necessary to -properly verify proofs against the client's consensus state. A client can be associated with any number -of connections to the counterparty chain. The client identifier is auto generated using the client type -and the global client counter appended in the format: `{client-type}-{N}`. - -A `ClientState` should contain chain specific and light client specific information necessary for verifying updates -and upgrades to the IBC client. The `ClientState` may contain information such as chain-id, latest height, proof specs, -unbonding periods or the status of the light client. The `ClientState` should not contain information that -is specific to a given block at a certain height, this is the function of the `ConsensusState`. Each `ConsensusState` -should be associated with a unique block and should be referenced using a height. IBC clients are given a -client identifier prefixed store to store their associated client state and consensus states along with -any metadata associated with the consensus states. Consensus states are stored using their associated height. - -The supported IBC clients are: - -- [Solo Machine light client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/06-solomachine): Devices such as phones, browsers, or laptops. -- [Tendermint light client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/07-tendermint): The default for Cosmos SDK-based chains. -- [Localhost (loopback) client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/09-localhost): Useful for -testing, simulation, and relaying packets to modules on the same application. - -### IBC Client Heights - -IBC Client Heights are represented by the struct: - -```go -type Height struct { - RevisionNumber uint64 - RevisionHeight uint64 -} -``` - -The `RevisionNumber` represents the revision of the chain that the height is representing. -A revision typically represents a continuous, monotonically increasing range of block-heights. -The `RevisionHeight` represents the height of the chain within the given revision. - -On any reset of the `RevisionHeight`—for example, when hard-forking a Tendermint chain— -the `RevisionNumber` will get incremented. This allows IBC clients to distinguish between a -block-height `n` of a previous revision of the chain (at revision `p`) and block-height `n` of the current -revision of the chain (at revision `e`). - -`Height`s that share the same revision number can be compared by simply comparing their respective `RevisionHeight`s. -`Height`s that do not share the same revision number will only be compared using their respective `RevisionNumber`s. -Thus a height `h` with revision number `e+1` will always be greater than a height `g` with revision number `e`, -**REGARDLESS** of the difference in revision heights. - -Ex: - -```go -Height{RevisionNumber: 3, RevisionHeight: 0} > Height{RevisionNumber: 2, RevisionHeight: 100000000000} -``` - -When a Tendermint chain is running a particular revision, relayers can simply submit headers and proofs with the revision number -given by the chain's `chainID`, and the revision height given by the Tendermint block height. When a chain updates using a hard-fork -and resets its block-height, it is responsible for updating its `chainID` to increment the revision number. -IBC Tendermint clients then verifies the revision number against their `chainID` and treat the `RevisionHeight` as the Tendermint block-height. - -Tendermint chains wishing to use revisions to maintain persistent IBC connections even across height-resetting upgrades must format their `chainID`s -in the following manner: `{chainID}-{revision_number}`. On any height-resetting upgrade, the `chainID` **MUST** be updated with a higher revision number -than the previous value. - -Ex: - -- Before upgrade `chainID`: `gaiamainnet-3` -- After upgrade `chainID`: `gaiamainnet-4` - -Clients that do not require revisions, such as the solo-machine client, simply hardcode `0` into the revision number whenever they -need to return an IBC height when implementing IBC interfaces and use the `RevisionHeight` exclusively. - -Other client-types can implement their own logic to verify the IBC heights that relayers provide in their `Update`, `Misbehavior`, and -`Verify` functions respectively. - -The IBC interfaces expect an `ibcexported.Height` interface, however all clients must use the concrete implementation provided in -`02-client/types` and reproduced above. - -### [Connections](https://github.com/cosmos/ibc-go/blob/main/modules/core/03-connection) - -Connections encapsulate two `ConnectionEnd` objects on two separate blockchains. Each -`ConnectionEnd` is associated with a client of the other blockchain (for example, the counterparty blockchain). -The connection handshake is responsible for verifying that the light clients on each chain are -correct for their respective counterparties. Connections, once established, are responsible for -facilitating all cross-chain verifications of IBC state. A connection can be associated with any -number of channels. - -### [Proofs](https://github.com/cosmos/ibc-go/blob/main/modules/core/23-commitment) and [Paths](https://github.com/cosmos/ibc-go/blob/main/modules/core/24-host) - -In IBC, blockchains do not directly pass messages to each other over the network. Instead, to -communicate, a blockchain commits some state to a specifically defined path that is reserved for a -specific message type and a specific counterparty. For example, for storing a specific connectionEnd as part -of a handshake or a packet intended to be relayed to a module on the counterparty chain. A relayer -process monitors for updates to these paths and relays messages by submitting the data stored -under the path and a proof to the counterparty chain. - -Proofs are passed from core IBC to light-clients as bytes. It is up to light client implementation to interpret these bytes appropriately. - -- The paths that all IBC implementations must use for committing IBC messages is defined in -[ICS-24 Host State Machine Requirements](https://github.com/cosmos/ics/tree/master/spec/core/ics-024-host-requirements). -- The proof format that all implementations must be able to produce and verify is defined in [ICS-23 Proofs](https://github.com/confio/ics23) implementation. - -### [Capabilities](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/advanced/10-ocap.md) - -IBC is intended to work in execution environments where modules do not necessarily trust each -other. Thus, IBC must authenticate module actions on ports and channels so that only modules with the -appropriate permissions can use them. - -This module authentication is accomplished using a [dynamic -capability store](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-003-dynamic-capability-store.md). Upon binding to a port or -creating a channel for a module, IBC returns a dynamic capability that the module must claim in -order to use that port or channel. The dynamic capability module prevents other modules from using that port or channel since -they do not own the appropriate capability. - -While this background information is useful, IBC modules do not need to interact at all with -these lower-level abstractions. The relevant abstraction layer for IBC application developers is -that of channels and ports. IBC applications must be written as self-contained **modules**. - -A module on one blockchain can communicate with other modules on other blockchains by sending, -receiving, and acknowledging packets through channels that are uniquely identified by the -`(channelID, portID)` tuple. - -A useful analogy is to consider IBC modules as internet applications on -a computer. A channel can then be conceptualized as an IP connection, with the IBC portID being -analogous to an IP port and the IBC channelID being analogous to an IP address. Thus, a single -instance of an IBC module can communicate on the same port with any number of other modules and -IBC correctly routes all packets to the relevant module using the (channelID, portID tuple). An -IBC module can also communicate with another IBC module over multiple ports, with each -`(portID<->portID)` packet stream being sent on a different unique channel. - -### [Ports](https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port) - -An IBC module can bind to any number of ports. Each port must be identified by a unique `portID`. -Since IBC is designed to be secure with mutually distrusted modules operating on the same ledger, -binding a port returns a dynamic object capability. In order to take action on a particular port -(for example, an open channel with its portID), a module must provide the dynamic object capability to the IBC -handler. This requirement prevents a malicious module from opening channels with ports it does not own. Thus, -IBC modules are responsible for claiming the capability that is returned on `BindPort`. - -### [Channels](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -An IBC channel can be established between two IBC ports. Currently, a port is exclusively owned by a -single module. IBC packets are sent over channels. Just as IP packets contain the destination IP -address and IP port, and the source IP address and source IP port, IBC packets contain -the destination portID and channelID, and the source portID and channelID. This packet structure enables IBC to -correctly route packets to the destination module while allowing modules receiving packets to -know the sender module. - -A channel can be `ORDERED`, where packets from a sending module must be processed by the -receiving module in the order they were sent. Or a channel can be `UNORDERED`, where packets -from a sending module are processed in the order they arrive (might be in a different order than they were sent). - -Modules can choose which channels they wish to communicate over with, thus IBC expects modules to -implement callbacks that are called during the channel handshake. These callbacks can do custom -channel initialization logic. If any callback returns an error, the channel handshake fails. Thus, by -returning errors on callbacks, modules can programmatically reject and accept channels. - -The channel handshake is a 4-step handshake. Briefly, if a given chain A wants to open a channel with -chain B using an already established connection: - -1. chain A sends a `ChanOpenInit` message to signal a channel initialization attempt with chain B. -2. chain B sends a `ChanOpenTry` message to try opening the channel on chain A. -3. chain A sends a `ChanOpenAck` message to mark its channel end status as open. -4. chain B sends a `ChanOpenConfirm` message to mark its channel end status as open. - -If all handshake steps are successful, the channel is opened on both sides. At each step in the handshake, the module -associated with the `ChannelEnd` executes its callback. So -on `ChanOpenInit`, the module on chain A executes its callback `OnChanOpenInit`. - -The channel identifier is auto derived in the format: `channel-{N}` where N is the next sequence to be used. - -Just as ports came with dynamic capabilities, channel initialization returns a dynamic capability -that the module **must** claim so that they can pass in a capability to authenticate channel actions -like sending packets. The channel capability is passed into the callback on the first parts of the -handshake; either `OnChanOpenInit` on the initializing chain or `OnChanOpenTry` on the other chain. - -#### Closing channels - -Closing a channel occurs in 2 handshake steps as defined in [ICS 04](https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics). - -`ChanCloseInit` closes a channel on the executing chain if the channel exists, it is not -already closed and the connection it exists upon is OPEN. Channels can only be closed by a -calling module or in the case of a packet timeout on an ORDERED channel. - -`ChanCloseConfirm` is a response to a counterparty channel executing `ChanCloseInit`. The channel -on the executing chain closes if the channel exists, the channel is not already closed, -the connection the channel exists upon is OPEN and the executing chain successfully verifies -that the counterparty channel has been closed. - -### [Packets](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -Modules communicate with each other by sending packets over IBC channels. All -IBC packets contain the destination `portID` and `channelID` along with the source `portID` and -`channelID`. This packet structure allows modules to know the sender module of a given packet. IBC packets -contain a sequence to optionally enforce ordering. - -IBC packets also contain a `TimeoutHeight` and a `TimeoutTimestamp` that determine the deadline before the receiving module must process a packet. - -Modules send custom application data to each other inside the `Data []byte` field of the IBC packet. -Thus, packet data is opaque to IBC handlers. It is incumbent on a sender module to encode -their application-specific packet information into the `Data` field of packets. The receiver -module must decode that `Data` back to the original application data. - -### [Receipts and Timeouts](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -Since IBC works over a distributed network and relies on potentially faulty relayers to relay messages between ledgers, -IBC must handle the case where a packet does not get sent to its destination in a timely manner or at all. Packets must -specify a non-zero value for timeout height (`TimeoutHeight`) or timeout timestamp (`TimeoutTimestamp` ) after which a packet can no longer be successfully received on the destination chain. - -- The `timeoutHeight` indicates a consensus height on the destination chain after which the packet is no longer be processed, and instead counts as having timed-out. -- The `timeoutTimestamp` indicates a timestamp on the destination chain after which the packet is no longer be processed, and instead counts as having timed-out. - -If the timeout passes without the packet being successfully received, the packet can no longer be -received on the destination chain. The sending module can timeout the packet and take appropriate actions. - -If the timeout is reached, then a proof of packet timeout can be submitted to the original chain. The original chain can then perform -application-specific logic to timeout the packet, perhaps by rolling back the packet send changes (refunding senders any locked funds, etc.). - -- In ORDERED channels, a timeout of a single packet in the channel causes the channel to close. - - - If packet sequence `n` times out, then a packet at sequence `k > n` cannot be received without violating the contract of ORDERED channels that packets are processed in the order that they are sent. - - Since ORDERED channels enforce this invariant, a proof that sequence `n` has not been received on the destination chain by the specified timeout of packet `n` is sufficient to timeout packet `n` and close the channel. - -- In UNORDERED channels, the application-specific timeout logic for that packet is applied and the channel is not closed. - - - Packets can be received in any order. - - - IBC writes a packet receipt for each sequence receives in the UNORDERED channel. This receipt does not contain information; it is simply a marker intended to signify that the UNORDERED channel has received a packet at the specified sequence. - - - To timeout a packet on an UNORDERED channel, a proof is required that a packet receipt **does not exist** for the packet's sequence by the specified timeout. - -For this reason, most modules should use UNORDERED channels as they require fewer liveness guarantees to function effectively for users of that channel. - -### [Acknowledgments](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -Modules can also choose to write application-specific acknowledgments upon processing a packet. Acknowledgments can be done: - -- Synchronously on `OnRecvPacket` if the module processes packets as soon as they are received from IBC module. -- Asynchronously if module processes packets at some later point after receiving the packet. - -This acknowledgment data is opaque to IBC much like the packet `Data` and is treated by IBC as a simple byte string `[]byte`. Receiver modules must encode their acknowledgment so that the sender module can decode it correctly. The encoding must be negotiated between the two parties during version negotiation in the channel handshake. - -The acknowledgment can encode whether the packet processing succeeded or failed, along with additional information that allows the sender module to take appropriate action. - -After the acknowledgment has been written by the receiving chain, a relayer relays the acknowledgment back to the original sender module. - -The original sender module then executes application-specific acknowledgment logic using the contents of the acknowledgment. - -- After an acknowledgement fails, packet-send changes can be rolled back (for example, refunding senders in ICS20). - -- After an acknowledgment is received successfully on the original sender on the chain, the corresponding packet commitment is deleted since it is no longer needed. - -## Further Readings and Specs - -If you want to learn more about IBC, check the following specifications: - -- [IBC specification overview](https://github.com/cosmos/ibc/blob/master/README.md) diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/02-integration.md b/docs/versioned_docs/version-v5.3.x/01-ibc/02-integration.md deleted file mode 100644 index 60bedf7e216..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/02-integration.md +++ /dev/null @@ -1,222 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 2 -slug: /ibc/integration ---- - -# Integration - -:::note Synopsis -Learn how to integrate IBC to your application and send data packets to other chains. -::: - -This document outlines the required steps to integrate and configure the [IBC -module](https://github.com/cosmos/ibc-go/tree/main/modules/core) to your Cosmos SDK application and -send fungible token transfers to other chains. - -## Integrating the IBC module - -Integrating the IBC module to your SDK-based application is straighforward. The general changes can be summarized in the following steps: - -- Add required modules to the `module.BasicManager` -- Define additional `Keeper` fields for the new modules on the `App` type -- Add the module's `StoreKeys` and initialize their `Keepers` -- Set up corresponding routers and routes for the `ibc` module -- Add the modules to the module `Manager` -- Add modules to `Begin/EndBlockers` and `InitGenesis` -- Update the module `SimulationManager` to enable simulations - -### Module `BasicManager` and `ModuleAccount` permissions - -The first step is to add the following modules to the `BasicManager`: `x/capability`, `x/ibc`, -and `x/ibc-transfer`. After that, we need to grant `Minter` and `Burner` permissions to -the `ibc-transfer` `ModuleAccount` to mint and burn relayed tokens. - -```go -// app.go -var ( - - ModuleBasics = module.NewBasicManager( - // ... - capability.AppModuleBasic{}, - ibc.AppModuleBasic{}, - transfer.AppModuleBasic{}, // i.e ibc-transfer module - ) - - // module account permissions - maccPerms = map[string][]string{ - // other module accounts permissions - // ... - ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, -) -``` - -### Application fields - -Then, we need to register the `Keepers` as follows: - -```go -// app.go -type App struct { - // baseapp, keys and subspaces definitions - - // other keepers - // ... - IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly - TransferKeeper ibctransferkeeper.Keeper // for cross-chain fungible token transfers - - // make scoped keepers public for test purposes - ScopedIBCKeeper capabilitykeeper.ScopedKeeper - ScopedTransferKeeper capabilitykeeper.ScopedKeeper - - /// ... - /// module and simulation manager definitions -} -``` - -### Configure the `Keepers` - -During initialization, besides initializing the IBC `Keepers` (for the `x/ibc`, and -`x/ibc-transfer` modules), we need to grant specific capabilities through the capability module -`ScopedKeepers` so that we can authenticate the object-capability permissions for each of the IBC -channels. - -```go -func NewApp(...args) *App { - // define codecs and baseapp - - // add capability keeper and ScopeToModule for ibc module - app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey]) - - // grant capabilities for the ibc and ibc-transfer modules - scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName) - scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) - - // ... other modules keepers - - // Create IBC Keeper - app.IBCKeeper = ibckeeper.NewKeeper( - appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper, - ) - - // Create Transfer Keepers - app.TransferKeeper = ibctransferkeeper.NewKeeper( - appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName), - app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, app.BankKeeper, scopedTransferKeeper, - ) - transferModule := transfer.NewAppModule(app.TransferKeeper) - - // .. continues -} -``` - -### Register `Routers` - -IBC needs to know which module is bound to which port so that it can route packets to the -appropriate module and call the appropriate callbacks. The port to module name mapping is handled by -IBC's port `Keeper`. However, the mapping from module name to the relevant callbacks is accomplished -by the port -[`Router`](https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port/types/router.go) on the -IBC module. - -Adding the module routes allows the IBC handler to call the appropriate callback when processing a -channel handshake or a packet. - -Currently, a `Router` is static so it must be initialized and set correctly on app initialization. -Once the `Router` has been set, no new routes can be added. - -```go -// app.go -func NewApp(...args) *App { - // .. continuation from above - - // Create static IBC router, add ibc-tranfer module route, then set and seal it - ibcRouter := port.NewRouter() - ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule) - // Setting Router will finalize all routes by sealing router - // No more routes can be added - app.IBCKeeper.SetRouter(ibcRouter) - - // .. continues -``` - -### Module Managers - -In order to use IBC, we need to add the new modules to the module `Manager` and to the `SimulationManager` in case your application supports [simulations](https://github.com/cosmos/cosmos-sdk/blob/main/docs/build/building-modules/14-simulator.md). - -```go -// app.go -func NewApp(...args) *App { - // .. continuation from above - - app.mm = module.NewManager( - // other modules - // ... - capability.NewAppModule(appCodec, *app.CapabilityKeeper), - ibc.NewAppModule(app.IBCKeeper), - transferModule, - ) - - // ... - - app.sm = module.NewSimulationManager( - // other modules - // ... - capability.NewAppModule(appCodec, *app.CapabilityKeeper), - ibc.NewAppModule(app.IBCKeeper), - transferModule, - ) - - // .. continues -``` - -### Application ABCI Ordering - -One addition from IBC is the concept of `HistoricalEntries` which are stored on the staking module. -Each entry contains the historical information for the `Header` and `ValidatorSet` of this chain which is stored -at each height during the `BeginBlock` call. The historical info is required to introspect the -past historical info at any given height in order to verify the light client `ConsensusState` during the -connection handhake. - -The IBC module also has -[`BeginBlock`](https://github.com/cosmos/ibc-go/blob/main/modules/core/02-client/abci.go) logic as well. This is optional as it is only required if your application uses the localhost client to connect two different modules from the same chain. - -:::tip -Only register the ibc module to the `SetOrderBeginBlockers` if your application will use the -localhost (*aka* loopback) client. -::: - -```go -// app.go -func NewApp(...args) *App { - // .. continuation from above - - // add staking and ibc modules to BeginBlockers - app.mm.SetOrderBeginBlockers( - // other modules ... - stakingtypes.ModuleName, ibchost.ModuleName, - ) - - // ... - - // 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. - app.mm.SetOrderInitGenesis( - capabilitytypes.ModuleName, - // other modules ... - ibchost.ModuleName, ibctransfertypes.ModuleName, - ) - - // .. continues -``` - -:::warning -**IMPORTANT**: The capability module **must** be declared first in `SetOrderInitGenesis` -::: - -That's it! You have now wired up the IBC module and are now able to send fungible tokens across -different chains. If you want to have a broader view of the changes take a look into the SDK's -[`SimApp`](https://github.com/cosmos/ibc-go/blob/main/testing/simapp/app.go). diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/01-apps.md b/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/01-apps.md deleted file mode 100644 index 58a1bb63045..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/01-apps.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: IBC Applications -sidebar_label: IBC Applications -sidebar_position: 1 -slug: /ibc/apps/apps ---- - -# IBC Applications - -:::note Synopsis -Learn how to build custom IBC application modules that enable packets to be sent to and received from other IBC-enabled chains. -::: - -This document serves as a guide for developers who want to write their own Inter-blockchain Communication Protocol (IBC) applications for custom use cases. - -Due to the modular design of the IBC protocol, IBC application developers do not need to concern themselves with the low-level details of clients, connections, and proof verification. Nevertheless, an overview of these low-level concepts can be found in [the Overview section](../01-overview.md). -The document goes into detail on the abstraction layer most relevant for application developers (channels and ports), and describes how to define your own custom packets, `IBCModule` callbacks and more to make an application module IBC ready. - -**To have your module interact over IBC you must:** - -- implement the `IBCModule` interface, i.e.: - - channel (opening) handshake callbacks - - channel closing handshake callbacks - - packet callbacks -- bind to a port(s) -- add keeper methods -- define your own packet data and acknowledgement structs as well as how to encode/decode them -- add a route to the IBC router - -The following sections provide a more detailed explanation of how to write an IBC application -module correctly corresponding to the listed steps. - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: - -## Working example - -For a real working example of an IBC application, you can look through the `ibc-transfer` module -which implements everything discussed in this section. - -Here are the useful parts of the module to look at: - -[Binding to transfer -port](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/genesis.go) - -[Sending transfer -packets](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/relay.go) - -[Implementing IBC -callbacks](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/ibc_module.go) diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/02-ibcmodule.md b/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/02-ibcmodule.md deleted file mode 100644 index ce96fbe4778..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/02-ibcmodule.md +++ /dev/null @@ -1,351 +0,0 @@ ---- -title: Implement `IBCModule` interface and callbacks -sidebar_label: Implement `IBCModule` interface and callbacks -sidebar_position: 2 -slug: /ibc/apps/ibcmodule ---- - -# Implement `IBCModule` interface and callbacks - -:::note Synopsis -Learn how to implement the `IBCModule` interface and all of the callbacks it requires. -::: - -The Cosmos SDK expects all IBC modules to implement the [`IBCModule` -interface](https://github.com/cosmos/ibc-go/tree/main/modules/core/05-port/types/module.go). This interface contains all of the callbacks IBC expects modules to implement. They include callbacks related to channel handshake, closing and packet callbacks (`OnRecvPacket`, `OnAcknowledgementPacket` and `OnTimeoutPacket`). - -```go -// IBCModule implements the ICS26 interface for given the keeper. -// The implementation of the IBCModule interface could for example be in a file called ibc_module.go, -// but ultimately file structure is up to the developer -type IBCModule struct { - keeper keeper.Keeper -} -``` - -Additionally, in the `module.go` file, add the following line: - -```go -var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} - // Add this line - _ porttypes.IBCModule = IBCModule{} -) -``` - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: - -## Channel handshake callbacks - -This section will describe the callbacks that are called during channel handshake execution. Among other things, it will claim channel capabilities passed on from core IBC. For a refresher on capabilities, check [the Overview section](../01-overview.md#capabilities). - -Here are the channel handshake callbacks that modules are expected to implement: - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `checkArguments` and `negotiateAppVersion` functions. - -```go -// Called by IBC Handler on MsgOpenInit -func (im IBCModule) OnChanOpenInit(ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) (string, error) { - // ... do custom initialization logic - - // Use above arguments to determine if we want to abort handshake - // Examples: - // - Abort if order == UNORDERED, - // - Abort if version is unsupported - if err := checkArguments(args); err != nil { - return "", err - } - - // OpenInit must claim the channelCapability that IBC passes into the callback - if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return "", err - } - - return version, nil -} - -// Called by IBC Handler on MsgOpenTry -func (im IBCModule) OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (string, error) { - // ... do custom initialization logic - - // Use above arguments to determine if we want to abort handshake - if err := checkArguments(args); err != nil { - return "", err - } - - // OpenTry must claim the channelCapability that IBC passes into the callback - if err := im.keeper.scopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return err - } - - // Construct application version - // IBC applications must return the appropriate application version - // This can be a simple string or it can be a complex version constructed - // from the counterpartyVersion and other arguments. - // The version returned will be the channel version used for both channel ends. - appVersion := negotiateAppVersion(counterpartyVersion, args) - - return appVersion, nil -} - -// Called by IBC Handler on MsgOpenAck -func (im IBCModule) OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyVersion string, -) error { - if counterpartyVersion != types.Version { - return sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: %s, expected %s", counterpartyVersion, types.Version) - } - - // do custom logic - - return nil -} - -// Called by IBC Handler on MsgOpenConfirm -func (im IBCModule) OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // do custom logic - - return nil -} -``` - -The channel closing handshake will also invoke module callbacks that can return errors to abort the closing handshake. Closing a channel is a 2-step handshake, the initiating chain calls `ChanCloseInit` and the finalizing chain calls `ChanCloseConfirm`. - -```go -// Called by IBC Handler on MsgCloseInit -func (im IBCModule) OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - // ... do custom finalization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} - -// Called by IBC Handler on MsgCloseConfirm -func (im IBCModule) OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // ... do custom finalization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} -``` - -### Channel handshake version negotiation - -Application modules are expected to verify versioning used during the channel handshake procedure. - -- `OnChanOpenInit` will verify that the relayer-chosen parameters - are valid and perform any custom `INIT` logic. - It may return an error if the chosen parameters are invalid - in which case the handshake is aborted. - If the provided version string is non-empty, `OnChanOpenInit` should return - the version string if valid or an error if the provided version is invalid. - **If the version string is empty, `OnChanOpenInit` is expected to - return a default version string representing the version(s) - it supports.** - If there is no default version string for the application, - it should return an error if the provided version is an empty string. -- `OnChanOpenTry` will verify the relayer-chosen parameters along with the - counterparty-chosen version string and perform custom `TRY` logic. - If the relayer-chosen parameters - are invalid, the callback must return an error to abort the handshake. - If the counterparty-chosen version is not compatible with this module's - supported versions, the callback must return an error to abort the handshake. - If the versions are compatible, the try callback must select the final version - string and return it to core IBC. - `OnChanOpenTry` may also perform custom initialization logic. -- `OnChanOpenAck` will error if the counterparty selected version string - is invalid and abort the handshake. It may also perform custom ACK logic. - -Versions must be strings but can implement any versioning structure. If your application plans to -have linear releases then semantic versioning is recommended. If your application plans to release -various features in between major releases then it is advised to use the same versioning scheme -as IBC. This versioning scheme specifies a version identifier and compatible feature set with -that identifier. Valid version selection includes selecting a compatible version identifier with -a subset of features supported by your application for that version. The struct used for this -scheme can be found in [03-connection/types](https://github.com/cosmos/ibc-go/blob/main/modules/core/03-connection/types/version.go#L16). - -Since the version type is a string, applications have the ability to do simple version verification -via string matching or they can use the already impelemented versioning system and pass the proto -encoded version into each handhshake call as necessary. - -ICS20 currently implements basic string matching with a single supported version. - -## Packet callbacks - -Just as IBC expects modules to implement callbacks for channel handshakes, it also expects modules to implement callbacks for handling the packet flow through a channel, as defined in the `IBCModule` interface. - -Once a module A and module B are connected to each other, relayers can start relaying packets and acknowledgements back and forth on the channel. - -![IBC packet flow diagram](./images/packet_flow.png) - -Briefly, a successful packet flow works as follows: - -1. module A sends a packet through the IBC module -2. the packet is received by module B -3. if module B writes an acknowledgement of the packet then module A will process the - acknowledgement -4. if the packet is not successfully received before the timeout, then module A processes the - packet's timeout. - -### Sending packets - -Modules **do not send packets through callbacks**, since the modules initiate the action of sending packets to the IBC module, as opposed to other parts of the packet flow where messages sent to the IBC -module must trigger execution on the port-bound module through the use of callbacks. Thus, to send a packet a module simply needs to call `SendPacket` on the `IBCChannelKeeper`. - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `EncodePacketData(customPacketData)` function. - -```go -// retrieve the dynamic capability for this channel -channelCap := scopedKeeper.GetCapability(ctx, channelCapName) -// Sending custom application packet data -data := EncodePacketData(customPacketData) -packet.Data = data -// Send packet to IBC, authenticating with channelCap -IBCChannelKeeper.SendPacket(ctx, channelCap, packet) -``` - -:::warning -In order to prevent modules from sending packets on channels they do not own, IBC expects -modules to pass in the correct channel capability for the packet's source channel. -::: - -### Receiving packets - -To handle receiving packets, the module must implement the `OnRecvPacket` callback. This gets -invoked by the IBC module after the packet has been proved valid and correctly processed by the IBC -keepers. Thus, the `OnRecvPacket` callback only needs to worry about making the appropriate state -changes given the packet data without worrying about whether the packet is valid or not. - -Modules may return to the IBC handler an acknowledgement which implements the `Acknowledgement` interface. -The IBC handler will then commit this acknowledgement of the packet so that a relayer may relay the -acknowledgement back to the sender module. - -The state changes that occurred during this callback will only be written if: - -- the acknowledgement was successful as indicated by the `Success()` function of the acknowledgement -- if the acknowledgement returned is nil indicating that an asynchronous process is occurring - -NOTE: Applications which process asynchronous acknowledgements must handle reverting state changes -when appropriate. Any state changes that occurred during the `OnRecvPacket` callback will be written -for asynchronous acknowledgements. - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `DecodePacketData(packet.Data)` function. - -```go -func (im IBCModule) OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, -) ibcexported.Acknowledgement { - // Decode the packet data - packetData := DecodePacketData(packet.Data) - - // do application state changes based on packet data and return the acknowledgement - // NOTE: The acknowledgement will indicate to the IBC handler if the application - // state changes should be written via the `Success()` function. Application state - // changes are only written if the acknowledgement is successful or the acknowledgement - // returned is nil indicating that an asynchronous acknowledgement will occur. - ack := processPacket(ctx, packet, packetData) - - return ack -} -``` - -Reminder, the `Acknowledgement` interface: - -```go -// Acknowledgement defines the interface used to return -// acknowledgements in the OnRecvPacket callback. -type Acknowledgement interface { - Success() bool - Acknowledgement() []byte -} -``` - -### Acknowledging packets - -After a module writes an acknowledgement, a relayer can relay back the acknowledgement to the sender module. The sender module can -then process the acknowledgement using the `OnAcknowledgementPacket` callback. The contents of the -acknowledgement is entirely up to the modules on the channel (just like the packet data); however, it -may often contain information on whether the packet was successfully processed along -with some additional data that could be useful for remediation if the packet processing failed. - -Since the modules are responsible for agreeing on an encoding/decoding standard for packet data and -acknowledgements, IBC will pass in the acknowledgements as `[]byte` to this callback. The callback -is responsible for decoding the acknowledgement and processing it. - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `DecodeAcknowledgement(acknowledgments)` and `processAck(ack)` functions. - -```go -func (im IBCModule) OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, -) (*sdk.Result, error) { - // Decode acknowledgement - ack := DecodeAcknowledgement(acknowledgement) - - // process ack - res, err := processAck(ack) - return res, err -} -``` - -### Timeout packets - -If the timeout for a packet is reached before the packet is successfully received or the -counterparty channel end is closed before the packet is successfully received, then the receiving -chain can no longer process it. Thus, the sending chain must process the timeout using -`OnTimeoutPacket` to handle this situation. Again the IBC module will verify that the timeout is -indeed valid, so our module only needs to implement the state machine logic for what to do once a -timeout is reached and the packet can no longer be received. - -```go -func (im IBCModule) OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, -) (*sdk.Result, error) { - // do custom timeout logic -} -``` diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/03-bindports.md b/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/03-bindports.md deleted file mode 100644 index a57ec4c6000..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/03-bindports.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -title: Bind ports -sidebar_label: Bind ports -sidebar_position: 3 -slug: /ibc/apps/bindports ---- - -# Bind ports - -:::note Synopsis -Learn what changes to make to bind modules to their ports on initialization. -::: - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: -Currently, ports must be bound on app initialization. In order to bind modules to their respective ports on initialization, the following needs to be implemented: - -> Note that `portID` does not refer to a certain numerical ID, like `localhost:8080` with a `portID` 8080. Rather it refers to the application module the port binds. For IBC Modules built with the Cosmos SDK, it defaults to the module's name and for Cosmwasm contracts it defaults to the contract address. - -1. Add port ID to the `GenesisState` proto definition: - - ```protobuf - message GenesisState { - string port_id = 1; - // other fields - } - ``` - -1. Add port ID as a key to the module store: - - ```go - // x//types/keys.go - const ( - // ModuleName defines the IBC Module name - ModuleName = "moduleName" - - // Version defines the current version the IBC - // module supports - Version = "moduleVersion-1" - - // PortID is the default port id that module binds to - PortID = "portID" - - // ... - ) - ``` - -1. Add port ID to `x//types/genesis.go`: - - ```go - // in x//types/genesis.go - - // DefaultGenesisState returns a GenesisState with "transfer" as the default PortID. - func DefaultGenesisState() *GenesisState { - return &GenesisState{ - PortId: PortID, - // additional k-v fields - } - } - - // Validate performs basic genesis state validation returning an error upon any - // failure. - func (gs GenesisState) Validate() error { - if err := host.PortIdentifierValidator(gs.PortId); err != nil { - return err - } - //addtional validations - - return gs.Params.Validate() - } - ``` - -1. Bind to port(s) in the module keeper's `InitGenesis`: - - ```go - // InitGenesis initializes the ibc-module state and binds to PortID. - func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) { - k.SetPort(ctx, state.PortId) - - // ... - - // Only try to bind to port if it is not already bound, since we may already own - // port capability from capability InitGenesis - if !k.IsBound(ctx, state.PortId) { - // transfer module binds to the transfer port on InitChain - // and claims the returned capability - err := k.BindPort(ctx, state.PortId) - if err != nil { - panic(fmt.Sprintf("could not claim port capability: %v", err)) - } - } - - // ... - } - ``` - - With: - - ```go - // IsBound checks if the module is already bound to the desired port - func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { - _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) - return ok - } - - // BindPort defines a wrapper function for the port Keeper's function in - // order to expose it to module's InitGenesis function - func (k Keeper) BindPort(ctx sdk.Context, portID string) error { - cap := k.portKeeper.BindPort(ctx, portID) - return k.ClaimCapability(ctx, cap, host.PortPath(portID)) - } - ``` - - The module binds to the desired port(s) and returns the capabilities. - - In the above we find reference to keeper methods that wrap other keeper functionality, in the next section the keeper methods that need to be implemented will be defined. diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/04-keeper.md b/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/04-keeper.md deleted file mode 100644 index e359e014f2c..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/04-keeper.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: Keeper -sidebar_label: Keeper -sidebar_position: 4 -slug: /ibc/apps/keeper ---- - -# Keeper - -:::note Synopsis -Learn how to implement the IBC Module keeper. -::: - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: -In the previous sections, on channel handshake callbacks and port binding in `InitGenesis`, a reference was made to keeper methods that need to be implemented when creating a custom IBC module. Below is an overview of how to define an IBC module's keeper. - -> Note that some code has been left out for clarity, to get a full code overview, please refer to [the transfer module's keeper in the ibc-go repo](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/keeper.go). - -```go -// Keeper defines the IBC app module keeper -type Keeper struct { - storeKey sdk.StoreKey - cdc codec.BinaryCodec - paramSpace paramtypes.Subspace - - channelKeeper types.ChannelKeeper - portKeeper types.PortKeeper - scopedKeeper capabilitykeeper.ScopedKeeper - - // ... additional according to custom logic -} - -// NewKeeper creates a new IBC app module Keeper instance -func NewKeeper( - // args -) Keeper { - // ... - - return Keeper{ - cdc: cdc, - storeKey: key, - paramSpace: paramSpace, - - channelKeeper: channelKeeper, - portKeeper: portKeeper, - scopedKeeper: scopedKeeper, - - // ... additional according to custom logic - } -} - -// IsBound checks if the IBC app module is already bound to the desired port -func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { - _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) - return ok -} - -// BindPort defines a wrapper function for the port Keeper's function in -// order to expose it to module's InitGenesis function -func (k Keeper) BindPort(ctx sdk.Context, portID string) error { - cap := k.portKeeper.BindPort(ctx, portID) - return k.ClaimCapability(ctx, cap, host.PortPath(portID)) -} - -// GetPort returns the portID for the IBC app module. Used in ExportGenesis -func (k Keeper) GetPort(ctx sdk.Context) string { - store := ctx.KVStore(k.storeKey) - return string(store.Get(types.PortKey)) -} - -// SetPort sets the portID for the IBC app module. Used in InitGenesis -func (k Keeper) SetPort(ctx sdk.Context, portID string) { - store := ctx.KVStore(k.storeKey) - store.Set(types.PortKey, []byte(portID)) -} - -// AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function -func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool { - return k.scopedKeeper.AuthenticateCapability(ctx, cap, name) -} - -// ClaimCapability allows the IBC app module to claim a capability that core IBC -// passes to it -func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { - return k.scopedKeeper.ClaimCapability(ctx, cap, name) -} - -// ... additional according to custom logic -``` diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/05-packets_acks.md b/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/05-packets_acks.md deleted file mode 100644 index 95bec486255..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/05-packets_acks.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -title: Define packets and acks -sidebar_label: Define packets and acks -sidebar_position: 5 -slug: /ibc/apps/packets_acks ---- - -# Define packets and acks - -:::note Synopsis -Learn how to define custom packet and acknowledgement structs and how to encode and decode them. -::: - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: - -## Custom packets - -Modules connected by a channel must agree on what application data they are sending over the -channel, as well as how they will encode/decode it. This process is not specified by IBC as it is up -to each application module to determine how to implement this agreement. However, for most -applications this will happen as a version negotiation during the channel handshake. While more -complex version negotiation is possible to implement inside the channel opening handshake, a very -simple version negotation is implemented in the [ibc-transfer module](https://github.com/cosmos/ibc-go/tree/main/modules/apps/transfer/module.go). - -Thus, a module must define its custom packet data structure, along with a well-defined way to -encode and decode it to and from `[]byte`. - -```go -// Custom packet data defined in application module -type CustomPacketData struct { - // Custom fields ... -} - -EncodePacketData(packetData CustomPacketData) []byte { - // encode packetData to bytes -} - -DecodePacketData(encoded []byte) (CustomPacketData) { - // decode from bytes to packet data -} -``` - -> Note that the `CustomPacketData` struct is defined in the proto definition and then compiled by the protobuf compiler. - -Then a module must encode its packet data before sending it through IBC. - -```go -// Sending custom application packet data -data := EncodePacketData(customPacketData) -packet.Data = data -IBCChannelKeeper.SendPacket(ctx, packet) -``` - -A module receiving a packet must decode the `PacketData` into a structure it expects so that it can -act on it. - -```go -// Receiving custom application packet data (in OnRecvPacket) -packetData := DecodePacketData(packet.Data) -// handle received custom packet data -``` - -## Acknowledgements - -Modules may commit an acknowledgement upon receiving and processing a packet in the case of synchronous packet processing. -In the case where a packet is processed at some later point after the packet has been received (asynchronous execution), the acknowledgement -will be written once the packet has been processed by the application which may be well after the packet receipt. - -NOTE: Most blockchain modules will want to use the synchronous execution model in which the module processes and writes the acknowledgement -for a packet as soon as it has been received from the IBC module. - -This acknowledgement can then be relayed back to the original sender chain, which can take action -depending on the contents of the acknowledgement. - -Just as packet data was opaque to IBC, acknowledgements are similarly opaque. Modules must pass and -receive acknowledegments with the IBC modules as byte strings. - -Thus, modules must agree on how to encode/decode acknowledgements. The process of creating an -acknowledgement struct along with encoding and decoding it, is very similar to the packet data -example above. [ICS 04](https://github.com/cosmos/ibc/blob/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope) -specifies a recommended format for acknowledgements. This acknowledgement type can be imported from -[channel types](https://github.com/cosmos/ibc-go/tree/main/modules/core/04-channel/types). - -While modules may choose arbitrary acknowledgement structs, a default acknowledgement types is provided by IBC [here](https://github.com/cosmos/ibc-go/blob/main/proto/ibc/core/channel/v1/channel.proto): - -```protobuf -// Acknowledgement is the recommended acknowledgement format to be used by -// app-specific protocols. -// NOTE: The field numbers 21 and 22 were explicitly chosen to avoid accidental -// conflicts with other protobuf message formats used for acknowledgements. -// The first byte of any message with this format will be the non-ASCII values -// `0xaa` (result) or `0xb2` (error). Implemented as defined by ICS: -// https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope -message Acknowledgement { - // response contains either a result or an error and must be non-empty - oneof response { - bytes result = 21; - string error = 22; - } -} -``` diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/06-routing.md b/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/06-routing.md deleted file mode 100644 index e11b3182e7f..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/06-routing.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Routing -sidebar_label: Routing -sidebar_position: 6 -slug: /ibc/apps/routing ---- - -# Routing - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: -:::note Synopsis -Learn how to hook a route to the IBC router for the custom IBC module. -::: - -As mentioned above, modules must implement the `IBCModule` interface (which contains both channel -handshake callbacks and packet handling callbacks). The concrete implementation of this interface -must be registered with the module name as a route on the IBC `Router`. - -```go -// app.go -func NewApp(...args) *App { -// ... - -// Create static IBC router, add module routes, then set and seal it -ibcRouter := port.NewRouter() - -ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule) -// Note: moduleCallbacks must implement IBCModule interface -ibcRouter.AddRoute(moduleName, moduleCallbacks) - -// Setting Router will finalize all routes by sealing router -// No more routes can be added -app.IBCKeeper.SetRouter(ibcRouter) - -// ... -} -``` diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/_category_.json b/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/_category_.json deleted file mode 100644 index 4561a95b84c..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Applications", - "position": 3, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/images/packet_flow.png b/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/images/packet_flow.png deleted file mode 100644 index db2d1d314b8..00000000000 Binary files a/docs/versioned_docs/version-v5.3.x/01-ibc/03-apps/images/packet_flow.png and /dev/null differ diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/04-middleware/01-develop.md b/docs/versioned_docs/version-v5.3.x/01-ibc/04-middleware/01-develop.md deleted file mode 100644 index 27304558b5f..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/04-middleware/01-develop.md +++ /dev/null @@ -1,422 +0,0 @@ ---- -title: IBC middleware -sidebar_label: IBC middleware -sidebar_position: 1 -slug: /ibc/middleware/develop ---- - -# IBC middleware - -:::note Synopsis -Learn how to write your own custom middleware to wrap an IBC application, and understand how to hook different middleware to IBC base applications to form different IBC application stacks -:::. - -This document serves as a guide for middleware developers who want to write their own middleware and for chain developers who want to use IBC middleware on their chains. - -IBC applications are designed to be self-contained modules that implement their own application-specific logic through a set of interfaces with the core IBC handlers. These core IBC handlers, in turn, are designed to enforce the correctness properties of IBC (transport, authentication, ordering) while delegating all application-specific handling to the IBC application modules. However, there are cases where some functionality may be desired by many applications, yet not appropriate to place in core IBC. - -Middleware allows developers to define the extensions as separate modules that can wrap over the base application. This middleware can thus perform its own custom logic, and pass data into the application so that it may run its logic without being aware of the middleware's existence. This allows both the application and the middleware to implement its own isolated logic while still being able to run as part of a single packet flow. - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC Integration](../02-integration.md) -- [IBC Application Developer Guide](../03-apps/01-apps.md) - -::: - -## Definitions - -`Middleware`: A self-contained module that sits between core IBC and an underlying IBC application during packet execution. All messages between core IBC and underlying application must flow through middleware, which may perform its own custom logic. - -`Underlying Application`: An underlying application is the application that is directly connected to the middleware in question. This underlying application may itself be middleware that is chained to a base application. - -`Base Application`: A base application is an IBC application that does not contain any middleware. It may be nested by 0 or multiple middleware to form an application stack. - -`Application Stack (or stack)`: A stack is the complete set of application logic (middleware(s) + base application) that gets connected to core IBC. A stack may be just a base application, or it may be a series of middlewares that nest a base application. - -## Create a custom IBC middleware - -IBC middleware will wrap over an underlying IBC application and sits between core IBC and the application. It has complete control in modifying any message coming from IBC to the application, and any message coming from the application to core IBC. Thus, middleware must be completely trusted by chain developers who wish to integrate them, however this gives them complete flexibility in modifying the application(s) they wrap. - -### Interfaces - -```go -// Middleware implements the ICS26 Module interface -type Middleware interface { - porttypes.IBCModule // middleware has acccess to an underlying application which may be wrapped by more middleware - ics4Wrapper: ICS4Wrapper // middleware has access to ICS4Wrapper which may be core IBC Channel Handler or a higher-level middleware that wraps this middleware. -} -``` - -```typescript -// This is implemented by ICS4 and all middleware that are wrapping base application. -// The base application will call `sendPacket` or `writeAcknowledgement` of the middleware directly above them -// which will call the next middleware until it reaches the core IBC handler. -type ICS4Wrapper interface { - SendPacket(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet exported.Packet) error - WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet exported.Packet, ack exported.Acknowledgement) error - GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) -} -``` - -### Implement `IBCModule` interface and callbacks - -The `IBCModule` is a struct that implements the [ICS-26 interface (`porttypes.IBCModule`)](https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port/types/module.go#L11-L106). It is recommended to separate these callbacks into a separate file `ibc_module.go`. As will be mentioned in the [integration section](02-integration.md), this struct should be different than the struct that implements `AppModule` in case the middleware maintains its own internal state and processes separate SDK messages. - -The middleware must have access to the underlying application, and be called before during all ICS-26 callbacks. It may execute custom logic during these callbacks, and then call the underlying application's callback. Middleware **may** choose not to call the underlying application's callback at all. Though these should generally be limited to error cases. - -In the case where the IBC middleware expects to speak to a compatible IBC middleware on the counterparty chain, they must use the channel handshake to negotiate the middleware version without interfering in the version negotiation of the underlying application. - -Middleware accomplishes this by formatting the version in a JSON-encoded string containing the middleware version and the application version. The application version may as well be a JSON-encoded string, possibly including further middleware and app versions, if the application stack consists of multiple milddlewares wrapping a base application. The format of the version is specified in ICS-30 as the following: - -```json -{ - "": "", - "app_version": "" -} -``` - -The `` key in the JSON struct should be replaced by the actual name of the key for the corresponding middleware (e.g. `fee_version`). - -During the handshake callbacks, the middleware can unmarshal the version string and retrieve the middleware and application versions. It can do its negotiation logic on ``, and pass the `` to the underlying application. - -The middleware should simply pass the capability in the callback arguments along to the underlying application so that it may be claimed by the base application. The base application will then pass the capability up the stack in order to authenticate an outgoing packet/acknowledgement. - -In the case where the middleware wishes to send a packet or acknowledgment without the involvement of the underlying application, it should be given access to the same `scopedKeeper` as the base application so that it can retrieve the capabilities by itself. - -### Handshake callbacks - -#### `OnChanOpenInit` - -```go -func (im IBCModule) OnChanOpenInit( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) (string, error) { - if version != "" { - // try to unmarshal JSON-encoded version string and pass - // the app-specific version to app callback. - // otherwise, pass version directly to app callback. - metadata, err := Unmarshal(version) - if err != nil { - // Since it is valid for fee version to not be specified, - // the above middleware version may be for another middleware. - // Pass the entire version string onto the underlying application. - return im.app.OnChanOpenInit( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - version, - ) - } - else { - metadata = { - // set middleware version to default value - MiddlewareVersion: defaultMiddlewareVersion, - // allow application to return its default version - AppVersion: "", - } - } - - doCustomLogic() - - // if the version string is empty, OnChanOpenInit is expected to return - // a default version string representing the version(s) it supports - appVersion, err := im.app.OnChanOpenInit( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - metadata.AppVersion, // note we only pass app version here - ) - if err != nil { - return "", err - } - - version := constructVersion(metadata.MiddlewareVersion, appVersion) - - return version, nil -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L34-L82) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnChanOpenTry` - -```go -func OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (string, error) { - // try to unmarshal JSON-encoded version string and pass - // the app-specific version to app callback. - // otherwise, pass version directly to app callback. - cpMetadata, err := Unmarshal(counterpartyVersion) - if err != nil { - return app.OnChanOpenTry( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - counterpartyVersion, - ) - } - - doCustomLogic() - - // Call the underlying application's OnChanOpenTry callback. - // The try callback must select the final app-specific version string and return it. - appVersion, err := app.OnChanOpenTry( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - cpMetadata.AppVersion, // note we only pass counterparty app version here - ) - if err != nil { - return "", err - } - - // negotiate final middleware version - middlewareVersion := negotiateMiddlewareVersion(cpMetadata.MiddlewareVersion) - version := constructVersion(middlewareVersion, appVersion) - - return version, nil -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L84-L124) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnChanOpenAck` - -```go -func OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyChannelID string, - counterpartyVersion string, -) error { - // try to unmarshal JSON-encoded version string and pass - // the app-specific version to app callback. - // otherwise, pass version directly to app callback. - cpMetadata, err = UnmarshalJSON(counterpartyVersion) - if err != nil { - return app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) - } - - if !isCompatible(cpMetadata.MiddlewareVersion) { - return error - } - doCustomLogic() - - // call the underlying application's OnChanOpenTry callback - return app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, cpMetadata.AppVersion) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L126-L152) an example implementation of this callback for the ICS29 Fee Middleware module. - -### `OnChanOpenConfirm` - -```go -func OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - doCustomLogic() - - return app.OnChanOpenConfirm(ctx, portID, channelID) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L154-L162) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnChanCloseInit` - -```go -func OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - doCustomLogic() - - return app.OnChanCloseInit(ctx, portID, channelID) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L164-L187) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnChanCloseConfirm` - -```go -func OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - doCustomLogic() - - return app.OnChanCloseConfirm(ctx, portID, channelID) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L189-L212) an example implementation of this callback for the ICS29 Fee Middleware module. - -**NOTE**: Middleware that does not need to negotiate with a counterparty middleware on the remote stack will not implement the version unmarshalling and negotiation, and will simply perform its own custom logic on the callbacks without relying on the counterparty behaving similarly. - -### Packet callbacks - -The packet callbacks just like the handshake callbacks wrap the application's packet callbacks. The packet callbacks are where the middleware performs most of its custom logic. The middleware may read the packet flow data and perform some additional packet handling, or it may modify the incoming data before it reaches the underlying application. This enables a wide degree of usecases, as a simple base application like token-transfer can be transformed for a variety of usecases by combining it with custom middleware. - -#### `OnRecvPacket` - -```go -func OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) ibcexported.Acknowledgement { - doCustomLogic(packet) - - ack := app.OnRecvPacket(ctx, packet, relayer) - - doCustomLogic(ack) // middleware may modify outgoing ack - return ack -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L214-L237) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnAcknowledgementPacket` - -```go -func OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - relayer sdk.AccAddress, -) error { - doCustomLogic(packet, ack) - - return app.OnAcknowledgementPacket(ctx, packet, ack, relayer) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L239-L292) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnTimeoutPacket` - -```go -func OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) error { - doCustomLogic(packet) - - return app.OnTimeoutPacket(ctx, packet, relayer) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L294-L334) an example implementation of this callback for the ICS29 Fee Middleware module. - -### ICS-4 wrappers - -Middleware must also wrap ICS-4 so that any communication from the application to the `channelKeeper` goes through the middleware first. Similar to the packet callbacks, the middleware may modify outgoing acknowledgements and packets in any way it wishes. - -#### `SendPacket` - -```go -func SendPacket( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - appPacket exported.PacketI, -) { - // middleware may modify packet - packet = doCustomLogic(appPacket) - - return ics4Keeper.SendPacket(ctx, chanCap, packet) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L336-L343) an example implementation of this function for the ICS29 Fee Middleware module. - -#### `WriteAcknowledgement` - -```go -// only called for async acks -func WriteAcknowledgement( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - packet exported.PacketI, - ack exported.Acknowledgement, -) { - // middleware may modify acknowledgement - ack_bytes = doCustomLogic(ack) - - return ics4Keeper.WriteAcknowledgement(packet, ack_bytes) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L345-L353) an example implementation of this function for the ICS29 Fee Middleware module. - -#### `GetAppVersion` - -```go -// middleware must return the underlying application version -func GetAppVersion( - ctx sdk.Context, - portID, - channelID string, -) (string, bool) { - version, found := ics4Keeper.GetAppVersion(ctx, portID, channelID) - if !found { - return "", false - } - - if !MiddlewareEnabled { - return version, true - } - - // unwrap channel version - metadata, err := Unmarshal(version) - if err != nil { - panic(fmt.Errof("unable to unmarshal version: %w", err)) - } - - return metadata.AppVersion, true -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L355-L358) an example implementation of this function for the ICS29 Fee Middleware module. diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/04-middleware/02-integration.md b/docs/versioned_docs/version-v5.3.x/01-ibc/04-middleware/02-integration.md deleted file mode 100644 index 7bda98b5f88..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/04-middleware/02-integration.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: Integrating IBC middleware into a chain -sidebar_label: Integrating IBC middleware into a chain -sidebar_position: 2 -slug: /ibc/middleware/integration ---- - - -# Integrating IBC middleware into a chain - -Learn how to integrate IBC middleware(s) with a base application to your chain. The following document only applies for Cosmos SDK chains. - -If the middleware is maintaining its own state and/or processing SDK messages, then it should create and register its SDK module **only once** with the module manager in `app.go`. - -All middleware must be connected to the IBC router and wrap over an underlying base IBC application. An IBC application may be wrapped by many layers of middleware, only the top layer middleware should be hooked to the IBC router, with all underlying middlewares and application getting wrapped by it. - -The order of middleware **matters**, function calls from IBC to the application travel from top-level middleware to the bottom middleware and then to the application. Function calls from the application to IBC goes through the bottom middleware in order to the top middleware and then to core IBC handlers. Thus the same set of middleware put in different orders may produce different effects. - -## Example integration - -```go -// app.go - -// middleware 1 and middleware 3 are stateful middleware, -// perhaps implementing separate sdk.Msg and Handlers -mw1Keeper := mw1.NewKeeper(storeKey1) -mw3Keeper := mw3.NewKeeper(storeKey3) - -// Only create App Module **once** and register in app module -// if the module maintains independent state and/or processes sdk.Msgs -app.moduleManager = module.NewManager( - ... - mw1.NewAppModule(mw1Keeper), - mw3.NewAppModule(mw3Keeper), - transfer.NewAppModule(transferKeeper), - custom.NewAppModule(customKeeper) -) - -mw1IBCModule := mw1.NewIBCModule(mw1Keeper) -mw2IBCModule := mw2.NewIBCModule() // middleware2 is stateless middleware -mw3IBCModule := mw3.NewIBCModule(mw3Keeper) - -scopedKeeperTransfer := capabilityKeeper.NewScopedKeeper("transfer") -scopedKeeperCustom1 := capabilityKeeper.NewScopedKeeper("custom1") -scopedKeeperCustom2 := capabilityKeeper.NewScopedKeeper("custom2") - -// NOTE: IBC Modules may be initialized any number of times provided they use a separate -// scopedKeeper and underlying port. - -// initialize base IBC applications -// if you want to create two different stacks with the same base application, -// they must be given different scopedKeepers and assigned different ports. -transferIBCModule := transfer.NewIBCModule(transferKeeper) -customIBCModule1 := custom.NewIBCModule(customKeeper, "portCustom1") -customIBCModule2 := custom.NewIBCModule(customKeeper, "portCustom2") - -// create IBC stacks by combining middleware with base application -// NOTE: since middleware2 is stateless it does not require a Keeper -// stack 1 contains mw1 -> mw3 -> transfer -stack1 := mw1.NewIBCMiddleware(mw3.NewIBCMiddleware(transferIBCModule, mw3Keeper), mw1Keeper) -// stack 2 contains mw3 -> mw2 -> custom1 -stack2 := mw3.NewIBCMiddleware(mw2.NewIBCMiddleware(customIBCModule1), mw3Keeper) -// stack 3 contains mw2 -> mw1 -> custom2 -stack3 := mw2.NewIBCMiddleware(mw1.NewIBCMiddleware(customIBCModule2, mw1Keeper)) - -// associate each stack with the moduleName provided by the underlying scopedKeeper -ibcRouter := porttypes.NewRouter() -ibcRouter.AddRoute("transfer", stack1) -ibcRouter.AddRoute("custom1", stack2) -ibcRouter.AddRoute("custom2", stack3) -app.IBCKeeper.SetRouter(ibcRouter) -``` diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/04-middleware/_category_.json b/docs/versioned_docs/version-v5.3.x/01-ibc/04-middleware/_category_.json deleted file mode 100644 index 6596fe16c13..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/04-middleware/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Middleware", - "position": 4, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/05-upgrades/00-intro.md b/docs/versioned_docs/version-v5.3.x/01-ibc/05-upgrades/00-intro.md deleted file mode 100644 index 14c82d3ff0d..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/05-upgrades/00-intro.md +++ /dev/null @@ -1,8 +0,0 @@ -### Upgrading IBC Chains Overview - -This directory contains information on how to upgrade an IBC chain without breaking counterparty clients and connections. - -IBC-connnected chains must be able to upgrade without breaking connections to other chains. Otherwise there would be a massive disincentive towards upgrading and disrupting high-value IBC connections, thus preventing chains in the IBC ecosystem from evolving and improving. Many chain upgrades may be irrelevant to IBC, however some upgrades could potentially break counterparty clients if not handled correctly. Thus, any IBC chain that wishes to perform a IBC-client-breaking upgrade must perform an IBC upgrade in order to allow counterparty clients to securely upgrade to the new light client. - -1. The [quick-guide](./01-quick-guide.md) describes how IBC-connected chains can perform client-breaking upgrades and how relayers can securely upgrade counterparty clients using the SDK. -2. The [developer-guide](./02-developer-guide.md) is a guide for developers intending to develop IBC client implementations with upgrade functionality. diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/05-upgrades/01-quick-guide.md b/docs/versioned_docs/version-v5.3.x/01-ibc/05-upgrades/01-quick-guide.md deleted file mode 100644 index 75931c2b2aa..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/05-upgrades/01-quick-guide.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: How to Upgrade IBC Chains and their Clients -sidebar_label: How to Upgrade IBC Chains and their Clients -sidebar_position: 1 -slug: /ibc/upgrades/quick-guide ---- - - -# How to Upgrade IBC Chains and their Clients - -:::note Synopsis -Learn how to upgrade your chain and counterparty clients. -::: - -The information in this doc for upgrading chains is relevant to SDK chains. However, the guide for counterparty clients is relevant to any Tendermint client that enables upgrades. - -## IBC Client Breaking Upgrades - -IBC-connected chains must perform an IBC upgrade if their upgrade will break counterparty IBC clients. The current IBC protocol supports upgrading tendermint chains for a specific subset of IBC-client-breaking upgrades. Here is the exhaustive list of IBC client-breaking upgrades and whether the IBC protocol currently supports such upgrades. - -IBC currently does **NOT** support unplanned upgrades. All of the following upgrades must be planned and committed to in advance by the upgrading chain, in order for counterparty clients to maintain their connections securely. - -Note: Since upgrades are only implemented for Tendermint clients, this doc only discusses upgrades on Tendermint chains that would break counterparty IBC Tendermint Clients. - -1. Changing the Chain-ID: **Supported** -2. Changing the UnbondingPeriod: **Partially Supported**, chains may increase the unbonding period with no issues. However, decreasing the unbonding period may irreversibly break some counterparty clients. Thus, it is **not recommended** that chains reduce the unbonding period. -3. Changing the height (resetting to 0): **Supported**, so long as chains remember to increment the revision number in their chain-id. -4. Changing the ProofSpecs: **Supported**, this should be changed if the proof structure needed to verify IBC proofs is changed across the upgrade. Ex: Switching from an IAVL store, to a SimpleTree Store -5. Changing the UpgradePath: **Supported**, this might involve changing the key under which upgraded clients and consensus states are stored in the upgrade store, or even migrating the upgrade store itself. -6. Migrating the IBC store: **Unsupported**, as the IBC store location is negotiated by the connection. -7. Upgrading to a backwards compatible version of IBC: Supported -8. Upgrading to a non-backwards compatible version of IBC: **Unsupported**, as IBC version is negotiated on connection handshake. -9. Changing the Tendermint LightClient algorithm: **Partially Supported**. Changes to the light client algorithm that do not change the ClientState or ConsensusState struct may be supported, provided that the counterparty is also upgraded to support the new light client algorithm. Changes that require updating the ClientState and ConsensusState structs themselves are theoretically possible by providing a path to translate an older ClientState struct into the new ClientState struct; however this is not currently implemented. - -### Step-by-Step Upgrade Process for SDK chains - -If the IBC-connected chain is conducting an upgrade that will break counterparty clients, it must ensure that the upgrade is first supported by IBC using the list above and then execute the upgrade process described below in order to prevent counterparty clients from breaking. - -1. Create a 02-client [`UpgradeProposal`](https://github.com/cosmos/ibc-go/blob/v5.3.1/proto/ibc/core/client/v1/client.proto#L58-L77) with an `UpgradePlan` and a new IBC ClientState in the `UpgradedClientState` field. Note that the `UpgradePlan` must specify an upgrade height **only** (no upgrade time), and the `ClientState` should only include the fields common to all valid clients and zero out any client-customizable fields (such as TrustingPeriod). -2. Vote on and pass the `UpgradeProposal` - -Upon the `UpgradeProposal` passing, the upgrade module will commit the UpgradedClient under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedClient`. On the block right before the upgrade height, the upgrade module will also commit an initial consensus state for the next chain under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedConsState`. - -Once the chain reaches the upgrade height and halts, a relayer can upgrade the counterparty clients to the last block of the old chain. They can then submit the proofs of the `UpgradedClient` and `UpgradedConsensusState` against this last block and upgrade the counterparty client. - -### Step-by-Step Upgrade Process for Relayers Upgrading Counterparty Clients - -Once the upgrading chain has committed to upgrading, relayers must wait till the chain halts at the upgrade height before upgrading counterparty clients. This is because chains may reschedule or cancel upgrade plans before they occur. Thus, relayers must wait till the chain reaches the upgrade height and halts before they can be sure the upgrade will take place. - -Thus, the upgrade process for relayers trying to upgrade the counterparty clients is as follows: - -1. Wait for the upgrading chain to reach the upgrade height and halt -2. Query a full node for the proofs of `UpgradedClient` and `UpgradedConsensusState` at the last height of the old chain. -3. Update the counterparty client to the last height of the old chain using the `UpdateClient` msg. -4. Submit an `UpgradeClient` msg to the counterparty chain with the `UpgradedClient`, `UpgradedConsensusState` and their respective proofs. -5. Submit an `UpdateClient` msg to the counterparty chain with a header from the new upgraded chain. - -The Tendermint client on the counterparty chain will verify that the upgrading chain did indeed commit to the upgraded client and upgraded consensus state at the upgrade height (since the upgrade height is included in the key). If the proofs are verified against the upgrade height, then the client will upgrade to the new client while retaining all of its client-customized fields. Thus, it will retain its old TrustingPeriod, TrustLevel, MaxClockDrift, etc; while adopting the new chain-specified fields such as UnbondingPeriod, ChainId, UpgradePath, etc. Note, this can lead to an invalid client since the old client-chosen fields may no longer be valid given the new chain-chosen fields. Upgrading chains should try to avoid these situations by not altering parameters that can break old clients. For an example, see the UnbondingPeriod example in the supported upgrades section. - -The upgraded consensus state will serve purely as a basis of trust for future `UpdateClientMsgs` and will not contain a consensus root to perform proof verification against. Thus, relayers must submit an `UpdateClientMsg` with a header from the new chain so that the connection can be used for proof verification again. diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/05-upgrades/02-developer-guide.md b/docs/versioned_docs/version-v5.3.x/01-ibc/05-upgrades/02-developer-guide.md deleted file mode 100644 index 0321bdbe594..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/05-upgrades/02-developer-guide.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: IBC Client Developer Guide to Upgrades -sidebar_label: IBC Client Developer Guide to Upgrades -sidebar_position: 2 -slug: /ibc/upgrades/developer-guide ---- - - -# IBC Client Developer Guide to Upgrades - -:::note Synopsis -Learn how to implement upgrade functionality for your custom IBC client. -::: - -As mentioned in the [README](./00-intro.md), it is vital that high-value IBC clients can upgrade along with their underlying chains to avoid disruption to the IBC ecosystem. Thus, IBC client developers will want to implement upgrade functionality to enable clients to maintain connections and channels even across chain upgrades. - -The IBC protocol allows client implementations to provide a path to upgrading clients given the upgraded client state, upgraded consensus state and proofs for each. - -```go -// Upgrade functions -// NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last -// height committed by the current revision. Clients are responsible for ensuring that the planned last -// height of the current revision is somehow encoded in the proof verification process. -// This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty -// may be cancelled or modified before the last planned height. -VerifyUpgradeAndUpdateState( - ctx sdk.Context, - cdc codec.BinaryCodec, - store sdk.KVStore, - newClient ClientState, - newConsState ConsensusState, - proofUpgradeClient, - proofUpgradeConsState []byte, -) (upgradedClient ClientState, upgradedConsensus ConsensusState, err error) -``` - -Note that the clients should have prior knowledge of the merkle path that the upgraded client and upgraded consensus states will use. The height at which the upgrade has occurred should also be encoded in the proof. The Tendermint client implementation accomplishes this by including an `UpgradePath` in the ClientState itself, which is used along with the upgrade height to construct the merkle path under which the client state and consensus state are committed. - -Developers must ensure that the `UpgradeClientMsg` does not pass until the last height of the old chain has been committed, and after the chain upgrades, the `UpgradeClientMsg` should pass once and only once on all counterparty clients. - -Developers must ensure that the new client adopts all of the new Client parameters that must be uniform across every valid light client of a chain (chain-chosen parameters), while maintaining the Client parameters that are customizable by each individual client (client-chosen parameters) from the previous version of the client. - -Upgrades must adhere to the IBC Security Model. IBC does not rely on the assumption of honest relayers for correctness. Thus users should not have to rely on relayers to maintain client correctness and security (though honest relayers must exist to maintain relayer liveness). While relayers may choose any set of client parameters while creating a new `ClientState`, this still holds under the security model since users can always choose a relayer-created client that suits their security and correctness needs or create a Client with their desired parameters if no such client exists. - -However, when upgrading an existing client, one must keep in mind that there are already many users who depend on this client's particular parameters. We cannot give the upgrading relayer free choice over these parameters once they have already been chosen. This would violate the security model since users who rely on the client would have to rely on the upgrading relayer to maintain the same level of security. Thus, developers must make sure that their upgrade mechanism allows clients to upgrade the chain-specified parameters whenever a chain upgrade changes these parameters (examples in the Tendermint client include `UnbondingPeriod`, `TrustingPeriod`, `ChainID`, `UpgradePath`, etc.), while ensuring that the relayer submitting the `UpgradeClientMsg` cannot alter the client-chosen parameters that the users are relying upon (examples in Tendermint client include `TrustLevel`, `MaxClockDrift`, etc). - -Developers should maintain the distinction between Client parameters that are uniform across every valid light client of a chain (chain-chosen parameters), and Client parameters that are customizable by each individual client (client-chosen parameters); since this distinction is necessary to implement the `ZeroCustomFields` method in the `ClientState` interface: - -```go -// Utility function that zeroes out any client customizable fields in client state -// Ledger enforced fields are maintained while all custom fields are zero values -// Used to verify upgrades -ZeroCustomFields() ClientState -``` - -Counterparty clients can upgrade securely by using all of the chain-chosen parameters from the chain-committed `UpgradedClient` and preserving all of the old client-chosen parameters. This enables chains to securely upgrade without relying on an honest relayer, however it can in some cases lead to an invalid final `ClientState` if the new chain-chosen parameters clash with the old client-chosen parameter. This can happen in the Tendermint client case if the upgrading chain lowers the `UnbondingPeriod` (chain-chosen) to a duration below that of a counterparty client's `TrustingPeriod` (client-chosen). Such cases should be clearly documented by developers, so that chains know which upgrades should be avoided to prevent this problem. The final upgraded client should also be validated in `VerifyUpgradeAndUpdateState` before returning to ensure that the client does not upgrade to an invalid `ClientState`. diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/05-upgrades/03-genesis-restart.md b/docs/versioned_docs/version-v5.3.x/01-ibc/05-upgrades/03-genesis-restart.md deleted file mode 100644 index e2465fb0d9a..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/05-upgrades/03-genesis-restart.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: Genesis Restart Upgrades -sidebar_label: Genesis Restart Upgrades -sidebar_position: 3 -slug: /ibc/upgrades/genesis-restart ---- - - -# Genesis Restart Upgrades - -:::note Synopsis -Learn how to upgrade your chain and counterparty clients using genesis restarts. -::: - -**NOTE**: Regular genesis restarts are currently unsupported by relayers! - -## IBC Client Breaking Upgrades - -IBC client breaking upgrades are possible using genesis restarts. -It is highly recommended to use the in-place migrations instead of a genesis restart. -Genesis restarts should be used sparingly and as backup plans. - -Genesis restarts still require the usage of an IBC upgrade proposal in order to correctly upgrade counterparty clients. - -### Step-by-Step Upgrade Process for SDK Chains - -If the IBC-connected chain is conducting an upgrade that will break counterparty clients, it must ensure that the upgrade is first supported by IBC using the [IBC Client Breaking Upgrade List](./01-quick-guide.md#ibc-client-breaking-upgrades) and then execute the upgrade process described below in order to prevent counterparty clients from breaking. - -1. Create a 02-client [`UpgradeProposal`](https://github.com/cosmos/ibc-go/blob/v5.3.1/proto/ibc/core/client/v1/client.proto#L58-L77) with an `UpgradePlan` and a new IBC ClientState in the `UpgradedClientState` field. Note that the `UpgradePlan` must specify an upgrade height **only** (no upgrade time), and the `ClientState` should only include the fields common to all valid clients and zero out any client-customizable fields (such as TrustingPeriod). -2. Vote on and pass the `UpgradeProposal` -3. Halt the node after successful upgrade. -4. Export the genesis file. -5. Swap to the new binary. -6. Run migrations on the genesis file. -7. Remove the `UpgradeProposal` plan from the genesis file. This may be done by migrations. -8. Change desired chain-specific fields (chain id, unbonding period, etc). This may be done by migrations. -8. Reset the node's data. -9. Start the chain. - -Upon the `UpgradeProposal` passing, the upgrade module will commit the UpgradedClient under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedClient`. On the block right before the upgrade height, the upgrade module will also commit an initial consensus state for the next chain under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedConsState`. - -Once the chain reaches the upgrade height and halts, a relayer can upgrade the counterparty clients to the last block of the old chain. They can then submit the proofs of the `UpgradedClient` and `UpgradedConsensusState` against this last block and upgrade the counterparty client. - -#### Step-by-Step Upgrade Process for Relayers Upgrading Counterparty Clients - -These steps are identical to the regular [IBC client breaking upgrade process](./01-quick-guide.md#step-by-step-upgrade-process-for-relayers-upgrading-counterparty-clients). - -### Non-IBC Client Breaking Upgrades - -While ibc-go supports genesis restarts which do not break IBC clients, relayers do not support this upgrade path. -Here is a tracking issue on [Hermes](https://github.com/informalsystems/ibc-rs/issues/1152). -Please do not attempt a regular genesis restarts unless you have a tool to update counterparty clients correctly. diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/05-upgrades/_category_.json b/docs/versioned_docs/version-v5.3.x/01-ibc/05-upgrades/_category_.json deleted file mode 100644 index 7c3191d2ce9..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/05-upgrades/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Upgrades", - "position": 5, - "link": { "type": "doc", "id": "intro" } -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/06-proposals.md b/docs/versioned_docs/version-v5.3.x/01-ibc/06-proposals.md deleted file mode 100644 index 39c0491a6aa..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/06-proposals.md +++ /dev/null @@ -1,130 +0,0 @@ ---- -title: Governance Proposals -sidebar_label: Governance Proposals -sidebar_position: 6 -slug: /ibc/proposals ---- - -# Governance Proposals - -In uncommon situations, a highly valued client may become frozen due to uncontrollable -circumstances. A highly valued client might have hundreds of channels being actively used. -Some of those channels might have a significant amount of locked tokens used for ICS 20. - -If the one third of the validator set of the chain the client represents decides to collude, -they can sign off on two valid but conflicting headers each signed by the other one third -of the honest validator set. The light client can now be updated with two valid, but conflicting -headers at the same height. The light client cannot know which header is trustworthy and therefore -evidence of such misbehaviour is likely to be submitted resulting in a frozen light client. - -Frozen light clients cannot be updated under any circumstance except via a governance proposal. -Since a quorum of validators can sign arbitrary state roots which may not be valid executions -of the state machine, a governance proposal has been added to ease the complexity of unfreezing -or updating clients which have become "stuck". Without this mechanism, validator sets would need -to construct a state root to unfreeze the client. Unfreezing clients, re-enables all of the channels -built upon that client. This may result in recovery of otherwise lost funds. - -Tendermint light clients may become expired if the trusting period has passed since their -last update. This may occur if relayers stop submitting headers to update the clients. - -An unplanned upgrade by the counterparty chain may also result in expired clients. If the counterparty -chain undergoes an unplanned upgrade, there may be no commitment to that upgrade signed by the validator -set before the chain-id changes. In this situation, the validator set of the last valid update for the -light client is never expected to produce another valid header since the chain-id has changed, which will -ultimately lead the on-chain light client to become expired. - -In the case that a highly valued light client is frozen, expired, or rendered non-updateable, a -governance proposal may be submitted to update this client, known as the subject client. The -proposal includes the client identifier for the subject and the client identifier for a substitute -client. Light client implementations may implement custom updating logic, but in most cases, -the subject will be updated to the latest consensus state of the substitute client, if the proposal passes. -The substitute client is used as a "stand in" while the subject is on trial. It is best practice to create -a substitute client *after* the subject has become frozen to avoid the substitute from also becoming frozen. -An active substitute client allows headers to be submitted during the voting period to prevent accidental expiry -once the proposal passes. - -## How to recover an expired client with a governance proposal - -See also the relevant documentation: [ADR-026, IBC client recovery mechanisms](/architecture/adr-026-ibc-client-recovery-mechanisms) - -> **Who is this information for?** -> Although technically anyone can submit the governance proposal to recover an expired client, often it will be **relayer operators** (at least coordinating the submission). - -### Preconditions - -- The chain is updated with ibc-go >= v1.1.0. -- There exists an active client (with a known client identifier) for the same counterparty chain as the expired client. -- The governance deposit. - -## Steps - -### Step 1 - -Check if the client is attached to the expected `chain-id`. For example, for an expired Tendermint client representing the Akash chain the client state looks like this on querying the client state: - -```text -{ - client_id: 07-tendermint-146 - client_state: - '@type': /ibc.lightclients.tendermint.v1.ClientState - allow_update_after_expiry: true - allow_update_after_misbehaviour: true - chain_id: akashnet-2 -} -``` - -The client is attached to the expected Akash `chain-id`. Note that although the parameters (`allow_update_after_expiry` and `allow_update_after_misbehaviour`) exist to signal intent, these parameters have been deprecated and will not enforce any checks on the revival of client. See ADR-026 for more context on this deprecation. - -### Step 2 - -If the chain has been updated to ibc-go >= v1.1.0, anyone can submit the governance proposal to recover the client by executing this via CLI. - -> Note that the Cosmos SDK has updated how governance proposals are submitted in SDK v0.46, now requiring to pass a .json proposal file - -- From SDK v0.46.x onwards - - ```bash - tx gov submit-proposal [path-to-proposal-json] - ``` - - where `proposal.json` contains: - - ```json - { - "messages": [ - { - "@type": "/ibc.core.client.v1.ClientUpdateProposal", - "title": "title_string", - "description": "description_string", - "subject_client_id": "expired_client_id_string", - "substitute_client_id": "active_client_id_string" - } - ], - "metadata": "", - "deposit": "10stake" - } - ``` - - Alternatively there's a legacy command (that is no longer recommended though): - - ```bash - tx gov submit-legacy-proposal update-client - ``` - -- Until SDK v0.45.x - - ```bash - tx gov submit-proposal update-client - ``` - -The `` identifier is the proposed client to be updated. This client must be either frozen or expired. - -The `` represents a substitute client. It carries all the state for the client which may be updated. It must have identical client and chain parameters to the client which may be updated (except for latest height, frozen height, and chain ID). It should be continually updated during the voting period. - -After this, all that remains is deciding who funds the governance deposit and ensuring the governance proposal passes. If it does, the client on trial will be updated to the latest state of the substitute. - -## Important considerations - -Please note that from v1.0.0 of ibc-go it will not be allowed for transactions to go to expired clients anymore, so please update to at least this version to prevent similar issues in the future. - -Please also note that if the client on the other end of the transaction is also expired, that client will also need to update. This process updates only one client. diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/07-relayer.md b/docs/versioned_docs/version-v5.3.x/01-ibc/07-relayer.md deleted file mode 100644 index f40e9e671a3..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/07-relayer.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: Relayer -sidebar_label: Relayer -sidebar_position: 7 -slug: /ibc/relayer ---- - -# Relayer - -:::note - -## Pre-requisite readings - -- [IBC Overview](01-overview.md) -- [Events](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/advanced/08-events.md) - -::: - -## Events - -Events are emitted for every transaction processed by the base application to indicate the execution -of some logic clients may want to be aware of. This is extremely useful when relaying IBC packets. -Any message that uses IBC will emit events for the corresponding TAO logic executed as defined in -the [IBC events document](/events/events). - -In the SDK, it can be assumed that for every message there is an event emitted with the type `message`, -attribute key `action`, and an attribute value representing the type of message sent -(`channel_open_init` would be the attribute value for `MsgChannelOpenInit`). If a relayer queries -for transaction events, it can split message events using this event Type/Attribute Key pair. - -The Event Type `message` with the Attribute Key `module` may be emitted multiple times for a single -message due to application callbacks. It can be assumed that any TAO logic executed will result in -a module event emission with the attribute value `ibc_` (02-client emits `ibc_client`). - -### Subscribing with Tendermint - -Calling the Tendermint RPC method `Subscribe` via [Tendermint's Websocket](https://docs.tendermint.com/main/rpc/) will return events using -Tendermint's internal representation of them. Instead of receiving back a list of events as they -were emitted, Tendermint will return the type `map[string][]string` which maps a string in the -form `.` to `attribute_value`. This causes extraction of the event -ordering to be non-trivial, but still possible. - -A relayer should use the `message.action` key to extract the number of messages in the transaction -and the type of IBC transactions sent. For every IBC transaction within the string array for -`message.action`, the necessary information should be extracted from the other event fields. If -`send_packet` appears at index 2 in the value for `message.action`, a relayer will need to use the -value at index 2 of the key `send_packet.packet_sequence`. This process should be repeated for each -piece of information needed to relay a packet. - -## Example Implementations - -- [Golang Relayer](https://github.com/cosmos/relayer) -- [Hermes](https://github.com/informalsystems/ibc-rs/tree/master/crates/relayer) diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/08-proto-docs.md b/docs/versioned_docs/version-v5.3.x/01-ibc/08-proto-docs.md deleted file mode 100644 index 226bd93d743..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/08-proto-docs.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: Protobuf Documentation -sidebar_label: Protobuf Documentation -sidebar_position: 8 -slug: /ibc/proto-docs ---- - -# Protobuf documentation - -See [ibc-go v5.3.x Buf Protobuf documentation](https://github.com/cosmos/ibc-go/blob/release/v5.3.x/docs/ibc/proto-docs.md). diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/09-roadmap.md b/docs/versioned_docs/version-v5.3.x/01-ibc/09-roadmap.md deleted file mode 100644 index cf7f7e6fafe..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/09-roadmap.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: Roadmap -sidebar_label: Roadmap -sidebar_position: 9 -slug: /roadmap/roadmap ---- - -# Roadmap ibc-go - -*Lastest update: July 7, 2022* - -This document endeavours to inform the wider IBC community about plans and priorities for work on ibc-go by the team at Interchain GmbH. It is intended to broadly inform all users of ibc-go, including developers and operators of IBC, relayer, chain and wallet applications. - -This roadmap should be read as a high-level guide, rather than a commitment to schedules and deliverables. The degree of specificity is inversely proportional to the timeline. We will update this document periodically to reflect the status and plans. - -## Q3 - 2022 - -At a high level we will focus on: - -### Features - -- Releasing [v4.0.0](https://github.com/cosmos/ibc-go/milestone/26), which includes the ICS-29 Fee Middleware module. -- Finishing and releasing the [refactoring of 02-client](https://github.com/cosmos/ibc-go/milestone/16). This refactor will make the development of light clients easier. -- Starting the implementation of channel upgradability (see [epic](https://github.com/cosmos/ibc-go/issues/1599) and [alpha milestone](https://github.com/cosmos/ibc-go/milestone/29)) with the goal of cutting an alpha1 pre-release by the end of the quarter. Channel upgradability will allow chains to renegotiate an existing channel to take advantage of new features without having to create a new channel, thus preserving all existing packet state processed on the channel. -- Implementing the new [`ORDERED_ALLOW_TIMEOUT` channel type](https://github.com/cosmos/ibc-go/milestone/31) and hopefully releasing it as well. This new channel type will allow packets on an ordered channel to timeout without causing the closure of the channel. - -### Testing and infrastructure - -- Adding [automated e2e tests](https://github.com/cosmos/ibc-go/milestone/32) to the repo's CI. - -### Documentation and backlog - -- Finishing and releasing the upgrade to Cosmos SDK v0.46. -- Writing the [light client implementation guide](https://github.com/cosmos/ibc-go/issues/59). -- Working on [core backlog issues](https://github.com/cosmos/ibc-go/milestone/28). -- Depending on the timeline of the Cosmos SDK, implementing and testing the changes needed to support the [transtion to SMT storage](https://github.com/cosmos/ibc-go/milestone/21). - -We have also received a lot of feedback to improve Interchain Accounts and we might also work on a few things, but will depend on priorities and availability. - -For a detail view of each iteration's planned work, please check out our [project board](https://github.com/orgs/cosmos/projects/7). - -### Release schedule - -#### **July** - -We will probably cut at least one more release candidate of v4.0.0 before the final release, which should happen around the end of the month. - -For the Rho upgrade of the Cosmos Hub we will also release a new minor version of v3 with SDK 0.46. - -#### **August** - -In the first half we will probably start cutting release candidates for the 02-client refactor. Final release would most likely come out at the end of the month or beginning of September. - -#### **September** - -We might cut some pre-releases for the new channel type, and by the end of the month we expect to cut the first alpha pre-release for channel upgradability. - -## Q4 - 2022 - -We will continue the implementation and cut the final release of [channel upgradability](https://github.com/cosmos/ibc/blob/master/spec/core/ics-004-channel-and-packet-semantics/UPGRADES.md). At the end of Q3 or maybe beginning of Q4 we might also work on designing the implementation and scoping the engineering work to add support for [multihop channels](https://github.com/cosmos/ibc/pull/741/files), so that we could start the implementation of this feature during Q4 (but this is still be decided). diff --git a/docs/versioned_docs/version-v5.3.x/01-ibc/_category_.json b/docs/versioned_docs/version-v5.3.x/01-ibc/_category_.json deleted file mode 100644 index 066f3af93b1..00000000000 --- a/docs/versioned_docs/version-v5.3.x/01-ibc/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Using IBC-Go", - "position": 1, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/01-overview.md b/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/01-overview.md deleted file mode 100644 index 7e257d1e805..00000000000 --- a/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/01-overview.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /apps/transfer/overview ---- - -# Overview - -:::note Synopsis -Learn about what the token Transfer module is -::: - -## What is the Transfer module? - -Transfer is the Cosmos SDK implementation of the [ICS-20](https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer) protocol, which enables cross-chain fungible token transfers. - -## Concepts - -### Acknowledgements - -ICS20 uses the recommended acknowledgement format as specified by [ICS 04](https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope). - -A successful receive of a transfer packet will result in a Result Acknowledgement being written -with the value `[]byte{byte(1)}` in the `Response` field. - -An unsuccessful receive of a transfer packet will result in an Error Acknowledgement being written -with the error message in the `Response` field. - -### Denomination trace - -The denomination trace corresponds to the information that allows a token to be traced back to its -origin chain. It contains a sequence of port and channel identifiers ordered from the most recent to -the oldest in the timeline of transfers. - -This information is included on the token denomination field in the form of a hash to prevent an -unbounded denomination length. For example, the token `transfer/channelToA/uatom` will be displayed -as `ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2`. - -Each send to any chain other than the one it was previously received from is a movement forwards in -the token's timeline. This causes trace to be added to the token's history and the destination port -and destination channel to be prefixed to the denomination. In these instances the sender chain is -acting as the "source zone". When the token is sent back to the chain it previously received from, the -prefix is removed. This is a backwards movement in the token's timeline and the sender chain is -acting as the "sink zone". - -It is strongly recommended to read the full details of [ADR 001: Coin Source Tracing](/architecture/adr-001-coin-source-tracing) to understand the implications and context of the IBC token representations. - -## UX suggestions for clients - -For clients (wallets, exchanges, applications, block explorers, etc) that want to display the source of the token, it is recommended to use the following alternatives for each of the cases below: - -### Direct connection - -If the denomination trace contains a single identifier prefix pair (as in the example above), then -the easiest way to retrieve the chain and light client identifier is to map the trace information -directly. In summary, this requires querying the channel from the denomination trace identifiers, -and then the counterparty client state using the counterparty port and channel identifiers from the -retrieved channel. - -A general pseudo algorithm would look like the following: - -1. Query the full denomination trace. -2. Query the channel with the `portID/channelID` pair, which corresponds to the first destination of the - token. -3. Query the client state using the identifiers pair. Note that this query will return a `"Not -Found"` response if the current chain is not connected to this channel. -4. Retrieve the client identifier or chain identifier from the client state (eg: on - Tendermint clients) and store it locally. - -Using the gRPC gateway client service the steps above would be, with a given IBC token `ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2` stored on `chainB`: - -1. `GET /ibc/apps/transfer/v1/denom_traces/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2` -> `{"path": "transfer/channelToA", "base_denom": "uatom"}` -2. `GET /ibc/apps/transfer/v1/channels/channelToA/ports/transfer/client_state"` -> `{"client_id": "clientA", "chain-id": "chainA", ...}` -3. `GET /ibc/apps/transfer/v1/channels/channelToA/ports/transfer"` -> `{"channel_id": "channelToA", port_id": "transfer", counterparty: {"channel_id": "channelToB", port_id": "transfer"}, ...}` -4. `GET /ibc/apps/transfer/v1/channels/channelToB/ports/transfer/client_state" -> {"client_id": "clientB", "chain-id": "chainB", ...}` - -Then, the token transfer chain path for the `uatom` denomination would be: `chainA` -> `chainB`. - -### Multiple hops - -The multiple channel hops case applies when the token has passed through multiple chains between the original source and final destination chains. - -The IBC protocol doesn't know the topology of the overall network (i.e connections between chains and identifier names between them). For this reason, in the multiple hops case, a particular chain in the timeline of the individual transfers can't query the chain and client identifiers of the other chains. - -Take for example the following sequence of transfers `A -> B -> C` for an IBC token, with a final prefix path (trace info) of `transfer/channelChainC/transfer/channelChainB`. What the paragraph above means is that even in the case that chain `C` is directly connected to chain `A`, querying the port and channel identifiers that chain `B` uses to connect to chain `A` (eg: `transfer/channelChainA`) can be completely different from the one that chain `C` uses to connect to chain `A` (eg: `transfer/channelToChainA`). - -Thus the proposed solution for clients that the IBC team recommends are the following: - -- **Connect to all chains**: Connecting to all the chains in the timeline would allow clients to - perform the queries outlined in the [direct connection](#direct-connection) section to each - relevant chain. By repeatedly following the port and channel denomination trace transfer timeline, - clients should always be able to find all the relevant identifiers. This comes at the tradeoff - that the client must connect to nodes on each of the chains in order to perform the queries. -- **Relayer as a Service (RaaS)**: A longer term solution is to use/create a relayer service that - could map the denomination trace to the chain path timeline for each token (i.e `origin chain -> -chain #1 -> ... -> chain #(n-1) -> final chain`). These services could provide merkle proofs in - order to allow clients to optionally verify the path timeline correctness for themselves by - running light clients. If the proofs are not verified, they should be considered as trusted third - parties services. Additionally, client would be advised in the future to use RaaS that support the - largest number of connections between chains in the ecosystem. Unfortunately, none of the existing - public relayers (in [Golang](https://github.com/cosmos/relayer) and - [Rust](https://github.com/informalsystems/ibc-rs)), provide this service to clients. - -:::tip -The only viable alternative for clients (at the time of writing) to tokens with multiple connection hops, is to connect to all chains directly and perform relevant queries to each of them in the sequence. -::: - -## Locked funds - -In some [exceptional cases](/architecture/adr-026-ibc-client-recovery-mechanisms#exceptional-cases), a client state associated with a given channel cannot be updated. This causes that funds from fungible tokens in that channel will be permanently locked and thus can no longer be transferred. - -To mitigate this, a client update governance proposal can be submitted to update the frozen client -with a new valid header. Once the proposal passes the client state will be unfrozen and the funds -from the associated channels will then be unlocked. This mechanism only applies to clients that -allow updates via governance, such as Tendermint clients. - -In addition to this, it's important to mention that a token must be sent back along the exact route -that it took originally in order to return it to its original form on the source chain (eg: the -Cosmos Hub for the `uatom`). Sending a token back to the same chain across a different channel will -**not** move the token back across its timeline. If a channel in the chain history closes before the -token can be sent back across that channel, then the token will not be returnable to its original -form. - -## Security considerations - -For safety, no other module must be capable of minting tokens with the `ibc/` prefix. The IBC -transfer module needs a subset of the denomination space that only it can create tokens in. diff --git a/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/02-state.md b/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/02-state.md deleted file mode 100644 index 916e99b46c3..00000000000 --- a/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/02-state.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: State -sidebar_label: State -sidebar_position: 2 -slug: /apps/transfer/state ---- - -# State - -The IBC transfer application module keeps state of the port to which the module is binded and the denomination trace information as outlined in [ADR 001](/architecture/adr-001-coin-source-tracing). - -- `Port`: `0x01 -> ProtocolBuffer(string)` -- `DenomTrace`: `0x02 | []bytes(traceHash) -> ProtocolBuffer(DenomTrace)` diff --git a/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/03-state-transitions.md b/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/03-state-transitions.md deleted file mode 100644 index 7c73b8da21c..00000000000 --- a/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/03-state-transitions.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: State Transitions -sidebar_label: State Transitions -sidebar_position: 3 -slug: /apps/transfer/state-transitions ---- - -# State transitions - -## Send fungible tokens - -A successful fungible token send has two state transitions depending if the transfer is a movement forward or backwards in the token's timeline: - -1. Sender chain is the source chain, *i.e* a transfer to any chain other than the one it was previously received from is a movement forwards in the token's timeline. This results in the following state transitions: - - - The coins are transferred to an escrow address (i.e locked) on the sender chain. - - The coins are transferred to the receiving chain through IBC TAO logic. - -2. Sender chain is the sink chain, *i.e* the token is sent back to the chain it previously received from. This is a backwards movement in the token's timeline. This results in the following state transitions: - - - The coins (vouchers) are burned on the sender chain. - - The coins are transferred to the receiving chain through IBC TAO logic. - -## Receive fungible tokens - -A successful fungible token receive has two state transitions depending if the transfer is a movement forward or backwards in the token's timeline: - -1. Receiver chain is the source chain. This is a backwards movement in the token's timeline. This results in the following state transitions: - - - The leftmost port and channel identifier pair is removed from the token denomination prefix. - - The tokens are unescrowed and sent to the receiving address. - -2. Receiver chain is the sink chain. This is a movement forwards in the token's timeline. This results in the following state transitions: - - - Token vouchers are minted by prefixing the destination port and channel identifiers to the trace information. - - The receiving chain stores the new trace information in the store (if not set already). - - The vouchers are sent to the receiving address. diff --git a/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/04-messages.md b/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/04-messages.md deleted file mode 100644 index 7eb46cd32a1..00000000000 --- a/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/04-messages.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: Messages -sidebar_label: Messages -sidebar_position: 4 -slug: /apps/transfer/messages ---- - -# Messages - -## `MsgTransfer` - -A fungible token cross chain transfer is achieved by using the `MsgTransfer`: - -```go -type MsgTransfer struct { - SourcePort string - SourceChannel string - Token sdk.Coin - Sender string - Receiver string - TimeoutHeight ibcexported.Height - TimeoutTimestamp uint64 - Memo string -} -``` - -This message is expected to fail if: - -- `SourcePort` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). -- `SourceChannel` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -- `Token` is invalid (denom is invalid or amount is negative) - - `Token.Amount` is not positive. - - `Token.Denom` is not a valid IBC denomination as per [ADR 001 - Coin Source Tracing](/architecture/adr-001-coin-source-tracing). -- `Sender` is empty. -- `Receiver` is empty. -- `TimeoutHeight` and `TimeoutTimestamp` are both zero. - -This message will send a fungible token to the counterparty chain represented by the counterparty Channel End connected to the Channel End with the identifiers `SourcePort` and `SourceChannel`. - -The denomination provided for transfer should correspond to the same denomination represented on this chain. The prefixes will be added as necessary upon by the receiving chain. - -### Memo - -The memo field was added to allow applications and users to attach metadata to transfer packets. The field is optional and may be left empty. When it is used to attach metadata for a particular middleware, the memo field should be represented as a json object where different middlewares use different json keys. - -You can find more information about applications that use the memo field in the [chain registry](https://github.com/cosmos/chain-registry/blob/master/_memo_keys/ICS20_memo_keys.json). diff --git a/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/05-events.md b/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/05-events.md deleted file mode 100644 index 888b26a959a..00000000000 --- a/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/05-events.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Events -sidebar_label: Events -sidebar_position: 5 -slug: /apps/transfer/events ---- - - -# Events - -## `MsgTransfer` - -| Type | Attribute Key | Attribute Value | -|--------------|---------------|-----------------| -| ibc_transfer | sender | {sender} | -| ibc_transfer | receiver | {receiver} | -| message | action | transfer | -| message | module | transfer | - -## `OnRecvPacket` callback - -| Type | Attribute Key | Attribute Value | -|-----------------------|---------------|-----------------| -| fungible_token_packet | module | transfer | -| fungible_token_packet | sender | {sender} | -| fungible_token_packet | receiver | {receiver} | -| fungible_token_packet | denom | {denom} | -| fungible_token_packet | amount | {amount} | -| fungible_token_packet | success | {ackSuccess} | -| fungible_token_packet | memo | {memo} | -| denomination_trace | trace_hash | {hex_hash} | - -## `OnAcknowledgePacket` callback - -| Type | Attribute Key | Attribute Value | -|-----------------------|-----------------|-------------------| -| fungible_token_packet | module | transfer | -| fungible_token_packet | sender | {sender} | -| fungible_token_packet | receiver | {receiver} | -| fungible_token_packet | denom | {denom} | -| fungible_token_packet | amount | {amount} | -| fungible_token_packet | memo | {memo} | -| fungible_token_packet | acknowledgement | {ack.String()} | -| fungible_token_packet | success | error | {ack.Response} | - -## `OnTimeoutPacket` callback - -| Type | Attribute Key | Attribute Value | -|-----------------------|-----------------|-----------------| -| fungible_token_packet | module | transfer | -| fungible_token_packet | refund_receiver | {receiver} | -| fungible_token_packet | denom | {denom} | -| fungible_token_packet | amount | {amount} | -| fungible_token_packet | memo | {memo} | diff --git a/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/06-metrics.md b/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/06-metrics.md deleted file mode 100644 index 104e5b4d3bc..00000000000 --- a/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/06-metrics.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: Metrics -sidebar_label: Metrics -sidebar_position: 6 -slug: /apps/transfer/metrics ---- - - -# Metrics - -The IBC transfer application module exposes the following set of [metrics](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/advanced/09-telemetry.md). - -| Metric | Description | Unit | Type | -|:--------------------------------|:------------------------------------------------------------------------------------------|:----------------|:--------| -| `tx_msg_ibc_transfer` | The total amount of tokens transferred via IBC in a `MsgTransfer` (source or sink chain) | token | gauge | -| `ibc_transfer_packet_receive` | The total amount of tokens received in a `FungibleTokenPacketData` (source or sink chain) | token | gauge | -| `ibc_transfer_send` | Total number of IBC transfers sent from a chain (source or sink) | transfer | counter | -| `ibc_transfer_receive` | Total number of IBC transfers received to a chain (source or sink) | transfer | counter | diff --git a/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/07-params.md b/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/07-params.md deleted file mode 100644 index f3d55f7388f..00000000000 --- a/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/07-params.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: Params -sidebar_label: Params -sidebar_position: 7 -slug: /apps/transfer/params ---- - - -# Parameters - -The IBC transfer application module contains the following parameters: - -| Key | Type | Default Value | -|------------------|------|---------------| -| `SendEnabled` | bool | `true` | -| `ReceiveEnabled` | bool | `true` | - -## `SendEnabled` - -The transfers enabled parameter controls send cross-chain transfer capabilities for all fungible tokens. - -To prevent a single token from being transferred from the chain, set the `SendEnabled` parameter to `true` and then, depending on the Cosmos SDK version, do one of the following: - -- For Cosmos SDK v0.46.x or earlier, set the bank module's [`SendEnabled` parameter](https://github.com/cosmos/cosmos-sdk/blob/release/v0.46.x/x/bank/spec/05_params.md#sendenabled) for the denomination to `false`. -- For Cosmos SDK versions above v0.46.x, set the bank module's `SendEnabled` entry for the denomination to `false` using `MsgSetSendEnabled` as a governance proposal. - -## `ReceiveEnabled` - -The transfers enabled parameter controls receive cross-chain transfer capabilities for all fungible tokens. - -To prevent a single token from being transferred to the chain, set the `ReceiveEnabled` parameter to `true` and then, depending on the Cosmos SDK version, do one of the following: - -- For Cosmos SDK v0.46.x or earlier, set the bank module's [`SendEnabled` parameter](https://github.com/cosmos/cosmos-sdk/blob/release/v0.46.x/x/bank/spec/05_params.md#sendenabled) for the denomination to `false`. -- For Cosmos SDK versions above v0.46.x, set the bank module's `SendEnabled` entry for the denomination to `false` using `MsgSetSendEnabled` as a governance proposal. diff --git a/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/_category_.json b/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/_category_.json deleted file mode 100644 index d643a498cdf..00000000000 --- a/docs/versioned_docs/version-v5.3.x/02-apps/01-transfer/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Transfer", - "position": 1, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/01-overview.md b/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/01-overview.md deleted file mode 100644 index 911cf5573ff..00000000000 --- a/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/01-overview.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /apps/interchain-accounts/overview ---- - - -# Overview - -:::note Synopsis -Learn about what the Interchain Accounts module is, and how to build custom modules that utilize Interchain Accounts functionality -::: - -## What is the Interchain Accounts module? - -Interchain Accounts is the Cosmos SDK implementation of the ICS-27 protocol, which enables cross-chain account management built upon IBC. Chains using the Interchain Accounts module can programmatically create accounts on other chains and control these accounts via IBC transactions. - -Interchain Accounts exposes a simple-to-use API which means IBC application developers do not require an in-depth knowledge of the underlying low-level details of IBC or the ICS-27 protocol. - -Developers looking to build upon Interchain Accounts must write custom logic in their own IBC application module, called authentication modules. - -- How is an interchain account different than a regular account? - -Regular accounts use a private key to sign transactions on-chain. Interchain Accounts are instead controlled programmatically by separate chains via IBC transactions. Interchain Accounts are implemented as sub-accounts of the interchain accounts module account. - -## Concepts - -`Host Chain`: The chain where the interchain account is registered. The host chain listens for IBC packets from a controller chain which should contain instructions (e.g. cosmos SDK messages) for which the interchain account will execute. - -`Controller Chain`: The chain registering and controlling an account on a host chain. The controller chain sends IBC packets to the host chain to control the account. A controller chain must have at least one interchain accounts authentication module in order to act as a controller chain. - -`Authentication Module`: A custom IBC application module on the controller chain that uses the Interchain Accounts module API to build custom logic for the creation & management of interchain accounts. For a controller chain to utilize the interchain accounts module functionality, an authentication module is required. - -`Interchain Account`: An account on a host chain. An interchain account has all the capabilities of a normal account. However, rather than signing transactions with a private key, a controller chain's authentication module will send IBC packets to the host chain which signals what transactions the interchain account should execute. - -## SDK Security Model - -SDK modules on a chain are assumed to be trustworthy. For example, there are no checks to prevent an untrustworthy module from accessing the bank keeper. - -The implementation of ICS27 on ibc-go uses this assumption in its security considerations. The implementation assumes the authentication module will not try to open channels on owner addresses it does not control. - -The implementation assumes other IBC application modules will not bind to ports within the ICS27 namespace. diff --git a/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/02-auth-modules.md b/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/02-auth-modules.md deleted file mode 100644 index 34b75c2f8d8..00000000000 --- a/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/02-auth-modules.md +++ /dev/null @@ -1,402 +0,0 @@ ---- -title: Authentication Modules -sidebar_label: Authentication Modules -sidebar_position: 2 -slug: /apps/interchain-accounts/auth-modules ---- - - -# Building an authentication module - -:::note Synopsis -Authentication modules play the role of the `Base Application` as described in [ICS30 IBC Middleware](https://github.com/cosmos/ibc/tree/master/spec/app/ics-030-middleware), and enable application developers to perform custom logic when working with the Interchain Accounts controller API. -::: - -The controller submodule is used for account registration and packet sending. -It executes only logic required of all controllers of interchain accounts. -The type of authentication used to manage the interchain accounts remains unspecified. -There may exist many different types of authentication which are desirable for different use cases. -Thus the purpose of the authentication module is to wrap the controller module with custom authentication logic. - -In ibc-go, authentication modules are connected to the controller chain via a middleware stack. -The controller module is implemented as [middleware](https://github.com/cosmos/ibc/tree/master/spec/app/ics-030-middleware) and the authentication module is connected to the controller module as the base application of the middleware stack. -To implement an authentication module, the `IBCModule` interface must be fulfilled. -By implementing the controller module as middleware, any amount of authentication modules can be created and connected to the controller module without writing redundant code. - -The authentication module must: - -- Authenticate interchain account owners -- Track the associated interchain account address for an owner -- Claim the channel capability in `OnChanOpenInit` -- Send packets on behalf of an owner (after authentication) - -## IBCModule implementation - -The following `IBCModule` callbacks must be implemented with appropriate custom logic: - -```go -// OnChanOpenInit implements the IBCModule interface -func (im IBCModule) OnChanOpenInit( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) (string, error) { - // the authentication module *must* claim the channel capability on OnChanOpenInit - if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return version, err - } - - // perform custom logic - - return version, nil -} - -// OnChanOpenAck implements the IBCModule interface -func (im IBCModule) OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyVersion string, -) error { - // perform custom logic - - return nil -} - -// OnChanCloseConfirm implements the IBCModule interface -func (im IBCModule) OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // perform custom logic - - return nil -} - -// OnAcknowledgementPacket implements the IBCModule interface -func (im IBCModule) OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - relayer sdk.AccAddress, -) error { - // perform custom logic - - return nil -} - -// OnTimeoutPacket implements the IBCModule interface. -func (im IBCModule) OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) error { - // perform custom logic - - return nil -} -``` - -**Note**: The channel capability must be claimed by the authentication module in `OnChanOpenInit` otherwise the authentication module will not be able to send packets on the channel created for the associated interchain account. - -The following functions must be defined to fulfill the `IBCModule` interface, but they will never be called by the controller module so they may error or panic. - -```go -// OnChanOpenTry implements the IBCModule interface -func (im IBCModule) OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (string, error) { - panic("UNIMPLEMENTED") -} - -// OnChanOpenConfirm implements the IBCModule interface -func (im IBCModule) OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - panic("UNIMPLEMENTED") -} - -// OnChanCloseInit implements the IBCModule interface -func (im IBCModule) OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - panic("UNIMPLEMENTED") -} - -// OnRecvPacket implements the IBCModule interface. A successful acknowledgement -// is returned if the packet data is succesfully decoded and the receive application -// logic returns without error. -func (im IBCModule) OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) ibcexported.Acknowledgement { - panic("UNIMPLEMENTED") -} -``` - -## `RegisterInterchainAccount` - -The authentication module can begin registering interchain accounts by calling `RegisterInterchainAccount`: - -```go -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, connectionID, owner.String(), version); err != nil { - return err -} - -return nil -``` - -The `version` argument is used to support ICS29 fee middleware for relayer incentivization of ICS27 packets. Consumers of the `RegisterInterchainAccount` are expected to build the appropriate JSON encoded version string themselves and pass it accordingly. If an empty string is passed in the `version` argument, then the version will be initialized to a default value in the `OnChanOpenInit` callback of the controller's handler, so that channel handshake can proceed. - -The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, controllerConnectionID, owner.String(), string(appVersion)); err != nil { - return err -} -``` - -Similarly, if the application stack is configured to route through ICS29 fee middleware and a fee enabled channel is desired, construct the appropriate ICS29 `Metadata` type: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -feeMetadata := feetypes.Metadata{ - AppVersion: string(appVersion), - FeeVersion: feetypes.Version, -} - -feeEnabledVersion, err := feetypes.ModuleCdc.MarshalJSON(&feeMetadata) -if err != nil { - return err -} - -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, controllerConnectionID, owner.String(), string(feeEnabledVersion)); err != nil { - return err -} -``` - -## `SendTx` - -The authentication module can attempt to send a packet by calling `SendTx`: - -```go - -// Authenticate owner -// perform custom logic - -// Construct controller portID based on interchain account owner address -portID, err := icatypes.NewControllerPortID(owner.String()) -if err != nil { - return err -} - -channelID, found := keeper.icaControllerKeeper.GetActiveChannelID(ctx, portID) -if !found { - return sdkerrors.Wrapf(icatypes.ErrActiveChannelNotFound, "failed to retrieve active channel for port %s", portID) -} - -// Obtain the channel capability, claimed in OnChanOpenInit -chanCap, found := keeper.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(portID, channelID)) -if !found { - return sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") -} - -// Obtain data to be sent to the host chain. -// In this example, the owner of the interchain account would like to send a bank MsgSend to the host chain. -// The appropriate serialization function should be called. The host chain must be able to deserialize the transaction. -// If the host chain is using the ibc-go host module, `SerializeCosmosTx` should be used. -msg := &banktypes.MsgSend{FromAddress: fromAddr, ToAddress: toAddr, Amount: amt} -data, err := icatypes.SerializeCosmosTx(keeper.cdc, []sdk.Msg{msg}) -if err != nil { - return err -} - -// Construct packet data -packetData := icatypes.InterchainAccountPacketData{ - Type: icatypes.EXECUTE_TX, - Data: data, -} - -// Obtain timeout timestamp -// An appropriate timeout timestamp must be determined based on the usage of the interchain account. -// If the packet times out, the channel will be closed requiring a new channel to be created -timeoutTimestamp := obtainTimeoutTimestamp() - -// Send the interchain accounts packet, returning the packet sequence -seq, err = keeper.icaControllerKeeper.SendTx(ctx, chanCap, portID, packetData, timeoutTimestamp) -``` - -The data within an `InterchainAccountPacketData` must be serialized using a format supported by the host chain. -If the host chain is using the ibc-go host chain submodule, `SerializeCosmosTx` should be used. If the `InterchainAccountPacketData.Data` is serialized using a format not support by the host chain, the packet will not be successfully received. - -## `OnAcknowledgementPacket` - -Controller chains will be able to access the acknowledgement written into the host chain state once a relayer relays the acknowledgement. -The acknowledgement bytes will be passed to the auth module via the `OnAcknowledgementPacket` callback. -Auth modules are expected to know how to decode the acknowledgement. - -If the controller chain is connected to a host chain using the host module on ibc-go, it may interpret the acknowledgement bytes as follows: - -Begin by unmarshaling the acknowledgement into `sdk.TxMsgData`: - -```go -var ack channeltypes.Acknowledgement -if err := channeltypes.SubModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { - return err -} - -txMsgData := &sdk.TxMsgData{} -if err := proto.Unmarshal(ack.GetResult(), txMsgData); err != nil { - return err -} -``` - -If the `txMsgData.Data` field is non nil, the host chain is using SDK version <= v0.45. -The auth module should interpret the `txMsgData.Data` as follows: - -```go -switch len(txMsgData.Data) { -case 0: - // see documentation below for SDK 0.46.x or greater -default: - for _, msgData := range txMsgData.Data { - if err := handler(msgData); err != nil { - return err - } - } -... -} -``` - -A handler will be needed to interpret what actions to perform based on the message type sent. -A router could be used, or more simply a switch statement. - -```go -func handler(msgData sdk.MsgData) error { -switch msgData.MsgType { -case sdk.MsgTypeURL(&banktypes.MsgSend{}): - msgResponse := &banktypes.MsgSendResponse{} - if err := proto.Unmarshal(msgData.Data, msgResponse}; err != nil { - return err - } - - handleBankSendMsg(msgResponse) - -case sdk.MsgTypeURL(&stakingtypes.MsgDelegate{}): - msgResponse := &stakingtypes.MsgDelegateResponse{} - if err := proto.Unmarshal(msgData.Data, msgResponse}; err != nil { - return err - } - - handleStakingDelegateMsg(msgResponse) - -case sdk.MsgTypeURL(&transfertypes.MsgTransfer{}): - msgResponse := &transfertypes.MsgTransferResponse{} - if err := proto.Unmarshal(msgData.Data, msgResponse}; err != nil { - return err - } - - handleIBCTransferMsg(msgResponse) - -default: - return -} -``` - -If the `txMsgData.Data` is empty, the host chain is using SDK version > v0.45. -The auth module should interpret the `txMsgData.Responses` as follows: - -```go -... -// switch statement from above -case 0: - for _, any := range txMsgData.MsgResponses { - if err := handleAny(any); err != nil { - return err - } - } -} -``` - -A handler will be needed to interpret what actions to perform based on the type url of the Any. -A router could be used, or more simply a switch statement. -It may be possible to deduplicate logic between `handler` and `handleAny`. - -```go -func handleAny(any *codectypes.Any) error { -switch any.TypeURL { -case banktypes.MsgSend: - msgResponse, err := unpackBankMsgSendResponse(any) - if err != nil { - return err - } - - handleBankSendMsg(msgResponse) - -case stakingtypes.MsgDelegate: - msgResponse, err := unpackStakingDelegateResponse(any) - if err != nil { - return err - } - - handleStakingDelegateMsg(msgResponse) - - case transfertypes.MsgTransfer: - msgResponse, err := unpackIBCTransferMsgResponse(any) - if err != nil { - return err - } - - handleIBCTransferMsg(msgResponse) - -default: - return -} -``` - -### Integration into `app.go` file - -To integrate the authentication module into your chain, please follow the steps outlined above in [app.go integration](04-integration.md#example-integration). diff --git a/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/03-active-channels.md b/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/03-active-channels.md deleted file mode 100644 index 6727055cb18..00000000000 --- a/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/03-active-channels.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: Active Channels -sidebar_label: Active Channels -sidebar_position: 3 -slug: /apps/interchain-accounts/active-channels ---- - - -# Understanding Active Channels - -The Interchain Accounts module uses [ORDERED channels](https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#ordering) to maintain the order of transactions when sending packets from a controller to a host chain. A limitation when using ORDERED channels is that when a packet times out the channel will be closed. - -In the case of a channel closing, a controller chain needs to be able to regain access to the interchain account registered on this channel. `Active Channels` enable this functionality. Future versions of the ICS-27 protocol and the Interchain Accounts module will likely use a new -channel type that provides ordering of packets without the channel closing on timing out, thus removing the need for `Active Channels` entirely. - -When an Interchain Account is registered using the `RegisterInterchainAccount` API, a new channel is created on a particular port. During the `OnChanOpenAck` and `OnChanOpenConfirm` steps (controller & host chain) the `Active Channel` for this interchain account -is stored in state. - -It is possible to create a new channel using the same controller chain portID if the previously set `Active Channel` is now in a `CLOSED` state. This channel creation can be initialized programatically by sending a new `MsgChannelOpenInit` message like so: - -```go -msg := channeltypes.NewMsgChannelOpenInit(portID, string(versionBytes), channeltypes.ORDERED, []string{connectionID}, icatypes.PortID, icatypes.ModuleName) -handler := k.msgRouter.Handler(msg) -``` - -Alternatively, any relayer operator may initiate a new channel handshake for this interchain account once the previously set `Active Channel` is in a `CLOSED` state. This is done by initiating the channel handshake on the controller chain using the same portID associated with the interchain account in question. - -It is important to note that once a channel has been opened for a given Interchain Account, new channels can not be opened for this account until the currently set `Active Channel` is set to `CLOSED`. diff --git a/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/04-integration.md b/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/04-integration.md deleted file mode 100644 index 2eede04b405..00000000000 --- a/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/04-integration.md +++ /dev/null @@ -1,194 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 4 -slug: /apps/interchain-accounts/integration ---- - - -# Integration - -:::note Synopsis -Learn how to integrate Interchain Accounts host and controller functionality to your chain. The following document only applies for Cosmos SDK chains. -::: - -The Interchain Accounts module contains two submodules. Each submodule has its own IBC application. The Interchain Accounts module should be registered as an `AppModule` in the same way all SDK modules are registered on a chain, but each submodule should create its own `IBCModule` as necessary. A route should be added to the IBC router for each submodule which will be used. - -Chains who wish to support ICS27 may elect to act as a host chain, a controller chain or both. Disabling host or controller functionality may be done statically by excluding the host or controller module entirely from the `app.go` file or it may be done dynamically by taking advantage of the on-chain parameters which enable or disable the host or controller submodules. - -Interchain Account authentication modules are the base application of a middleware stack. The controller submodule is the middleware in this stack. - -## Example integration - -```go -// app.go - -// Register the AppModule for the Interchain Accounts module and the authentication module -// Note: No `icaauth` exists, this must be substituted with an actual Interchain Accounts authentication module -ModuleBasics = module.NewBasicManager( - ... - ica.AppModuleBasic{}, - icaauth.AppModuleBasic{}, - ... -) - -... - -// Add module account permissions for the Interchain Accounts module -// Only necessary for host chain functionality -// Each Interchain Account created on the host chain is derived from the module account created -maccPerms = map[string][]string{ - ... - icatypes.ModuleName: nil, -} - -... - -// Add Interchain Accounts Keepers for each submodule used and the authentication module -// If a submodule is being statically disabled, the associated Keeper does not need to be added. -type App struct { - ... - - ICAControllerKeeper icacontrollerkeeper.Keeper - ICAHostKeeper icahostkeeper.Keeper - ICAAuthKeeper icaauthkeeper.Keeper - - ... -} - -... - -// Create store keys for each submodule Keeper and the authentication module -keys := sdk.NewKVStoreKeys( - ... - icacontrollertypes.StoreKey, - icahosttypes.StoreKey, - icaauthtypes.StoreKey, - ... -) - -... - -// Create the scoped keepers for each submodule keeper and authentication keeper -scopedICAControllerKeeper := app.CapabilityKeeper.ScopeToModule(icacontrollertypes.SubModuleName) -scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icahosttypes.SubModuleName) -scopedICAAuthKeeper := app.CapabilityKeeper.ScopeToModule(icaauthtypes.ModuleName) - -... - -// Create the Keeper for each submodule -app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( - appCodec, keys[icacontrollertypes.StoreKey], app.GetSubspace(icacontrollertypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - scopedICAControllerKeeper, app.MsgServiceRouter(), -) -app.ICAHostKeeper = icahostkeeper.NewKeeper( - appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), -) - -// Create Interchain Accounts AppModule -icaModule := ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper) - -// Create your Interchain Accounts authentication module -app.ICAAuthKeeper = icaauthkeeper.NewKeeper(appCodec, keys[icaauthtypes.StoreKey], app.ICAControllerKeeper, scopedICAAuthKeeper) - -// ICA auth AppModule -icaAuthModule := icaauth.NewAppModule(appCodec, app.ICAAuthKeeper) - -// ICA auth IBC Module -icaAuthIBCModule := icaauth.NewIBCModule(app.ICAAuthKeeper) - -// Create controller IBC application stack and host IBC module as desired -icaControllerStack := icacontroller.NewIBCMiddleware(icaAuthIBCModule, app.ICAControllerKeeper) -icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - -// Register host and authentication routes -ibcRouter. - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icahosttypes.SubModuleName, icaHostIBCModule). - AddRoute(icaauthtypes.ModuleName, icaControllerStack) // Note, the authentication module is routed to the top level of the middleware stack - -... - -// Register Interchain Accounts and authentication module AppModule's -app.moduleManager = module.NewManager( - ... - icaModule, - icaAuthModule, -) - -... - -// Add fee middleware to begin blocker logic -app.moduleManager.SetOrderBeginBlockers( - ... - icatypes.ModuleName, - ... -) - -// Add fee middleware to end blocker logic -app.moduleManager.SetOrderEndBlockers( - ... - icatypes.ModuleName, - ... -) - -// Add Interchain Accounts module InitGenesis logic -app.moduleManager.SetOrderInitGenesis( - ... - icatypes.ModuleName, - ... -) - -// initParamsKeeper init params keeper and its subspaces -func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) paramskeeper.Keeper { - ... - paramsKeeper.Subspace(icahosttypes.SubModuleName) - paramsKeeper.Subspace(icacontrollertypes.SubModuleName) - ... -``` - -### Using submodules exclusively - -As described above, the Interchain Accounts application module is structured to support the ability of exclusively enabling controller or host functionality. -This can be achieved by simply omitting either controller or host `Keeper` from the Interchain Accounts `NewAppModule` constructor function, and mounting only the desired submodule via the `IBCRouter`. -Alternatively, submodules can be enabled and disabled dynamically using [on-chain parameters](05-parameters.md). - -The following snippets show basic examples of statically disabling submodules using `app.go`. - -#### Disabling controller chain functionality - -```go -// Create Interchain Accounts AppModule omitting the controller keeper -icaModule := ica.NewAppModule(nil, &app.ICAHostKeeper) - -// Create host IBC Module -icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - -// Register host route -ibcRouter.AddRoute(icahosttypes.SubModuleName, icaHostIBCModule) -``` - -#### Disabling host chain functionality - -```go -// Create Interchain Accounts AppModule omitting the host keeper -icaModule := ica.NewAppModule(&app.ICAControllerKeeper, nil) - -// Create your Interchain Accounts authentication module, setting up the Keeper, AppModule and IBCModule appropriately -app.ICAAuthKeeper = icaauthkeeper.NewKeeper(appCodec, keys[icaauthtypes.StoreKey], app.ICAControllerKeeper, scopedICAAuthKeeper) -icaAuthModule := icaauth.NewAppModule(appCodec, app.ICAAuthKeeper) -icaAuthIBCModule := icaauth.NewIBCModule(app.ICAAuthKeeper) - -// Create controller IBC application stack -icaControllerStack := icacontroller.NewIBCMiddleware(icaAuthIBCModule, app.ICAControllerKeeper) - -// Register controller and authentication routes -ibcRouter. - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icaauthtypes.ModuleName, icaControllerStack) // Note, the authentication module is routed to the top level of the middleware stack -``` diff --git a/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/05-parameters.md b/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/05-parameters.md deleted file mode 100644 index 15e827fda87..00000000000 --- a/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/05-parameters.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -title: Parameters -sidebar_label: Parameters -sidebar_position: 5 -slug: /apps/interchain-accounts/parameters ---- - - -# Parameters - -The Interchain Accounts module contains the following on-chain parameters, logically separated for each distinct submodule: - -## Controller Submodule Parameters - -| Key | Type | Default Value | -|------------------------|------|---------------| -| `ControllerEnabled` | bool | `true` | - -### ControllerEnabled - -The `ControllerEnabled` parameter controls a chains ability to service ICS-27 controller specific logic. This includes the sending of Interchain Accounts packet data as well as the following ICS-26 callback handlers: - -- `OnChanOpenInit` -- `OnChanOpenAck` -- `OnChanCloseConfirm` -- `OnAcknowledgementPacket` -- `OnTimeoutPacket` - -## Host Submodule Parameters - -| Key | Type | Default Value | -|------------------------|----------|---------------| -| `HostEnabled` | bool | `true` | -| `AllowMessages` | []string | `[]` | - -### HostEnabled - -The `HostEnabled` parameter controls a chains ability to service ICS27 host specific logic. This includes the following ICS-26 callback handlers: - -- `OnChanOpenTry` -- `OnChanOpenConfirm` -- `OnChanCloseConfirm` -- `OnRecvPacket` - -### AllowMessages - -The `AllowMessages` parameter provides the ability for a chain to limit the types of messages or transactions that hosted interchain accounts are authorized to execute by defining an allowlist using the Protobuf message TypeURL format. - -For example, a Cosmos SDK based chain that elects to provide hosted Interchain Accounts with the ability of governance voting and staking delegations will define its parameters as follows: - -```json -"params": { - "host_enabled": true, - "allow_messages": ["/cosmos.staking.v1beta1.MsgDelegate", "/cosmos.gov.v1beta1.MsgVote"] -} -``` - -There is also a special wildcard `"*"` message type which allows any type of message to be executed by the interchain account. This must be the only message in the `allow_messages` array. - -```json -"params": { - "host_enabled": true, - "allow_messages": ["*"] -} -``` diff --git a/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/06-transactions.md b/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/06-transactions.md deleted file mode 100644 index 394d374989f..00000000000 --- a/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/06-transactions.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: Transactions -sidebar_label: Transactions -sidebar_position: 6 -slug: /apps/interchain-accounts/transactions ---- - - -# Transactions - -:::note Synopsis -Learn about Interchain Accounts transaction execution -::: - -## Executing a transaction - -As described in [Authentication Modules](02-auth-modules.md#trysendtx) transactions are executed using the interchain accounts controller API and require a `Base Application` as outlined in [ICS30 IBC Middleware](https://github.com/cosmos/ibc/tree/master/spec/app/ics-030-middleware) to facilitate authentication. The method of authentication remains unspecified to provide flexibility for the authentication module developer. - -Transactions are executed via the ICS27 [`SendTx` API](02-auth-modules.md#trysendtx). This must be invoked through an Interchain Accounts authentication module and follows the outlined path of execution below. Packet relaying semantics provided by the IBC core transport, authentication, and ordering (IBC/TAO) layer are omitted for brevity. - -![send-interchain-tx.png](./images/send-interchain-tx.png) - -## Atomicity - -As the Interchain Accounts module supports the execution of multiple transactions using the Cosmos SDK `Msg` interface, it provides the same atomicity guarantees as Cosmos SDK-based applications, leveraging the [`CacheMultiStore`](https://docs.cosmos.network/main/learn/advanced/store#cachemultistore) architecture provided by the [`Context`](https://docs.cosmos.network/main/learn/advanced/context.html) type. - -This provides atomic execution of transactions when using Interchain Accounts, where state changes are only committed if all `Msg`s succeed. diff --git a/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/_category_.json b/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/_category_.json deleted file mode 100644 index 5ac86ce8ff6..00000000000 --- a/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Interchain Accounts", - "position": 2, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/images/send-interchain-tx.png b/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/images/send-interchain-tx.png deleted file mode 100644 index ecaaa98157e..00000000000 Binary files a/docs/versioned_docs/version-v5.3.x/02-apps/02-interchain-accounts/images/send-interchain-tx.png and /dev/null differ diff --git a/docs/versioned_docs/version-v5.3.x/02-apps/_category_.json b/docs/versioned_docs/version-v5.3.x/02-apps/_category_.json deleted file mode 100644 index fa5fbf0ac9a..00000000000 --- a/docs/versioned_docs/version-v5.3.x/02-apps/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "IBC Application Modules", - "position": 2, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/01-overview.md b/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/01-overview.md deleted file mode 100644 index f6edae76ceb..00000000000 --- a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/01-overview.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /middleware/ics29-fee/overview ---- - - -# Overview - -:::note Synopsis -Learn about what the Fee Middleware module is, and how to build custom modules that utilize the Fee Middleware functionality -::: - -## What is the Fee Middleware module? - -IBC does not depend on relayer operators for transaction verification. However, the relayer infrastructure ensures liveness of the Interchain network — operators listen for packets sent through channels opened between chains, and perform the vital service of ferrying these packets (and proof of the transaction on the sending chain/receipt on the receiving chain) to the clients on each side of the channel. - -Though relaying is permissionless and completely decentralized and accessible, it does come with operational costs. Running full nodes to query transaction proofs and paying for transaction fees associated with IBC packets are two of the primary cost burdens which have driven the overall discussion on **a general, in-protocol incentivization mechanism for relayers**. - -Initially, a [simple proposal](https://github.com/cosmos/ibc/pull/577/files) was created to incentivize relaying on ICS20 token transfers on the destination chain. However, the proposal was specific to ICS20 token transfers and would have to be reimplemented in this format on every other IBC application module. - -After much discussion, the proposal was expanded to a [general incentivisation design](https://github.com/cosmos/ibc/tree/master/spec/app/ics-029-fee-payment) that can be adopted by any ICS application protocol as [middleware](../../01-ibc/04-middleware/01-develop.md). - -## Concepts - -ICS29 fee payments in this middleware design are built on the assumption that sender chains are the source of incentives — the chain on which packets are incentivized is the chain that distributes fees to relayer operators. However, as part of the IBC packet flow, messages have to be submitted on both sender and destination chains. This introduces the requirement of a mapping of relayer operator's addresses on both chains. - -To achieve the stated requirements, the **fee middleware module has two main groups of functionality**: - -- Registering of relayer addresses associated with each party involved in relaying the packet on the source chain. This registration process can be automated on start up of relayer infrastructure and happens only once, not every packet flow. - - This is described in the [Fee distribution section](04-fee-distribution.md). - -- Escrowing fees by any party which will be paid out to each rightful party on completion of the packet lifecycle. - - This is described in the [Fee messages section](03-msgs.md). - -We complete the introduction by giving a list of definitions of relevant terminolgy. - -`Forward relayer`: The relayer that submits the `MsgRecvPacket` message for a given packet (on the destination chain). - -`Reverse relayer`: The relayer that submits the `MsgAcknowledgement` message for a given packet (on the source chain). - -`Timeout relayer`: The relayer that submits the `MsgTimeout` or `MsgTimeoutOnClose` messages for a given packet (on the source chain). - -`Payee`: The account address on the source chain to be paid on completion of the packet lifecycle. The packet lifecycle on the source chain completes with the receipt of a `MsgTimeout`/`MsgTimeoutOnClose` or a `MsgAcknowledgement`. - -`Counterparty payee`: The account address to be paid on completion of the packet lifecycle on the destination chain. The package lifecycle on the destination chain completes with a successful `MsgRecvPacket`. - -`Refund address`: The address of the account paying for the incentivization of packet relaying. The account is refunded timeout fees upon successful acknowledgement. In the event of a packet timeout, both acknowledgement and receive fees are refunded. - -## Known Limitations - -The first version of fee payments middleware will only support incentivisation of new channels, however, channel upgradeability will enable incentivisation of all existing channels. diff --git a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/02-integration.md b/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/02-integration.md deleted file mode 100644 index 4fa2909e316..00000000000 --- a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/02-integration.md +++ /dev/null @@ -1,174 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 2 -slug: /middleware/ics29-fee/integration ---- - - -# Integration - -:::note Synopsis -Learn how to configure the Fee Middleware module with IBC applications. The following document is intended for developers building on top of the Cosmos SDK and only applies for Cosmos SDK chains. -::: - -## Pre-requisite Readings - -- [IBC middleware development](../../01-ibc/04-middleware/01-develop.md) -- [IBC middleware integration](../../01-ibc/04-middleware/02-integration.md) - -The Fee Middleware module, as the name suggests, plays the role of an IBC middleware and as such must be configured by chain developers to route and handle IBC messages correctly. -For Cosmos SDK chains this setup is done via the `app/app.go` file, where modules are constructed and configured in order to bootstrap the blockchain application. - -## Example integration of the Fee Middleware module - -```go -// app.go - -// Register the AppModule for the fee middleware module -ModuleBasics = module.NewBasicManager( - ... - ibcfee.AppModuleBasic{}, - ... -) - -... - -// Add module account permissions for the fee middleware module -maccPerms = map[string][]string{ - ... - ibcfeetypes.ModuleName: nil, -} - -... - -// Add fee middleware Keeper -type App struct { - ... - - IBCFeeKeeper ibcfeekeeper.Keeper - - ... -} - -... - -// Create store keys -keys := sdk.NewKVStoreKeys( - ... - ibcfeetypes.StoreKey, - ... -) - -... - -app.IBCFeeKeeper = ibcfeekeeper.NewKeeper( - appCodec, keys[ibcfeetypes.StoreKey], - app.IBCKeeper.ChannelKeeper, // may be replaced with IBC middleware - app.IBCKeeper.ChannelKeeper, - &app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, -) - - -// See the section below for configuring an application stack with the fee middleware module - -... - -// Register fee middleware AppModule -app.moduleManager = module.NewManager( - ... - ibcfee.NewAppModule(app.IBCFeeKeeper), -) - -... - -// Add fee middleware to begin blocker logic -app.moduleManager.SetOrderBeginBlockers( - ... - ibcfeetypes.ModuleName, - ... -) - -// Add fee middleware to end blocker logic -app.moduleManager.SetOrderEndBlockers( - ... - ibcfeetypes.ModuleName, - ... -) - -// Add fee middleware to init genesis logic -app.moduleManager.SetOrderInitGenesis( - ... - ibcfeetypes.ModuleName, - ... -) -``` - -## Configuring an application stack with Fee Middleware - -As mentioned in [IBC middleware development](../../01-ibc/04-middleware/01-develop.md) an application stack may be composed of many or no middlewares that nest a base application. -These layers form the complete set of application logic that enable developers to build composable and flexible IBC application stacks. -For example, an application stack may be just a single base application like `transfer`, however, the same application stack composed with `29-fee` will nest the `transfer` base application -by wrapping it with the Fee Middleware module. - -### Transfer - -See below for an example of how to create an application stack using `transfer` and `29-fee`. -The following `transferStack` is configured in `app/app.go` and added to the IBC `Router`. -The in-line comments describe the execution flow of packets between the application stack and IBC core. - -```go -// Create Transfer Stack -// SendPacket, since it is originating from the application to core IBC: -// transferKeeper.SendPacket -> fee.SendPacket -> channel.SendPacket - -// RecvPacket, message that originates from core IBC and goes down to app, the flow is the other way -// channel.RecvPacket -> fee.OnRecvPacket -> transfer.OnRecvPacket - -// transfer stack contains (from top to bottom): -// - IBC Fee Middleware -// - Transfer - -// create IBC module from bottom to top of stack -var transferStack porttypes.IBCModule -transferStack = transfer.NewIBCModule(app.TransferKeeper) -transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) - -// Add transfer stack to IBC Router -ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) -``` - -### Interchain Accounts - -See below for an example of how to create an application stack using `27-interchain-accounts` and `29-fee`. -The following `icaControllerStack` and `icaHostStack` are configured in `app/app.go` and added to the IBC `Router` with the associated authentication module. -The in-line comments describe the execution flow of packets between the application stack and IBC core. - -```go -// Create Interchain Accounts Stack -// SendPacket, since it is originating from the application to core IBC: -// icaAuthModuleKeeper.SendTx -> icaController.SendPacket -> fee.SendPacket -> channel.SendPacket - -// initialize ICA module with mock module as the authentication module on the controller side -var icaControllerStack porttypes.IBCModule -icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp("", scopedICAMockKeeper)) -app.ICAAuthModule = icaControllerStack.(ibcmock.IBCModule) -icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) -icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) - -// RecvPacket, message that originates from core IBC and goes down to app, the flow is: -// channel.RecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket - -var icaHostStack porttypes.IBCModule -icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) -icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) - -// Add authentication module, controller and host to IBC router -ibcRouter. - // the ICA Controller middleware needs to be explicitly added to the IBC Router because the - // ICA controller module owns the port capability for ICA. The ICA authentication module - // owns the channel capability. - AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack) - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icahosttypes.SubModuleName, icaHostStack). -``` diff --git a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/03-msgs.md b/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/03-msgs.md deleted file mode 100644 index b9b69adfac3..00000000000 --- a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/03-msgs.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: Fee Messages -sidebar_label: Fee Messages -sidebar_position: 3 -slug: /middleware/ics29-fee/msgs ---- - - -# Fee messages - -:::note Synopsis -Learn about the different ways to pay for fees, how the fees are paid out and what happens when not enough escrowed fees are available for payout -::: - -## Escrowing fees - -The fee middleware module exposes two different ways to pay fees for relaying IBC packets: - -1. `MsgPayPacketFee`, which enables the escrowing of fees for a packet at the next sequence send and should be combined into one `MultiMsgTx` with the message that will be paid for. - - Note that the `Relayers` field has been set up to allow for an optional whitelist of relayers permitted to receive this fee, however, this feature has not yet been enabled at this time. - - ```go - type MsgPayPacketFee struct{ - // fee encapsulates the recv, ack and timeout fees associated with an IBC packet - Fee Fee - // the source port unique identifier - SourcePortId string - // the source channel unique identifer - SourceChannelId string - // account address to refund fee if necessary - Signer string - // optional list of relayers permitted to the receive packet fee - Relayers []string - } - ``` - - The `Fee` message contained in this synchronous fee payment method configures different fees which will be paid out for `MsgRecvPacket`, `MsgAcknowledgement`, and `MsgTimeout`/`MsgTimeoutOnClose`. - - ```go - type Fee struct { - RecvFee types.Coins - AckFee types.Coins - TimeoutFee types.Coins - } - ``` - - The diagram below shows the `MultiMsgTx` with the `MsgTransfer` coming from a token transfer message, along with `MsgPayPacketFee`. - - ![msgpaypacket.png](./images/msgpaypacket.png) - -2. `MsgPayPacketFeeAsync`, which enables the asynchronous escrowing of fees for a specified packet: - - Note that a packet can be 'topped up' multiple times with additional fees of any coin denomination by broadcasting multiple `MsgPayPacketFeeAsync` messages. - - ```go - type MsgPayPacketFeeAsync struct { - // unique packet identifier comprised of the channel ID, port ID and sequence - PacketId channeltypes.PacketId - // the packet fee associated with a particular IBC packet - PacketFee PacketFee - } - ``` - - where the `PacketFee` also specifies the `Fee` to be paid as well as the refund address for fees which are not paid out - - ```go - type PacketFee struct { - Fee Fee - RefundAddress string - Relayers []string - } - ``` - -The diagram below shows how multiple `MsgPayPacketFeeAsync` can be broadcasted asynchronously. Escrowing of the fee associated with a packet can be carried out by any party because ICS-29 does not dictate a particular fee payer. In fact, chains can choose to simply not expose this fee payment to end users at all and rely on a different module account or even the community pool as the source of relayer incentives. - -![paypacketfeeasync.png](./images/paypacketfeeasync.png) - -Please see our [wiki](https://github.com/cosmos/ibc-go/wiki/Fee-enabled-fungible-token-transfers) for example flows on how to use these messages to incentivise a token transfer channel using a CLI. - -## Paying out the escrowed fees - -Following diagram takes a look at the packet flow for an incentivized token transfer and investigates the several scenario's for paying out the escrowed fees. We assume that the relayers have registered their counterparty address, detailed in the [Fee distribution section](04-fee-distribution.md). - -![feeflow.png](./images/feeflow.png) - -- In the case of a successful transaction, `RecvFee` will be paid out to the designated counterparty payee address which has been registered on the receiver chain and sent back with the `MsgAcknowledgement`, `AckFee` will be paid out to the relayer address which has submitted the `MsgAcknowledgement` on the sending chain (or the registered payee in case one has been registered for the relayer address), and `TimeoutFee` will be reimbursed to the account which escrowed the fee. -- In case of a timeout transaction, `RecvFee` and `AckFee` will be reimbursed. The `TimeoutFee` will be paid to the `Timeout Relayer` (who submits the timeout message to the source chain). - -> Please note that fee payments are built on the assumption that sender chains are the source of incentives — the chain that sends the packets is the same chain where fee payments will occur -- please see the [Fee distribution section](04-fee-distribution.md) to understand the flow for registering payee and counterparty payee (fee receiving) addresses. - -## A locked fee middleware module - -The fee middleware module can become locked if the situation arises that the escrow account for the fees does not have sufficient funds to pay out the fees which have been escrowed for each packet. *This situation indicates a severe bug.* In this case, the fee module will be locked until manual intervention fixes the issue. - -> A locked fee module will simply skip fee logic and continue on to the underlying packet flow. A channel with a locked fee module will temporarily function as a fee disabled channel, and the locking of a fee module will not affect the continued flow of packets over the channel. diff --git a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/04-fee-distribution.md b/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/04-fee-distribution.md deleted file mode 100644 index 9cfd4f3e5a6..00000000000 --- a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/04-fee-distribution.md +++ /dev/null @@ -1,114 +0,0 @@ ---- -title: Fee Distribution -sidebar_label: Fee Distribution -sidebar_position: 4 -slug: /middleware/ics29-fee/fee-distribution ---- - - -# Fee distribution - -:::note Synopsis -Learn about payee registration for the distribution of packet fees. The following document is intended for relayer operators. -::: - -## Pre-requisite readings - -- [Fee Middleware](01-overview.md) - -Packet fees are divided into 3 distinct amounts in order to compensate relayer operators for packet relaying on fee enabled IBC channels. - -- `RecvFee`: The sum of all packet receive fees distributed to a payee for successful execution of `MsgRecvPacket`. -- `AckFee`: The sum of all packet acknowledgement fees distributed to a payee for successful execution of `MsgAcknowledgement`. -- `TimeoutFee`: The sum of all packet timeout fees distributed to a payee for successful execution of `MsgTimeout`. - -## Register a counterparty payee address for forward relaying - -As mentioned in [ICS29 Concepts](01-overview.md#concepts), the forward relayer describes the actor who performs the submission of `MsgRecvPacket` on the destination chain. -Fee distribution for incentivized packet relays takes place on the packet source chain. - -> Relayer operators are expected to register a counterparty payee address, in order to be compensated accordingly with `RecvFee`s upon completion of a packet lifecycle. - -The counterparty payee address registered on the destination chain is encoded into the packet acknowledgement and communicated as such to the source chain for fee distribution. -**If a counterparty payee is not registered for the forward relayer on the destination chain, the escrowed fees will be refunded upon fee distribution.** - -### Relayer operator actions? - -A transaction must be submitted **to the destination chain** including a `CounterpartyPayee` address of an account on the source chain. -The transaction must be signed by the `Relayer`. - -Note: If a module account address is used as the `CounterpartyPayee` but the module has been set as a blocked address in the `BankKeeper`, the refunding to the module account will fail. This is because many modules use invariants to compare internal tracking of module account balances against the actual balance of the account stored in the `BankKeeper`. If a token transfer to the module account occurs without going through this module and updating the account balance of the module on the `BankKeeper`, then invariants may break and unknown behaviour could occur depending on the module implementation. Therefore, if it is desirable to use a module account that is currently blocked, the module developers should be consulted to gauge to possibility of removing the module account from the blocked list. - -```go -type MsgRegisterCounterpartyPayee struct { - // unique port identifier - PortId string - // unique channel identifier - ChannelId string - // the relayer address - Relayer string - // the counterparty payee address - CounterpartyPayee string -} -``` - -> This message is expected to fail if: -> -> - `PortId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). -> - `ChannelId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -> - `Relayer` is an invalid address (see [Cosmos SDK Addresses](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/beginner/03-accounts.md#addresses)). -> - `CounterpartyPayee` is empty. - -See below for an example CLI command: - -```bash -simd tx ibc-fee register-counterparty-payee transfer channel-0 \ -cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh \ -osmo1v5y0tz01llxzf4c2afml8s3awue0ymju22wxx2 \ ---from cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh -``` - -## Register an alternative payee address for reverse and timeout relaying - -As mentioned in [ICS29 Concepts](01-overview.md#concepts), the reverse relayer describes the actor who performs the submission of `MsgAcknowledgement` on the source chain. -Similarly the timeout relayer describes the actor who performs the submission of `MsgTimeout` (or `MsgTimeoutOnClose`) on the source chain. - -> Relayer operators **may choose** to register an optional payee address, in order to be compensated accordingly with `AckFee`s and `TimeoutFee`s upon completion of a packet life cycle. - -If a payee is not registered for the reverse or timeout relayer on the source chain, then fee distribution assumes the default behaviour, where fees are paid out to the relayer account which delivers `MsgAcknowledgement` or `MsgTimeout`/`MsgTimeoutOnClose`. - -### Relayer operator actions - -A transaction must be submitted **to the source chain** including a `Payee` address of an account on the source chain. -The transaction must be signed by the `Relayer`. - -Note: If a module account address is used as the `Payee` it is recommended to [turn off invariant checks](https://github.com/cosmos/ibc-go/blob/71d7480c923f4227453e8a80f51be01ae7ee845e/testing/simapp/app.go#L659) for that module. - -```go -type MsgRegisterPayee struct { - // unique port identifier - PortId string - // unique channel identifier - ChannelId string - // the relayer address - Relayer string - // the payee address - Payee string -} -``` - -> This message is expected to fail if: -> -> - `PortId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). -> - `ChannelId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -> - `Relayer` is an invalid address (see [Cosmos SDK Addresses](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/beginner/03-accounts.md#addresses)). -> - `Payee` is an invalid address (see [Cosmos SDK Addresses](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/beginner/03-accounts.md#addresses)). - -See below for an example CLI command: - -```bash -simd tx ibc-fee register-payee transfer channel-0 \ -cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh \ -cosmos153lf4zntqt33a4v0sm5cytrxyqn78q7kz8j8x5 \ ---from cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh -``` diff --git a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/05-events.md b/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/05-events.md deleted file mode 100644 index eddb296b70c..00000000000 --- a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/05-events.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: Events -sidebar_label: Events -sidebar_position: 5 -slug: /middleware/ics29-fee/events ---- - - -# Events - -:::note Synopsis -An overview of all events related to ICS-29 -::: - -## `MsgPayPacketFee`, `MsgPayPacketFeeAsync` - -| Type | Attribute Key | Attribute Value | -| ----------------------- | --------------- | --------------- | -| incentivized_ibc_packet | port_id | {portID} | -| incentivized_ibc_packet | channel_id | {channelID} | -| incentivized_ibc_packet | packet_sequence | {sequence} | -| incentivized_ibc_packet | recv_fee | {recvFee} | -| incentivized_ibc_packet | ack_fee | {ackFee} | -| incentivized_ibc_packet | timeout_fee | {timeoutFee} | -| message | module | fee-ibc | - -## `RegisterPayee` - -| Type | Attribute Key | Attribute Value | -| -------------- | ------------- | --------------- | -| register_payee | relayer | {relayer} | -| register_payee | payee | {payee} | -| register_payee | channel_id | {channelID} | -| message | module | fee-ibc | - -## `RegisterCounterpartyPayee` - -| Type | Attribute Key | Attribute Value | -| --------------------------- | ------------------ | ------------------- | -| register_counterparty_payee | relayer | {relayer} | -| register_counterparty_payee | counterparty_payee | {counterpartyPayee} | -| register_counterparty_payee | channel_id | {channelID} | -| message | module | fee-ibc | diff --git a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/06-end-users.md b/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/06-end-users.md deleted file mode 100644 index fbea38d0ded..00000000000 --- a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/06-end-users.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: End Users -sidebar_label: End Users -sidebar_position: 6 -slug: /middleware/ics29-fee/end-users ---- - - -# For end users - -:::note Synopsis -Learn how to incentivize IBC packets using the ICS29 Fee Middleware module. -::: - -## Pre-requisite readings - -- [Fee Middleware](01-overview.md) - -## Summary - -Different types of end users: - -- CLI users who want to manually incentivize IBC packets -- Client developers - -The Fee Middleware module allows end users to add a 'tip' to each IBC packet which will incentivize relayer operators to relay packets between chains. gRPC endpoints are exposed for client developers as well as a simple CLI for manually incentivizing IBC packets. - -## CLI Users - -For an in depth guide on how to use the ICS29 Fee Middleware module using the CLI please take a look at the [wiki](https://github.com/cosmos/ibc-go/wiki/Fee-enabled-fungible-token-transfers#asynchronous-incentivization-of-a-fungible-token-transfer) on the `ibc-go` repo. - -## Client developers - -Client developers can read more about the relevant ICS29 message types in the [Fee messages section](03-msgs.md). - -[CosmJS](https://github.com/cosmos/cosmjs) is a useful client library for signing and broadcasting Cosmos SDK messages. diff --git a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/_category_.json b/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/_category_.json deleted file mode 100644 index ddca8d29da6..00000000000 --- a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Fee Middleware", - "position": 1, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/images/feeflow.png b/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/images/feeflow.png deleted file mode 100644 index ba02071f4d8..00000000000 Binary files a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/images/feeflow.png and /dev/null differ diff --git a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/images/msgpaypacket.png b/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/images/msgpaypacket.png deleted file mode 100644 index 1bd5deb01fd..00000000000 Binary files a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/images/msgpaypacket.png and /dev/null differ diff --git a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/images/paypacketfeeasync.png b/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/images/paypacketfeeasync.png deleted file mode 100644 index 27c486a6f82..00000000000 Binary files a/docs/versioned_docs/version-v5.3.x/03-middleware/01-ics29-fee/images/paypacketfeeasync.png and /dev/null differ diff --git a/docs/versioned_docs/version-v5.3.x/03-middleware/_category_.json b/docs/versioned_docs/version-v5.3.x/03-middleware/_category_.json deleted file mode 100644 index 886249e8634..00000000000 --- a/docs/versioned_docs/version-v5.3.x/03-middleware/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "IBC Middleware Modules", - "position": 3, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v5.3.x/04-migrations/01-support-denoms-with-slashes.md b/docs/versioned_docs/version-v5.3.x/04-migrations/01-support-denoms-with-slashes.md deleted file mode 100644 index 54bbd96227e..00000000000 --- a/docs/versioned_docs/version-v5.3.x/04-migrations/01-support-denoms-with-slashes.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: Support transfer of coins whose base denom contains slashes -sidebar_label: Support transfer of coins whose base denom contains slashes -sidebar_position: 1 -slug: /migrations/support-denoms-with-slashes ---- -# Migrating from not supporting base denoms with slashes to supporting base denoms with slashes - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -This document is necessary when chains are upgrading from a version that does not support base denoms with slashes (e.g. v3.0.0) to a version that does (e.g. v3.2.0). All versions of ibc-go smaller than v1.5.0 for the v1.x release line, v2.3.0 for the v2.x release line, and v3.1.0 for the v3.x release line do **NOT** support IBC token transfers of coins whose base denoms contain slashes. Therefore the in-place of genesis migration described in this document are required when upgrading. - -If a chain receives coins of a base denom with slashes before it upgrades to supporting it, the receive may pass however the trace information will be incorrect. - -E.g. If a base denom of `testcoin/testcoin/testcoin` is sent to a chain that does not support slashes in the base denom, the receive will be successful. However, the trace information stored on the receiving chain will be: `Trace: "transfer/{channel-id}/testcoin/testcoin", BaseDenom: "testcoin"`. - -This incorrect trace information must be corrected when the chain does upgrade to fully supporting denominations with slashes. - -To do so, chain binaries should include a migration script that will run when the chain upgrades from not supporting base denominations with slashes to supporting base denominations with slashes. - -## Chains - -### ICS20 - Transfer - -The transfer module will now support slashes in base denoms, so we must iterate over current traces to check if any of them are incorrectly formed and correct the trace information. - -### Upgrade Proposal - -```go -app.UpgradeKeeper.SetUpgradeHandler("MigrateTraces", - func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - // transfer module consensus version has been bumped to 2 - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) - -``` - -This is only necessary if there are denom traces in the store with incorrect trace information from previously received coins that had a slash in the base denom. However, it is recommended that any chain upgrading to support base denominations with slashes runs this code for safety. - -For a more detailed sample, please check out the code changes in [this pull request](https://github.com/cosmos/ibc-go/pull/1680). - -### Genesis Migration - -If the chain chooses to add support for slashes in base denoms via genesis export, then the trace information must be corrected during genesis migration. - -The migration code required may look like: - -```go -func migrateGenesisSlashedDenomsUpgrade(appState genutiltypes.AppMap, clientCtx client.Context, genDoc *tmtypes.GenesisDoc) (genutiltypes.AppMap, error) { - if appState[ibctransfertypes.ModuleName] != nil { - transferGenState := &ibctransfertypes.GenesisState{} - clientCtx.Codec.MustUnmarshalJSON(appState[ibctransfertypes.ModuleName], transferGenState) - - substituteTraces := make([]ibctransfertypes.DenomTrace, len(transferGenState.DenomTraces)) - for i, dt := range transferGenState.DenomTraces { - // replace all previous traces with the latest trace if validation passes - // note most traces will have same value - newTrace := ibctransfertypes.ParseDenomTrace(dt.GetFullDenomPath()) - - if err := newTrace.Validate(); err != nil { - substituteTraces[i] = dt - } else { - substituteTraces[i] = newTrace - } - } - - transferGenState.DenomTraces = substituteTraces - - // delete old genesis state - delete(appState, ibctransfertypes.ModuleName) - - // set new ibc transfer genesis state - appState[ibctransfertypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(transferGenState) - } - - return appState, nil -} -``` - -For a more detailed sample, please check out the code changes in [this pull request](https://github.com/cosmos/ibc-go/pull/1528). diff --git a/docs/versioned_docs/version-v5.3.x/04-migrations/02-sdk-to-v1.md b/docs/versioned_docs/version-v5.3.x/04-migrations/02-sdk-to-v1.md deleted file mode 100644 index f979034e272..00000000000 --- a/docs/versioned_docs/version-v5.3.x/04-migrations/02-sdk-to-v1.md +++ /dev/null @@ -1,195 +0,0 @@ ---- -title: SDK v0.43 to IBC-Go v1 -sidebar_label: SDK v0.43 to IBC-Go v1 -sidebar_position: 2 -slug: /migrations/sdk-to-v1 ---- -# Migrating to ibc-go - -This file contains information on how to migrate from the IBC module contained in the SDK 0.41.x and 0.42.x lines to the IBC module in the ibc-go repository based on the 0.44 SDK version. - -## Import Changes - -The most obvious changes is import name changes. We need to change: - -- applications -> apps -- cosmos-sdk/x/ibc -> ibc-go - -On my GNU/Linux based machine I used the following commands, executed in order: - -```bash -grep -RiIl 'cosmos-sdk\/x\/ibc\/applications' | xargs sed -i 's/cosmos-sdk\/x\/ibc\/applications/ibc-go\/modules\/apps/g' -``` - -```bash -grep -RiIl 'cosmos-sdk\/x\/ibc' | xargs sed -i 's/cosmos-sdk\/x\/ibc/ibc-go\/modules/g' -``` - -ref: [explanation of the above commands](https://www.internalpointers.com/post/linux-find-and-replace-text-multiple-files) - -Executing these commands out of order will cause issues. - -Feel free to use your own method for modifying import names. - -NOTE: Updating to the `v0.44.0` SDK release and then running `go mod tidy` will cause a downgrade to `v0.42.0` in order to support the old IBC import paths. -Update the import paths before running `go mod tidy`. - -## Chain Upgrades - -Chains may choose to upgrade via an upgrade proposal or genesis upgrades. Both in-place store migrations and genesis migrations are supported. - -**WARNING**: Please read at least the quick guide for [IBC client upgrades](../01-ibc/05-upgrades/00-intro.md) before upgrading your chain. It is highly recommended you do not change the chain-ID during an upgrade, otherwise you must follow the IBC client upgrade instructions. - -Both in-place store migrations and genesis migrations will: - -- migrate the solo machine client state from v1 to v2 protobuf definitions -- prune all solo machine consensus states -- prune all expired tendermint consensus states - -Chains must set a new connection parameter during either in place store migrations or genesis migration. The new parameter, max expected block time, is used to enforce packet processing delays on the receiving end of an IBC packet flow. Checkout the [docs](https://github.com/cosmos/ibc-go/blob/release/v1.0.x/docs/ibc/proto-docs.md#params-2) for more information. - -### In-Place Store Migrations - -The new chain binary will need to run migrations in the upgrade handler. The fromVM (previous module version) for the IBC module should be 1. This will allow migrations to be run for IBC updating the version from 1 to 2. - -Ex: - -```go -app.UpgradeKeeper.SetUpgradeHandler("my-upgrade-proposal", - func(ctx sdk.Context, _ upgradetypes.Plan, _ module.VersionMap) (module.VersionMap, error) { - // set max expected block time parameter. Replace the default with your expected value - // https://github.com/cosmos/ibc-go/blob/release/v1.0.x/docs/ibc/proto-docs.md#params-2 - app.IBCKeeper.ConnectionKeeper.SetParams(ctx, ibcconnectiontypes.DefaultParams()) - - fromVM := map[string]uint64{ - ... // other modules - "ibc": 1, - ... - } - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) - -``` - -### Genesis Migrations - -To perform genesis migrations, the following code must be added to your existing migration code. - -```go -// add imports as necessary -import ( - ibcv100 "github.com/cosmos/ibc-go/modules/core/legacy/v100" - ibchost "github.com/cosmos/ibc-go/modules/core/24-host" -) - -... - -// add in migrate cmd function -// expectedTimePerBlock is a new connection parameter -// https://github.com/cosmos/ibc-go/blob/release/v1.0.x/docs/ibc/proto-docs.md#params-2 -newGenState, err = ibcv100.MigrateGenesis(newGenState, clientCtx, *genDoc, expectedTimePerBlock) -if err != nil { - return err -} -``` - -**NOTE:** The genesis chain-id, time and height MUST be updated before migrating IBC, otherwise the tendermint consensus state will not be pruned. - -## IBC Keeper Changes - -The IBC Keeper now takes in the Upgrade Keeper. Please add the chains' Upgrade Keeper after the Staking Keeper: - -```diff - // Create IBC Keeper - app.IBCKeeper = ibckeeper.NewKeeper( -- appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, scopedIBCKeeper, -+ appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper, - ) - -``` - -## Proposals - -### UpdateClientProposal - -The `UpdateClient` has been modified to take in two client-identifiers and one initial height. Please see the [documentation](../01-ibc/06-proposals.md) for more information. - -### UpgradeProposal - -A new IBC proposal type has been added, `UpgradeProposal`. This handles an IBC (breaking) Upgrade. -The previous `UpgradedClientState` field in an Upgrade `Plan` has been deprecated in favor of this new proposal type. - -### Proposal Handler Registration - -The `ClientUpdateProposalHandler` has been renamed to `ClientProposalHandler`. -It handles both `UpdateClientProposal`s and `UpgradeProposal`s. - -Add this import: - -```diff -+ ibcclienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" -``` - -Please ensure the governance module adds the correct route: - -```diff -- AddRoute(ibchost.RouterKey, ibcclient.NewClientUpdateProposalHandler(app.IBCKeeper.ClientKeeper)) -+ AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)) -``` - -NOTE: Simapp registration was incorrect in the 0.41.x releases. The `UpdateClient` proposal handler should be registered with the router key belonging to `ibc-go/core/02-client/types` -as shown in the diffs above. - -### Proposal CLI Registration - -Please ensure both proposal type CLI commands are registered on the governance module by adding the following arguments to `gov.NewAppModuleBasic()`: - -Add the following import: - -```diff -+ ibcclientclient "github.com/cosmos/ibc-go/modules/core/02-client/client" -``` - -Register the cli commands: - -```diff - gov.NewAppModuleBasic( - paramsclient.ProposalHandler, distrclient.ProposalHandler, upgradeclient.ProposalHandler, upgradeclient.CancelProposalHandler, -+ ibcclientclient.UpdateClientProposalHandler, ibcclientclient.UpgradeProposalHandler, - ), -``` - -REST routes are not supported for these proposals. - -## Proto file changes - -The gRPC querier service endpoints have changed slightly. The previous files used `v1beta1` gRPC route, this has been updated to `v1`. - -The solo machine has replaced the FrozenSequence uint64 field with a IsFrozen boolean field. The package has been bumped from `v1` to `v2` - -## IBC callback changes - -### OnRecvPacket - -Application developers need to update their `OnRecvPacket` callback logic. - -The `OnRecvPacket` callback has been modified to only return the acknowledgement. The acknowledgement returned must implement the `Acknowledgement` interface. The acknowledgement should indicate if it represents a successful processing of a packet by returning true on `Success()` and false in all other cases. A return value of false on `Success()` will result in all state changes which occurred in the callback being discarded. More information can be found in the [documentation](../01-ibc/03-apps/02-ibcmodule.md#receiving-packets). - -The `OnRecvPacket`, `OnAcknowledgementPacket`, and `OnTimeoutPacket` callbacks are now passed the `sdk.AccAddress` of the relayer who relayed the IBC packet. Applications may use or ignore this information. - -## IBC Event changes - -The `packet_data` attribute has been deprecated in favor of `packet_data_hex`, in order to provide standardized encoding/decoding of packet data in events. While the `packet_data` event still exists, all relayers and IBC Event consumers are strongly encouraged to switch over to using `packet_data_hex` as soon as possible. - -The `packet_ack` attribute has also been deprecated in favor of `packet_ack_hex` for the same reason stated above. All relayers and IBC Event consumers are strongly encouraged to switch over to using `packet_ack_hex` as soon as possible. - -The `consensus_height` attribute has been removed in the Misbehaviour event emitted. IBC clients no longer have a frozen height and misbehaviour does not necessarily have an associated height. - -## Relevant SDK changes - -- (codec) [\#9226](https://github.com/cosmos/cosmos-sdk/pull/9226) Rename codec interfaces and methods, to follow a general Go interfaces: - - `codec.Marshaler` → `codec.Codec` (this defines objects which serialize other objects) - - `codec.BinaryMarshaler` → `codec.BinaryCodec` - - `codec.JSONMarshaler` → `codec.JSONCodec` - - Removed `BinaryBare` suffix from `BinaryCodec` methods (`MarshalBinaryBare`, `UnmarshalBinaryBare`, ...) - - Removed `Binary` infix from `BinaryCodec` methods (`MarshalBinaryLengthPrefixed`, `UnmarshalBinaryLengthPrefixed`, ...) diff --git a/docs/versioned_docs/version-v5.3.x/04-migrations/03-v1-to-v2.md b/docs/versioned_docs/version-v5.3.x/04-migrations/03-v1-to-v2.md deleted file mode 100644 index 577ddf995bf..00000000000 --- a/docs/versioned_docs/version-v5.3.x/04-migrations/03-v1-to-v2.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: IBC-Go v1 to v2 -sidebar_label: IBC-Go v1 to v2 -sidebar_position: 3 -slug: /migrations/v1-to-v2 ---- -# Migrating from ibc-go v1 to v2 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -```go -github.com/cosmos/ibc-go -> github.com/cosmos/ibc-go/v2 -``` - -## Chains - -- No relevant changes were made in this release. - -## IBC Apps - -A new function has been added to the app module interface: - -```go -// NegotiateAppVersion performs application version negotiation given the provided channel ordering, connectionID, portID, counterparty and proposed version. - // An error is returned if version negotiation cannot be performed. For example, an application module implementing this interface - // may decide to return an error in the event of the proposed version being incompatible with it's own - NegotiateAppVersion( - ctx sdk.Context, - order channeltypes.Order, - connectionID string, - portID string, - counterparty channeltypes.Counterparty, - proposedVersion string, - ) (version string, err error) -} -``` - -This function should perform application version negotiation and return the negotiated version. If the version cannot be negotiated, an error should be returned. This function is only used on the client side. - -### sdk.Result removed - -sdk.Result has been removed as a return value in the application callbacks. Previously it was being discarded by core IBC and was thus unused. - -## Relayers - -A new gRPC has been added to 05-port, `AppVersion`. It returns the negotiated app version. This function should be used for the `ChanOpenTry` channel handshake step to decide upon the application version which should be set in the channel. - -## IBC Light Clients - -- No relevant changes were made in this release. diff --git a/docs/versioned_docs/version-v5.3.x/04-migrations/04-v2-to-v3.md b/docs/versioned_docs/version-v5.3.x/04-migrations/04-v2-to-v3.md deleted file mode 100644 index 34d87b46862..00000000000 --- a/docs/versioned_docs/version-v5.3.x/04-migrations/04-v2-to-v3.md +++ /dev/null @@ -1,186 +0,0 @@ ---- -title: IBC-Go v2 to v3 -sidebar_label: IBC-Go v2 to v3 -sidebar_position: 4 -slug: /migrations/v2-to-v3 ---- -# Migrating from ibc-go v2 to v3 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -```go -github.com/cosmos/ibc-go/v2 -> github.com/cosmos/ibc-go/v3 -``` - -No genesis or in-place migrations are required when upgrading from v1 or v2 of ibc-go. - -## Chains - -### ICS20 - -The `transferkeeper.NewKeeper(...)` now takes in an ICS4Wrapper. -The ICS4Wrapper should be the IBC Channel Keeper unless ICS 20 is being connected to a middleware application. - -### ICS27 - -ICS27 Interchain Accounts has been added as a supported IBC application of ibc-go. -Please see the [ICS27 documentation](../02-apps/02-interchain-accounts/01-overview.md) for more information. - -### Upgrade Proposal - -If the chain will adopt ICS27, it must set the appropriate params during the execution of the upgrade handler in `app.go`: - -```go -app.UpgradeKeeper.SetUpgradeHandler("v3", - func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - // set the ICS27 consensus version so InitGenesis is not run - fromVM[icatypes.ModuleName] = icamodule.ConsensusVersion() - - // create ICS27 Controller submodule params - controllerParams := icacontrollertypes.Params{ - ControllerEnabled: true, - } - - // create ICS27 Host submodule params - hostParams := icahosttypes.Params{ - HostEnabled: true, - AllowMessages: []string{"/cosmos.bank.v1beta1.MsgSend", ...}, - } - - // initialize ICS27 module - icamodule.InitModule(ctx, controllerParams, hostParams) - - ... - - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) - -``` - -The host and controller submodule params only need to be set if the chain integrates those submodules. -For example, if a chain chooses not to integrate a controller submodule, it may pass empty params into `InitModule`. - -#### Add `StoreUpgrades` for ICS27 module - -For ICS27 it is also necessary to [manually add store upgrades](https://docs.cosmos.network/main/learn/advanced/upgrade#add-storeupgrades-for-new-modules) for the new ICS27 module and then configure the store loader to apply those upgrades in `app.go`: - -```go -if upgradeInfo.Name == "v3" && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { - storeUpgrades := store.StoreUpgrades{ - Added: []string{icacontrollertypes.StoreKey, icahosttypes.StoreKey}, - } - - app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) -} -``` - -This ensures that the new module's stores are added to the multistore before the migrations begin. -The host and controller submodule keys only need to be added if the chain integrates those submodules. -For example, if a chain chooses not to integrate a controller submodule, it does not need to add the controller key to the `Added` field. - -### Genesis migrations - -If the chain will adopt ICS27 and chooses to upgrade via a genesis export, then the ICS27 parameters must be set during genesis migration. - -The migration code required may look like: - -```go - controllerGenesisState := icatypes.DefaultControllerGenesis() - // overwrite parameters as desired - controllerGenesisState.Params = icacontrollertypes.Params{ - ControllerEnabled: true, - } - - hostGenesisState := icatypes.DefaultHostGenesis() - // overwrite parameters as desired - hostGenesisState.Params = icahosttypes.Params{ - HostEnabled: true, - AllowMessages: []string{"/cosmos.bank.v1beta1.MsgSend", ...}, - } - - icaGenesisState := icatypes.NewGenesisState(controllerGenesisState, hostGenesisState) - - // set new ics27 genesis state - appState[icatypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(icaGenesisState) -``` - -### Ante decorator - -The field of type `channelkeeper.Keeper` in the `AnteDecorator` structure has been replaced with a field of type `*keeper.Keeper`: - -```diff -type AnteDecorator struct { -- k channelkeeper.Keeper -+ k *keeper.Keeper -} - -- func NewAnteDecorator(k channelkeeper.Keeper) AnteDecorator { -+ func NewAnteDecorator(k *keeper.Keeper) AnteDecorator { - return AnteDecorator{k: k} -} -``` - -## IBC Apps - -### `OnChanOpenTry` must return negotiated application version - -The `OnChanOpenTry` application callback has been modified. -The return signature now includes the application version. -IBC applications must perform application version negoitation in `OnChanOpenTry` using the counterparty version. -The negotiated application version then must be returned in `OnChanOpenTry` to core IBC. -Core IBC will set this version in the TRYOPEN channel. - -### `OnChanOpenAck` will take additional `counterpartyChannelID` argument - -The `OnChanOpenAck` application callback has been modified. -The arguments now include the counterparty channel id. - -### `NegotiateAppVersion` removed from `IBCModule` interface - -Previously this logic was handled by the `NegotiateAppVersion` function. -Relayers would query this function before calling `ChanOpenTry`. -Applications would then need to verify that the passed in version was correct. -Now applications will perform this version negotiation during the channel handshake, thus removing the need for `NegotiateAppVersion`. - -### Channel state will not be set before application callback - -The channel handshake logic has been reorganized within core IBC. -Channel state will not be set in state after the application callback is performed. -Applications must rely only on the passed in channel parameters instead of querying the channel keeper for channel state. - -### IBC application callbacks moved from `AppModule` to `IBCModule` - -Previously, IBC module callbacks were apart of the `AppModule` type. -The recommended approach is to create an `IBCModule` type and move the IBC module callbacks from `AppModule` to `IBCModule` in a separate file `ibc_module.go`. - -The mock module go API has been broken in this release by applying the above format. -The IBC module callbacks have been moved from the mock modules `AppModule` into a new type `IBCModule`. - -As apart of this release, the mock module now supports middleware testing. Please see the [README](https://github.com/cosmos/ibc-go/blob/v5.3.0/testing/README.md#middleware-testing) for more information. - -Please review the [mock](https://github.com/cosmos/ibc-go/blob/v5.3.0/testing/mock/ibc_module.go) and [transfer](https://github.com/cosmos/ibc-go/blob/v5.3.0/modules/apps/transfer/ibc_module.go) modules as examples. Additionally, [simapp](https://github.com/cosmos/ibc-go/blob/v5.3.0/testing/simapp/app.go) provides an example of how `IBCModule` types should now be added to the IBC router in favour of `AppModule`. - -### IBC testing package - -`TestChain`s are now created with chainID's beginning from an index of 1. Any calls to `GetChainID(0)` will now fail. Please increment all calls to `GetChainID` by 1. - -## Relayers - -`AppVersion` gRPC has been removed. -The `version` string in `MsgChanOpenTry` has been deprecated and will be ignored by core IBC. -Relayers no longer need to determine the version to use on the `ChanOpenTry` step. -IBC applications will determine the correct version using the counterparty version. - -## IBC Light Clients - -The `GetProofSpecs` function has been removed from the `ClientState` interface. This function was previously unused by core IBC. Light clients which don't use this function may remove it. diff --git a/docs/versioned_docs/version-v5.3.x/04-migrations/05-v3-to-v4.md b/docs/versioned_docs/version-v5.3.x/04-migrations/05-v3-to-v4.md deleted file mode 100644 index 067d8738e68..00000000000 --- a/docs/versioned_docs/version-v5.3.x/04-migrations/05-v3-to-v4.md +++ /dev/null @@ -1,160 +0,0 @@ ---- -title: IBC-Go v3 to v4 -sidebar_label: IBC-Go v3 to v4 -sidebar_position: 5 -slug: /migrations/v3-to-v4 ---- -# Migrating from ibc-go v3 to v4 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -```go -github.com/cosmos/ibc-go/v3 -> github.com/cosmos/ibc-go/v4 -``` - -No genesis or in-place migrations required when upgrading from v1 or v2 of ibc-go. - -## Chains - -### ICS27 - Interchain Accounts - -The controller submodule implements now the 05-port `Middleware` interface instead of the 05-port `IBCModule` interface. Chains that integrate the controller submodule, need to create it with the `NewIBCMiddleware` constructor function. For example: - -```diff -- icacontroller.NewIBCModule(app.ICAControllerKeeper, icaAuthIBCModule) -+ icacontroller.NewIBCMiddleware(icaAuthIBCModule, app.ICAControllerKeeper) -``` - -where `icaAuthIBCModule` is the Interchain Accounts authentication IBC Module. - -### ICS29 - Fee Middleware - -The Fee Middleware module, as the name suggests, plays the role of an IBC middleware and as such must be configured by chain developers to route and handle IBC messages correctly. - -Please read the Fee Middleware [integration documentation](https://ibc.cosmos.network/main/middleware/ics29-fee/integration.html) for an in depth guide on how to congfigure the module correctly in order to incentivize IBC packets. - -Take a look at the following diff for an [example setup](https://github.com/cosmos/ibc-go/pull/1432/files#diff-d18972debee5e64f16e40807b2ae112ddbe609504a93ea5e1c80a5d489c3a08aL366) of how to incentivize ics27 channels. - -### Migration to fix support for base denoms with slashes - -As part of [v1.5.0](https://github.com/cosmos/ibc-go/releases/tag/v1.5.0), [v2.3.0](https://github.com/cosmos/ibc-go/releases/tag/v2.3.0) and [v3.1.0](https://github.com/cosmos/ibc-go/releases/tag/v3.1.0) some [migration handler code sample was documented](./01-support-denoms-with-slashes.md#upgrade-proposal) that needs to run in order to correct the trace information of coins transferred using ICS20 whose base denom contains slashes. - -Based on feedback from the community we add now an improved solution to run the same migration that does not require copying a large piece of code over from the migration document, but instead requires only adding a one-line upgrade handler. - -If the chain will migrate to supporting base denoms with slashes, it must set the appropriate params during the execution of the upgrade handler in `app.go`: - -```go -app.UpgradeKeeper.SetUpgradeHandler("MigrateTraces", - func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - // transfer module consensus version has been bumped to 2 - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) - -``` - -If a chain receives coins of a base denom with slashes before it upgrades to supporting it, the receive may pass however the trace information will be incorrect. - -E.g. If a base denom of `testcoin/testcoin/testcoin` is sent to a chain that does not support slashes in the base denom, the receive will be successful. However, the trace information stored on the receiving chain will be: `Trace: "transfer/{channel-id}/testcoin/testcoin", BaseDenom: "testcoin"`. - -This incorrect trace information must be corrected when the chain does upgrade to fully supporting denominations with slashes. - -## IBC Apps - -### ICS03 - Connection - -Crossing hellos have been removed from 03-connection handshake negotiation. -`PreviousConnectionId` in `MsgConnectionOpenTry` has been deprecated and is no longer used by core IBC. - -`NewMsgConnectionOpenTry` no longer takes in the `PreviousConnectionId` as crossing hellos are no longer supported. A non-empty `PreviousConnectionId` will fail basic validation for this message. - -### ICS04 - Channel - -The `WriteAcknowledgement` API now takes the `exported.Acknowledgement` type instead of passing in the acknowledgement byte array directly. -This is an API breaking change and as such IBC application developers will have to update any calls to `WriteAcknowledgement`. - -The `OnChanOpenInit` application callback has been modified. -The return signature now includes the application version as detailed in the latest IBC [spec changes](https://github.com/cosmos/ibc/pull/629). - -The `NewErrorAcknowledgement` method signature has changed. -It now accepts an `error` rather than a `string`. This was done in order to prevent accidental state changes. -All error acknowledgements now contain a deterministic ABCI code and error message. It is the responsibility of the application developer to emit error details in events. - -Crossing hellos have been removed from 04-channel handshake negotiation. -IBC Applications no longer need to account from already claimed capabilities in the `OnChanOpenTry` callback. The capability provided by core IBC must be able to be claimed with error. -`PreviousChannelId` in `MsgChannelOpenTry` has been deprecated and is no longer used by core IBC. - -`NewMsgChannelOpenTry` no longer takes in the `PreviousChannelId` as crossing hellos are no longer supported. A non-empty `PreviousChannelId` will fail basic validation for this message. - -### ICS27 - Interchain Accounts - -The `RegisterInterchainAccount` API has been modified to include an additional `version` argument. This change has been made in order to support ICS29 fee middleware, for relayer incentivization of ICS27 packets. -Consumers of the `RegisterInterchainAccount` are now expected to build the appropriate JSON encoded version string themselves and pass it accordingly. -This should be constructed within the interchain accounts authentication module which leverages the APIs exposed via the interchain accounts `controllerKeeper`. If an empty string is passed in the `version` argument, then the version will be initialized to a default value in the `OnChanOpenInit` callback of the controller's handler, so that channel handshake can proceed. - -The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, msg.Owner, string(appVersion)); err != nil { - return err -} -``` - -Similarly, if the application stack is configured to route through ICS29 fee middleware and a fee enabled channel is desired, construct the appropriate ICS29 `Metadata` type: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -feeMetadata := feetypes.Metadata{ - AppVersion: string(appVersion), - FeeVersion: feetypes.Version, -} - -feeEnabledVersion, err := feetypes.ModuleCdc.MarshalJSON(&feeMetadata) -if err != nil { - return err -} - -if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, msg.Owner, string(feeEnabledVersion)); err != nil { - return err -} -``` - -## Relayers - -When using the `DenomTrace` gRPC, the full IBC denomination with the `ibc/` prefix may now be passed in. - -Crossing hellos are no longer supported by core IBC for 03-connection and 04-channel. The handshake should be completed in the logical 4 step process (INIT, TRY, ACK, CONFIRM). diff --git a/docs/versioned_docs/version-v5.3.x/04-migrations/_category_.json b/docs/versioned_docs/version-v5.3.x/04-migrations/_category_.json deleted file mode 100644 index 95db8e5579e..00000000000 --- a/docs/versioned_docs/version-v5.3.x/04-migrations/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Migrations", - "position": 4, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v6.2.x/00-intro.md b/docs/versioned_docs/version-v6.2.x/00-intro.md deleted file mode 100644 index c842dac0022..00000000000 --- a/docs/versioned_docs/version-v6.2.x/00-intro.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -slug: / -sidebar_position: 0 ---- - -# IBC-Go Documentation - -Welcome to the IBC-Go documentation! - -The Inter-Blockchain Communication protocol (IBC) is an end-to-end, connection-oriented, stateful protocol for reliable, ordered, and authenticated communication between heterogeneous blockchains arranged in an unknown and dynamic topology. - -IBC is a protocol that allows blockchains to talk to each other. - -The protocol realizes this interoperability by specifying a set of data structures, abstractions, and semantics that can be implemented by any distributed ledger that satisfies a small set of requirements. - -IBC can be used to build a wide range of cross-chain applications that include token transfers, atomic swaps, multi-chain smart contracts (with or without mutually comprehensible VMs), and data and code sharding of various kinds. diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/01-overview.md b/docs/versioned_docs/version-v6.2.x/01-ibc/01-overview.md deleted file mode 100644 index e8767d36cdb..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/01-overview.md +++ /dev/null @@ -1,297 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /ibc/overview ---- - - -# Overview - -:::note Synopsis -Learn about IBC, its components, and IBC use cases. -::: - -## What is the Interblockchain Communication Protocol (IBC)? - -This document serves as a guide for developers who want to write their own Inter-Blockchain -Communication protocol (IBC) applications for custom use cases. - -> IBC applications must be written as self-contained modules. - -Due to the modular design of the IBC protocol, IBC -application developers do not need to be concerned with the low-level details of clients, -connections, and proof verification. - -This brief explanation of the lower levels of the -stack gives application developers a broad understanding of the IBC -protocol. Abstraction layer details for channels and ports are most relevant for application developers and describe how to define custom packets and `IBCModule` callbacks. - -The requirements to have your module interact over IBC are: - -- Bind to a port or ports. -- Define your packet data. -- Use the default acknowledgment struct provided by core IBC or optionally define a custom acknowledgment struct. -- Standardize an encoding of the packet data. -- Implement the `IBCModule` interface. - -Read on for a detailed explanation of how to write a self-contained IBC application module. - -## Components Overview - -### [Clients](https://github.com/cosmos/ibc-go/blob/main/modules/core/02-client) - -IBC clients are on-chain light clients. Each light client is identified by a unique client-id. -IBC clients track the consensus states of other blockchains, along with the proof spec necessary to -properly verify proofs against the client's consensus state. A client can be associated with any number -of connections to the counterparty chain. The client identifier is auto generated using the client type -and the global client counter appended in the format: `{client-type}-{N}`. - -A `ClientState` should contain chain specific and light client specific information necessary for verifying updates -and upgrades to the IBC client. The `ClientState` may contain information such as chain-id, latest height, proof specs, -unbonding periods or the status of the light client. The `ClientState` should not contain information that -is specific to a given block at a certain height, this is the function of the `ConsensusState`. Each `ConsensusState` -should be associated with a unique block and should be referenced using a height. IBC clients are given a -client identifier prefixed store to store their associated client state and consensus states along with -any metadata associated with the consensus states. Consensus states are stored using their associated height. - -The supported IBC clients are: - -- [Solo Machine light client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/06-solomachine): Devices such as phones, browsers, or laptops. -- [Tendermint light client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/07-tendermint): The default for Cosmos SDK-based chains. -- [Localhost (loopback) client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/09-localhost): Useful for -testing, simulation, and relaying packets to modules on the same application. - -### IBC Client Heights - -IBC Client Heights are represented by the struct: - -```go -type Height struct { - RevisionNumber uint64 - RevisionHeight uint64 -} -``` - -The `RevisionNumber` represents the revision of the chain that the height is representing. -A revision typically represents a continuous, monotonically increasing range of block-heights. -The `RevisionHeight` represents the height of the chain within the given revision. - -On any reset of the `RevisionHeight`—for example, when hard-forking a Tendermint chain— -the `RevisionNumber` will get incremented. This allows IBC clients to distinguish between a -block-height `n` of a previous revision of the chain (at revision `p`) and block-height `n` of the current -revision of the chain (at revision `e`). - -`Height`s that share the same revision number can be compared by simply comparing their respective `RevisionHeight`s. -`Height`s that do not share the same revision number will only be compared using their respective `RevisionNumber`s. -Thus a height `h` with revision number `e+1` will always be greater than a height `g` with revision number `e`, -**REGARDLESS** of the difference in revision heights. - -Ex: - -```go -Height{RevisionNumber: 3, RevisionHeight: 0} > Height{RevisionNumber: 2, RevisionHeight: 100000000000} -``` - -When a Tendermint chain is running a particular revision, relayers can simply submit headers and proofs with the revision number -given by the chain's `chainID`, and the revision height given by the Tendermint block height. When a chain updates using a hard-fork -and resets its block-height, it is responsible for updating its `chainID` to increment the revision number. -IBC Tendermint clients then verifies the revision number against their `chainID` and treat the `RevisionHeight` as the Tendermint block-height. - -Tendermint chains wishing to use revisions to maintain persistent IBC connections even across height-resetting upgrades must format their `chainID`s -in the following manner: `{chainID}-{revision_number}`. On any height-resetting upgrade, the `chainID` **MUST** be updated with a higher revision number -than the previous value. - -Ex: - -- Before upgrade `chainID`: `gaiamainnet-3` -- After upgrade `chainID`: `gaiamainnet-4` - -Clients that do not require revisions, such as the solo-machine client, simply hardcode `0` into the revision number whenever they -need to return an IBC height when implementing IBC interfaces and use the `RevisionHeight` exclusively. - -Other client-types can implement their own logic to verify the IBC heights that relayers provide in their `Update`, `Misbehavior`, and -`Verify` functions respectively. - -The IBC interfaces expect an `ibcexported.Height` interface, however all clients must use the concrete implementation provided in -`02-client/types` and reproduced above. - -### [Connections](https://github.com/cosmos/ibc-go/blob/main/modules/core/03-connection) - -Connections encapsulate two `ConnectionEnd` objects on two separate blockchains. Each -`ConnectionEnd` is associated with a client of the other blockchain (for example, the counterparty blockchain). -The connection handshake is responsible for verifying that the light clients on each chain are -correct for their respective counterparties. Connections, once established, are responsible for -facilitating all cross-chain verifications of IBC state. A connection can be associated with any -number of channels. - -### [Proofs](https://github.com/cosmos/ibc-go/blob/main/modules/core/23-commitment) and [Paths](https://github.com/cosmos/ibc-go/blob/main/modules/core/24-host) - -In IBC, blockchains do not directly pass messages to each other over the network. Instead, to -communicate, a blockchain commits some state to a specifically defined path that is reserved for a -specific message type and a specific counterparty. For example, for storing a specific connectionEnd as part -of a handshake or a packet intended to be relayed to a module on the counterparty chain. A relayer -process monitors for updates to these paths and relays messages by submitting the data stored -under the path and a proof to the counterparty chain. - -Proofs are passed from core IBC to light-clients as bytes. It is up to light client implementation to interpret these bytes appropriately. - -- The paths that all IBC implementations must use for committing IBC messages is defined in -[ICS-24 Host State Machine Requirements](https://github.com/cosmos/ics/tree/master/spec/core/ics-024-host-requirements). -- The proof format that all implementations must be able to produce and verify is defined in [ICS-23 Proofs](https://github.com/confio/ics23) implementation. - -### [Capabilities](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/advanced/10-ocap.md) - -IBC is intended to work in execution environments where modules do not necessarily trust each -other. Thus, IBC must authenticate module actions on ports and channels so that only modules with the -appropriate permissions can use them. - -This module authentication is accomplished using a [dynamic -capability store](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-003-dynamic-capability-store.md). Upon binding to a port or -creating a channel for a module, IBC returns a dynamic capability that the module must claim in -order to use that port or channel. The dynamic capability module prevents other modules from using that port or channel since -they do not own the appropriate capability. - -While this background information is useful, IBC modules do not need to interact at all with -these lower-level abstractions. The relevant abstraction layer for IBC application developers is -that of channels and ports. IBC applications must be written as self-contained **modules**. - -A module on one blockchain can communicate with other modules on other blockchains by sending, -receiving, and acknowledging packets through channels that are uniquely identified by the -`(channelID, portID)` tuple. - -A useful analogy is to consider IBC modules as internet applications on -a computer. A channel can then be conceptualized as an IP connection, with the IBC portID being -analogous to an IP port and the IBC channelID being analogous to an IP address. Thus, a single -instance of an IBC module can communicate on the same port with any number of other modules and -IBC correctly routes all packets to the relevant module using the (channelID, portID tuple). An -IBC module can also communicate with another IBC module over multiple ports, with each -`(portID<->portID)` packet stream being sent on a different unique channel. - -### [Ports](https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port) - -An IBC module can bind to any number of ports. Each port must be identified by a unique `portID`. -Since IBC is designed to be secure with mutually distrusted modules operating on the same ledger, -binding a port returns a dynamic object capability. In order to take action on a particular port -(for example, an open channel with its portID), a module must provide the dynamic object capability to the IBC -handler. This requirement prevents a malicious module from opening channels with ports it does not own. Thus, -IBC modules are responsible for claiming the capability that is returned on `BindPort`. - -### [Channels](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -An IBC channel can be established between two IBC ports. Currently, a port is exclusively owned by a -single module. IBC packets are sent over channels. Just as IP packets contain the destination IP -address and IP port, and the source IP address and source IP port, IBC packets contain -the destination portID and channelID, and the source portID and channelID. This packet structure enables IBC to -correctly route packets to the destination module while allowing modules receiving packets to -know the sender module. - -A channel can be `ORDERED`, where packets from a sending module must be processed by the -receiving module in the order they were sent. Or a channel can be `UNORDERED`, where packets -from a sending module are processed in the order they arrive (might be in a different order than they were sent). - -Modules can choose which channels they wish to communicate over with, thus IBC expects modules to -implement callbacks that are called during the channel handshake. These callbacks can do custom -channel initialization logic. If any callback returns an error, the channel handshake fails. Thus, by -returning errors on callbacks, modules can programmatically reject and accept channels. - -The channel handshake is a 4-step handshake. Briefly, if a given chain A wants to open a channel with -chain B using an already established connection: - -1. chain A sends a `ChanOpenInit` message to signal a channel initialization attempt with chain B. -2. chain B sends a `ChanOpenTry` message to try opening the channel on chain A. -3. chain A sends a `ChanOpenAck` message to mark its channel end status as open. -4. chain B sends a `ChanOpenConfirm` message to mark its channel end status as open. - -If all handshake steps are successful, the channel is opened on both sides. At each step in the handshake, the module -associated with the `ChannelEnd` executes its callback. So -on `ChanOpenInit`, the module on chain A executes its callback `OnChanOpenInit`. - -The channel identifier is auto derived in the format: `channel-{N}` where N is the next sequence to be used. - -Just as ports came with dynamic capabilities, channel initialization returns a dynamic capability -that the module **must** claim so that they can pass in a capability to authenticate channel actions -like sending packets. The channel capability is passed into the callback on the first parts of the -handshake; either `OnChanOpenInit` on the initializing chain or `OnChanOpenTry` on the other chain. - -#### Closing channels - -Closing a channel occurs in 2 handshake steps as defined in [ICS 04](https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics). - -`ChanCloseInit` closes a channel on the executing chain if the channel exists, it is not -already closed and the connection it exists upon is OPEN. Channels can only be closed by a -calling module or in the case of a packet timeout on an ORDERED channel. - -`ChanCloseConfirm` is a response to a counterparty channel executing `ChanCloseInit`. The channel -on the executing chain closes if the channel exists, the channel is not already closed, -the connection the channel exists upon is OPEN and the executing chain successfully verifies -that the counterparty channel has been closed. - -### [Packets](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -Modules communicate with each other by sending packets over IBC channels. All -IBC packets contain the destination `portID` and `channelID` along with the source `portID` and -`channelID`. This packet structure allows modules to know the sender module of a given packet. IBC packets -contain a sequence to optionally enforce ordering. - -IBC packets also contain a `TimeoutHeight` and a `TimeoutTimestamp` that determine the deadline before the receiving module must process a packet. - -Modules send custom application data to each other inside the `Data []byte` field of the IBC packet. -Thus, packet data is opaque to IBC handlers. It is incumbent on a sender module to encode -their application-specific packet information into the `Data` field of packets. The receiver -module must decode that `Data` back to the original application data. - -### [Receipts and Timeouts](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -Since IBC works over a distributed network and relies on potentially faulty relayers to relay messages between ledgers, -IBC must handle the case where a packet does not get sent to its destination in a timely manner or at all. Packets must -specify a non-zero value for timeout height (`TimeoutHeight`) or timeout timestamp (`TimeoutTimestamp` ) after which a packet can no longer be successfully received on the destination chain. - -- The `timeoutHeight` indicates a consensus height on the destination chain after which the packet is no longer be processed, and instead counts as having timed-out. -- The `timeoutTimestamp` indicates a timestamp on the destination chain after which the packet is no longer be processed, and instead counts as having timed-out. - -If the timeout passes without the packet being successfully received, the packet can no longer be -received on the destination chain. The sending module can timeout the packet and take appropriate actions. - -If the timeout is reached, then a proof of packet timeout can be submitted to the original chain. The original chain can then perform -application-specific logic to timeout the packet, perhaps by rolling back the packet send changes (refunding senders any locked funds, etc.). - -- In ORDERED channels, a timeout of a single packet in the channel causes the channel to close. - - - If packet sequence `n` times out, then a packet at sequence `k > n` cannot be received without violating the contract of ORDERED channels that packets are processed in the order that they are sent. - - Since ORDERED channels enforce this invariant, a proof that sequence `n` has not been received on the destination chain by the specified timeout of packet `n` is sufficient to timeout packet `n` and close the channel. - -- In UNORDERED channels, the application-specific timeout logic for that packet is applied and the channel is not closed. - - - Packets can be received in any order. - - - IBC writes a packet receipt for each sequence receives in the UNORDERED channel. This receipt does not contain information; it is simply a marker intended to signify that the UNORDERED channel has received a packet at the specified sequence. - - - To timeout a packet on an UNORDERED channel, a proof is required that a packet receipt **does not exist** for the packet's sequence by the specified timeout. - -For this reason, most modules should use UNORDERED channels as they require fewer liveness guarantees to function effectively for users of that channel. - -### [Acknowledgments](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -Modules can also choose to write application-specific acknowledgments upon processing a packet. Acknowledgments can be done: - -- Synchronously on `OnRecvPacket` if the module processes packets as soon as they are received from IBC module. -- Asynchronously if module processes packets at some later point after receiving the packet. - -This acknowledgment data is opaque to IBC much like the packet `Data` and is treated by IBC as a simple byte string `[]byte`. Receiver modules must encode their acknowledgment so that the sender module can decode it correctly. The encoding must be negotiated between the two parties during version negotiation in the channel handshake. - -The acknowledgment can encode whether the packet processing succeeded or failed, along with additional information that allows the sender module to take appropriate action. - -After the acknowledgment has been written by the receiving chain, a relayer relays the acknowledgment back to the original sender module. - -The original sender module then executes application-specific acknowledgment logic using the contents of the acknowledgment. - -- After an acknowledgement fails, packet-send changes can be rolled back (for example, refunding senders in ICS20). - -- After an acknowledgment is received successfully on the original sender on the chain, the corresponding packet commitment is deleted since it is no longer needed. - -## Further Readings and Specs - -If you want to learn more about IBC, check the following specifications: - -- [IBC specification overview](https://github.com/cosmos/ibc/blob/master/README.md) diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/02-integration.md b/docs/versioned_docs/version-v6.2.x/01-ibc/02-integration.md deleted file mode 100644 index 60bedf7e216..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/02-integration.md +++ /dev/null @@ -1,222 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 2 -slug: /ibc/integration ---- - -# Integration - -:::note Synopsis -Learn how to integrate IBC to your application and send data packets to other chains. -::: - -This document outlines the required steps to integrate and configure the [IBC -module](https://github.com/cosmos/ibc-go/tree/main/modules/core) to your Cosmos SDK application and -send fungible token transfers to other chains. - -## Integrating the IBC module - -Integrating the IBC module to your SDK-based application is straighforward. The general changes can be summarized in the following steps: - -- Add required modules to the `module.BasicManager` -- Define additional `Keeper` fields for the new modules on the `App` type -- Add the module's `StoreKeys` and initialize their `Keepers` -- Set up corresponding routers and routes for the `ibc` module -- Add the modules to the module `Manager` -- Add modules to `Begin/EndBlockers` and `InitGenesis` -- Update the module `SimulationManager` to enable simulations - -### Module `BasicManager` and `ModuleAccount` permissions - -The first step is to add the following modules to the `BasicManager`: `x/capability`, `x/ibc`, -and `x/ibc-transfer`. After that, we need to grant `Minter` and `Burner` permissions to -the `ibc-transfer` `ModuleAccount` to mint and burn relayed tokens. - -```go -// app.go -var ( - - ModuleBasics = module.NewBasicManager( - // ... - capability.AppModuleBasic{}, - ibc.AppModuleBasic{}, - transfer.AppModuleBasic{}, // i.e ibc-transfer module - ) - - // module account permissions - maccPerms = map[string][]string{ - // other module accounts permissions - // ... - ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, -) -``` - -### Application fields - -Then, we need to register the `Keepers` as follows: - -```go -// app.go -type App struct { - // baseapp, keys and subspaces definitions - - // other keepers - // ... - IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly - TransferKeeper ibctransferkeeper.Keeper // for cross-chain fungible token transfers - - // make scoped keepers public for test purposes - ScopedIBCKeeper capabilitykeeper.ScopedKeeper - ScopedTransferKeeper capabilitykeeper.ScopedKeeper - - /// ... - /// module and simulation manager definitions -} -``` - -### Configure the `Keepers` - -During initialization, besides initializing the IBC `Keepers` (for the `x/ibc`, and -`x/ibc-transfer` modules), we need to grant specific capabilities through the capability module -`ScopedKeepers` so that we can authenticate the object-capability permissions for each of the IBC -channels. - -```go -func NewApp(...args) *App { - // define codecs and baseapp - - // add capability keeper and ScopeToModule for ibc module - app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey]) - - // grant capabilities for the ibc and ibc-transfer modules - scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName) - scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) - - // ... other modules keepers - - // Create IBC Keeper - app.IBCKeeper = ibckeeper.NewKeeper( - appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper, - ) - - // Create Transfer Keepers - app.TransferKeeper = ibctransferkeeper.NewKeeper( - appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName), - app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, app.BankKeeper, scopedTransferKeeper, - ) - transferModule := transfer.NewAppModule(app.TransferKeeper) - - // .. continues -} -``` - -### Register `Routers` - -IBC needs to know which module is bound to which port so that it can route packets to the -appropriate module and call the appropriate callbacks. The port to module name mapping is handled by -IBC's port `Keeper`. However, the mapping from module name to the relevant callbacks is accomplished -by the port -[`Router`](https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port/types/router.go) on the -IBC module. - -Adding the module routes allows the IBC handler to call the appropriate callback when processing a -channel handshake or a packet. - -Currently, a `Router` is static so it must be initialized and set correctly on app initialization. -Once the `Router` has been set, no new routes can be added. - -```go -// app.go -func NewApp(...args) *App { - // .. continuation from above - - // Create static IBC router, add ibc-tranfer module route, then set and seal it - ibcRouter := port.NewRouter() - ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule) - // Setting Router will finalize all routes by sealing router - // No more routes can be added - app.IBCKeeper.SetRouter(ibcRouter) - - // .. continues -``` - -### Module Managers - -In order to use IBC, we need to add the new modules to the module `Manager` and to the `SimulationManager` in case your application supports [simulations](https://github.com/cosmos/cosmos-sdk/blob/main/docs/build/building-modules/14-simulator.md). - -```go -// app.go -func NewApp(...args) *App { - // .. continuation from above - - app.mm = module.NewManager( - // other modules - // ... - capability.NewAppModule(appCodec, *app.CapabilityKeeper), - ibc.NewAppModule(app.IBCKeeper), - transferModule, - ) - - // ... - - app.sm = module.NewSimulationManager( - // other modules - // ... - capability.NewAppModule(appCodec, *app.CapabilityKeeper), - ibc.NewAppModule(app.IBCKeeper), - transferModule, - ) - - // .. continues -``` - -### Application ABCI Ordering - -One addition from IBC is the concept of `HistoricalEntries` which are stored on the staking module. -Each entry contains the historical information for the `Header` and `ValidatorSet` of this chain which is stored -at each height during the `BeginBlock` call. The historical info is required to introspect the -past historical info at any given height in order to verify the light client `ConsensusState` during the -connection handhake. - -The IBC module also has -[`BeginBlock`](https://github.com/cosmos/ibc-go/blob/main/modules/core/02-client/abci.go) logic as well. This is optional as it is only required if your application uses the localhost client to connect two different modules from the same chain. - -:::tip -Only register the ibc module to the `SetOrderBeginBlockers` if your application will use the -localhost (*aka* loopback) client. -::: - -```go -// app.go -func NewApp(...args) *App { - // .. continuation from above - - // add staking and ibc modules to BeginBlockers - app.mm.SetOrderBeginBlockers( - // other modules ... - stakingtypes.ModuleName, ibchost.ModuleName, - ) - - // ... - - // 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. - app.mm.SetOrderInitGenesis( - capabilitytypes.ModuleName, - // other modules ... - ibchost.ModuleName, ibctransfertypes.ModuleName, - ) - - // .. continues -``` - -:::warning -**IMPORTANT**: The capability module **must** be declared first in `SetOrderInitGenesis` -::: - -That's it! You have now wired up the IBC module and are now able to send fungible tokens across -different chains. If you want to have a broader view of the changes take a look into the SDK's -[`SimApp`](https://github.com/cosmos/ibc-go/blob/main/testing/simapp/app.go). diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/01-apps.md b/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/01-apps.md deleted file mode 100644 index 58a1bb63045..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/01-apps.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: IBC Applications -sidebar_label: IBC Applications -sidebar_position: 1 -slug: /ibc/apps/apps ---- - -# IBC Applications - -:::note Synopsis -Learn how to build custom IBC application modules that enable packets to be sent to and received from other IBC-enabled chains. -::: - -This document serves as a guide for developers who want to write their own Inter-blockchain Communication Protocol (IBC) applications for custom use cases. - -Due to the modular design of the IBC protocol, IBC application developers do not need to concern themselves with the low-level details of clients, connections, and proof verification. Nevertheless, an overview of these low-level concepts can be found in [the Overview section](../01-overview.md). -The document goes into detail on the abstraction layer most relevant for application developers (channels and ports), and describes how to define your own custom packets, `IBCModule` callbacks and more to make an application module IBC ready. - -**To have your module interact over IBC you must:** - -- implement the `IBCModule` interface, i.e.: - - channel (opening) handshake callbacks - - channel closing handshake callbacks - - packet callbacks -- bind to a port(s) -- add keeper methods -- define your own packet data and acknowledgement structs as well as how to encode/decode them -- add a route to the IBC router - -The following sections provide a more detailed explanation of how to write an IBC application -module correctly corresponding to the listed steps. - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: - -## Working example - -For a real working example of an IBC application, you can look through the `ibc-transfer` module -which implements everything discussed in this section. - -Here are the useful parts of the module to look at: - -[Binding to transfer -port](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/genesis.go) - -[Sending transfer -packets](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/relay.go) - -[Implementing IBC -callbacks](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/ibc_module.go) diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/02-ibcmodule.md b/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/02-ibcmodule.md deleted file mode 100644 index 6b25e53ab20..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/02-ibcmodule.md +++ /dev/null @@ -1,358 +0,0 @@ ---- -title: Implement `IBCModule` interface and callbacks -sidebar_label: Implement `IBCModule` interface and callbacks -sidebar_position: 2 -slug: /ibc/apps/ibcmodule ---- - -# Implement `IBCModule` interface and callbacks - -:::note Synopsis -Learn how to implement the `IBCModule` interface and all of the callbacks it requires. -::: - -The Cosmos SDK expects all IBC modules to implement the [`IBCModule` -interface](https://github.com/cosmos/ibc-go/tree/main/modules/core/05-port/types/module.go). This interface contains all of the callbacks IBC expects modules to implement. They include callbacks related to channel handshake, closing and packet callbacks (`OnRecvPacket`, `OnAcknowledgementPacket` and `OnTimeoutPacket`). - -```go -// IBCModule implements the ICS26 interface for given the keeper. -// The implementation of the IBCModule interface could for example be in a file called ibc_module.go, -// but ultimately file structure is up to the developer -type IBCModule struct { - keeper keeper.Keeper -} -``` - -Additionally, in the `module.go` file, add the following line: - -```go -var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} - // Add this line - _ porttypes.IBCModule = IBCModule{} -) -``` - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: - -## Channel handshake callbacks - -This section will describe the callbacks that are called during channel handshake execution. Among other things, it will claim channel capabilities passed on from core IBC. For a refresher on capabilities, check [the Overview section](../01-overview.md#capabilities). - -Here are the channel handshake callbacks that modules are expected to implement: - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `checkArguments` and `negotiateAppVersion` functions. - -```go -// Called by IBC Handler on MsgOpenInit -func (im IBCModule) OnChanOpenInit(ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) (string, error) { - // ... do custom initialization logic - - // Use above arguments to determine if we want to abort handshake - // Examples: - // - Abort if order == UNORDERED, - // - Abort if version is unsupported - if err := checkArguments(args); err != nil { - return "", err - } - - // OpenInit must claim the channelCapability that IBC passes into the callback - if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return "", err - } - - return version, nil -} - -// Called by IBC Handler on MsgOpenTry -func (im IBCModule) OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (string, error) { - // ... do custom initialization logic - - // Use above arguments to determine if we want to abort handshake - if err := checkArguments(args); err != nil { - return "", err - } - - // OpenTry must claim the channelCapability that IBC passes into the callback - if err := im.keeper.scopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return err - } - - // Construct application version - // IBC applications must return the appropriate application version - // This can be a simple string or it can be a complex version constructed - // from the counterpartyVersion and other arguments. - // The version returned will be the channel version used for both channel ends. - appVersion := negotiateAppVersion(counterpartyVersion, args) - - return appVersion, nil -} - -// Called by IBC Handler on MsgOpenAck -func (im IBCModule) OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyVersion string, -) error { - if counterpartyVersion != types.Version { - return sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: %s, expected %s", counterpartyVersion, types.Version) - } - - // do custom logic - - return nil -} - -// Called by IBC Handler on MsgOpenConfirm -func (im IBCModule) OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // do custom logic - - return nil -} -``` - -The channel closing handshake will also invoke module callbacks that can return errors to abort the closing handshake. Closing a channel is a 2-step handshake, the initiating chain calls `ChanCloseInit` and the finalizing chain calls `ChanCloseConfirm`. - -```go -// Called by IBC Handler on MsgCloseInit -func (im IBCModule) OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - // ... do custom finalization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} - -// Called by IBC Handler on MsgCloseConfirm -func (im IBCModule) OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // ... do custom finalization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} -``` - -### Channel handshake version negotiation - -Application modules are expected to verify versioning used during the channel handshake procedure. - -- `OnChanOpenInit` will verify that the relayer-chosen parameters - are valid and perform any custom `INIT` logic. - It may return an error if the chosen parameters are invalid - in which case the handshake is aborted. - If the provided version string is non-empty, `OnChanOpenInit` should return - the version string if valid or an error if the provided version is invalid. - **If the version string is empty, `OnChanOpenInit` is expected to - return a default version string representing the version(s) - it supports.** - If there is no default version string for the application, - it should return an error if the provided version is an empty string. -- `OnChanOpenTry` will verify the relayer-chosen parameters along with the - counterparty-chosen version string and perform custom `TRY` logic. - If the relayer-chosen parameters - are invalid, the callback must return an error to abort the handshake. - If the counterparty-chosen version is not compatible with this module's - supported versions, the callback must return an error to abort the handshake. - If the versions are compatible, the try callback must select the final version - string and return it to core IBC. - `OnChanOpenTry` may also perform custom initialization logic. -- `OnChanOpenAck` will error if the counterparty selected version string - is invalid and abort the handshake. It may also perform custom ACK logic. - -Versions must be strings but can implement any versioning structure. If your application plans to -have linear releases then semantic versioning is recommended. If your application plans to release -various features in between major releases then it is advised to use the same versioning scheme -as IBC. This versioning scheme specifies a version identifier and compatible feature set with -that identifier. Valid version selection includes selecting a compatible version identifier with -a subset of features supported by your application for that version. The struct used for this -scheme can be found in [03-connection/types](https://github.com/cosmos/ibc-go/blob/main/modules/core/03-connection/types/version.go#L16). - -Since the version type is a string, applications have the ability to do simple version verification -via string matching or they can use the already impelemented versioning system and pass the proto -encoded version into each handhshake call as necessary. - -ICS20 currently implements basic string matching with a single supported version. - -## Packet callbacks - -Just as IBC expects modules to implement callbacks for channel handshakes, it also expects modules to implement callbacks for handling the packet flow through a channel, as defined in the `IBCModule` interface. - -Once a module A and module B are connected to each other, relayers can start relaying packets and acknowledgements back and forth on the channel. - -![IBC packet flow diagram](./images/packet_flow.png) - -Briefly, a successful packet flow works as follows: - -1. module A sends a packet through the IBC module -2. the packet is received by module B -3. if module B writes an acknowledgement of the packet then module A will process the - acknowledgement -4. if the packet is not successfully received before the timeout, then module A processes the - packet's timeout. - -### Sending packets - -Modules **do not send packets through callbacks**, since the modules initiate the action of sending packets to the IBC module, as opposed to other parts of the packet flow where messages sent to the IBC -module must trigger execution on the port-bound module through the use of callbacks. Thus, to send a packet a module simply needs to call `SendPacket` on the `IBCChannelKeeper`. - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `EncodePacketData(customPacketData)` function. - -```go -// retrieve the dynamic capability for this channel -channelCap := scopedKeeper.GetCapability(ctx, channelCapName) -// Sending custom application packet data -data := EncodePacketData(customPacketData) -// Send packet to IBC, authenticating with channelCap -sequence, err := IBCChannelKeeper.SendPacket( - ctx, - channelCap, - sourcePort, - sourceChannel, - timeoutHeight, - timeoutTimestamp, - data, -) -``` - -:::warning -In order to prevent modules from sending packets on channels they do not own, IBC expects -modules to pass in the correct channel capability for the packet's source channel. -::: - -### Receiving packets - -To handle receiving packets, the module must implement the `OnRecvPacket` callback. This gets -invoked by the IBC module after the packet has been proved valid and correctly processed by the IBC -keepers. Thus, the `OnRecvPacket` callback only needs to worry about making the appropriate state -changes given the packet data without worrying about whether the packet is valid or not. - -Modules may return to the IBC handler an acknowledgement which implements the `Acknowledgement` interface. -The IBC handler will then commit this acknowledgement of the packet so that a relayer may relay the -acknowledgement back to the sender module. - -The state changes that occurred during this callback will only be written if: - -- the acknowledgement was successful as indicated by the `Success()` function of the acknowledgement -- if the acknowledgement returned is nil indicating that an asynchronous process is occurring - -NOTE: Applications which process asynchronous acknowledgements must handle reverting state changes -when appropriate. Any state changes that occurred during the `OnRecvPacket` callback will be written -for asynchronous acknowledgements. - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `DecodePacketData(packet.Data)` function. - -```go -func (im IBCModule) OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, -) ibcexported.Acknowledgement { - // Decode the packet data - packetData := DecodePacketData(packet.Data) - - // do application state changes based on packet data and return the acknowledgement - // NOTE: The acknowledgement will indicate to the IBC handler if the application - // state changes should be written via the `Success()` function. Application state - // changes are only written if the acknowledgement is successful or the acknowledgement - // returned is nil indicating that an asynchronous acknowledgement will occur. - ack := processPacket(ctx, packet, packetData) - - return ack -} -``` - -Reminder, the `Acknowledgement` interface: - -```go -// Acknowledgement defines the interface used to return -// acknowledgements in the OnRecvPacket callback. -type Acknowledgement interface { - Success() bool - Acknowledgement() []byte -} -``` - -### Acknowledging packets - -After a module writes an acknowledgement, a relayer can relay back the acknowledgement to the sender module. The sender module can -then process the acknowledgement using the `OnAcknowledgementPacket` callback. The contents of the -acknowledgement is entirely up to the modules on the channel (just like the packet data); however, it -may often contain information on whether the packet was successfully processed along -with some additional data that could be useful for remediation if the packet processing failed. - -Since the modules are responsible for agreeing on an encoding/decoding standard for packet data and -acknowledgements, IBC will pass in the acknowledgements as `[]byte` to this callback. The callback -is responsible for decoding the acknowledgement and processing it. - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `DecodeAcknowledgement(acknowledgments)` and `processAck(ack)` functions. - -```go -func (im IBCModule) OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, -) (*sdk.Result, error) { - // Decode acknowledgement - ack := DecodeAcknowledgement(acknowledgement) - - // process ack - res, err := processAck(ack) - return res, err -} -``` - -### Timeout packets - -If the timeout for a packet is reached before the packet is successfully received or the -counterparty channel end is closed before the packet is successfully received, then the receiving -chain can no longer process it. Thus, the sending chain must process the timeout using -`OnTimeoutPacket` to handle this situation. Again the IBC module will verify that the timeout is -indeed valid, so our module only needs to implement the state machine logic for what to do once a -timeout is reached and the packet can no longer be received. - -```go -func (im IBCModule) OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, -) (*sdk.Result, error) { - // do custom timeout logic -} -``` diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/03-bindports.md b/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/03-bindports.md deleted file mode 100644 index a57ec4c6000..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/03-bindports.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -title: Bind ports -sidebar_label: Bind ports -sidebar_position: 3 -slug: /ibc/apps/bindports ---- - -# Bind ports - -:::note Synopsis -Learn what changes to make to bind modules to their ports on initialization. -::: - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: -Currently, ports must be bound on app initialization. In order to bind modules to their respective ports on initialization, the following needs to be implemented: - -> Note that `portID` does not refer to a certain numerical ID, like `localhost:8080` with a `portID` 8080. Rather it refers to the application module the port binds. For IBC Modules built with the Cosmos SDK, it defaults to the module's name and for Cosmwasm contracts it defaults to the contract address. - -1. Add port ID to the `GenesisState` proto definition: - - ```protobuf - message GenesisState { - string port_id = 1; - // other fields - } - ``` - -1. Add port ID as a key to the module store: - - ```go - // x//types/keys.go - const ( - // ModuleName defines the IBC Module name - ModuleName = "moduleName" - - // Version defines the current version the IBC - // module supports - Version = "moduleVersion-1" - - // PortID is the default port id that module binds to - PortID = "portID" - - // ... - ) - ``` - -1. Add port ID to `x//types/genesis.go`: - - ```go - // in x//types/genesis.go - - // DefaultGenesisState returns a GenesisState with "transfer" as the default PortID. - func DefaultGenesisState() *GenesisState { - return &GenesisState{ - PortId: PortID, - // additional k-v fields - } - } - - // Validate performs basic genesis state validation returning an error upon any - // failure. - func (gs GenesisState) Validate() error { - if err := host.PortIdentifierValidator(gs.PortId); err != nil { - return err - } - //addtional validations - - return gs.Params.Validate() - } - ``` - -1. Bind to port(s) in the module keeper's `InitGenesis`: - - ```go - // InitGenesis initializes the ibc-module state and binds to PortID. - func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) { - k.SetPort(ctx, state.PortId) - - // ... - - // Only try to bind to port if it is not already bound, since we may already own - // port capability from capability InitGenesis - if !k.IsBound(ctx, state.PortId) { - // transfer module binds to the transfer port on InitChain - // and claims the returned capability - err := k.BindPort(ctx, state.PortId) - if err != nil { - panic(fmt.Sprintf("could not claim port capability: %v", err)) - } - } - - // ... - } - ``` - - With: - - ```go - // IsBound checks if the module is already bound to the desired port - func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { - _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) - return ok - } - - // BindPort defines a wrapper function for the port Keeper's function in - // order to expose it to module's InitGenesis function - func (k Keeper) BindPort(ctx sdk.Context, portID string) error { - cap := k.portKeeper.BindPort(ctx, portID) - return k.ClaimCapability(ctx, cap, host.PortPath(portID)) - } - ``` - - The module binds to the desired port(s) and returns the capabilities. - - In the above we find reference to keeper methods that wrap other keeper functionality, in the next section the keeper methods that need to be implemented will be defined. diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/04-keeper.md b/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/04-keeper.md deleted file mode 100644 index e359e014f2c..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/04-keeper.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: Keeper -sidebar_label: Keeper -sidebar_position: 4 -slug: /ibc/apps/keeper ---- - -# Keeper - -:::note Synopsis -Learn how to implement the IBC Module keeper. -::: - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: -In the previous sections, on channel handshake callbacks and port binding in `InitGenesis`, a reference was made to keeper methods that need to be implemented when creating a custom IBC module. Below is an overview of how to define an IBC module's keeper. - -> Note that some code has been left out for clarity, to get a full code overview, please refer to [the transfer module's keeper in the ibc-go repo](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/keeper.go). - -```go -// Keeper defines the IBC app module keeper -type Keeper struct { - storeKey sdk.StoreKey - cdc codec.BinaryCodec - paramSpace paramtypes.Subspace - - channelKeeper types.ChannelKeeper - portKeeper types.PortKeeper - scopedKeeper capabilitykeeper.ScopedKeeper - - // ... additional according to custom logic -} - -// NewKeeper creates a new IBC app module Keeper instance -func NewKeeper( - // args -) Keeper { - // ... - - return Keeper{ - cdc: cdc, - storeKey: key, - paramSpace: paramSpace, - - channelKeeper: channelKeeper, - portKeeper: portKeeper, - scopedKeeper: scopedKeeper, - - // ... additional according to custom logic - } -} - -// IsBound checks if the IBC app module is already bound to the desired port -func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { - _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) - return ok -} - -// BindPort defines a wrapper function for the port Keeper's function in -// order to expose it to module's InitGenesis function -func (k Keeper) BindPort(ctx sdk.Context, portID string) error { - cap := k.portKeeper.BindPort(ctx, portID) - return k.ClaimCapability(ctx, cap, host.PortPath(portID)) -} - -// GetPort returns the portID for the IBC app module. Used in ExportGenesis -func (k Keeper) GetPort(ctx sdk.Context) string { - store := ctx.KVStore(k.storeKey) - return string(store.Get(types.PortKey)) -} - -// SetPort sets the portID for the IBC app module. Used in InitGenesis -func (k Keeper) SetPort(ctx sdk.Context, portID string) { - store := ctx.KVStore(k.storeKey) - store.Set(types.PortKey, []byte(portID)) -} - -// AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function -func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool { - return k.scopedKeeper.AuthenticateCapability(ctx, cap, name) -} - -// ClaimCapability allows the IBC app module to claim a capability that core IBC -// passes to it -func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { - return k.scopedKeeper.ClaimCapability(ctx, cap, name) -} - -// ... additional according to custom logic -``` diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/05-packets_acks.md b/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/05-packets_acks.md deleted file mode 100644 index fc6070e6ea6..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/05-packets_acks.md +++ /dev/null @@ -1,118 +0,0 @@ ---- -title: Define packets and acks -sidebar_label: Define packets and acks -sidebar_position: 5 -slug: /ibc/apps/packets_acks ---- - -# Define packets and acks - -:::note Synopsis -Learn how to define custom packet and acknowledgement structs and how to encode and decode them. -::: - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: - -## Custom packets - -Modules connected by a channel must agree on what application data they are sending over the -channel, as well as how they will encode/decode it. This process is not specified by IBC as it is up -to each application module to determine how to implement this agreement. However, for most -applications this will happen as a version negotiation during the channel handshake. While more -complex version negotiation is possible to implement inside the channel opening handshake, a very -simple version negotation is implemented in the [ibc-transfer module](https://github.com/cosmos/ibc-go/tree/main/modules/apps/transfer/module.go). - -Thus, a module must define its custom packet data structure, along with a well-defined way to -encode and decode it to and from `[]byte`. - -```go -// Custom packet data defined in application module -type CustomPacketData struct { - // Custom fields ... -} - -EncodePacketData(packetData CustomPacketData) []byte { - // encode packetData to bytes -} - -DecodePacketData(encoded []byte) (CustomPacketData) { - // decode from bytes to packet data -} -``` - -> Note that the `CustomPacketData` struct is defined in the proto definition and then compiled by the protobuf compiler. - -Then a module must encode its packet data before sending it through IBC. - -```go -// retrieve the dynamic capability for this channel -channelCap := scopedKeeper.GetCapability(ctx, channelCapName) -// Sending custom application packet data -data := EncodePacketData(customPacketData) -// Send packet to IBC, authenticating with channelCap -sequence, err := IBCChannelKeeper.SendPacket( - ctx, - channelCap, - sourcePort, - sourceChannel, - timeoutHeight, - timeoutTimestamp, - data, -) -``` - -A module receiving a packet must decode the `PacketData` into a structure it expects so that it can -act on it. - -```go -// Receiving custom application packet data (in OnRecvPacket) -packetData := DecodePacketData(packet.Data) -// handle received custom packet data -``` - -## Acknowledgements - -Modules may commit an acknowledgement upon receiving and processing a packet in the case of synchronous packet processing. -In the case where a packet is processed at some later point after the packet has been received (asynchronous execution), the acknowledgement -will be written once the packet has been processed by the application which may be well after the packet receipt. - -NOTE: Most blockchain modules will want to use the synchronous execution model in which the module processes and writes the acknowledgement -for a packet as soon as it has been received from the IBC module. - -This acknowledgement can then be relayed back to the original sender chain, which can take action -depending on the contents of the acknowledgement. - -Just as packet data was opaque to IBC, acknowledgements are similarly opaque. Modules must pass and -receive acknowledegments with the IBC modules as byte strings. - -Thus, modules must agree on how to encode/decode acknowledgements. The process of creating an -acknowledgement struct along with encoding and decoding it, is very similar to the packet data -example above. [ICS 04](https://github.com/cosmos/ibc/blob/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope) -specifies a recommended format for acknowledgements. This acknowledgement type can be imported from -[channel types](https://github.com/cosmos/ibc-go/tree/main/modules/core/04-channel/types). - -While modules may choose arbitrary acknowledgement structs, a default acknowledgement types is provided by IBC [here](https://github.com/cosmos/ibc-go/blob/main/proto/ibc/core/channel/v1/channel.proto): - -```protobuf -// Acknowledgement is the recommended acknowledgement format to be used by -// app-specific protocols. -// NOTE: The field numbers 21 and 22 were explicitly chosen to avoid accidental -// conflicts with other protobuf message formats used for acknowledgements. -// The first byte of any message with this format will be the non-ASCII values -// `0xaa` (result) or `0xb2` (error). Implemented as defined by ICS: -// https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope -message Acknowledgement { - // response contains either a result or an error and must be non-empty - oneof response { - bytes result = 21; - string error = 22; - } -} -``` diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/06-routing.md b/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/06-routing.md deleted file mode 100644 index e11b3182e7f..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/06-routing.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Routing -sidebar_label: Routing -sidebar_position: 6 -slug: /ibc/apps/routing ---- - -# Routing - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: -:::note Synopsis -Learn how to hook a route to the IBC router for the custom IBC module. -::: - -As mentioned above, modules must implement the `IBCModule` interface (which contains both channel -handshake callbacks and packet handling callbacks). The concrete implementation of this interface -must be registered with the module name as a route on the IBC `Router`. - -```go -// app.go -func NewApp(...args) *App { -// ... - -// Create static IBC router, add module routes, then set and seal it -ibcRouter := port.NewRouter() - -ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule) -// Note: moduleCallbacks must implement IBCModule interface -ibcRouter.AddRoute(moduleName, moduleCallbacks) - -// Setting Router will finalize all routes by sealing router -// No more routes can be added -app.IBCKeeper.SetRouter(ibcRouter) - -// ... -} -``` diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/_category_.json b/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/_category_.json deleted file mode 100644 index 4561a95b84c..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Applications", - "position": 3, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/images/packet_flow.png b/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/images/packet_flow.png deleted file mode 100644 index db2d1d314b8..00000000000 Binary files a/docs/versioned_docs/version-v6.2.x/01-ibc/03-apps/images/packet_flow.png and /dev/null differ diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/04-middleware/01-develop.md b/docs/versioned_docs/version-v6.2.x/01-ibc/04-middleware/01-develop.md deleted file mode 100644 index cf376ee1ba8..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/04-middleware/01-develop.md +++ /dev/null @@ -1,453 +0,0 @@ ---- -title: IBC middleware -sidebar_label: IBC middleware -sidebar_position: 1 -slug: /ibc/middleware/develop ---- - -# IBC middleware - -:::note Synopsis -Learn how to write your own custom middleware to wrap an IBC application, and understand how to hook different middleware to IBC base applications to form different IBC application stacks -:::. - -This document serves as a guide for middleware developers who want to write their own middleware and for chain developers who want to use IBC middleware on their chains. - -IBC applications are designed to be self-contained modules that implement their own application-specific logic through a set of interfaces with the core IBC handlers. These core IBC handlers, in turn, are designed to enforce the correctness properties of IBC (transport, authentication, ordering) while delegating all application-specific handling to the IBC application modules. However, there are cases where some functionality may be desired by many applications, yet not appropriate to place in core IBC. - -Middleware allows developers to define the extensions as separate modules that can wrap over the base application. This middleware can thus perform its own custom logic, and pass data into the application so that it may run its logic without being aware of the middleware's existence. This allows both the application and the middleware to implement its own isolated logic while still being able to run as part of a single packet flow. - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC Integration](../02-integration.md) -- [IBC Application Developer Guide](../03-apps/01-apps.md) - -::: - -## Definitions - -`Middleware`: A self-contained module that sits between core IBC and an underlying IBC application during packet execution. All messages between core IBC and underlying application must flow through middleware, which may perform its own custom logic. - -`Underlying Application`: An underlying application is the application that is directly connected to the middleware in question. This underlying application may itself be middleware that is chained to a base application. - -`Base Application`: A base application is an IBC application that does not contain any middleware. It may be nested by 0 or multiple middleware to form an application stack. - -`Application Stack (or stack)`: A stack is the complete set of application logic (middleware(s) + base application) that gets connected to core IBC. A stack may be just a base application, or it may be a series of middlewares that nest a base application. - -## Create a custom IBC middleware - -IBC middleware will wrap over an underlying IBC application and sits between core IBC and the application. It has complete control in modifying any message coming from IBC to the application, and any message coming from the application to core IBC. Thus, middleware must be completely trusted by chain developers who wish to integrate them, however this gives them complete flexibility in modifying the application(s) they wrap. - -### Interfaces - -```go -// Middleware implements the ICS26 Module interface -type Middleware interface { - porttypes.IBCModule // middleware has acccess to an underlying application which may be wrapped by more middleware - ics4Wrapper: ICS4Wrapper // middleware has access to ICS4Wrapper which may be core IBC Channel Handler or a higher-level middleware that wraps this middleware. -} -``` - -```typescript -// This is implemented by ICS4 and all middleware that are wrapping base application. -// The base application will call `sendPacket` or `writeAcknowledgement` of the middleware directly above them -// which will call the next middleware until it reaches the core IBC handler. -type ICS4Wrapper interface { - SendPacket( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - data []byte, - ) (sequence uint64, err error) - - WriteAcknowledgement( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - packet exported.PacketI, - ack exported.Acknowledgement, - ) error - - GetAppVersion( - ctx sdk.Context, - portID, - channelID string, - ) (string, bool) -} -``` - -### Implement `IBCModule` interface and callbacks - -The `IBCModule` is a struct that implements the [ICS-26 interface (`porttypes.IBCModule`)](https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port/types/module.go#L11-L106). It is recommended to separate these callbacks into a separate file `ibc_module.go`. As will be mentioned in the [integration section](02-integration.md), this struct should be different than the struct that implements `AppModule` in case the middleware maintains its own internal state and processes separate SDK messages. - -The middleware must have access to the underlying application, and be called before during all ICS-26 callbacks. It may execute custom logic during these callbacks, and then call the underlying application's callback. Middleware **may** choose not to call the underlying application's callback at all. Though these should generally be limited to error cases. - -In the case where the IBC middleware expects to speak to a compatible IBC middleware on the counterparty chain, they must use the channel handshake to negotiate the middleware version without interfering in the version negotiation of the underlying application. - -Middleware accomplishes this by formatting the version in a JSON-encoded string containing the middleware version and the application version. The application version may as well be a JSON-encoded string, possibly including further middleware and app versions, if the application stack consists of multiple milddlewares wrapping a base application. The format of the version is specified in ICS-30 as the following: - -```json -{ - "": "", - "app_version": "" -} -``` - -The `` key in the JSON struct should be replaced by the actual name of the key for the corresponding middleware (e.g. `fee_version`). - -During the handshake callbacks, the middleware can unmarshal the version string and retrieve the middleware and application versions. It can do its negotiation logic on ``, and pass the `` to the underlying application. - -The middleware should simply pass the capability in the callback arguments along to the underlying application so that it may be claimed by the base application. The base application will then pass the capability up the stack in order to authenticate an outgoing packet/acknowledgement. - -In the case where the middleware wishes to send a packet or acknowledgment without the involvement of the underlying application, it should be given access to the same `scopedKeeper` as the base application so that it can retrieve the capabilities by itself. - -### Handshake callbacks - -#### `OnChanOpenInit` - -```go -func (im IBCModule) OnChanOpenInit( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) (string, error) { - if version != "" { - // try to unmarshal JSON-encoded version string and pass - // the app-specific version to app callback. - // otherwise, pass version directly to app callback. - metadata, err := Unmarshal(version) - if err != nil { - // Since it is valid for fee version to not be specified, - // the above middleware version may be for another middleware. - // Pass the entire version string onto the underlying application. - return im.app.OnChanOpenInit( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - version, - ) - } - else { - metadata = { - // set middleware version to default value - MiddlewareVersion: defaultMiddlewareVersion, - // allow application to return its default version - AppVersion: "", - } - } - - doCustomLogic() - - // if the version string is empty, OnChanOpenInit is expected to return - // a default version string representing the version(s) it supports - appVersion, err := im.app.OnChanOpenInit( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - metadata.AppVersion, // note we only pass app version here - ) - if err != nil { - return "", err - } - - version := constructVersion(metadata.MiddlewareVersion, appVersion) - - return version, nil -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L34-L82) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnChanOpenTry` - -```go -func OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (string, error) { - // try to unmarshal JSON-encoded version string and pass - // the app-specific version to app callback. - // otherwise, pass version directly to app callback. - cpMetadata, err := Unmarshal(counterpartyVersion) - if err != nil { - return app.OnChanOpenTry( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - counterpartyVersion, - ) - } - - doCustomLogic() - - // Call the underlying application's OnChanOpenTry callback. - // The try callback must select the final app-specific version string and return it. - appVersion, err := app.OnChanOpenTry( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - cpMetadata.AppVersion, // note we only pass counterparty app version here - ) - if err != nil { - return "", err - } - - // negotiate final middleware version - middlewareVersion := negotiateMiddlewareVersion(cpMetadata.MiddlewareVersion) - version := constructVersion(middlewareVersion, appVersion) - - return version, nil -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L84-L124) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnChanOpenAck` - -```go -func OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyChannelID string, - counterpartyVersion string, -) error { - // try to unmarshal JSON-encoded version string and pass - // the app-specific version to app callback. - // otherwise, pass version directly to app callback. - cpMetadata, err = UnmarshalJSON(counterpartyVersion) - if err != nil { - return app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) - } - - if !isCompatible(cpMetadata.MiddlewareVersion) { - return error - } - doCustomLogic() - - // call the underlying application's OnChanOpenTry callback - return app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, cpMetadata.AppVersion) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L126-L152) an example implementation of this callback for the ICS29 Fee Middleware module. - -### `OnChanOpenConfirm` - -```go -func OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - doCustomLogic() - - return app.OnChanOpenConfirm(ctx, portID, channelID) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L154-L162) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnChanCloseInit` - -```go -func OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - doCustomLogic() - - return app.OnChanCloseInit(ctx, portID, channelID) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L164-L187) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnChanCloseConfirm` - -```go -func OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - doCustomLogic() - - return app.OnChanCloseConfirm(ctx, portID, channelID) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L189-L212) an example implementation of this callback for the ICS29 Fee Middleware module. - -**NOTE**: Middleware that does not need to negotiate with a counterparty middleware on the remote stack will not implement the version unmarshalling and negotiation, and will simply perform its own custom logic on the callbacks without relying on the counterparty behaving similarly. - -### Packet callbacks - -The packet callbacks just like the handshake callbacks wrap the application's packet callbacks. The packet callbacks are where the middleware performs most of its custom logic. The middleware may read the packet flow data and perform some additional packet handling, or it may modify the incoming data before it reaches the underlying application. This enables a wide degree of usecases, as a simple base application like token-transfer can be transformed for a variety of usecases by combining it with custom middleware. - -#### `OnRecvPacket` - -```go -func OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) ibcexported.Acknowledgement { - doCustomLogic(packet) - - ack := app.OnRecvPacket(ctx, packet, relayer) - - doCustomLogic(ack) // middleware may modify outgoing ack - return ack -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L214-L237) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnAcknowledgementPacket` - -```go -func OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - relayer sdk.AccAddress, -) error { - doCustomLogic(packet, ack) - - return app.OnAcknowledgementPacket(ctx, packet, ack, relayer) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L239-L292) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnTimeoutPacket` - -```go -func OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) error { - doCustomLogic(packet) - - return app.OnTimeoutPacket(ctx, packet, relayer) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L294-L334) an example implementation of this callback for the ICS29 Fee Middleware module. - -### ICS-4 wrappers - -Middleware must also wrap ICS-4 so that any communication from the application to the `channelKeeper` goes through the middleware first. Similar to the packet callbacks, the middleware may modify outgoing acknowledgements and packets in any way it wishes. - -#### `SendPacket` - -```go -func SendPacket( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - appData []byte, -) { - // middleware may modify data - data = doCustomLogic(appData) - - return ics4Keeper.SendPacket( - ctx, - chanCap, - sourcePort, - sourceChannel, - timeoutHeight, - timeoutTimestamp, - data, - ) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L336-L343) an example implementation of this function for the ICS29 Fee Middleware module. - -#### `WriteAcknowledgement` - -```go -// only called for async acks -func WriteAcknowledgement( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - packet exported.PacketI, - ack exported.Acknowledgement, -) { - // middleware may modify acknowledgement - ack_bytes = doCustomLogic(ack) - - return ics4Keeper.WriteAcknowledgement(packet, ack_bytes) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L345-L353) an example implementation of this function for the ICS29 Fee Middleware module. - -#### `GetAppVersion` - -```go -// middleware must return the underlying application version -func GetAppVersion( - ctx sdk.Context, - portID, - channelID string, -) (string, bool) { - version, found := ics4Keeper.GetAppVersion(ctx, portID, channelID) - if !found { - return "", false - } - - if !MiddlewareEnabled { - return version, true - } - - // unwrap channel version - metadata, err := Unmarshal(version) - if err != nil { - panic(fmt.Errof("unable to unmarshal version: %w", err)) - } - - return metadata.AppVersion, true -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L355-L358) an example implementation of this function for the ICS29 Fee Middleware module. diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/04-middleware/02-integration.md b/docs/versioned_docs/version-v6.2.x/01-ibc/04-middleware/02-integration.md deleted file mode 100644 index 7bda98b5f88..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/04-middleware/02-integration.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: Integrating IBC middleware into a chain -sidebar_label: Integrating IBC middleware into a chain -sidebar_position: 2 -slug: /ibc/middleware/integration ---- - - -# Integrating IBC middleware into a chain - -Learn how to integrate IBC middleware(s) with a base application to your chain. The following document only applies for Cosmos SDK chains. - -If the middleware is maintaining its own state and/or processing SDK messages, then it should create and register its SDK module **only once** with the module manager in `app.go`. - -All middleware must be connected to the IBC router and wrap over an underlying base IBC application. An IBC application may be wrapped by many layers of middleware, only the top layer middleware should be hooked to the IBC router, with all underlying middlewares and application getting wrapped by it. - -The order of middleware **matters**, function calls from IBC to the application travel from top-level middleware to the bottom middleware and then to the application. Function calls from the application to IBC goes through the bottom middleware in order to the top middleware and then to core IBC handlers. Thus the same set of middleware put in different orders may produce different effects. - -## Example integration - -```go -// app.go - -// middleware 1 and middleware 3 are stateful middleware, -// perhaps implementing separate sdk.Msg and Handlers -mw1Keeper := mw1.NewKeeper(storeKey1) -mw3Keeper := mw3.NewKeeper(storeKey3) - -// Only create App Module **once** and register in app module -// if the module maintains independent state and/or processes sdk.Msgs -app.moduleManager = module.NewManager( - ... - mw1.NewAppModule(mw1Keeper), - mw3.NewAppModule(mw3Keeper), - transfer.NewAppModule(transferKeeper), - custom.NewAppModule(customKeeper) -) - -mw1IBCModule := mw1.NewIBCModule(mw1Keeper) -mw2IBCModule := mw2.NewIBCModule() // middleware2 is stateless middleware -mw3IBCModule := mw3.NewIBCModule(mw3Keeper) - -scopedKeeperTransfer := capabilityKeeper.NewScopedKeeper("transfer") -scopedKeeperCustom1 := capabilityKeeper.NewScopedKeeper("custom1") -scopedKeeperCustom2 := capabilityKeeper.NewScopedKeeper("custom2") - -// NOTE: IBC Modules may be initialized any number of times provided they use a separate -// scopedKeeper and underlying port. - -// initialize base IBC applications -// if you want to create two different stacks with the same base application, -// they must be given different scopedKeepers and assigned different ports. -transferIBCModule := transfer.NewIBCModule(transferKeeper) -customIBCModule1 := custom.NewIBCModule(customKeeper, "portCustom1") -customIBCModule2 := custom.NewIBCModule(customKeeper, "portCustom2") - -// create IBC stacks by combining middleware with base application -// NOTE: since middleware2 is stateless it does not require a Keeper -// stack 1 contains mw1 -> mw3 -> transfer -stack1 := mw1.NewIBCMiddleware(mw3.NewIBCMiddleware(transferIBCModule, mw3Keeper), mw1Keeper) -// stack 2 contains mw3 -> mw2 -> custom1 -stack2 := mw3.NewIBCMiddleware(mw2.NewIBCMiddleware(customIBCModule1), mw3Keeper) -// stack 3 contains mw2 -> mw1 -> custom2 -stack3 := mw2.NewIBCMiddleware(mw1.NewIBCMiddleware(customIBCModule2, mw1Keeper)) - -// associate each stack with the moduleName provided by the underlying scopedKeeper -ibcRouter := porttypes.NewRouter() -ibcRouter.AddRoute("transfer", stack1) -ibcRouter.AddRoute("custom1", stack2) -ibcRouter.AddRoute("custom2", stack3) -app.IBCKeeper.SetRouter(ibcRouter) -``` diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/04-middleware/_category_.json b/docs/versioned_docs/version-v6.2.x/01-ibc/04-middleware/_category_.json deleted file mode 100644 index 6596fe16c13..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/04-middleware/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Middleware", - "position": 4, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/05-upgrades/00-intro.md b/docs/versioned_docs/version-v6.2.x/01-ibc/05-upgrades/00-intro.md deleted file mode 100644 index 3ff92aba64f..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/05-upgrades/00-intro.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: Upgrading IBC Chains Overview -sidebar_label: Overview -sidebar_position: 0 -slug: /ibc/upgrades/intro ---- - -### Upgrading IBC Chains Overview - -This directory contains information on how to upgrade an IBC chain without breaking counterparty clients and connections. - -IBC-connnected chains must be able to upgrade without breaking connections to other chains. Otherwise there would be a massive disincentive towards upgrading and disrupting high-value IBC connections, thus preventing chains in the IBC ecosystem from evolving and improving. Many chain upgrades may be irrelevant to IBC, however some upgrades could potentially break counterparty clients if not handled correctly. Thus, any IBC chain that wishes to perform a IBC-client-breaking upgrade must perform an IBC upgrade in order to allow counterparty clients to securely upgrade to the new light client. - -1. The [quick-guide](./01-quick-guide.md) describes how IBC-connected chains can perform client-breaking upgrades and how relayers can securely upgrade counterparty clients using the SDK. -2. The [developer-guide](./02-developer-guide.md) is a guide for developers intending to develop IBC client implementations with upgrade functionality. diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/05-upgrades/01-quick-guide.md b/docs/versioned_docs/version-v6.2.x/01-ibc/05-upgrades/01-quick-guide.md deleted file mode 100644 index c78a3ac6f70..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/05-upgrades/01-quick-guide.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: How to Upgrade IBC Chains and their Clients -sidebar_label: How to Upgrade IBC Chains and their Clients -sidebar_position: 1 -slug: /ibc/upgrades/quick-guide ---- - - -# How to Upgrade IBC Chains and their Clients - -:::note Synopsis -Learn how to upgrade your chain and counterparty clients. -::: - -The information in this doc for upgrading chains is relevant to SDK chains. However, the guide for counterparty clients is relevant to any Tendermint client that enables upgrades. - -## IBC Client Breaking Upgrades - -IBC-connected chains must perform an IBC upgrade if their upgrade will break counterparty IBC clients. The current IBC protocol supports upgrading tendermint chains for a specific subset of IBC-client-breaking upgrades. Here is the exhaustive list of IBC client-breaking upgrades and whether the IBC protocol currently supports such upgrades. - -IBC currently does **NOT** support unplanned upgrades. All of the following upgrades must be planned and committed to in advance by the upgrading chain, in order for counterparty clients to maintain their connections securely. - -Note: Since upgrades are only implemented for Tendermint clients, this doc only discusses upgrades on Tendermint chains that would break counterparty IBC Tendermint Clients. - -1. Changing the Chain-ID: **Supported** -2. Changing the UnbondingPeriod: **Partially Supported**, chains may increase the unbonding period with no issues. However, decreasing the unbonding period may irreversibly break some counterparty clients. Thus, it is **not recommended** that chains reduce the unbonding period. -3. Changing the height (resetting to 0): **Supported**, so long as chains remember to increment the revision number in their chain-id. -4. Changing the ProofSpecs: **Supported**, this should be changed if the proof structure needed to verify IBC proofs is changed across the upgrade. Ex: Switching from an IAVL store, to a SimpleTree Store -5. Changing the UpgradePath: **Supported**, this might involve changing the key under which upgraded clients and consensus states are stored in the upgrade store, or even migrating the upgrade store itself. -6. Migrating the IBC store: **Unsupported**, as the IBC store location is negotiated by the connection. -7. Upgrading to a backwards compatible version of IBC: Supported -8. Upgrading to a non-backwards compatible version of IBC: **Unsupported**, as IBC version is negotiated on connection handshake. -9. Changing the Tendermint LightClient algorithm: **Partially Supported**. Changes to the light client algorithm that do not change the ClientState or ConsensusState struct may be supported, provided that the counterparty is also upgraded to support the new light client algorithm. Changes that require updating the ClientState and ConsensusState structs themselves are theoretically possible by providing a path to translate an older ClientState struct into the new ClientState struct; however this is not currently implemented. - -### Step-by-Step Upgrade Process for SDK chains - -If the IBC-connected chain is conducting an upgrade that will break counterparty clients, it must ensure that the upgrade is first supported by IBC using the list above and then execute the upgrade process described below in order to prevent counterparty clients from breaking. - -1. Create a 02-client [`UpgradeProposal`](https://github.com/cosmos/ibc-go/blob/v6.2.0/proto/ibc/core/client/v1/client.proto#L58-L77) with an `UpgradePlan` and a new IBC ClientState in the `UpgradedClientState` field. Note that the `UpgradePlan` must specify an upgrade height **only** (no upgrade time), and the `ClientState` should only include the fields common to all valid clients and zero out any client-customizable fields (such as TrustingPeriod). -2. Vote on and pass the `UpgradeProposal` - -Upon the `UpgradeProposal` passing, the upgrade module will commit the UpgradedClient under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedClient`. On the block right before the upgrade height, the upgrade module will also commit an initial consensus state for the next chain under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedConsState`. - -Once the chain reaches the upgrade height and halts, a relayer can upgrade the counterparty clients to the last block of the old chain. They can then submit the proofs of the `UpgradedClient` and `UpgradedConsensusState` against this last block and upgrade the counterparty client. - -### Step-by-Step Upgrade Process for Relayers Upgrading Counterparty Clients - -Once the upgrading chain has committed to upgrading, relayers must wait till the chain halts at the upgrade height before upgrading counterparty clients. This is because chains may reschedule or cancel upgrade plans before they occur. Thus, relayers must wait till the chain reaches the upgrade height and halts before they can be sure the upgrade will take place. - -Thus, the upgrade process for relayers trying to upgrade the counterparty clients is as follows: - -1. Wait for the upgrading chain to reach the upgrade height and halt -2. Query a full node for the proofs of `UpgradedClient` and `UpgradedConsensusState` at the last height of the old chain. -3. Update the counterparty client to the last height of the old chain using the `UpdateClient` msg. -4. Submit an `UpgradeClient` msg to the counterparty chain with the `UpgradedClient`, `UpgradedConsensusState` and their respective proofs. -5. Submit an `UpdateClient` msg to the counterparty chain with a header from the new upgraded chain. - -The Tendermint client on the counterparty chain will verify that the upgrading chain did indeed commit to the upgraded client and upgraded consensus state at the upgrade height (since the upgrade height is included in the key). If the proofs are verified against the upgrade height, then the client will upgrade to the new client while retaining all of its client-customized fields. Thus, it will retain its old TrustingPeriod, TrustLevel, MaxClockDrift, etc; while adopting the new chain-specified fields such as UnbondingPeriod, ChainId, UpgradePath, etc. Note, this can lead to an invalid client since the old client-chosen fields may no longer be valid given the new chain-chosen fields. Upgrading chains should try to avoid these situations by not altering parameters that can break old clients. For an example, see the UnbondingPeriod example in the supported upgrades section. - -The upgraded consensus state will serve purely as a basis of trust for future `UpdateClientMsgs` and will not contain a consensus root to perform proof verification against. Thus, relayers must submit an `UpdateClientMsg` with a header from the new chain so that the connection can be used for proof verification again. diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/05-upgrades/02-developer-guide.md b/docs/versioned_docs/version-v6.2.x/01-ibc/05-upgrades/02-developer-guide.md deleted file mode 100644 index 0321bdbe594..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/05-upgrades/02-developer-guide.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: IBC Client Developer Guide to Upgrades -sidebar_label: IBC Client Developer Guide to Upgrades -sidebar_position: 2 -slug: /ibc/upgrades/developer-guide ---- - - -# IBC Client Developer Guide to Upgrades - -:::note Synopsis -Learn how to implement upgrade functionality for your custom IBC client. -::: - -As mentioned in the [README](./00-intro.md), it is vital that high-value IBC clients can upgrade along with their underlying chains to avoid disruption to the IBC ecosystem. Thus, IBC client developers will want to implement upgrade functionality to enable clients to maintain connections and channels even across chain upgrades. - -The IBC protocol allows client implementations to provide a path to upgrading clients given the upgraded client state, upgraded consensus state and proofs for each. - -```go -// Upgrade functions -// NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last -// height committed by the current revision. Clients are responsible for ensuring that the planned last -// height of the current revision is somehow encoded in the proof verification process. -// This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty -// may be cancelled or modified before the last planned height. -VerifyUpgradeAndUpdateState( - ctx sdk.Context, - cdc codec.BinaryCodec, - store sdk.KVStore, - newClient ClientState, - newConsState ConsensusState, - proofUpgradeClient, - proofUpgradeConsState []byte, -) (upgradedClient ClientState, upgradedConsensus ConsensusState, err error) -``` - -Note that the clients should have prior knowledge of the merkle path that the upgraded client and upgraded consensus states will use. The height at which the upgrade has occurred should also be encoded in the proof. The Tendermint client implementation accomplishes this by including an `UpgradePath` in the ClientState itself, which is used along with the upgrade height to construct the merkle path under which the client state and consensus state are committed. - -Developers must ensure that the `UpgradeClientMsg` does not pass until the last height of the old chain has been committed, and after the chain upgrades, the `UpgradeClientMsg` should pass once and only once on all counterparty clients. - -Developers must ensure that the new client adopts all of the new Client parameters that must be uniform across every valid light client of a chain (chain-chosen parameters), while maintaining the Client parameters that are customizable by each individual client (client-chosen parameters) from the previous version of the client. - -Upgrades must adhere to the IBC Security Model. IBC does not rely on the assumption of honest relayers for correctness. Thus users should not have to rely on relayers to maintain client correctness and security (though honest relayers must exist to maintain relayer liveness). While relayers may choose any set of client parameters while creating a new `ClientState`, this still holds under the security model since users can always choose a relayer-created client that suits their security and correctness needs or create a Client with their desired parameters if no such client exists. - -However, when upgrading an existing client, one must keep in mind that there are already many users who depend on this client's particular parameters. We cannot give the upgrading relayer free choice over these parameters once they have already been chosen. This would violate the security model since users who rely on the client would have to rely on the upgrading relayer to maintain the same level of security. Thus, developers must make sure that their upgrade mechanism allows clients to upgrade the chain-specified parameters whenever a chain upgrade changes these parameters (examples in the Tendermint client include `UnbondingPeriod`, `TrustingPeriod`, `ChainID`, `UpgradePath`, etc.), while ensuring that the relayer submitting the `UpgradeClientMsg` cannot alter the client-chosen parameters that the users are relying upon (examples in Tendermint client include `TrustLevel`, `MaxClockDrift`, etc). - -Developers should maintain the distinction between Client parameters that are uniform across every valid light client of a chain (chain-chosen parameters), and Client parameters that are customizable by each individual client (client-chosen parameters); since this distinction is necessary to implement the `ZeroCustomFields` method in the `ClientState` interface: - -```go -// Utility function that zeroes out any client customizable fields in client state -// Ledger enforced fields are maintained while all custom fields are zero values -// Used to verify upgrades -ZeroCustomFields() ClientState -``` - -Counterparty clients can upgrade securely by using all of the chain-chosen parameters from the chain-committed `UpgradedClient` and preserving all of the old client-chosen parameters. This enables chains to securely upgrade without relying on an honest relayer, however it can in some cases lead to an invalid final `ClientState` if the new chain-chosen parameters clash with the old client-chosen parameter. This can happen in the Tendermint client case if the upgrading chain lowers the `UnbondingPeriod` (chain-chosen) to a duration below that of a counterparty client's `TrustingPeriod` (client-chosen). Such cases should be clearly documented by developers, so that chains know which upgrades should be avoided to prevent this problem. The final upgraded client should also be validated in `VerifyUpgradeAndUpdateState` before returning to ensure that the client does not upgrade to an invalid `ClientState`. diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/05-upgrades/03-genesis-restart.md b/docs/versioned_docs/version-v6.2.x/01-ibc/05-upgrades/03-genesis-restart.md deleted file mode 100644 index f566ad7bab3..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/05-upgrades/03-genesis-restart.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: Genesis Restart Upgrades -sidebar_label: Genesis Restart Upgrades -sidebar_position: 3 -slug: /ibc/upgrades/genesis-restart ---- - - -# Genesis Restart Upgrades - -:::note Synopsis -Learn how to upgrade your chain and counterparty clients using genesis restarts. -::: - -**NOTE**: Regular genesis restarts are currently unsupported by relayers! - -## IBC Client Breaking Upgrades - -IBC client breaking upgrades are possible using genesis restarts. -It is highly recommended to use the in-place migrations instead of a genesis restart. -Genesis restarts should be used sparingly and as backup plans. - -Genesis restarts still require the usage of an IBC upgrade proposal in order to correctly upgrade counterparty clients. - -### Step-by-Step Upgrade Process for SDK Chains - -If the IBC-connected chain is conducting an upgrade that will break counterparty clients, it must ensure that the upgrade is first supported by IBC using the [IBC Client Breaking Upgrade List](./01-quick-guide.md#ibc-client-breaking-upgrades) and then execute the upgrade process described below in order to prevent counterparty clients from breaking. - -1. Create a 02-client [`UpgradeProposal`](https://github.com/cosmos/ibc-go/blob/v6.2.0/proto/ibc/core/client/v1/client.proto#L58-L77) with an `UpgradePlan` and a new IBC ClientState in the `UpgradedClientState` field. Note that the `UpgradePlan` must specify an upgrade height **only** (no upgrade time), and the `ClientState` should only include the fields common to all valid clients and zero out any client-customizable fields (such as TrustingPeriod). -2. Vote on and pass the `UpgradeProposal` -3. Halt the node after successful upgrade. -4. Export the genesis file. -5. Swap to the new binary. -6. Run migrations on the genesis file. -7. Remove the `UpgradeProposal` plan from the genesis file. This may be done by migrations. -8. Change desired chain-specific fields (chain id, unbonding period, etc). This may be done by migrations. -8. Reset the node's data. -9. Start the chain. - -Upon the `UpgradeProposal` passing, the upgrade module will commit the UpgradedClient under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedClient`. On the block right before the upgrade height, the upgrade module will also commit an initial consensus state for the next chain under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedConsState`. - -Once the chain reaches the upgrade height and halts, a relayer can upgrade the counterparty clients to the last block of the old chain. They can then submit the proofs of the `UpgradedClient` and `UpgradedConsensusState` against this last block and upgrade the counterparty client. - -#### Step-by-Step Upgrade Process for Relayers Upgrading Counterparty Clients - -These steps are identical to the regular [IBC client breaking upgrade process](./01-quick-guide.md#step-by-step-upgrade-process-for-relayers-upgrading-counterparty-clients). - -### Non-IBC Client Breaking Upgrades - -While ibc-go supports genesis restarts which do not break IBC clients, relayers do not support this upgrade path. -Here is a tracking issue on [Hermes](https://github.com/informalsystems/ibc-rs/issues/1152). -Please do not attempt a regular genesis restarts unless you have a tool to update counterparty clients correctly. diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/05-upgrades/_category_.json b/docs/versioned_docs/version-v6.2.x/01-ibc/05-upgrades/_category_.json deleted file mode 100644 index 7c3191d2ce9..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/05-upgrades/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Upgrades", - "position": 5, - "link": { "type": "doc", "id": "intro" } -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/06-proposals.md b/docs/versioned_docs/version-v6.2.x/01-ibc/06-proposals.md deleted file mode 100644 index 39c0491a6aa..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/06-proposals.md +++ /dev/null @@ -1,130 +0,0 @@ ---- -title: Governance Proposals -sidebar_label: Governance Proposals -sidebar_position: 6 -slug: /ibc/proposals ---- - -# Governance Proposals - -In uncommon situations, a highly valued client may become frozen due to uncontrollable -circumstances. A highly valued client might have hundreds of channels being actively used. -Some of those channels might have a significant amount of locked tokens used for ICS 20. - -If the one third of the validator set of the chain the client represents decides to collude, -they can sign off on two valid but conflicting headers each signed by the other one third -of the honest validator set. The light client can now be updated with two valid, but conflicting -headers at the same height. The light client cannot know which header is trustworthy and therefore -evidence of such misbehaviour is likely to be submitted resulting in a frozen light client. - -Frozen light clients cannot be updated under any circumstance except via a governance proposal. -Since a quorum of validators can sign arbitrary state roots which may not be valid executions -of the state machine, a governance proposal has been added to ease the complexity of unfreezing -or updating clients which have become "stuck". Without this mechanism, validator sets would need -to construct a state root to unfreeze the client. Unfreezing clients, re-enables all of the channels -built upon that client. This may result in recovery of otherwise lost funds. - -Tendermint light clients may become expired if the trusting period has passed since their -last update. This may occur if relayers stop submitting headers to update the clients. - -An unplanned upgrade by the counterparty chain may also result in expired clients. If the counterparty -chain undergoes an unplanned upgrade, there may be no commitment to that upgrade signed by the validator -set before the chain-id changes. In this situation, the validator set of the last valid update for the -light client is never expected to produce another valid header since the chain-id has changed, which will -ultimately lead the on-chain light client to become expired. - -In the case that a highly valued light client is frozen, expired, or rendered non-updateable, a -governance proposal may be submitted to update this client, known as the subject client. The -proposal includes the client identifier for the subject and the client identifier for a substitute -client. Light client implementations may implement custom updating logic, but in most cases, -the subject will be updated to the latest consensus state of the substitute client, if the proposal passes. -The substitute client is used as a "stand in" while the subject is on trial. It is best practice to create -a substitute client *after* the subject has become frozen to avoid the substitute from also becoming frozen. -An active substitute client allows headers to be submitted during the voting period to prevent accidental expiry -once the proposal passes. - -## How to recover an expired client with a governance proposal - -See also the relevant documentation: [ADR-026, IBC client recovery mechanisms](/architecture/adr-026-ibc-client-recovery-mechanisms) - -> **Who is this information for?** -> Although technically anyone can submit the governance proposal to recover an expired client, often it will be **relayer operators** (at least coordinating the submission). - -### Preconditions - -- The chain is updated with ibc-go >= v1.1.0. -- There exists an active client (with a known client identifier) for the same counterparty chain as the expired client. -- The governance deposit. - -## Steps - -### Step 1 - -Check if the client is attached to the expected `chain-id`. For example, for an expired Tendermint client representing the Akash chain the client state looks like this on querying the client state: - -```text -{ - client_id: 07-tendermint-146 - client_state: - '@type': /ibc.lightclients.tendermint.v1.ClientState - allow_update_after_expiry: true - allow_update_after_misbehaviour: true - chain_id: akashnet-2 -} -``` - -The client is attached to the expected Akash `chain-id`. Note that although the parameters (`allow_update_after_expiry` and `allow_update_after_misbehaviour`) exist to signal intent, these parameters have been deprecated and will not enforce any checks on the revival of client. See ADR-026 for more context on this deprecation. - -### Step 2 - -If the chain has been updated to ibc-go >= v1.1.0, anyone can submit the governance proposal to recover the client by executing this via CLI. - -> Note that the Cosmos SDK has updated how governance proposals are submitted in SDK v0.46, now requiring to pass a .json proposal file - -- From SDK v0.46.x onwards - - ```bash - tx gov submit-proposal [path-to-proposal-json] - ``` - - where `proposal.json` contains: - - ```json - { - "messages": [ - { - "@type": "/ibc.core.client.v1.ClientUpdateProposal", - "title": "title_string", - "description": "description_string", - "subject_client_id": "expired_client_id_string", - "substitute_client_id": "active_client_id_string" - } - ], - "metadata": "", - "deposit": "10stake" - } - ``` - - Alternatively there's a legacy command (that is no longer recommended though): - - ```bash - tx gov submit-legacy-proposal update-client - ``` - -- Until SDK v0.45.x - - ```bash - tx gov submit-proposal update-client - ``` - -The `` identifier is the proposed client to be updated. This client must be either frozen or expired. - -The `` represents a substitute client. It carries all the state for the client which may be updated. It must have identical client and chain parameters to the client which may be updated (except for latest height, frozen height, and chain ID). It should be continually updated during the voting period. - -After this, all that remains is deciding who funds the governance deposit and ensuring the governance proposal passes. If it does, the client on trial will be updated to the latest state of the substitute. - -## Important considerations - -Please note that from v1.0.0 of ibc-go it will not be allowed for transactions to go to expired clients anymore, so please update to at least this version to prevent similar issues in the future. - -Please also note that if the client on the other end of the transaction is also expired, that client will also need to update. This process updates only one client. diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/07-relayer.md b/docs/versioned_docs/version-v6.2.x/01-ibc/07-relayer.md deleted file mode 100644 index f40e9e671a3..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/07-relayer.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: Relayer -sidebar_label: Relayer -sidebar_position: 7 -slug: /ibc/relayer ---- - -# Relayer - -:::note - -## Pre-requisite readings - -- [IBC Overview](01-overview.md) -- [Events](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/advanced/08-events.md) - -::: - -## Events - -Events are emitted for every transaction processed by the base application to indicate the execution -of some logic clients may want to be aware of. This is extremely useful when relaying IBC packets. -Any message that uses IBC will emit events for the corresponding TAO logic executed as defined in -the [IBC events document](/events/events). - -In the SDK, it can be assumed that for every message there is an event emitted with the type `message`, -attribute key `action`, and an attribute value representing the type of message sent -(`channel_open_init` would be the attribute value for `MsgChannelOpenInit`). If a relayer queries -for transaction events, it can split message events using this event Type/Attribute Key pair. - -The Event Type `message` with the Attribute Key `module` may be emitted multiple times for a single -message due to application callbacks. It can be assumed that any TAO logic executed will result in -a module event emission with the attribute value `ibc_` (02-client emits `ibc_client`). - -### Subscribing with Tendermint - -Calling the Tendermint RPC method `Subscribe` via [Tendermint's Websocket](https://docs.tendermint.com/main/rpc/) will return events using -Tendermint's internal representation of them. Instead of receiving back a list of events as they -were emitted, Tendermint will return the type `map[string][]string` which maps a string in the -form `.` to `attribute_value`. This causes extraction of the event -ordering to be non-trivial, but still possible. - -A relayer should use the `message.action` key to extract the number of messages in the transaction -and the type of IBC transactions sent. For every IBC transaction within the string array for -`message.action`, the necessary information should be extracted from the other event fields. If -`send_packet` appears at index 2 in the value for `message.action`, a relayer will need to use the -value at index 2 of the key `send_packet.packet_sequence`. This process should be repeated for each -piece of information needed to relay a packet. - -## Example Implementations - -- [Golang Relayer](https://github.com/cosmos/relayer) -- [Hermes](https://github.com/informalsystems/ibc-rs/tree/master/crates/relayer) diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/08-proto-docs.md b/docs/versioned_docs/version-v6.2.x/01-ibc/08-proto-docs.md deleted file mode 100644 index 1154ff03a79..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/08-proto-docs.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: Protobuf Documentation -sidebar_label: Protobuf Documentation -sidebar_position: 8 -slug: /ibc/proto-docs ---- - -# Protobuf documentation - -See [ibc-go v6.2.x Buf Protobuf documentation](https://github.com/cosmos/ibc-go/blob/release/v6.2.x/docs/ibc/proto-docs.md). diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/09-roadmap.md b/docs/versioned_docs/version-v6.2.x/01-ibc/09-roadmap.md deleted file mode 100644 index cf7f7e6fafe..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/09-roadmap.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: Roadmap -sidebar_label: Roadmap -sidebar_position: 9 -slug: /roadmap/roadmap ---- - -# Roadmap ibc-go - -*Lastest update: July 7, 2022* - -This document endeavours to inform the wider IBC community about plans and priorities for work on ibc-go by the team at Interchain GmbH. It is intended to broadly inform all users of ibc-go, including developers and operators of IBC, relayer, chain and wallet applications. - -This roadmap should be read as a high-level guide, rather than a commitment to schedules and deliverables. The degree of specificity is inversely proportional to the timeline. We will update this document periodically to reflect the status and plans. - -## Q3 - 2022 - -At a high level we will focus on: - -### Features - -- Releasing [v4.0.0](https://github.com/cosmos/ibc-go/milestone/26), which includes the ICS-29 Fee Middleware module. -- Finishing and releasing the [refactoring of 02-client](https://github.com/cosmos/ibc-go/milestone/16). This refactor will make the development of light clients easier. -- Starting the implementation of channel upgradability (see [epic](https://github.com/cosmos/ibc-go/issues/1599) and [alpha milestone](https://github.com/cosmos/ibc-go/milestone/29)) with the goal of cutting an alpha1 pre-release by the end of the quarter. Channel upgradability will allow chains to renegotiate an existing channel to take advantage of new features without having to create a new channel, thus preserving all existing packet state processed on the channel. -- Implementing the new [`ORDERED_ALLOW_TIMEOUT` channel type](https://github.com/cosmos/ibc-go/milestone/31) and hopefully releasing it as well. This new channel type will allow packets on an ordered channel to timeout without causing the closure of the channel. - -### Testing and infrastructure - -- Adding [automated e2e tests](https://github.com/cosmos/ibc-go/milestone/32) to the repo's CI. - -### Documentation and backlog - -- Finishing and releasing the upgrade to Cosmos SDK v0.46. -- Writing the [light client implementation guide](https://github.com/cosmos/ibc-go/issues/59). -- Working on [core backlog issues](https://github.com/cosmos/ibc-go/milestone/28). -- Depending on the timeline of the Cosmos SDK, implementing and testing the changes needed to support the [transtion to SMT storage](https://github.com/cosmos/ibc-go/milestone/21). - -We have also received a lot of feedback to improve Interchain Accounts and we might also work on a few things, but will depend on priorities and availability. - -For a detail view of each iteration's planned work, please check out our [project board](https://github.com/orgs/cosmos/projects/7). - -### Release schedule - -#### **July** - -We will probably cut at least one more release candidate of v4.0.0 before the final release, which should happen around the end of the month. - -For the Rho upgrade of the Cosmos Hub we will also release a new minor version of v3 with SDK 0.46. - -#### **August** - -In the first half we will probably start cutting release candidates for the 02-client refactor. Final release would most likely come out at the end of the month or beginning of September. - -#### **September** - -We might cut some pre-releases for the new channel type, and by the end of the month we expect to cut the first alpha pre-release for channel upgradability. - -## Q4 - 2022 - -We will continue the implementation and cut the final release of [channel upgradability](https://github.com/cosmos/ibc/blob/master/spec/core/ics-004-channel-and-packet-semantics/UPGRADES.md). At the end of Q3 or maybe beginning of Q4 we might also work on designing the implementation and scoping the engineering work to add support for [multihop channels](https://github.com/cosmos/ibc/pull/741/files), so that we could start the implementation of this feature during Q4 (but this is still be decided). diff --git a/docs/versioned_docs/version-v6.2.x/01-ibc/_category_.json b/docs/versioned_docs/version-v6.2.x/01-ibc/_category_.json deleted file mode 100644 index 066f3af93b1..00000000000 --- a/docs/versioned_docs/version-v6.2.x/01-ibc/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Using IBC-Go", - "position": 1, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/01-overview.md b/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/01-overview.md deleted file mode 100644 index 7e257d1e805..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/01-overview.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /apps/transfer/overview ---- - -# Overview - -:::note Synopsis -Learn about what the token Transfer module is -::: - -## What is the Transfer module? - -Transfer is the Cosmos SDK implementation of the [ICS-20](https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer) protocol, which enables cross-chain fungible token transfers. - -## Concepts - -### Acknowledgements - -ICS20 uses the recommended acknowledgement format as specified by [ICS 04](https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope). - -A successful receive of a transfer packet will result in a Result Acknowledgement being written -with the value `[]byte{byte(1)}` in the `Response` field. - -An unsuccessful receive of a transfer packet will result in an Error Acknowledgement being written -with the error message in the `Response` field. - -### Denomination trace - -The denomination trace corresponds to the information that allows a token to be traced back to its -origin chain. It contains a sequence of port and channel identifiers ordered from the most recent to -the oldest in the timeline of transfers. - -This information is included on the token denomination field in the form of a hash to prevent an -unbounded denomination length. For example, the token `transfer/channelToA/uatom` will be displayed -as `ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2`. - -Each send to any chain other than the one it was previously received from is a movement forwards in -the token's timeline. This causes trace to be added to the token's history and the destination port -and destination channel to be prefixed to the denomination. In these instances the sender chain is -acting as the "source zone". When the token is sent back to the chain it previously received from, the -prefix is removed. This is a backwards movement in the token's timeline and the sender chain is -acting as the "sink zone". - -It is strongly recommended to read the full details of [ADR 001: Coin Source Tracing](/architecture/adr-001-coin-source-tracing) to understand the implications and context of the IBC token representations. - -## UX suggestions for clients - -For clients (wallets, exchanges, applications, block explorers, etc) that want to display the source of the token, it is recommended to use the following alternatives for each of the cases below: - -### Direct connection - -If the denomination trace contains a single identifier prefix pair (as in the example above), then -the easiest way to retrieve the chain and light client identifier is to map the trace information -directly. In summary, this requires querying the channel from the denomination trace identifiers, -and then the counterparty client state using the counterparty port and channel identifiers from the -retrieved channel. - -A general pseudo algorithm would look like the following: - -1. Query the full denomination trace. -2. Query the channel with the `portID/channelID` pair, which corresponds to the first destination of the - token. -3. Query the client state using the identifiers pair. Note that this query will return a `"Not -Found"` response if the current chain is not connected to this channel. -4. Retrieve the client identifier or chain identifier from the client state (eg: on - Tendermint clients) and store it locally. - -Using the gRPC gateway client service the steps above would be, with a given IBC token `ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2` stored on `chainB`: - -1. `GET /ibc/apps/transfer/v1/denom_traces/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2` -> `{"path": "transfer/channelToA", "base_denom": "uatom"}` -2. `GET /ibc/apps/transfer/v1/channels/channelToA/ports/transfer/client_state"` -> `{"client_id": "clientA", "chain-id": "chainA", ...}` -3. `GET /ibc/apps/transfer/v1/channels/channelToA/ports/transfer"` -> `{"channel_id": "channelToA", port_id": "transfer", counterparty: {"channel_id": "channelToB", port_id": "transfer"}, ...}` -4. `GET /ibc/apps/transfer/v1/channels/channelToB/ports/transfer/client_state" -> {"client_id": "clientB", "chain-id": "chainB", ...}` - -Then, the token transfer chain path for the `uatom` denomination would be: `chainA` -> `chainB`. - -### Multiple hops - -The multiple channel hops case applies when the token has passed through multiple chains between the original source and final destination chains. - -The IBC protocol doesn't know the topology of the overall network (i.e connections between chains and identifier names between them). For this reason, in the multiple hops case, a particular chain in the timeline of the individual transfers can't query the chain and client identifiers of the other chains. - -Take for example the following sequence of transfers `A -> B -> C` for an IBC token, with a final prefix path (trace info) of `transfer/channelChainC/transfer/channelChainB`. What the paragraph above means is that even in the case that chain `C` is directly connected to chain `A`, querying the port and channel identifiers that chain `B` uses to connect to chain `A` (eg: `transfer/channelChainA`) can be completely different from the one that chain `C` uses to connect to chain `A` (eg: `transfer/channelToChainA`). - -Thus the proposed solution for clients that the IBC team recommends are the following: - -- **Connect to all chains**: Connecting to all the chains in the timeline would allow clients to - perform the queries outlined in the [direct connection](#direct-connection) section to each - relevant chain. By repeatedly following the port and channel denomination trace transfer timeline, - clients should always be able to find all the relevant identifiers. This comes at the tradeoff - that the client must connect to nodes on each of the chains in order to perform the queries. -- **Relayer as a Service (RaaS)**: A longer term solution is to use/create a relayer service that - could map the denomination trace to the chain path timeline for each token (i.e `origin chain -> -chain #1 -> ... -> chain #(n-1) -> final chain`). These services could provide merkle proofs in - order to allow clients to optionally verify the path timeline correctness for themselves by - running light clients. If the proofs are not verified, they should be considered as trusted third - parties services. Additionally, client would be advised in the future to use RaaS that support the - largest number of connections between chains in the ecosystem. Unfortunately, none of the existing - public relayers (in [Golang](https://github.com/cosmos/relayer) and - [Rust](https://github.com/informalsystems/ibc-rs)), provide this service to clients. - -:::tip -The only viable alternative for clients (at the time of writing) to tokens with multiple connection hops, is to connect to all chains directly and perform relevant queries to each of them in the sequence. -::: - -## Locked funds - -In some [exceptional cases](/architecture/adr-026-ibc-client-recovery-mechanisms#exceptional-cases), a client state associated with a given channel cannot be updated. This causes that funds from fungible tokens in that channel will be permanently locked and thus can no longer be transferred. - -To mitigate this, a client update governance proposal can be submitted to update the frozen client -with a new valid header. Once the proposal passes the client state will be unfrozen and the funds -from the associated channels will then be unlocked. This mechanism only applies to clients that -allow updates via governance, such as Tendermint clients. - -In addition to this, it's important to mention that a token must be sent back along the exact route -that it took originally in order to return it to its original form on the source chain (eg: the -Cosmos Hub for the `uatom`). Sending a token back to the same chain across a different channel will -**not** move the token back across its timeline. If a channel in the chain history closes before the -token can be sent back across that channel, then the token will not be returnable to its original -form. - -## Security considerations - -For safety, no other module must be capable of minting tokens with the `ibc/` prefix. The IBC -transfer module needs a subset of the denomination space that only it can create tokens in. diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/02-state.md b/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/02-state.md deleted file mode 100644 index 916e99b46c3..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/02-state.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: State -sidebar_label: State -sidebar_position: 2 -slug: /apps/transfer/state ---- - -# State - -The IBC transfer application module keeps state of the port to which the module is binded and the denomination trace information as outlined in [ADR 001](/architecture/adr-001-coin-source-tracing). - -- `Port`: `0x01 -> ProtocolBuffer(string)` -- `DenomTrace`: `0x02 | []bytes(traceHash) -> ProtocolBuffer(DenomTrace)` diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/03-state-transitions.md b/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/03-state-transitions.md deleted file mode 100644 index 7c73b8da21c..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/03-state-transitions.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: State Transitions -sidebar_label: State Transitions -sidebar_position: 3 -slug: /apps/transfer/state-transitions ---- - -# State transitions - -## Send fungible tokens - -A successful fungible token send has two state transitions depending if the transfer is a movement forward or backwards in the token's timeline: - -1. Sender chain is the source chain, *i.e* a transfer to any chain other than the one it was previously received from is a movement forwards in the token's timeline. This results in the following state transitions: - - - The coins are transferred to an escrow address (i.e locked) on the sender chain. - - The coins are transferred to the receiving chain through IBC TAO logic. - -2. Sender chain is the sink chain, *i.e* the token is sent back to the chain it previously received from. This is a backwards movement in the token's timeline. This results in the following state transitions: - - - The coins (vouchers) are burned on the sender chain. - - The coins are transferred to the receiving chain through IBC TAO logic. - -## Receive fungible tokens - -A successful fungible token receive has two state transitions depending if the transfer is a movement forward or backwards in the token's timeline: - -1. Receiver chain is the source chain. This is a backwards movement in the token's timeline. This results in the following state transitions: - - - The leftmost port and channel identifier pair is removed from the token denomination prefix. - - The tokens are unescrowed and sent to the receiving address. - -2. Receiver chain is the sink chain. This is a movement forwards in the token's timeline. This results in the following state transitions: - - - Token vouchers are minted by prefixing the destination port and channel identifiers to the trace information. - - The receiving chain stores the new trace information in the store (if not set already). - - The vouchers are sent to the receiving address. diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/04-messages.md b/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/04-messages.md deleted file mode 100644 index 7eb46cd32a1..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/04-messages.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: Messages -sidebar_label: Messages -sidebar_position: 4 -slug: /apps/transfer/messages ---- - -# Messages - -## `MsgTransfer` - -A fungible token cross chain transfer is achieved by using the `MsgTransfer`: - -```go -type MsgTransfer struct { - SourcePort string - SourceChannel string - Token sdk.Coin - Sender string - Receiver string - TimeoutHeight ibcexported.Height - TimeoutTimestamp uint64 - Memo string -} -``` - -This message is expected to fail if: - -- `SourcePort` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). -- `SourceChannel` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -- `Token` is invalid (denom is invalid or amount is negative) - - `Token.Amount` is not positive. - - `Token.Denom` is not a valid IBC denomination as per [ADR 001 - Coin Source Tracing](/architecture/adr-001-coin-source-tracing). -- `Sender` is empty. -- `Receiver` is empty. -- `TimeoutHeight` and `TimeoutTimestamp` are both zero. - -This message will send a fungible token to the counterparty chain represented by the counterparty Channel End connected to the Channel End with the identifiers `SourcePort` and `SourceChannel`. - -The denomination provided for transfer should correspond to the same denomination represented on this chain. The prefixes will be added as necessary upon by the receiving chain. - -### Memo - -The memo field was added to allow applications and users to attach metadata to transfer packets. The field is optional and may be left empty. When it is used to attach metadata for a particular middleware, the memo field should be represented as a json object where different middlewares use different json keys. - -You can find more information about applications that use the memo field in the [chain registry](https://github.com/cosmos/chain-registry/blob/master/_memo_keys/ICS20_memo_keys.json). diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/05-events.md b/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/05-events.md deleted file mode 100644 index 888b26a959a..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/05-events.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Events -sidebar_label: Events -sidebar_position: 5 -slug: /apps/transfer/events ---- - - -# Events - -## `MsgTransfer` - -| Type | Attribute Key | Attribute Value | -|--------------|---------------|-----------------| -| ibc_transfer | sender | {sender} | -| ibc_transfer | receiver | {receiver} | -| message | action | transfer | -| message | module | transfer | - -## `OnRecvPacket` callback - -| Type | Attribute Key | Attribute Value | -|-----------------------|---------------|-----------------| -| fungible_token_packet | module | transfer | -| fungible_token_packet | sender | {sender} | -| fungible_token_packet | receiver | {receiver} | -| fungible_token_packet | denom | {denom} | -| fungible_token_packet | amount | {amount} | -| fungible_token_packet | success | {ackSuccess} | -| fungible_token_packet | memo | {memo} | -| denomination_trace | trace_hash | {hex_hash} | - -## `OnAcknowledgePacket` callback - -| Type | Attribute Key | Attribute Value | -|-----------------------|-----------------|-------------------| -| fungible_token_packet | module | transfer | -| fungible_token_packet | sender | {sender} | -| fungible_token_packet | receiver | {receiver} | -| fungible_token_packet | denom | {denom} | -| fungible_token_packet | amount | {amount} | -| fungible_token_packet | memo | {memo} | -| fungible_token_packet | acknowledgement | {ack.String()} | -| fungible_token_packet | success | error | {ack.Response} | - -## `OnTimeoutPacket` callback - -| Type | Attribute Key | Attribute Value | -|-----------------------|-----------------|-----------------| -| fungible_token_packet | module | transfer | -| fungible_token_packet | refund_receiver | {receiver} | -| fungible_token_packet | denom | {denom} | -| fungible_token_packet | amount | {amount} | -| fungible_token_packet | memo | {memo} | diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/06-metrics.md b/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/06-metrics.md deleted file mode 100644 index 104e5b4d3bc..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/06-metrics.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: Metrics -sidebar_label: Metrics -sidebar_position: 6 -slug: /apps/transfer/metrics ---- - - -# Metrics - -The IBC transfer application module exposes the following set of [metrics](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/advanced/09-telemetry.md). - -| Metric | Description | Unit | Type | -|:--------------------------------|:------------------------------------------------------------------------------------------|:----------------|:--------| -| `tx_msg_ibc_transfer` | The total amount of tokens transferred via IBC in a `MsgTransfer` (source or sink chain) | token | gauge | -| `ibc_transfer_packet_receive` | The total amount of tokens received in a `FungibleTokenPacketData` (source or sink chain) | token | gauge | -| `ibc_transfer_send` | Total number of IBC transfers sent from a chain (source or sink) | transfer | counter | -| `ibc_transfer_receive` | Total number of IBC transfers received to a chain (source or sink) | transfer | counter | diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/07-params.md b/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/07-params.md deleted file mode 100644 index f3d55f7388f..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/07-params.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: Params -sidebar_label: Params -sidebar_position: 7 -slug: /apps/transfer/params ---- - - -# Parameters - -The IBC transfer application module contains the following parameters: - -| Key | Type | Default Value | -|------------------|------|---------------| -| `SendEnabled` | bool | `true` | -| `ReceiveEnabled` | bool | `true` | - -## `SendEnabled` - -The transfers enabled parameter controls send cross-chain transfer capabilities for all fungible tokens. - -To prevent a single token from being transferred from the chain, set the `SendEnabled` parameter to `true` and then, depending on the Cosmos SDK version, do one of the following: - -- For Cosmos SDK v0.46.x or earlier, set the bank module's [`SendEnabled` parameter](https://github.com/cosmos/cosmos-sdk/blob/release/v0.46.x/x/bank/spec/05_params.md#sendenabled) for the denomination to `false`. -- For Cosmos SDK versions above v0.46.x, set the bank module's `SendEnabled` entry for the denomination to `false` using `MsgSetSendEnabled` as a governance proposal. - -## `ReceiveEnabled` - -The transfers enabled parameter controls receive cross-chain transfer capabilities for all fungible tokens. - -To prevent a single token from being transferred to the chain, set the `ReceiveEnabled` parameter to `true` and then, depending on the Cosmos SDK version, do one of the following: - -- For Cosmos SDK v0.46.x or earlier, set the bank module's [`SendEnabled` parameter](https://github.com/cosmos/cosmos-sdk/blob/release/v0.46.x/x/bank/spec/05_params.md#sendenabled) for the denomination to `false`. -- For Cosmos SDK versions above v0.46.x, set the bank module's `SendEnabled` entry for the denomination to `false` using `MsgSetSendEnabled` as a governance proposal. diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/08-authorizations.md b/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/08-authorizations.md deleted file mode 100644 index 4efa9d749e7..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/08-authorizations.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Authorizations -sidebar_label: Authorizations -sidebar_position: 8 -slug: /apps/transfer/authorizations ---- - -# `TransferAuthorization` - -`TransferAuthorization` implements the `Authorization` interface for `ibc.applications.transfer.v1.MsgTransfer`. It allows a granter to grant a grantee the privilege to submit `MsgTransfer` on its behalf. Please see the [Cosmos SDK docs](https://docs.cosmos.network/v0.47/modules/authz) for more details on granting privileges via the `x/authz` module. - -More specifically, the granter allows the grantee to transfer funds that belong to the granter over a specified channel. - -For the specified channel, the granter must be able to specify a spend limit of a specific denomination they wish to allow the grantee to be able to transfer. - -The granter may be able to specify the list of addresses that they allow to receive funds. If empty, then all addresses are allowed. - -It takes: - -- a `SourcePort` and a `SourceChannel` which together comprise the unique transfer channel identifier over which authorized funds can be transferred. - -- a `SpendLimit` that specifies the maximum amount of tokens the grantee can transfer. The `SpendLimit` is updated as the tokens are transfered, unless the sentinel value of the maximum value for a 256-bit unsigned integer (i.e. 2^256 - 1) is used for the amount, in which case the `SpendLimit` will not be updated (please be aware that using this sentinel value will grant the grantee the privilege to transfer **all** the tokens of a given denomination available at the granter's account). The helper function `UnboundedSpendLimit` in the `types` package of the `transfer` module provides the sentinel value that can be used. This `SpendLimit` may also be updated to increase or decrease the limit as the granter wishes. - -- an `AllowList` list that specifies the list of addresses that are allowed to receive funds. If this list is empty, then all addresses are allowed to receive funds from the `TransferAuthorization`. - -Setting a `TransferAuthorization` is expected to fail if: - -- the spend limit is nil -- the denomination of the spend limit is an invalid coin type -- the source port ID is invalid -- the source channel ID is invalid -- there are duplicate entries in the `AllowList` - -Below is the `TransferAuthorization` message: - -```golang -func NewTransferAuthorization(allocations ...Allocation) *TransferAuthorization { - return &TransferAuthorization{ - Allocations: allocations, - } -} - -type Allocation struct { - // the port on which the packet will be sent - SourcePort string - // the channel by which the packet will be sent - SourceChannel string - // spend limitation on the channel - SpendLimit sdk.Coins - // allow list of receivers, an empty allow list permits any receiver address - AllowList []string -} - -``` diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/_category_.json b/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/_category_.json deleted file mode 100644 index d643a498cdf..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/01-transfer/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Transfer", - "position": 1, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/01-overview.md b/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/01-overview.md deleted file mode 100644 index 80e7339ab62..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/01-overview.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /apps/interchain-accounts/overview ---- - - -# Overview - -:::note Synopsis -Learn about what the Interchain Accounts module is -::: - -## What is the Interchain Accounts module? - -Interchain Accounts is the Cosmos SDK implementation of the ICS-27 protocol, which enables cross-chain account management built upon IBC. - -- How does an interchain account differ from a regular account? - -Regular accounts use a private key to sign transactions. Interchain Accounts are instead controlled programmatically by counterparty chains via IBC packets. - -## Concepts - -`Host Chain`: The chain where the interchain account is registered. The host chain listens for IBC packets from a controller chain which should contain instructions (e.g. Cosmos SDK messages) for which the interchain account will execute. - -`Controller Chain`: The chain registering and controlling an account on a host chain. The controller chain sends IBC packets to the host chain to control the account. - -`Interchain Account`: An account on a host chain created using the ICS-27 protocol. An interchain account has all the capabilities of a normal account. However, rather than signing transactions with a private key, a controller chain will send IBC packets to the host chain which signals what transactions the interchain account should execute. - -`Authentication Module`: A custom application module on the controller chain that uses the Interchain Accounts module to build custom logic for the creation & management of interchain accounts. It can be either an IBC application module using the [legacy API](09-legacy/03-keeper-api.md), or a regular Cosmos SDK application module sending messages to the controller submodule's `MsgServer` (this is the recommended approach from ibc-go v6 if access to packet callbacks is not needed). Please note that the legacy API will eventually be removed and IBC applications will not be able to use them in later releases. - -## SDK security model - -SDK modules on a chain are assumed to be trustworthy. For example, there are no checks to prevent an untrustworthy module from accessing the bank keeper. - -The implementation of ICS-27 in ibc-go uses this assumption in its security considerations. - -The implementation assumes other IBC application modules will not bind to ports within the ICS-27 namespace. diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/02-development.md b/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/02-development.md deleted file mode 100644 index d2c7345ae79..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/02-development.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: Development Use Cases -sidebar_label: Development Use Cases -sidebar_position: 2 -slug: /apps/interchain-accounts/development ---- - - -# Development use cases - -The initial version of Interchain Accounts allowed for the controller submodule to be extended by providing it with an underlying application which would handle all packet callbacks. -That functionality is now being deprecated in favor of alternative approaches. -This document will outline potential use cases and redirect each use case to the appropriate documentation. - -## Custom authentication - -Interchain accounts may be associated with alternative types of authentication relative to the traditional public/private key signing. -If you wish to develop or use Interchain Accounts with a custom authentication module and do not need to execute custom logic on the packet callbacks, we recommend you use ibc-go v6 or greater and that your custom authentication module interacts with the controller submodule via the [`MsgServer`](05-messages.md). - -If you wish to consume and execute custom logic in the packet callbacks, then please read the section [Packet callbacks](#packet-callbacks) below. - -## Redirection to a smart contract - -It may be desirable to allow smart contracts to control an interchain account. -To faciliate such an action, the controller submodule may be provided an underlying application which redirects to smart contract callers. -An improved design has been suggested in [ADR 008](https://github.com/cosmos/ibc-go/pull/1976) which performs this action via middleware. - -Implementors of this use case are recommended to follow the ADR 008 approach. -The underlying application may continue to be used as a short term solution for ADR 008 and the [legacy API](03-auth-modules.md#registerinterchainaccount) should continue to be utilized in such situations. - -## Packet callbacks - -If a developer requires access to packet callbacks for their use case, then they have the following options: - -1. Write a smart contract which is connected via an ADR 008 or equivalent IBC application (recommended). -2. Use the controller's underlying application to implement packet callback logic. - -In the first case, the smart contract should use the [`MsgServer`](05-messages.md). - -In the second case, the underlying application should use the [legacy API](09-legacy/03-keeper-api.md). diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/03-auth-modules.md b/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/03-auth-modules.md deleted file mode 100644 index 46bc9f7e2dd..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/03-auth-modules.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: Authentication Modules -sidebar_label: Authentication Modules -sidebar_position: 3 -slug: /apps/interchain-accounts/auth-modules ---- - - -# Building an authentication module - -:::note Synopsis -Authentication modules enable application developers to perform custom logic when interacting with the Interchain Accounts controller sumbmodule's `MsgServer`. -::: - -The controller submodule is used for account registration and packet sending. It executes only logic required of all controllers of interchain accounts. The type of authentication used to manage the interchain accounts remains unspecified. There may exist many different types of authentication which are desirable for different use cases. Thus the purpose of the authentication module is to wrap the controller submodule with custom authentication logic. - -In ibc-go, authentication modules can communicate with the controller submodule by passing messages through `baseapp`'s `MsgServiceRouter`. To implement an authentication module, the `IBCModule` interface need not be fulfilled; it is only required to fulfill Cosmos SDK's `AppModuleBasic` interface, just like any regular Cosmos SDK application module. - -The authentication module must: - -- Authenticate interchain account owners. -- Track the associated interchain account address for an owner. -- Send packets on behalf of an owner (after authentication). - -## Integration into `app.go` file - -To integrate the authentication module into your chain, please follow the steps outlined in [`app.go` integration](04-integration.md#example-integration). diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/04-integration.md b/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/04-integration.md deleted file mode 100644 index 373ff3ce5bf..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/04-integration.md +++ /dev/null @@ -1,199 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 4 -slug: /apps/interchain-accounts/integration ---- - - -# Integration - -:::note Synopsis -Learn how to integrate Interchain Accounts host and controller functionality to your chain. The following document only applies for Cosmos SDK chains. -::: - -The Interchain Accounts module contains two submodules. Each submodule has its own IBC application. The Interchain Accounts module should be registered as an `AppModule` in the same way all SDK modules are registered on a chain, but each submodule should create its own `IBCModule` as necessary. A route should be added to the IBC router for each submodule which will be used. - -Chains who wish to support ICS-27 may elect to act as a host chain, a controller chain or both. Disabling host or controller functionality may be done statically by excluding the host or controller submodule entirely from the `app.go` file or it may be done dynamically by taking advantage of the on-chain parameters which enable or disable the host or controller submodules. - -Interchain Account authentication modules (both custom or generic, such as the `x/gov`, `x/group` or `x/auth` Cosmos SDK modules) can send messages to the controller submodule's [`MsgServer`](05-messages.md) to register interchain accounts and send packets to the interchain account. To accomplish this, the authentication module needs to be composed with `baseapp`'s `MsgServiceRouter`. - -![ica-v6.png](./images/ica-v6.png) - -## Example integration - -```go -// app.go - -// Register the AppModule for the Interchain Accounts module and the authentication module -// Note: No `icaauth` exists, this must be substituted with an actual Interchain Accounts authentication module -ModuleBasics = module.NewBasicManager( - ... - ica.AppModuleBasic{}, - icaauth.AppModuleBasic{}, - ... -) - -... - -// Add module account permissions for the Interchain Accounts module -// Only necessary for host chain functionality -// Each Interchain Account created on the host chain is derived from the module account created -maccPerms = map[string][]string{ - ... - icatypes.ModuleName: nil, -} - -... - -// Add Interchain Accounts Keepers for each submodule used and the authentication module -// If a submodule is being statically disabled, the associated Keeper does not need to be added. -type App struct { - ... - - ICAControllerKeeper icacontrollerkeeper.Keeper - ICAHostKeeper icahostkeeper.Keeper - ICAAuthKeeper icaauthkeeper.Keeper - - ... -} - -... - -// Create store keys for each submodule Keeper and the authentication module -keys := sdk.NewKVStoreKeys( - ... - icacontrollertypes.StoreKey, - icahosttypes.StoreKey, - icaauthtypes.StoreKey, - ... -) - -... - -// Create the scoped keepers for each submodule keeper and authentication keeper -scopedICAControllerKeeper := app.CapabilityKeeper.ScopeToModule(icacontrollertypes.SubModuleName) -scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icahosttypes.SubModuleName) -scopedICAAuthKeeper := app.CapabilityKeeper.ScopeToModule(icaauthtypes.ModuleName) - -... - -// Create the Keeper for each submodule -app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( - appCodec, keys[icacontrollertypes.StoreKey], app.GetSubspace(icacontrollertypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - scopedICAControllerKeeper, app.MsgServiceRouter(), -) -app.ICAHostKeeper = icahostkeeper.NewKeeper( - appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), -) - -// Create Interchain Accounts AppModule -icaModule := ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper) - -// Create your Interchain Accounts authentication module -app.ICAAuthKeeper = icaauthkeeper.NewKeeper(appCodec, keys[icaauthtypes.StoreKey], app.MsgServiceRouter()) - -// ICA auth AppModule -icaAuthModule := icaauth.NewAppModule(appCodec, app.ICAAuthKeeper) - -// Create controller IBC application stack and host IBC module as desired -icaControllerStack := icacontroller.NewIBCMiddleware(nil, app.ICAControllerKeeper) -icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - -// Register host and authentication routes -ibcRouter. - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icahosttypes.SubModuleName, icaHostIBCModule) -... - -// Register Interchain Accounts and authentication module AppModule's -app.moduleManager = module.NewManager( - ... - icaModule, - icaAuthModule, -) - -... - -// Add Interchain Accounts to begin blocker logic -app.moduleManager.SetOrderBeginBlockers( - ... - icatypes.ModuleName, - ... -) - -// Add Interchain Accounts to end blocker logic -app.moduleManager.SetOrderEndBlockers( - ... - icatypes.ModuleName, - ... -) - -// Add Interchain Accounts module InitGenesis logic -app.moduleManager.SetOrderInitGenesis( - ... - icatypes.ModuleName, - ... -) - -// initParamsKeeper init params keeper and its subspaces -func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) paramskeeper.Keeper { - ... - paramsKeeper.Subspace(icahosttypes.SubModuleName) - paramsKeeper.Subspace(icacontrollertypes.SubModuleName) - ... -} -``` - -If no custom athentication module is needed and a generic Cosmos SDK authentication module can be used, then from the sample integration code above all references to `ICAAuthKeeper` and `icaAuthModule` can be removed. That's it, the following code would not be needed: - -```go -// Create your Interchain Accounts authentication module -app.ICAAuthKeeper = icaauthkeeper.NewKeeper(appCodec, keys[icaauthtypes.StoreKey], app.MsgServiceRouter()) - -// ICA auth AppModule -icaAuthModule := icaauth.NewAppModule(appCodec, app.ICAAuthKeeper) -``` - -### Using submodules exclusively - -As described above, the Interchain Accounts application module is structured to support the ability of exclusively enabling controller or host functionality. -This can be achieved by simply omitting either controller or host `Keeper` from the Interchain Accounts `NewAppModule` constructor function, and mounting only the desired submodule via the `IBCRouter`. -Alternatively, submodules can be enabled and disabled dynamically using [on-chain parameters](06-parameters.md). - -The following snippets show basic examples of statically disabling submodules using `app.go`. - -#### Disabling controller chain functionality - -```go -// Create Interchain Accounts AppModule omitting the controller keeper -icaModule := ica.NewAppModule(nil, &app.ICAHostKeeper) - -// Create host IBC Module -icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - -// Register host route -ibcRouter.AddRoute(icahosttypes.SubModuleName, icaHostIBCModule) -``` - -#### Disabling host chain functionality - -```go -// Create Interchain Accounts AppModule omitting the host keeper -icaModule := ica.NewAppModule(&app.ICAControllerKeeper, nil) - - -// Optionally instantiate your custom authentication module if needed, or not otherwise -... - -// Create controller IBC application stack -icaControllerStack := icacontroller.NewIBCMiddleware(nil, app.ICAControllerKeeper) - -// Register controller route -ibcRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) -``` diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/05-messages.md b/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/05-messages.md deleted file mode 100644 index e9d6c517752..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/05-messages.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: Messages -sidebar_label: Messages -sidebar_position: 5 -slug: /apps/interchain-accounts/messages ---- - - -# Messages - -## `MsgRegisterInterchainAccount` - -An Interchain Accounts channel handshake can be initated using `MsgRegisterInterchainAccount`: - -```go -type MsgRegisterInterchainAccount struct { - Owner string - ConnectionID string - Version string -} -``` - -This message is expected to fail if: - -- `Owner` is an empty string. -- `ConnectionID` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). - -This message will construct a new `MsgChannelOpenInit` on chain and route it to the core IBC message server to initiate the opening step of the channel handshake. - -The controller submodule will generate a new port identifier and claim the associated port capability. The caller is expected to provide an appropriate application version string. For example, this may be an ICS-27 JSON encoded [`Metadata`](https://github.com/cosmos/ibc-go/blob/v6.0.0-rc0/proto/ibc/applications/interchain_accounts/v1/metadata.proto#L11) type or an ICS-29 JSON encoded [`Metadata`](https://github.com/cosmos/ibc-go/blob/v6.0.0-rc0/proto/ibc/applications/fee/v1/metadata.proto#L11) type with a nested application version. -If the `Version` string is omitted, the controller submodule will construct a default version string in the `OnChanOpenInit` handshake callback. - -```go -type MsgRegisterInterchainAccountResponse struct { - ChannelID string -} -``` - -The `ChannelID` is returned in the message response. - -## `MsgSendTx` - -An Interchain Accounts transaction can be executed on a remote host chain by sending a `MsgSendTx` from the corresponding controller chain: - -```go -type MsgSendTx struct { - Owner string - ConnectionID string - PacketData InterchainAccountPacketData - RelativeTimeout uint64 -} -``` - -This message is expected to fail if: - -- `Owner` is an empty string. -- `ConnectionID` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -- `PacketData` contains an `UNSPECIFIED` type enum, the length of `Data` bytes is zero or the `Memo` field exceeds 256 characters in length. -- `RelativeTimeout` is zero. - -This message will create a new IBC packet with the provided `PacketData` and send it via the channel associated with the `Owner` and `ConnectionID`. -The `PacketData` is expected to contain a list of serialized `[]sdk.Msg` in the form of `CosmosTx`. Please note the signer field of each `sdk.Msg` must be the interchain account address. -When the packet is relayed to the host chain, the `PacketData` is unmarshalled and the messages are authenticated and executed. - -```go -type MsgSendTxResponse struct { - Sequence uint64 -} -``` - -The packet `Sequence` is returned in the message response. - -## Atomicity - -As the Interchain Accounts module supports the execution of multiple transactions using the Cosmos SDK `Msg` interface, it provides the same atomicity guarantees as Cosmos SDK-based applications, leveraging the [`CacheMultiStore`](https://docs.cosmos.network/main/learn/advanced/store#cachemultistore) architecture provided by the [`Context`](https://docs.cosmos.network/main/learn/advanced/context.html) type. - -This provides atomic execution of transactions when using Interchain Accounts, where state changes are only committed if all `Msg`s succeed. diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/06-parameters.md b/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/06-parameters.md deleted file mode 100644 index 9e01bb75ec2..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/06-parameters.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -title: Parameters -sidebar_label: Parameters -sidebar_position: 6 -slug: /apps/interchain-accounts/parameters ---- - - -# Parameters - -The Interchain Accounts module contains the following on-chain parameters, logically separated for each distinct submodule: - -## Controller Submodule Parameters - -| Key | Type | Default Value | -|------------------------|------|---------------| -| `ControllerEnabled` | bool | `true` | - -### ControllerEnabled - -The `ControllerEnabled` parameter controls a chains ability to service ICS-27 controller specific logic. This includes the sending of Interchain Accounts packet data as well as the following ICS-26 callback handlers: - -- `OnChanOpenInit` -- `OnChanOpenAck` -- `OnChanCloseConfirm` -- `OnAcknowledgementPacket` -- `OnTimeoutPacket` - -## Host Submodule Parameters - -| Key | Type | Default Value | -|------------------------|----------|---------------| -| `HostEnabled` | bool | `true` | -| `AllowMessages` | []string | `["*"]` | - -### HostEnabled - -The `HostEnabled` parameter controls a chains ability to service ICS-27 host specific logic. This includes the following ICS-26 callback handlers: - -- `OnChanOpenTry` -- `OnChanOpenConfirm` -- `OnChanCloseConfirm` -- `OnRecvPacket` - -### AllowMessages - -The `AllowMessages` parameter provides the ability for a chain to limit the types of messages or transactions that hosted interchain accounts are authorized to execute by defining an allowlist using the Protobuf message type URL format. - -For example, a Cosmos SDK-based chain that elects to provide hosted Interchain Accounts with the ability of governance voting and staking delegations will define its parameters as follows: - -```json -"params": { - "host_enabled": true, - "allow_messages": ["/cosmos.staking.v1beta1.MsgDelegate", "/cosmos.gov.v1beta1.MsgVote"] -} -``` - -There is also a special wildcard `"*"` value which allows any type of message to be executed by the interchain account. This must be the only value in the `allow_messages` array. - -```json -"params": { - "host_enabled": true, - "allow_messages": ["*"] -} -``` diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/07-client.md b/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/07-client.md deleted file mode 100644 index eb7a074d78e..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/07-client.md +++ /dev/null @@ -1,184 +0,0 @@ ---- -title: Client -sidebar_label: Client -sidebar_position: 7 -slug: /apps/interchain-accounts/client ---- - - -# Client - -## CLI - -A user can query and interact with the Interchain Accounts module using the CLI. Use the `--help` flag to discover the available commands: - -```shell -simd query interchain-accounts --help -``` - -> Please not that this section does not document all the available commands, but only the ones that deserved extra documentation that was not possible to fit in the command line documentation. - -### Controller - -A user can query and interact with the controller submodule. - -#### Query - -The `query` commands allow users to query the controller submodule. - -```shell -simd query interchain-accounts controller --help -``` - -#### Transactions - -The `tx` commands allow users to interact with the controller submodule. - -```shell -simd tx interchain-accounts controller --help -``` - -#### `send-tx` - -The `send-tx` command allows users to send a transaction on the provided connection to be executed using an interchain account on the host chain. - -```shell -simd tx interchain-accounts controller send-tx [connection-id] [path/to/packet_msg.json] -``` - -Example: - -```shell -simd tx interchain-accounts controller send-tx connection-0 packet-data.json --from cosmos1.. -``` - -See below for example contents of `packet-data.json`. The CLI handler will unmarshal the following into `InterchainAccountPacketData` appropriately. - -```json -{ - "type":"TYPE_EXECUTE_TX", - "data":"CqIBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEoEBCkFjb3Ntb3MxNWNjc2hobXAwZ3N4MjlxcHFxNmc0em1sdG5udmdteXU5dWV1YWRoOXkybmM1emowc3psczVndGRkehItY29zbW9zMTBoOXN0YzV2Nm50Z2V5Z2Y1eGY5NDVuanFxNWgzMnI1M3VxdXZ3Gg0KBXN0YWtlEgQxMDAw", - "memo":"" -} -``` - -Note the `data` field is a base64 encoded byte string as per the [proto3 JSON encoding specification](https://developers.google.com/protocol-buffers/docs/proto3#json). - -A helper CLI is provided in the host submodule which can be used to generate the packet data JSON using the counterparty chain's binary. See the [`generate-packet-data` command](#generate-packet-data) for an example. - -### Host - -A user can query and interact with the host submodule. - -#### Query - -The `query` commands allow users to query the host submodule. - -```shell -simd query interchain-accounts host --help -``` - -#### Transactions - -The `tx` commands allow users to interact with the controller submodule. - -```shell -simd tx interchain-accounts host --help -``` - -##### `generate-packet-data` - -The `generate-packet-data` command allows users to generate interchain accounts packet data for input message(s). The packet data can then be used with the controller submodule's [`send-tx` command](#send-tx). - -```shell -simd tx interchain-accounts host generate-packet-data [message] -``` - -Example: - -```shell -simd tx interchain-accounts host generate-packet-data '[{ - "@type":"/cosmos.bank.v1beta1.MsgSend", - "from_address":"cosmos15ccshhmp0gsx29qpqq6g4zmltnnvgmyu9ueuadh9y2nc5zj0szls5gtddz", - "to_address":"cosmos10h9stc5v6ntgeygf5xf945njqq5h32r53uquvw", - "amount": [ - { - "denom": "stake", - "amount": "1000" - } - ] -}]' --memo memo -``` - -The command accepts a single `sdk.Msg` or a list of `sdk.Msg`s that will be encoded into the outputs `data` field. - -Example output: - -```json -{ - "type":"TYPE_EXECUTE_TX", - "data":"CqIBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEoEBCkFjb3Ntb3MxNWNjc2hobXAwZ3N4MjlxcHFxNmc0em1sdG5udmdteXU5dWV1YWRoOXkybmM1emowc3psczVndGRkehItY29zbW9zMTBoOXN0YzV2Nm50Z2V5Z2Y1eGY5NDVuanFxNWgzMnI1M3VxdXZ3Gg0KBXN0YWtlEgQxMDAw", - "memo":"memo" -} -``` - -## gRPC - -A user can query the interchain account module using gRPC endpoints. - -### Controller - -A user can query the controller submodule using gRPC endpoints. - -#### `InterchainAccount` - -The `InterchainAccount` endpoint allows users to query the controller submodule for the interchain account address for a given owner on a particular connection. - -```shell -ibc.applications.interchain_accounts.controller.v1.Query/InterchainAccount -``` - -Example: - -```shell -grpcurl -plaintext \ - -d '{"owner":"cosmos1..","connection_id":"connection-0"}' \ - localhost:9090 \ - ibc.applications.interchain_accounts.controller.v1.Query/InterchainAccount -``` - -#### `Params` - -The `Params` endpoint users to query the current controller submodule parameters. - -```shell -ibc.applications.interchain_accounts.controller.v1.Query/Params -``` - -Example: - -```shell -grpcurl -plaintext \ - localhost:9090 \ - ibc.applications.interchain_accounts.controller.v1.Query/Params -``` - -### Host - -A user can query the host submodule using gRPC endpoints. - -#### `Params` - -The `Params` endpoint users to query the current host submodule parameters. - -```shell -ibc.applications.interchain_accounts.host.v1.Query/Params -``` - -Example: - -```shell -grpcurl -plaintext \ - localhost:9090 \ - ibc.applications.interchain_accounts.host.v1.Query/Params -``` diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/08-active-channels.md b/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/08-active-channels.md deleted file mode 100644 index c4750792719..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/08-active-channels.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: Active Channels -sidebar_label: Active Channels -sidebar_position: 8 -slug: /apps/interchain-accounts/active-channels ---- - - -# Understanding Active Channels - -The Interchain Accounts module uses [ORDERED channels](https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#ordering) to maintain the order of transactions when sending packets from a controller to a host chain. A limitation when using ORDERED channels is that when a packet times out the channel will be closed. - -In the case of a channel closing, a controller chain needs to be able to regain access to the interchain account registered on this channel. `Active Channels` enable this functionality. - -When an Interchain Account is registered using `MsgRegisterInterchainAccount`, a new channel is created on a particular port. During the `OnChanOpenAck` and `OnChanOpenConfirm` steps (on controller & host chain respectively) the `Active Channel` for this interchain account is stored in state. - -It is possible to create a new channel using the same controller chain portID if the previously set `Active Channel` is now in a `CLOSED` state. This channel creation can be initialized programatically by sending a new `MsgChannelOpenInit` message like so: - -```go -msg := channeltypes.NewMsgChannelOpenInit(portID, string(versionBytes), channeltypes.ORDERED, []string{connectionID}, icatypes.HostPortID, authtypes.NewModuleAddress(icatypes.ModuleName).String()) -handler := keeper.msgRouter.Handler(msg) -res, err := handler(ctx, msg) -if err != nil { - return err -} -``` - -Alternatively, any relayer operator may initiate a new channel handshake for this interchain account once the previously set `Active Channel` is in a `CLOSED` state. This is done by initiating the channel handshake on the controller chain using the same portID associated with the interchain account in question. - -It is important to note that once a channel has been opened for a given interchain account, new channels can not be opened for this account until the currently set `Active Channel` is set to `CLOSED`. - -## Future improvements - -Future versions of the ICS-27 protocol and the Interchain Accounts module will likely use a new channel type that provides ordering of packets without the channel closing in the event of a packet timing out, thus removing the need for `Active Channels` entirely. -The following is a list of issues which will provide the infrastructure to make this possible: - -- [IBC Channel Upgrades](https://github.com/cosmos/ibc-go/issues/1599) -- [Implement ORDERED_ALLOW_TIMEOUT logic in 04-channel](https://github.com/cosmos/ibc-go/issues/1661) -- [Add ORDERED_ALLOW_TIMEOUT as supported ordering in 03-connection](https://github.com/cosmos/ibc-go/issues/1662) -- [Allow ICA channels to be opened as ORDERED_ALLOW_TIMEOUT](https://github.com/cosmos/ibc-go/issues/1663) diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/09-legacy/01-auth-modules.md b/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/09-legacy/01-auth-modules.md deleted file mode 100644 index 5903f81e6a2..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/09-legacy/01-auth-modules.md +++ /dev/null @@ -1,274 +0,0 @@ ---- -title: Authentication Modules -sidebar_label: Authentication Modules -sidebar_position: 1 -slug: /apps/interchain-accounts/legacy/auth-modules ---- - - -# Building an authentication module - -## Deprecation Notice - -**This document is deprecated and will be removed in future releases**. - -:::note Synopsis -Authentication modules play the role of the `Base Application` as described in [ICS-30 IBC Middleware](https://github.com/cosmos/ibc/tree/master/spec/app/ics-030-middleware), and enable application developers to perform custom logic when working with the Interchain Accounts controller API. -::: - -The controller submodule is used for account registration and packet sending. It executes only logic required of all controllers of interchain accounts. The type of authentication used to manage the interchain accounts remains unspecified. There may exist many different types of authentication which are desirable for different use cases. Thus the purpose of the authentication module is to wrap the controller submodule with custom authentication logic. - -In ibc-go, authentication modules are connected to the controller chain via a middleware stack. The controller submodule is implemented as [middleware](https://github.com/cosmos/ibc/tree/master/spec/app/ics-030-middleware) and the authentication module is connected to the controller submodule as the base application of the middleware stack. To implement an authentication module, the `IBCModule` interface must be fulfilled. By implementing the controller submodule as middleware, any amount of authentication modules can be created and connected to the controller submodule without writing redundant code. - -The authentication module must: - -- Authenticate interchain account owners. -- Track the associated interchain account address for an owner. -- Send packets on behalf of an owner (after authentication). - -> Please note that since ibc-go v6 the channel capability is claimed by the controller submodule and therefore it is not required for authentication modules to claim the capability in the `OnChanOpenInit` callback. When the authentication module sends packets on the channel created for the associated interchain account it can pass a `nil` capability to the legacy function `SendTx` of the controller keeper (see [section `SendTx`](./03-keeper-api.md#sendtx) below for mode information). - -## `IBCModule` implementation - -The following `IBCModule` callbacks must be implemented with appropriate custom logic: - -```go -// OnChanOpenInit implements the IBCModule interface -func (im IBCModule) OnChanOpenInit( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) (string, error) { - // since ibc-go v6 the authentication module *must not* claim the channel capability on OnChanOpenInit - - // perform custom logic - - return version, nil -} - -// OnChanOpenAck implements the IBCModule interface -func (im IBCModule) OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyVersion string, -) error { - // perform custom logic - - return nil -} - -// OnChanCloseConfirm implements the IBCModule interface -func (im IBCModule) OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // perform custom logic - - return nil -} - -// OnAcknowledgementPacket implements the IBCModule interface -func (im IBCModule) OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - relayer sdk.AccAddress, -) error { - // perform custom logic - - return nil -} - -// OnTimeoutPacket implements the IBCModule interface. -func (im IBCModule) OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) error { - // perform custom logic - - return nil -} -``` - -The following functions must be defined to fulfill the `IBCModule` interface, but they will never be called by the controller submodule so they may error or panic. That is because in Interchain Accounts, the channel handshake is always initiated on the controller chain and packets are always sent to the host chain and never to the controller chain. - -```go -// OnChanOpenTry implements the IBCModule interface -func (im IBCModule) OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (string, error) { - panic("UNIMPLEMENTED") -} - -// OnChanOpenConfirm implements the IBCModule interface -func (im IBCModule) OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - panic("UNIMPLEMENTED") -} - -// OnChanCloseInit implements the IBCModule interface -func (im IBCModule) OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - panic("UNIMPLEMENTED") -} - -// OnRecvPacket implements the IBCModule interface. A successful acknowledgement -// is returned if the packet data is succesfully decoded and the receive application -// logic returns without error. -func (im IBCModule) OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) ibcexported.Acknowledgement { - panic("UNIMPLEMENTED") -} -``` - -## `OnAcknowledgementPacket` - -Controller chains will be able to access the acknowledgement written into the host chain state once a relayer relays the acknowledgement. -The acknowledgement bytes contain either the response of the execution of the message(s) on the host chain or an error. They will be passed to the auth module via the `OnAcknowledgementPacket` callback. Auth modules are expected to know how to decode the acknowledgement. - -If the controller chain is connected to a host chain using the host module on ibc-go, it may interpret the acknowledgement bytes as follows: - -Begin by unmarshaling the acknowledgement into `sdk.TxMsgData`: - -```go -var ack channeltypes.Acknowledgement -if err := channeltypes.SubModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { - return err -} - -txMsgData := &sdk.TxMsgData{} -if err := proto.Unmarshal(ack.GetResult(), txMsgData); err != nil { - return err -} -``` - -If the `txMsgData.Data` field is non nil, the host chain is using SDK version <= v0.45. -The auth module should interpret the `txMsgData.Data` as follows: - -```go -switch len(txMsgData.Data) { -case 0: - // see documentation below for SDK 0.46.x or greater -default: - for _, msgData := range txMsgData.Data { - if err := handler(msgData); err != nil { - return err - } - } -... -} -``` - -A handler will be needed to interpret what actions to perform based on the message type sent. -A router could be used, or more simply a switch statement. - -```go -func handler(msgData sdk.MsgData) error { -switch msgData.MsgType { -case sdk.MsgTypeURL(&banktypes.MsgSend{}): - msgResponse := &banktypes.MsgSendResponse{} - if err := proto.Unmarshal(msgData.Data, msgResponse}; err != nil { - return err - } - - handleBankSendMsg(msgResponse) - -case sdk.MsgTypeURL(&stakingtypes.MsgDelegate{}): - msgResponse := &stakingtypes.MsgDelegateResponse{} - if err := proto.Unmarshal(msgData.Data, msgResponse}; err != nil { - return err - } - - handleStakingDelegateMsg(msgResponse) - -case sdk.MsgTypeURL(&transfertypes.MsgTransfer{}): - msgResponse := &transfertypes.MsgTransferResponse{} - if err := proto.Unmarshal(msgData.Data, msgResponse}; err != nil { - return err - } - - handleIBCTransferMsg(msgResponse) - -default: - return -} -``` - -If the `txMsgData.Data` is empty, the host chain is using SDK version > v0.45. -The auth module should interpret the `txMsgData.Responses` as follows: - -```go -... -// switch statement from above -case 0: - for _, any := range txMsgData.MsgResponses { - if err := handleAny(any); err != nil { - return err - } - } -} -``` - -A handler will be needed to interpret what actions to perform based on the type URL of the Any. -A router could be used, or more simply a switch statement. -It may be possible to deduplicate logic between `handler` and `handleAny`. - -```go -func handleAny(any *codectypes.Any) error { -switch any.TypeURL { -case banktypes.MsgSend: - msgResponse, err := unpackBankMsgSendResponse(any) - if err != nil { - return err - } - - handleBankSendMsg(msgResponse) - -case stakingtypes.MsgDelegate: - msgResponse, err := unpackStakingDelegateResponse(any) - if err != nil { - return err - } - - handleStakingDelegateMsg(msgResponse) - - case transfertypes.MsgTransfer: - msgResponse, err := unpackIBCTransferMsgResponse(any) - if err != nil { - return err - } - - handleIBCTransferMsg(msgResponse) - -default: - return -} -``` - -## Integration into `app.go` file - -To integrate the authentication module into your chain, please follow the steps outlined in [`app.go` integration](02-integration.md#example-integration). diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/09-legacy/02-integration.md b/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/09-legacy/02-integration.md deleted file mode 100644 index ac687cbc65e..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/09-legacy/02-integration.md +++ /dev/null @@ -1,201 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 2 -slug: /apps/interchain-accounts/legacy/integration ---- - - -# Integration - -## Deprecation Notice - -**This document is deprecated and will be removed in future releases**. - -:::note Synopsis -Learn how to integrate Interchain Accounts host and controller functionality to your chain. The following document only applies for Cosmos SDK chains. -::: - -The Interchain Accounts module contains two submodules. Each submodule has its own IBC application. The Interchain Accounts module should be registered as an `AppModule` in the same way all SDK modules are registered on a chain, but each submodule should create its own `IBCModule` as necessary. A route should be added to the IBC router for each submodule which will be used. - -Chains who wish to support ICS-27 may elect to act as a host chain, a controller chain or both. Disabling host or controller functionality may be done statically by excluding the host or controller module entirely from the `app.go` file or it may be done dynamically by taking advantage of the on-chain parameters which enable or disable the host or controller submodules. - -Interchain Account authentication modules are the base application of a middleware stack. The controller submodule is the middleware in this stack. - -![ica-pre-v6.png](./images/ica-pre-v6.png) - -> Please note that since ibc-go v6 the channel capability is claimed by the controller submodule and therefore it is not required for authentication modules to claim the capability in the `OnChanOpenInit` callback. Therefore the custom authentication module does not need a scoped keeper anymore. - -## Example integration - -```go -// app.go - -// Register the AppModule for the Interchain Accounts module and the authentication module -// Note: No `icaauth` exists, this must be substituted with an actual Interchain Accounts authentication module -ModuleBasics = module.NewBasicManager( - ... - ica.AppModuleBasic{}, - icaauth.AppModuleBasic{}, - ... -) - -... - -// Add module account permissions for the Interchain Accounts module -// Only necessary for host chain functionality -// Each Interchain Account created on the host chain is derived from the module account created -maccPerms = map[string][]string{ - ... - icatypes.ModuleName: nil, -} - -... - -// Add Interchain Accounts Keepers for each submodule used and the authentication module -// If a submodule is being statically disabled, the associated Keeper does not need to be added. -type App struct { - ... - - ICAControllerKeeper icacontrollerkeeper.Keeper - ICAHostKeeper icahostkeeper.Keeper - ICAAuthKeeper icaauthkeeper.Keeper - - ... -} - -... - -// Create store keys for each submodule Keeper and the authentication module -keys := sdk.NewKVStoreKeys( - ... - icacontrollertypes.StoreKey, - icahosttypes.StoreKey, - icaauthtypes.StoreKey, - ... -) - -... - -// Create the scoped keepers for each submodule keeper and authentication keeper -scopedICAControllerKeeper := app.CapabilityKeeper.ScopeToModule(icacontrollertypes.SubModuleName) -scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icahosttypes.SubModuleName) - -... - -// Create the Keeper for each submodule -app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( - appCodec, keys[icacontrollertypes.StoreKey], app.GetSubspace(icacontrollertypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - scopedICAControllerKeeper, app.MsgServiceRouter(), -) -app.ICAHostKeeper = icahostkeeper.NewKeeper( - appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), -) - -// Create Interchain Accounts AppModule -icaModule := ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper) - -// Create your Interchain Accounts authentication module -app.ICAAuthKeeper = icaauthkeeper.NewKeeper(appCodec, keys[icaauthtypes.StoreKey], app.ICAControllerKeeper) - -// ICA auth AppModule -icaAuthModule := icaauth.NewAppModule(appCodec, app.ICAAuthKeeper) - -// ICA auth IBC Module -icaAuthIBCModule := icaauth.NewIBCModule(app.ICAAuthKeeper) - -// Create controller IBC application stack and host IBC module as desired -icaControllerStack := icacontroller.NewIBCMiddleware(icaAuthIBCModule, app.ICAControllerKeeper) -icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - -// Register host and authentication routes -ibcRouter. - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icahosttypes.SubModuleName, icaHostIBCModule). - AddRoute(icaauthtypes.ModuleName, icaControllerStack) // Note, the authentication module is routed to the top level of the middleware stack - -... - -// Register Interchain Accounts and authentication module AppModule's -app.moduleManager = module.NewManager( - ... - icaModule, - icaAuthModule, -) - -... - -// Add fee middleware to begin blocker logic -app.moduleManager.SetOrderBeginBlockers( - ... - icatypes.ModuleName, - ... -) - -// Add fee middleware to end blocker logic -app.moduleManager.SetOrderEndBlockers( - ... - icatypes.ModuleName, - ... -) - -// Add Interchain Accounts module InitGenesis logic -app.moduleManager.SetOrderInitGenesis( - ... - icatypes.ModuleName, - ... -) - -// initParamsKeeper init params keeper and its subspaces -func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) paramskeeper.Keeper { - ... - paramsKeeper.Subspace(icahosttypes.SubModuleName) - paramsKeeper.Subspace(icacontrollertypes.SubModuleName) - ... -``` - -## Using submodules exclusively - -As described above, the Interchain Accounts application module is structured to support the ability of exclusively enabling controller or host functionality. -This can be achieved by simply omitting either controller or host `Keeper` from the Interchain Accounts `NewAppModule` constructor function, and mounting only the desired submodule via the `IBCRouter`. -Alternatively, submodules can be enabled and disabled dynamically using [on-chain parameters](../06-parameters.md). - -The following snippets show basic examples of statically disabling submodules using `app.go`. - -### Disabling controller chain functionality - -```go -// Create Interchain Accounts AppModule omitting the controller keeper -icaModule := ica.NewAppModule(nil, &app.ICAHostKeeper) - -// Create host IBC Module -icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - -// Register host route -ibcRouter.AddRoute(icahosttypes.SubModuleName, icaHostIBCModule) -``` - -### Disabling host chain functionality - -```go -// Create Interchain Accounts AppModule omitting the host keeper -icaModule := ica.NewAppModule(&app.ICAControllerKeeper, nil) - -// Create your Interchain Accounts authentication module, setting up the Keeper, AppModule and IBCModule appropriately -app.ICAAuthKeeper = icaauthkeeper.NewKeeper(appCodec, keys[icaauthtypes.StoreKey], app.ICAControllerKeeper) -icaAuthModule := icaauth.NewAppModule(appCodec, app.ICAAuthKeeper) -icaAuthIBCModule := icaauth.NewIBCModule(app.ICAAuthKeeper) - -// Create controller IBC application stack -icaControllerStack := icacontroller.NewIBCMiddleware(icaAuthIBCModule, app.ICAControllerKeeper) - -// Register controller and authentication routes -ibcRouter. - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icaauthtypes.ModuleName, icaControllerStack) // Note, the authentication module is routed to the top level of the middleware stack -``` diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/09-legacy/03-keeper-api.md b/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/09-legacy/03-keeper-api.md deleted file mode 100644 index ffb59aa5647..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/09-legacy/03-keeper-api.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -title: Keeper API -sidebar_label: Keeper API -sidebar_position: 3 -slug: /apps/interchain-accounts/legacy/keeper-api ---- - - -# Keeper API - -## Deprecation Notice - -**This document is deprecated and will be removed in future releases**. - -The controller submodule keeper exposes two legacy functions that allow respectively for custom authentication modules to register interchain accounts and send packets to the interchain account. - -## `RegisterInterchainAccount` - -The authentication module can begin registering interchain accounts by calling `RegisterInterchainAccount`: - -```go -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, connectionID, owner.String(), version); err != nil { - return err -} - -return nil -``` - -The `version` argument is used to support ICS-29 fee middleware for relayer incentivization of ICS-27 packets. Consumers of the `RegisterInterchainAccount` are expected to build the appropriate JSON encoded version string themselves and pass it accordingly. If an empty string is passed in the `version` argument, then the version will be initialized to a default value in the `OnChanOpenInit` callback of the controller's handler, so that channel handshake can proceed. - -The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, controllerConnectionID, owner.String(), string(appVersion)); err != nil { - return err -} -``` - -Similarly, if the application stack is configured to route through ICS-29 fee middleware and a fee enabled channel is desired, construct the appropriate ICS-29 `Metadata` type: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -feeMetadata := feetypes.Metadata{ - AppVersion: string(appVersion), - FeeVersion: feetypes.Version, -} - -feeEnabledVersion, err := feetypes.ModuleCdc.MarshalJSON(&feeMetadata) -if err != nil { - return err -} - -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, controllerConnectionID, owner.String(), string(feeEnabledVersion)); err != nil { - return err -} -``` - -## `SendTx` - -The authentication module can attempt to send a packet by calling `SendTx`: - -```go -// Authenticate owner -// perform custom logic - -// Construct controller portID based on interchain account owner address -portID, err := icatypes.NewControllerPortID(owner.String()) -if err != nil { - return err -} - -// Obtain data to be sent to the host chain. -// In this example, the owner of the interchain account would like to send a bank MsgSend to the host chain. -// The appropriate serialization function should be called. The host chain must be able to deserialize the transaction. -// If the host chain is using the ibc-go host module, `SerializeCosmosTx` should be used. -msg := &banktypes.MsgSend{FromAddress: fromAddr, ToAddress: toAddr, Amount: amt} -data, err := icatypes.SerializeCosmosTx(keeper.cdc, []proto.Message{msg}) -if err != nil { - return err -} - -// Construct packet data -packetData := icatypes.InterchainAccountPacketData{ - Type: icatypes.EXECUTE_TX, - Data: data, -} - -// Obtain timeout timestamp -// An appropriate timeout timestamp must be determined based on the usage of the interchain account. -// If the packet times out, the channel will be closed requiring a new channel to be created. -timeoutTimestamp := obtainTimeoutTimestamp() - -// Send the interchain accounts packet, returning the packet sequence -// A nil channel capability can be passed, since the controller submodule (and not the authentication module) -// claims the channel capability since ibc-go v6. -seq, err = keeper.icaControllerKeeper.SendTx(ctx, nil, portID, packetData, timeoutTimestamp) -``` - -The data within an `InterchainAccountPacketData` must be serialized using a format supported by the host chain. -If the host chain is using the ibc-go host chain submodule, `SerializeCosmosTx` should be used. If the `InterchainAccountPacketData.Data` is serialized using a format not supported by the host chain, the packet will not be successfully received. diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/09-legacy/_category_.json b/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/09-legacy/_category_.json deleted file mode 100644 index 4423a11d4d6..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/09-legacy/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Legacy", - "position": 9, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/09-legacy/images/ica-pre-v6.png b/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/09-legacy/images/ica-pre-v6.png deleted file mode 100644 index acd00d1294b..00000000000 Binary files a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/09-legacy/images/ica-pre-v6.png and /dev/null differ diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/_category_.json b/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/_category_.json deleted file mode 100644 index 5ac86ce8ff6..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Interchain Accounts", - "position": 2, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/images/ica-v6.png b/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/images/ica-v6.png deleted file mode 100644 index 0ffa707c981..00000000000 Binary files a/docs/versioned_docs/version-v6.2.x/02-apps/02-interchain-accounts/images/ica-v6.png and /dev/null differ diff --git a/docs/versioned_docs/version-v6.2.x/02-apps/_category_.json b/docs/versioned_docs/version-v6.2.x/02-apps/_category_.json deleted file mode 100644 index fa5fbf0ac9a..00000000000 --- a/docs/versioned_docs/version-v6.2.x/02-apps/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "IBC Application Modules", - "position": 2, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/01-overview.md b/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/01-overview.md deleted file mode 100644 index f6edae76ceb..00000000000 --- a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/01-overview.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /middleware/ics29-fee/overview ---- - - -# Overview - -:::note Synopsis -Learn about what the Fee Middleware module is, and how to build custom modules that utilize the Fee Middleware functionality -::: - -## What is the Fee Middleware module? - -IBC does not depend on relayer operators for transaction verification. However, the relayer infrastructure ensures liveness of the Interchain network — operators listen for packets sent through channels opened between chains, and perform the vital service of ferrying these packets (and proof of the transaction on the sending chain/receipt on the receiving chain) to the clients on each side of the channel. - -Though relaying is permissionless and completely decentralized and accessible, it does come with operational costs. Running full nodes to query transaction proofs and paying for transaction fees associated with IBC packets are two of the primary cost burdens which have driven the overall discussion on **a general, in-protocol incentivization mechanism for relayers**. - -Initially, a [simple proposal](https://github.com/cosmos/ibc/pull/577/files) was created to incentivize relaying on ICS20 token transfers on the destination chain. However, the proposal was specific to ICS20 token transfers and would have to be reimplemented in this format on every other IBC application module. - -After much discussion, the proposal was expanded to a [general incentivisation design](https://github.com/cosmos/ibc/tree/master/spec/app/ics-029-fee-payment) that can be adopted by any ICS application protocol as [middleware](../../01-ibc/04-middleware/01-develop.md). - -## Concepts - -ICS29 fee payments in this middleware design are built on the assumption that sender chains are the source of incentives — the chain on which packets are incentivized is the chain that distributes fees to relayer operators. However, as part of the IBC packet flow, messages have to be submitted on both sender and destination chains. This introduces the requirement of a mapping of relayer operator's addresses on both chains. - -To achieve the stated requirements, the **fee middleware module has two main groups of functionality**: - -- Registering of relayer addresses associated with each party involved in relaying the packet on the source chain. This registration process can be automated on start up of relayer infrastructure and happens only once, not every packet flow. - - This is described in the [Fee distribution section](04-fee-distribution.md). - -- Escrowing fees by any party which will be paid out to each rightful party on completion of the packet lifecycle. - - This is described in the [Fee messages section](03-msgs.md). - -We complete the introduction by giving a list of definitions of relevant terminolgy. - -`Forward relayer`: The relayer that submits the `MsgRecvPacket` message for a given packet (on the destination chain). - -`Reverse relayer`: The relayer that submits the `MsgAcknowledgement` message for a given packet (on the source chain). - -`Timeout relayer`: The relayer that submits the `MsgTimeout` or `MsgTimeoutOnClose` messages for a given packet (on the source chain). - -`Payee`: The account address on the source chain to be paid on completion of the packet lifecycle. The packet lifecycle on the source chain completes with the receipt of a `MsgTimeout`/`MsgTimeoutOnClose` or a `MsgAcknowledgement`. - -`Counterparty payee`: The account address to be paid on completion of the packet lifecycle on the destination chain. The package lifecycle on the destination chain completes with a successful `MsgRecvPacket`. - -`Refund address`: The address of the account paying for the incentivization of packet relaying. The account is refunded timeout fees upon successful acknowledgement. In the event of a packet timeout, both acknowledgement and receive fees are refunded. - -## Known Limitations - -The first version of fee payments middleware will only support incentivisation of new channels, however, channel upgradeability will enable incentivisation of all existing channels. diff --git a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/02-integration.md b/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/02-integration.md deleted file mode 100644 index 4fa2909e316..00000000000 --- a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/02-integration.md +++ /dev/null @@ -1,174 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 2 -slug: /middleware/ics29-fee/integration ---- - - -# Integration - -:::note Synopsis -Learn how to configure the Fee Middleware module with IBC applications. The following document is intended for developers building on top of the Cosmos SDK and only applies for Cosmos SDK chains. -::: - -## Pre-requisite Readings - -- [IBC middleware development](../../01-ibc/04-middleware/01-develop.md) -- [IBC middleware integration](../../01-ibc/04-middleware/02-integration.md) - -The Fee Middleware module, as the name suggests, plays the role of an IBC middleware and as such must be configured by chain developers to route and handle IBC messages correctly. -For Cosmos SDK chains this setup is done via the `app/app.go` file, where modules are constructed and configured in order to bootstrap the blockchain application. - -## Example integration of the Fee Middleware module - -```go -// app.go - -// Register the AppModule for the fee middleware module -ModuleBasics = module.NewBasicManager( - ... - ibcfee.AppModuleBasic{}, - ... -) - -... - -// Add module account permissions for the fee middleware module -maccPerms = map[string][]string{ - ... - ibcfeetypes.ModuleName: nil, -} - -... - -// Add fee middleware Keeper -type App struct { - ... - - IBCFeeKeeper ibcfeekeeper.Keeper - - ... -} - -... - -// Create store keys -keys := sdk.NewKVStoreKeys( - ... - ibcfeetypes.StoreKey, - ... -) - -... - -app.IBCFeeKeeper = ibcfeekeeper.NewKeeper( - appCodec, keys[ibcfeetypes.StoreKey], - app.IBCKeeper.ChannelKeeper, // may be replaced with IBC middleware - app.IBCKeeper.ChannelKeeper, - &app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, -) - - -// See the section below for configuring an application stack with the fee middleware module - -... - -// Register fee middleware AppModule -app.moduleManager = module.NewManager( - ... - ibcfee.NewAppModule(app.IBCFeeKeeper), -) - -... - -// Add fee middleware to begin blocker logic -app.moduleManager.SetOrderBeginBlockers( - ... - ibcfeetypes.ModuleName, - ... -) - -// Add fee middleware to end blocker logic -app.moduleManager.SetOrderEndBlockers( - ... - ibcfeetypes.ModuleName, - ... -) - -// Add fee middleware to init genesis logic -app.moduleManager.SetOrderInitGenesis( - ... - ibcfeetypes.ModuleName, - ... -) -``` - -## Configuring an application stack with Fee Middleware - -As mentioned in [IBC middleware development](../../01-ibc/04-middleware/01-develop.md) an application stack may be composed of many or no middlewares that nest a base application. -These layers form the complete set of application logic that enable developers to build composable and flexible IBC application stacks. -For example, an application stack may be just a single base application like `transfer`, however, the same application stack composed with `29-fee` will nest the `transfer` base application -by wrapping it with the Fee Middleware module. - -### Transfer - -See below for an example of how to create an application stack using `transfer` and `29-fee`. -The following `transferStack` is configured in `app/app.go` and added to the IBC `Router`. -The in-line comments describe the execution flow of packets between the application stack and IBC core. - -```go -// Create Transfer Stack -// SendPacket, since it is originating from the application to core IBC: -// transferKeeper.SendPacket -> fee.SendPacket -> channel.SendPacket - -// RecvPacket, message that originates from core IBC and goes down to app, the flow is the other way -// channel.RecvPacket -> fee.OnRecvPacket -> transfer.OnRecvPacket - -// transfer stack contains (from top to bottom): -// - IBC Fee Middleware -// - Transfer - -// create IBC module from bottom to top of stack -var transferStack porttypes.IBCModule -transferStack = transfer.NewIBCModule(app.TransferKeeper) -transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) - -// Add transfer stack to IBC Router -ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) -``` - -### Interchain Accounts - -See below for an example of how to create an application stack using `27-interchain-accounts` and `29-fee`. -The following `icaControllerStack` and `icaHostStack` are configured in `app/app.go` and added to the IBC `Router` with the associated authentication module. -The in-line comments describe the execution flow of packets between the application stack and IBC core. - -```go -// Create Interchain Accounts Stack -// SendPacket, since it is originating from the application to core IBC: -// icaAuthModuleKeeper.SendTx -> icaController.SendPacket -> fee.SendPacket -> channel.SendPacket - -// initialize ICA module with mock module as the authentication module on the controller side -var icaControllerStack porttypes.IBCModule -icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp("", scopedICAMockKeeper)) -app.ICAAuthModule = icaControllerStack.(ibcmock.IBCModule) -icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) -icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) - -// RecvPacket, message that originates from core IBC and goes down to app, the flow is: -// channel.RecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket - -var icaHostStack porttypes.IBCModule -icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) -icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) - -// Add authentication module, controller and host to IBC router -ibcRouter. - // the ICA Controller middleware needs to be explicitly added to the IBC Router because the - // ICA controller module owns the port capability for ICA. The ICA authentication module - // owns the channel capability. - AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack) - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icahosttypes.SubModuleName, icaHostStack). -``` diff --git a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/03-msgs.md b/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/03-msgs.md deleted file mode 100644 index b43cd8443b0..00000000000 --- a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/03-msgs.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: Fee Messages -sidebar_label: Fee Messages -sidebar_position: 3 -slug: /middleware/ics29-fee/msgs ---- - -# Fee messages - -:::note Synopsis -Learn about the different ways to pay for fees, how the fees are paid out and what happens when not enough escrowed fees are available for payout -::: - -## Escrowing fees - -The fee middleware module exposes two different ways to pay fees for relaying IBC packets: - -1. `MsgPayPacketFee`, which enables the escrowing of fees for a packet at the next sequence send and should be combined into one `MultiMsgTx` with the message that will be paid for. - - Note that the `Relayers` field has been set up to allow for an optional whitelist of relayers permitted to receive this fee, however, this feature has not yet been enabled at this time. - - ```go - type MsgPayPacketFee struct{ - // fee encapsulates the recv, ack and timeout fees associated with an IBC packet - Fee Fee - // the source port unique identifier - SourcePortId string - // the source channel unique identifer - SourceChannelId string - // account address to refund fee if necessary - Signer string - // optional list of relayers permitted to the receive packet fee - Relayers []string - } - ``` - - The `Fee` message contained in this synchronous fee payment method configures different fees which will be paid out for `MsgRecvPacket`, `MsgAcknowledgement`, and `MsgTimeout`/`MsgTimeoutOnClose`. - - ```go - type Fee struct { - RecvFee types.Coins - AckFee types.Coins - TimeoutFee types.Coins - } - ``` - - The diagram below shows the `MultiMsgTx` with the `MsgTransfer` coming from a token transfer message, along with `MsgPayPacketFee`. - - ![msgpaypacket.png](./images/msgpaypacket.png) - -2. `MsgPayPacketFeeAsync`, which enables the asynchronous escrowing of fees for a specified packet: - - Note that a packet can be 'topped up' multiple times with additional fees of any coin denomination by broadcasting multiple `MsgPayPacketFeeAsync` messages. - - ```go - type MsgPayPacketFeeAsync struct { - // unique packet identifier comprised of the channel ID, port ID and sequence - PacketId channeltypes.PacketId - // the packet fee associated with a particular IBC packet - PacketFee PacketFee - } - ``` - - where the `PacketFee` also specifies the `Fee` to be paid as well as the refund address for fees which are not paid out - - ```go - type PacketFee struct { - Fee Fee - RefundAddress string - Relayers []string - } - ``` - -The diagram below shows how multiple `MsgPayPacketFeeAsync` can be broadcasted asynchronously. Escrowing of the fee associated with a packet can be carried out by any party because ICS-29 does not dictate a particular fee payer. In fact, chains can choose to simply not expose this fee payment to end users at all and rely on a different module account or even the community pool as the source of relayer incentives. - -![paypacketfeeasync.png](./images/paypacketfeeasync.png) - -Please see our [wiki](https://github.com/cosmos/ibc-go/wiki/Fee-enabled-fungible-token-transfers) for example flows on how to use these messages to incentivise a token transfer channel using a CLI. - -## Paying out the escrowed fees - -Following diagram takes a look at the packet flow for an incentivized token transfer and investigates the several scenario's for paying out the escrowed fees. We assume that the relayers have registered their counterparty address, detailed in the [Fee distribution section](04-fee-distribution.md). - -![feeflow.png](./images/feeflow.png) - -- In the case of a successful transaction, `RecvFee` will be paid out to the designated counterparty payee address which has been registered on the receiver chain and sent back with the `MsgAcknowledgement`, `AckFee` will be paid out to the relayer address which has submitted the `MsgAcknowledgement` on the sending chain (or the registered payee in case one has been registered for the relayer address), and `TimeoutFee` will be reimbursed to the account which escrowed the fee. -- In case of a timeout transaction, `RecvFee` and `AckFee` will be reimbursed. The `TimeoutFee` will be paid to the `Timeout Relayer` (who submits the timeout message to the source chain). - -> Please note that fee payments are built on the assumption that sender chains are the source of incentives — the chain that sends the packets is the same chain where fee payments will occur -- please see the [Fee distribution section](04-fee-distribution.md) to understand the flow for registering payee and counterparty payee (fee receiving) addresses. - -## A locked fee middleware module - -The fee middleware module can become locked if the situation arises that the escrow account for the fees does not have sufficient funds to pay out the fees which have been escrowed for each packet. *This situation indicates a severe bug.* In this case, the fee module will be locked until manual intervention fixes the issue. - -> A locked fee module will simply skip fee logic and continue on to the underlying packet flow. A channel with a locked fee module will temporarily function as a fee disabled channel, and the locking of a fee module will not affect the continued flow of packets over the channel. diff --git a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/04-fee-distribution.md b/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/04-fee-distribution.md deleted file mode 100644 index 9cfd4f3e5a6..00000000000 --- a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/04-fee-distribution.md +++ /dev/null @@ -1,114 +0,0 @@ ---- -title: Fee Distribution -sidebar_label: Fee Distribution -sidebar_position: 4 -slug: /middleware/ics29-fee/fee-distribution ---- - - -# Fee distribution - -:::note Synopsis -Learn about payee registration for the distribution of packet fees. The following document is intended for relayer operators. -::: - -## Pre-requisite readings - -- [Fee Middleware](01-overview.md) - -Packet fees are divided into 3 distinct amounts in order to compensate relayer operators for packet relaying on fee enabled IBC channels. - -- `RecvFee`: The sum of all packet receive fees distributed to a payee for successful execution of `MsgRecvPacket`. -- `AckFee`: The sum of all packet acknowledgement fees distributed to a payee for successful execution of `MsgAcknowledgement`. -- `TimeoutFee`: The sum of all packet timeout fees distributed to a payee for successful execution of `MsgTimeout`. - -## Register a counterparty payee address for forward relaying - -As mentioned in [ICS29 Concepts](01-overview.md#concepts), the forward relayer describes the actor who performs the submission of `MsgRecvPacket` on the destination chain. -Fee distribution for incentivized packet relays takes place on the packet source chain. - -> Relayer operators are expected to register a counterparty payee address, in order to be compensated accordingly with `RecvFee`s upon completion of a packet lifecycle. - -The counterparty payee address registered on the destination chain is encoded into the packet acknowledgement and communicated as such to the source chain for fee distribution. -**If a counterparty payee is not registered for the forward relayer on the destination chain, the escrowed fees will be refunded upon fee distribution.** - -### Relayer operator actions? - -A transaction must be submitted **to the destination chain** including a `CounterpartyPayee` address of an account on the source chain. -The transaction must be signed by the `Relayer`. - -Note: If a module account address is used as the `CounterpartyPayee` but the module has been set as a blocked address in the `BankKeeper`, the refunding to the module account will fail. This is because many modules use invariants to compare internal tracking of module account balances against the actual balance of the account stored in the `BankKeeper`. If a token transfer to the module account occurs without going through this module and updating the account balance of the module on the `BankKeeper`, then invariants may break and unknown behaviour could occur depending on the module implementation. Therefore, if it is desirable to use a module account that is currently blocked, the module developers should be consulted to gauge to possibility of removing the module account from the blocked list. - -```go -type MsgRegisterCounterpartyPayee struct { - // unique port identifier - PortId string - // unique channel identifier - ChannelId string - // the relayer address - Relayer string - // the counterparty payee address - CounterpartyPayee string -} -``` - -> This message is expected to fail if: -> -> - `PortId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). -> - `ChannelId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -> - `Relayer` is an invalid address (see [Cosmos SDK Addresses](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/beginner/03-accounts.md#addresses)). -> - `CounterpartyPayee` is empty. - -See below for an example CLI command: - -```bash -simd tx ibc-fee register-counterparty-payee transfer channel-0 \ -cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh \ -osmo1v5y0tz01llxzf4c2afml8s3awue0ymju22wxx2 \ ---from cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh -``` - -## Register an alternative payee address for reverse and timeout relaying - -As mentioned in [ICS29 Concepts](01-overview.md#concepts), the reverse relayer describes the actor who performs the submission of `MsgAcknowledgement` on the source chain. -Similarly the timeout relayer describes the actor who performs the submission of `MsgTimeout` (or `MsgTimeoutOnClose`) on the source chain. - -> Relayer operators **may choose** to register an optional payee address, in order to be compensated accordingly with `AckFee`s and `TimeoutFee`s upon completion of a packet life cycle. - -If a payee is not registered for the reverse or timeout relayer on the source chain, then fee distribution assumes the default behaviour, where fees are paid out to the relayer account which delivers `MsgAcknowledgement` or `MsgTimeout`/`MsgTimeoutOnClose`. - -### Relayer operator actions - -A transaction must be submitted **to the source chain** including a `Payee` address of an account on the source chain. -The transaction must be signed by the `Relayer`. - -Note: If a module account address is used as the `Payee` it is recommended to [turn off invariant checks](https://github.com/cosmos/ibc-go/blob/71d7480c923f4227453e8a80f51be01ae7ee845e/testing/simapp/app.go#L659) for that module. - -```go -type MsgRegisterPayee struct { - // unique port identifier - PortId string - // unique channel identifier - ChannelId string - // the relayer address - Relayer string - // the payee address - Payee string -} -``` - -> This message is expected to fail if: -> -> - `PortId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). -> - `ChannelId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -> - `Relayer` is an invalid address (see [Cosmos SDK Addresses](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/beginner/03-accounts.md#addresses)). -> - `Payee` is an invalid address (see [Cosmos SDK Addresses](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/beginner/03-accounts.md#addresses)). - -See below for an example CLI command: - -```bash -simd tx ibc-fee register-payee transfer channel-0 \ -cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh \ -cosmos153lf4zntqt33a4v0sm5cytrxyqn78q7kz8j8x5 \ ---from cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh -``` diff --git a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/05-events.md b/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/05-events.md deleted file mode 100644 index eddb296b70c..00000000000 --- a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/05-events.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: Events -sidebar_label: Events -sidebar_position: 5 -slug: /middleware/ics29-fee/events ---- - - -# Events - -:::note Synopsis -An overview of all events related to ICS-29 -::: - -## `MsgPayPacketFee`, `MsgPayPacketFeeAsync` - -| Type | Attribute Key | Attribute Value | -| ----------------------- | --------------- | --------------- | -| incentivized_ibc_packet | port_id | {portID} | -| incentivized_ibc_packet | channel_id | {channelID} | -| incentivized_ibc_packet | packet_sequence | {sequence} | -| incentivized_ibc_packet | recv_fee | {recvFee} | -| incentivized_ibc_packet | ack_fee | {ackFee} | -| incentivized_ibc_packet | timeout_fee | {timeoutFee} | -| message | module | fee-ibc | - -## `RegisterPayee` - -| Type | Attribute Key | Attribute Value | -| -------------- | ------------- | --------------- | -| register_payee | relayer | {relayer} | -| register_payee | payee | {payee} | -| register_payee | channel_id | {channelID} | -| message | module | fee-ibc | - -## `RegisterCounterpartyPayee` - -| Type | Attribute Key | Attribute Value | -| --------------------------- | ------------------ | ------------------- | -| register_counterparty_payee | relayer | {relayer} | -| register_counterparty_payee | counterparty_payee | {counterpartyPayee} | -| register_counterparty_payee | channel_id | {channelID} | -| message | module | fee-ibc | diff --git a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/06-end-users.md b/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/06-end-users.md deleted file mode 100644 index fbea38d0ded..00000000000 --- a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/06-end-users.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: End Users -sidebar_label: End Users -sidebar_position: 6 -slug: /middleware/ics29-fee/end-users ---- - - -# For end users - -:::note Synopsis -Learn how to incentivize IBC packets using the ICS29 Fee Middleware module. -::: - -## Pre-requisite readings - -- [Fee Middleware](01-overview.md) - -## Summary - -Different types of end users: - -- CLI users who want to manually incentivize IBC packets -- Client developers - -The Fee Middleware module allows end users to add a 'tip' to each IBC packet which will incentivize relayer operators to relay packets between chains. gRPC endpoints are exposed for client developers as well as a simple CLI for manually incentivizing IBC packets. - -## CLI Users - -For an in depth guide on how to use the ICS29 Fee Middleware module using the CLI please take a look at the [wiki](https://github.com/cosmos/ibc-go/wiki/Fee-enabled-fungible-token-transfers#asynchronous-incentivization-of-a-fungible-token-transfer) on the `ibc-go` repo. - -## Client developers - -Client developers can read more about the relevant ICS29 message types in the [Fee messages section](03-msgs.md). - -[CosmJS](https://github.com/cosmos/cosmjs) is a useful client library for signing and broadcasting Cosmos SDK messages. diff --git a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/_category_.json b/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/_category_.json deleted file mode 100644 index ddca8d29da6..00000000000 --- a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Fee Middleware", - "position": 1, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/images/feeflow.png b/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/images/feeflow.png deleted file mode 100644 index ba02071f4d8..00000000000 Binary files a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/images/feeflow.png and /dev/null differ diff --git a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/images/msgpaypacket.png b/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/images/msgpaypacket.png deleted file mode 100644 index 1bd5deb01fd..00000000000 Binary files a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/images/msgpaypacket.png and /dev/null differ diff --git a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/images/paypacketfeeasync.png b/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/images/paypacketfeeasync.png deleted file mode 100644 index 27c486a6f82..00000000000 Binary files a/docs/versioned_docs/version-v6.2.x/03-middleware/01-ics29-fee/images/paypacketfeeasync.png and /dev/null differ diff --git a/docs/versioned_docs/version-v6.2.x/03-middleware/_category_.json b/docs/versioned_docs/version-v6.2.x/03-middleware/_category_.json deleted file mode 100644 index 886249e8634..00000000000 --- a/docs/versioned_docs/version-v6.2.x/03-middleware/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "IBC Middleware Modules", - "position": 3, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v6.2.x/04-migrations/01-support-denoms-with-slashes.md b/docs/versioned_docs/version-v6.2.x/04-migrations/01-support-denoms-with-slashes.md deleted file mode 100644 index 54bbd96227e..00000000000 --- a/docs/versioned_docs/version-v6.2.x/04-migrations/01-support-denoms-with-slashes.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: Support transfer of coins whose base denom contains slashes -sidebar_label: Support transfer of coins whose base denom contains slashes -sidebar_position: 1 -slug: /migrations/support-denoms-with-slashes ---- -# Migrating from not supporting base denoms with slashes to supporting base denoms with slashes - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -This document is necessary when chains are upgrading from a version that does not support base denoms with slashes (e.g. v3.0.0) to a version that does (e.g. v3.2.0). All versions of ibc-go smaller than v1.5.0 for the v1.x release line, v2.3.0 for the v2.x release line, and v3.1.0 for the v3.x release line do **NOT** support IBC token transfers of coins whose base denoms contain slashes. Therefore the in-place of genesis migration described in this document are required when upgrading. - -If a chain receives coins of a base denom with slashes before it upgrades to supporting it, the receive may pass however the trace information will be incorrect. - -E.g. If a base denom of `testcoin/testcoin/testcoin` is sent to a chain that does not support slashes in the base denom, the receive will be successful. However, the trace information stored on the receiving chain will be: `Trace: "transfer/{channel-id}/testcoin/testcoin", BaseDenom: "testcoin"`. - -This incorrect trace information must be corrected when the chain does upgrade to fully supporting denominations with slashes. - -To do so, chain binaries should include a migration script that will run when the chain upgrades from not supporting base denominations with slashes to supporting base denominations with slashes. - -## Chains - -### ICS20 - Transfer - -The transfer module will now support slashes in base denoms, so we must iterate over current traces to check if any of them are incorrectly formed and correct the trace information. - -### Upgrade Proposal - -```go -app.UpgradeKeeper.SetUpgradeHandler("MigrateTraces", - func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - // transfer module consensus version has been bumped to 2 - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) - -``` - -This is only necessary if there are denom traces in the store with incorrect trace information from previously received coins that had a slash in the base denom. However, it is recommended that any chain upgrading to support base denominations with slashes runs this code for safety. - -For a more detailed sample, please check out the code changes in [this pull request](https://github.com/cosmos/ibc-go/pull/1680). - -### Genesis Migration - -If the chain chooses to add support for slashes in base denoms via genesis export, then the trace information must be corrected during genesis migration. - -The migration code required may look like: - -```go -func migrateGenesisSlashedDenomsUpgrade(appState genutiltypes.AppMap, clientCtx client.Context, genDoc *tmtypes.GenesisDoc) (genutiltypes.AppMap, error) { - if appState[ibctransfertypes.ModuleName] != nil { - transferGenState := &ibctransfertypes.GenesisState{} - clientCtx.Codec.MustUnmarshalJSON(appState[ibctransfertypes.ModuleName], transferGenState) - - substituteTraces := make([]ibctransfertypes.DenomTrace, len(transferGenState.DenomTraces)) - for i, dt := range transferGenState.DenomTraces { - // replace all previous traces with the latest trace if validation passes - // note most traces will have same value - newTrace := ibctransfertypes.ParseDenomTrace(dt.GetFullDenomPath()) - - if err := newTrace.Validate(); err != nil { - substituteTraces[i] = dt - } else { - substituteTraces[i] = newTrace - } - } - - transferGenState.DenomTraces = substituteTraces - - // delete old genesis state - delete(appState, ibctransfertypes.ModuleName) - - // set new ibc transfer genesis state - appState[ibctransfertypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(transferGenState) - } - - return appState, nil -} -``` - -For a more detailed sample, please check out the code changes in [this pull request](https://github.com/cosmos/ibc-go/pull/1528). diff --git a/docs/versioned_docs/version-v6.2.x/04-migrations/02-sdk-to-v1.md b/docs/versioned_docs/version-v6.2.x/04-migrations/02-sdk-to-v1.md deleted file mode 100644 index f979034e272..00000000000 --- a/docs/versioned_docs/version-v6.2.x/04-migrations/02-sdk-to-v1.md +++ /dev/null @@ -1,195 +0,0 @@ ---- -title: SDK v0.43 to IBC-Go v1 -sidebar_label: SDK v0.43 to IBC-Go v1 -sidebar_position: 2 -slug: /migrations/sdk-to-v1 ---- -# Migrating to ibc-go - -This file contains information on how to migrate from the IBC module contained in the SDK 0.41.x and 0.42.x lines to the IBC module in the ibc-go repository based on the 0.44 SDK version. - -## Import Changes - -The most obvious changes is import name changes. We need to change: - -- applications -> apps -- cosmos-sdk/x/ibc -> ibc-go - -On my GNU/Linux based machine I used the following commands, executed in order: - -```bash -grep -RiIl 'cosmos-sdk\/x\/ibc\/applications' | xargs sed -i 's/cosmos-sdk\/x\/ibc\/applications/ibc-go\/modules\/apps/g' -``` - -```bash -grep -RiIl 'cosmos-sdk\/x\/ibc' | xargs sed -i 's/cosmos-sdk\/x\/ibc/ibc-go\/modules/g' -``` - -ref: [explanation of the above commands](https://www.internalpointers.com/post/linux-find-and-replace-text-multiple-files) - -Executing these commands out of order will cause issues. - -Feel free to use your own method for modifying import names. - -NOTE: Updating to the `v0.44.0` SDK release and then running `go mod tidy` will cause a downgrade to `v0.42.0` in order to support the old IBC import paths. -Update the import paths before running `go mod tidy`. - -## Chain Upgrades - -Chains may choose to upgrade via an upgrade proposal or genesis upgrades. Both in-place store migrations and genesis migrations are supported. - -**WARNING**: Please read at least the quick guide for [IBC client upgrades](../01-ibc/05-upgrades/00-intro.md) before upgrading your chain. It is highly recommended you do not change the chain-ID during an upgrade, otherwise you must follow the IBC client upgrade instructions. - -Both in-place store migrations and genesis migrations will: - -- migrate the solo machine client state from v1 to v2 protobuf definitions -- prune all solo machine consensus states -- prune all expired tendermint consensus states - -Chains must set a new connection parameter during either in place store migrations or genesis migration. The new parameter, max expected block time, is used to enforce packet processing delays on the receiving end of an IBC packet flow. Checkout the [docs](https://github.com/cosmos/ibc-go/blob/release/v1.0.x/docs/ibc/proto-docs.md#params-2) for more information. - -### In-Place Store Migrations - -The new chain binary will need to run migrations in the upgrade handler. The fromVM (previous module version) for the IBC module should be 1. This will allow migrations to be run for IBC updating the version from 1 to 2. - -Ex: - -```go -app.UpgradeKeeper.SetUpgradeHandler("my-upgrade-proposal", - func(ctx sdk.Context, _ upgradetypes.Plan, _ module.VersionMap) (module.VersionMap, error) { - // set max expected block time parameter. Replace the default with your expected value - // https://github.com/cosmos/ibc-go/blob/release/v1.0.x/docs/ibc/proto-docs.md#params-2 - app.IBCKeeper.ConnectionKeeper.SetParams(ctx, ibcconnectiontypes.DefaultParams()) - - fromVM := map[string]uint64{ - ... // other modules - "ibc": 1, - ... - } - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) - -``` - -### Genesis Migrations - -To perform genesis migrations, the following code must be added to your existing migration code. - -```go -// add imports as necessary -import ( - ibcv100 "github.com/cosmos/ibc-go/modules/core/legacy/v100" - ibchost "github.com/cosmos/ibc-go/modules/core/24-host" -) - -... - -// add in migrate cmd function -// expectedTimePerBlock is a new connection parameter -// https://github.com/cosmos/ibc-go/blob/release/v1.0.x/docs/ibc/proto-docs.md#params-2 -newGenState, err = ibcv100.MigrateGenesis(newGenState, clientCtx, *genDoc, expectedTimePerBlock) -if err != nil { - return err -} -``` - -**NOTE:** The genesis chain-id, time and height MUST be updated before migrating IBC, otherwise the tendermint consensus state will not be pruned. - -## IBC Keeper Changes - -The IBC Keeper now takes in the Upgrade Keeper. Please add the chains' Upgrade Keeper after the Staking Keeper: - -```diff - // Create IBC Keeper - app.IBCKeeper = ibckeeper.NewKeeper( -- appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, scopedIBCKeeper, -+ appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper, - ) - -``` - -## Proposals - -### UpdateClientProposal - -The `UpdateClient` has been modified to take in two client-identifiers and one initial height. Please see the [documentation](../01-ibc/06-proposals.md) for more information. - -### UpgradeProposal - -A new IBC proposal type has been added, `UpgradeProposal`. This handles an IBC (breaking) Upgrade. -The previous `UpgradedClientState` field in an Upgrade `Plan` has been deprecated in favor of this new proposal type. - -### Proposal Handler Registration - -The `ClientUpdateProposalHandler` has been renamed to `ClientProposalHandler`. -It handles both `UpdateClientProposal`s and `UpgradeProposal`s. - -Add this import: - -```diff -+ ibcclienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" -``` - -Please ensure the governance module adds the correct route: - -```diff -- AddRoute(ibchost.RouterKey, ibcclient.NewClientUpdateProposalHandler(app.IBCKeeper.ClientKeeper)) -+ AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)) -``` - -NOTE: Simapp registration was incorrect in the 0.41.x releases. The `UpdateClient` proposal handler should be registered with the router key belonging to `ibc-go/core/02-client/types` -as shown in the diffs above. - -### Proposal CLI Registration - -Please ensure both proposal type CLI commands are registered on the governance module by adding the following arguments to `gov.NewAppModuleBasic()`: - -Add the following import: - -```diff -+ ibcclientclient "github.com/cosmos/ibc-go/modules/core/02-client/client" -``` - -Register the cli commands: - -```diff - gov.NewAppModuleBasic( - paramsclient.ProposalHandler, distrclient.ProposalHandler, upgradeclient.ProposalHandler, upgradeclient.CancelProposalHandler, -+ ibcclientclient.UpdateClientProposalHandler, ibcclientclient.UpgradeProposalHandler, - ), -``` - -REST routes are not supported for these proposals. - -## Proto file changes - -The gRPC querier service endpoints have changed slightly. The previous files used `v1beta1` gRPC route, this has been updated to `v1`. - -The solo machine has replaced the FrozenSequence uint64 field with a IsFrozen boolean field. The package has been bumped from `v1` to `v2` - -## IBC callback changes - -### OnRecvPacket - -Application developers need to update their `OnRecvPacket` callback logic. - -The `OnRecvPacket` callback has been modified to only return the acknowledgement. The acknowledgement returned must implement the `Acknowledgement` interface. The acknowledgement should indicate if it represents a successful processing of a packet by returning true on `Success()` and false in all other cases. A return value of false on `Success()` will result in all state changes which occurred in the callback being discarded. More information can be found in the [documentation](../01-ibc/03-apps/02-ibcmodule.md#receiving-packets). - -The `OnRecvPacket`, `OnAcknowledgementPacket`, and `OnTimeoutPacket` callbacks are now passed the `sdk.AccAddress` of the relayer who relayed the IBC packet. Applications may use or ignore this information. - -## IBC Event changes - -The `packet_data` attribute has been deprecated in favor of `packet_data_hex`, in order to provide standardized encoding/decoding of packet data in events. While the `packet_data` event still exists, all relayers and IBC Event consumers are strongly encouraged to switch over to using `packet_data_hex` as soon as possible. - -The `packet_ack` attribute has also been deprecated in favor of `packet_ack_hex` for the same reason stated above. All relayers and IBC Event consumers are strongly encouraged to switch over to using `packet_ack_hex` as soon as possible. - -The `consensus_height` attribute has been removed in the Misbehaviour event emitted. IBC clients no longer have a frozen height and misbehaviour does not necessarily have an associated height. - -## Relevant SDK changes - -- (codec) [\#9226](https://github.com/cosmos/cosmos-sdk/pull/9226) Rename codec interfaces and methods, to follow a general Go interfaces: - - `codec.Marshaler` → `codec.Codec` (this defines objects which serialize other objects) - - `codec.BinaryMarshaler` → `codec.BinaryCodec` - - `codec.JSONMarshaler` → `codec.JSONCodec` - - Removed `BinaryBare` suffix from `BinaryCodec` methods (`MarshalBinaryBare`, `UnmarshalBinaryBare`, ...) - - Removed `Binary` infix from `BinaryCodec` methods (`MarshalBinaryLengthPrefixed`, `UnmarshalBinaryLengthPrefixed`, ...) diff --git a/docs/versioned_docs/version-v6.2.x/04-migrations/03-v1-to-v2.md b/docs/versioned_docs/version-v6.2.x/04-migrations/03-v1-to-v2.md deleted file mode 100644 index 577ddf995bf..00000000000 --- a/docs/versioned_docs/version-v6.2.x/04-migrations/03-v1-to-v2.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: IBC-Go v1 to v2 -sidebar_label: IBC-Go v1 to v2 -sidebar_position: 3 -slug: /migrations/v1-to-v2 ---- -# Migrating from ibc-go v1 to v2 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -```go -github.com/cosmos/ibc-go -> github.com/cosmos/ibc-go/v2 -``` - -## Chains - -- No relevant changes were made in this release. - -## IBC Apps - -A new function has been added to the app module interface: - -```go -// NegotiateAppVersion performs application version negotiation given the provided channel ordering, connectionID, portID, counterparty and proposed version. - // An error is returned if version negotiation cannot be performed. For example, an application module implementing this interface - // may decide to return an error in the event of the proposed version being incompatible with it's own - NegotiateAppVersion( - ctx sdk.Context, - order channeltypes.Order, - connectionID string, - portID string, - counterparty channeltypes.Counterparty, - proposedVersion string, - ) (version string, err error) -} -``` - -This function should perform application version negotiation and return the negotiated version. If the version cannot be negotiated, an error should be returned. This function is only used on the client side. - -### sdk.Result removed - -sdk.Result has been removed as a return value in the application callbacks. Previously it was being discarded by core IBC and was thus unused. - -## Relayers - -A new gRPC has been added to 05-port, `AppVersion`. It returns the negotiated app version. This function should be used for the `ChanOpenTry` channel handshake step to decide upon the application version which should be set in the channel. - -## IBC Light Clients - -- No relevant changes were made in this release. diff --git a/docs/versioned_docs/version-v6.2.x/04-migrations/04-v2-to-v3.md b/docs/versioned_docs/version-v6.2.x/04-migrations/04-v2-to-v3.md deleted file mode 100644 index cf4e1c1b8e3..00000000000 --- a/docs/versioned_docs/version-v6.2.x/04-migrations/04-v2-to-v3.md +++ /dev/null @@ -1,186 +0,0 @@ ---- -title: IBC-Go v2 to v3 -sidebar_label: IBC-Go v2 to v3 -sidebar_position: 4 -slug: /migrations/v2-to-v3 ---- -# Migrating from ibc-go v2 to v3 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -```go -github.com/cosmos/ibc-go/v2 -> github.com/cosmos/ibc-go/v3 -``` - -No genesis or in-place migrations are required when upgrading from v1 or v2 of ibc-go. - -## Chains - -### ICS20 - -The `transferkeeper.NewKeeper(...)` now takes in an ICS4Wrapper. -The ICS4Wrapper should be the IBC Channel Keeper unless ICS 20 is being connected to a middleware application. - -### ICS27 - -ICS27 Interchain Accounts has been added as a supported IBC application of ibc-go. -Please see the [ICS27 documentation](../02-apps/02-interchain-accounts/01-overview.md) for more information. - -### Upgrade Proposal - -If the chain will adopt ICS27, it must set the appropriate params during the execution of the upgrade handler in `app.go`: - -```go -app.UpgradeKeeper.SetUpgradeHandler("v3", - func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - // set the ICS27 consensus version so InitGenesis is not run - fromVM[icatypes.ModuleName] = icamodule.ConsensusVersion() - - // create ICS27 Controller submodule params - controllerParams := icacontrollertypes.Params{ - ControllerEnabled: true, - } - - // create ICS27 Host submodule params - hostParams := icahosttypes.Params{ - HostEnabled: true, - AllowMessages: []string{"/cosmos.bank.v1beta1.MsgSend", ...}, - } - - // initialize ICS27 module - icamodule.InitModule(ctx, controllerParams, hostParams) - - ... - - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) - -``` - -The host and controller submodule params only need to be set if the chain integrates those submodules. -For example, if a chain chooses not to integrate a controller submodule, it may pass empty params into `InitModule`. - -#### Add `StoreUpgrades` for ICS27 module - -For ICS27 it is also necessary to [manually add store upgrades](https://docs.cosmos.network/main/learn/advanced/upgrade#add-storeupgrades-for-new-modules) for the new ICS27 module and then configure the store loader to apply those upgrades in `app.go`: - -```go -if upgradeInfo.Name == "v3" && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { - storeUpgrades := store.StoreUpgrades{ - Added: []string{icacontrollertypes.StoreKey, icahosttypes.StoreKey}, - } - - app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) -} -``` - -This ensures that the new module's stores are added to the multistore before the migrations begin. -The host and controller submodule keys only need to be added if the chain integrates those submodules. -For example, if a chain chooses not to integrate a controller submodule, it does not need to add the controller key to the `Added` field. - -### Genesis migrations - -If the chain will adopt ICS27 and chooses to upgrade via a genesis export, then the ICS27 parameters must be set during genesis migration. - -The migration code required may look like: - -```go - controllerGenesisState := icatypes.DefaultControllerGenesis() - // overwrite parameters as desired - controllerGenesisState.Params = icacontrollertypes.Params{ - ControllerEnabled: true, - } - - hostGenesisState := icatypes.DefaultHostGenesis() - // overwrite parameters as desired - hostGenesisState.Params = icahosttypes.Params{ - HostEnabled: true, - AllowMessages: []string{"/cosmos.bank.v1beta1.MsgSend", ...}, - } - - icaGenesisState := icatypes.NewGenesisState(controllerGenesisState, hostGenesisState) - - // set new ics27 genesis state - appState[icatypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(icaGenesisState) -``` - -### Ante decorator - -The field of type `channelkeeper.Keeper` in the `AnteDecorator` structure has been replaced with a field of type `*keeper.Keeper`: - -```diff -type AnteDecorator struct { -- k channelkeeper.Keeper -+ k *keeper.Keeper -} - -- func NewAnteDecorator(k channelkeeper.Keeper) AnteDecorator { -+ func NewAnteDecorator(k *keeper.Keeper) AnteDecorator { - return AnteDecorator{k: k} -} -``` - -## IBC Apps - -### `OnChanOpenTry` must return negotiated application version - -The `OnChanOpenTry` application callback has been modified. -The return signature now includes the application version. -IBC applications must perform application version negoitation in `OnChanOpenTry` using the counterparty version. -The negotiated application version then must be returned in `OnChanOpenTry` to core IBC. -Core IBC will set this version in the TRYOPEN channel. - -### `OnChanOpenAck` will take additional `counterpartyChannelID` argument - -The `OnChanOpenAck` application callback has been modified. -The arguments now include the counterparty channel id. - -### `NegotiateAppVersion` removed from `IBCModule` interface - -Previously this logic was handled by the `NegotiateAppVersion` function. -Relayers would query this function before calling `ChanOpenTry`. -Applications would then need to verify that the passed in version was correct. -Now applications will perform this version negotiation during the channel handshake, thus removing the need for `NegotiateAppVersion`. - -### Channel state will not be set before application callback - -The channel handshake logic has been reorganized within core IBC. -Channel state will not be set in state after the application callback is performed. -Applications must rely only on the passed in channel parameters instead of querying the channel keeper for channel state. - -### IBC application callbacks moved from `AppModule` to `IBCModule` - -Previously, IBC module callbacks were apart of the `AppModule` type. -The recommended approach is to create an `IBCModule` type and move the IBC module callbacks from `AppModule` to `IBCModule` in a separate file `ibc_module.go`. - -The mock module go API has been broken in this release by applying the above format. -The IBC module callbacks have been moved from the mock modules `AppModule` into a new type `IBCModule`. - -As apart of this release, the mock module now supports middleware testing. Please see the [README](https://github.com/cosmos/ibc-go/blob/v6.1.0/testing/README.md#middleware-testing) for more information. - -Please review the [mock](https://github.com/cosmos/ibc-go/blob/v6.1.0/testing/mock/ibc_module.go) and [transfer](https://github.com/cosmos/ibc-go/blob/v6.1.0/modules/apps/transfer/ibc_module.go) modules as examples. Additionally, [simapp](https://github.com/cosmos/ibc-go/blob/v6.1.0/testing/simapp/app.go) provides an example of how `IBCModule` types should now be added to the IBC router in favour of `AppModule`. - -### IBC testing package - -`TestChain`s are now created with chainID's beginning from an index of 1. Any calls to `GetChainID(0)` will now fail. Please increment all calls to `GetChainID` by 1. - -## Relayers - -`AppVersion` gRPC has been removed. -The `version` string in `MsgChanOpenTry` has been deprecated and will be ignored by core IBC. -Relayers no longer need to determine the version to use on the `ChanOpenTry` step. -IBC applications will determine the correct version using the counterparty version. - -## IBC Light Clients - -The `GetProofSpecs` function has been removed from the `ClientState` interface. This function was previously unused by core IBC. Light clients which don't use this function may remove it. diff --git a/docs/versioned_docs/version-v6.2.x/04-migrations/05-v3-to-v4.md b/docs/versioned_docs/version-v6.2.x/04-migrations/05-v3-to-v4.md deleted file mode 100644 index 067d8738e68..00000000000 --- a/docs/versioned_docs/version-v6.2.x/04-migrations/05-v3-to-v4.md +++ /dev/null @@ -1,160 +0,0 @@ ---- -title: IBC-Go v3 to v4 -sidebar_label: IBC-Go v3 to v4 -sidebar_position: 5 -slug: /migrations/v3-to-v4 ---- -# Migrating from ibc-go v3 to v4 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -```go -github.com/cosmos/ibc-go/v3 -> github.com/cosmos/ibc-go/v4 -``` - -No genesis or in-place migrations required when upgrading from v1 or v2 of ibc-go. - -## Chains - -### ICS27 - Interchain Accounts - -The controller submodule implements now the 05-port `Middleware` interface instead of the 05-port `IBCModule` interface. Chains that integrate the controller submodule, need to create it with the `NewIBCMiddleware` constructor function. For example: - -```diff -- icacontroller.NewIBCModule(app.ICAControllerKeeper, icaAuthIBCModule) -+ icacontroller.NewIBCMiddleware(icaAuthIBCModule, app.ICAControllerKeeper) -``` - -where `icaAuthIBCModule` is the Interchain Accounts authentication IBC Module. - -### ICS29 - Fee Middleware - -The Fee Middleware module, as the name suggests, plays the role of an IBC middleware and as such must be configured by chain developers to route and handle IBC messages correctly. - -Please read the Fee Middleware [integration documentation](https://ibc.cosmos.network/main/middleware/ics29-fee/integration.html) for an in depth guide on how to congfigure the module correctly in order to incentivize IBC packets. - -Take a look at the following diff for an [example setup](https://github.com/cosmos/ibc-go/pull/1432/files#diff-d18972debee5e64f16e40807b2ae112ddbe609504a93ea5e1c80a5d489c3a08aL366) of how to incentivize ics27 channels. - -### Migration to fix support for base denoms with slashes - -As part of [v1.5.0](https://github.com/cosmos/ibc-go/releases/tag/v1.5.0), [v2.3.0](https://github.com/cosmos/ibc-go/releases/tag/v2.3.0) and [v3.1.0](https://github.com/cosmos/ibc-go/releases/tag/v3.1.0) some [migration handler code sample was documented](./01-support-denoms-with-slashes.md#upgrade-proposal) that needs to run in order to correct the trace information of coins transferred using ICS20 whose base denom contains slashes. - -Based on feedback from the community we add now an improved solution to run the same migration that does not require copying a large piece of code over from the migration document, but instead requires only adding a one-line upgrade handler. - -If the chain will migrate to supporting base denoms with slashes, it must set the appropriate params during the execution of the upgrade handler in `app.go`: - -```go -app.UpgradeKeeper.SetUpgradeHandler("MigrateTraces", - func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - // transfer module consensus version has been bumped to 2 - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) - -``` - -If a chain receives coins of a base denom with slashes before it upgrades to supporting it, the receive may pass however the trace information will be incorrect. - -E.g. If a base denom of `testcoin/testcoin/testcoin` is sent to a chain that does not support slashes in the base denom, the receive will be successful. However, the trace information stored on the receiving chain will be: `Trace: "transfer/{channel-id}/testcoin/testcoin", BaseDenom: "testcoin"`. - -This incorrect trace information must be corrected when the chain does upgrade to fully supporting denominations with slashes. - -## IBC Apps - -### ICS03 - Connection - -Crossing hellos have been removed from 03-connection handshake negotiation. -`PreviousConnectionId` in `MsgConnectionOpenTry` has been deprecated and is no longer used by core IBC. - -`NewMsgConnectionOpenTry` no longer takes in the `PreviousConnectionId` as crossing hellos are no longer supported. A non-empty `PreviousConnectionId` will fail basic validation for this message. - -### ICS04 - Channel - -The `WriteAcknowledgement` API now takes the `exported.Acknowledgement` type instead of passing in the acknowledgement byte array directly. -This is an API breaking change and as such IBC application developers will have to update any calls to `WriteAcknowledgement`. - -The `OnChanOpenInit` application callback has been modified. -The return signature now includes the application version as detailed in the latest IBC [spec changes](https://github.com/cosmos/ibc/pull/629). - -The `NewErrorAcknowledgement` method signature has changed. -It now accepts an `error` rather than a `string`. This was done in order to prevent accidental state changes. -All error acknowledgements now contain a deterministic ABCI code and error message. It is the responsibility of the application developer to emit error details in events. - -Crossing hellos have been removed from 04-channel handshake negotiation. -IBC Applications no longer need to account from already claimed capabilities in the `OnChanOpenTry` callback. The capability provided by core IBC must be able to be claimed with error. -`PreviousChannelId` in `MsgChannelOpenTry` has been deprecated and is no longer used by core IBC. - -`NewMsgChannelOpenTry` no longer takes in the `PreviousChannelId` as crossing hellos are no longer supported. A non-empty `PreviousChannelId` will fail basic validation for this message. - -### ICS27 - Interchain Accounts - -The `RegisterInterchainAccount` API has been modified to include an additional `version` argument. This change has been made in order to support ICS29 fee middleware, for relayer incentivization of ICS27 packets. -Consumers of the `RegisterInterchainAccount` are now expected to build the appropriate JSON encoded version string themselves and pass it accordingly. -This should be constructed within the interchain accounts authentication module which leverages the APIs exposed via the interchain accounts `controllerKeeper`. If an empty string is passed in the `version` argument, then the version will be initialized to a default value in the `OnChanOpenInit` callback of the controller's handler, so that channel handshake can proceed. - -The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, msg.Owner, string(appVersion)); err != nil { - return err -} -``` - -Similarly, if the application stack is configured to route through ICS29 fee middleware and a fee enabled channel is desired, construct the appropriate ICS29 `Metadata` type: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -feeMetadata := feetypes.Metadata{ - AppVersion: string(appVersion), - FeeVersion: feetypes.Version, -} - -feeEnabledVersion, err := feetypes.ModuleCdc.MarshalJSON(&feeMetadata) -if err != nil { - return err -} - -if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, msg.Owner, string(feeEnabledVersion)); err != nil { - return err -} -``` - -## Relayers - -When using the `DenomTrace` gRPC, the full IBC denomination with the `ibc/` prefix may now be passed in. - -Crossing hellos are no longer supported by core IBC for 03-connection and 04-channel. The handshake should be completed in the logical 4 step process (INIT, TRY, ACK, CONFIRM). diff --git a/docs/versioned_docs/version-v6.2.x/04-migrations/06-v4-to-v5.md b/docs/versioned_docs/version-v6.2.x/04-migrations/06-v4-to-v5.md deleted file mode 100644 index 5cff00cf833..00000000000 --- a/docs/versioned_docs/version-v6.2.x/04-migrations/06-v4-to-v5.md +++ /dev/null @@ -1,441 +0,0 @@ ---- -title: IBC-Go v4 to v5 -sidebar_label: IBC-Go v4 to v5 -sidebar_position: 6 -slug: /migrations/v4-to-v5 ---- - -# Migrating from v4 to v5 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- [Chains](#chains) -- [IBC Apps](#ibc-apps) -- [Relayers](#relayers) -- [IBC Light Clients](#relayers) - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -```go -github.com/cosmos/ibc-go/v4 -> github.com/cosmos/ibc-go/v5 -``` - -## Chains - -### Ante decorator - -The `AnteDecorator` type in `core/ante` has been renamed to `RedundantRelayDecorator` (and the corresponding constructor function to `NewRedundantRelayDecorator`). Therefore in the function that creates the instance of the `sdk.AnteHandler` type (e.g. `NewAnteHandler`) the change would be like this: - -```diff -func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { - // parameter validation - - anteDecorators := []sdk.AnteDecorator{ - // other ante decorators -- ibcante.NewAnteDecorator(opts.IBCkeeper), -+ ibcante.NewRedundantRelayDecorator(options.IBCKeeper), - } - - return sdk.ChainAnteDecorators(anteDecorators...), nil -} -``` - -The `AnteDecorator` was actually renamed twice, but in [this PR](https://github.com/cosmos/ibc-go/pull/1820) you can see the changes made for the final rename. - -## IBC Apps - -### Core - -The `key` parameter of the `NewKeeper` function in `modules/core/keeper` is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`): - -```diff -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - stakingKeeper clienttypes.StakingKeeper, - upgradeKeeper clienttypes.UpgradeKeeper, - scopedKeeper capabilitykeeper.ScopedKeeper, -) *Keeper -``` - -The `RegisterRESTRoutes` function in `modules/core` has been removed. - -### ICS03 - Connection - -The `key` parameter of the `NewKeeper` function in `modules/core/03-connection/keeper` is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`): - -```diff -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - ck types.ClientKeeper -) Keeper -``` - -### ICS04 - Channel - -The function `NewPacketId` in `modules/core/04-channel/types` has been renamed to `NewPacketID`: - -```diff -- func NewPacketId( -+ func NewPacketID( - portID, - channelID string, - seq uint64 -) PacketId -``` - -The `key` parameter of the `NewKeeper` function in `modules/core/04-channel/keeper` is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`): - -```diff -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - clientKeeper types.ClientKeeper, - connectionKeeper types.ConnectionKeeper, - portKeeper types.PortKeeper, - scopedKeeper capabilitykeeper.ScopedKeeper, -) Keeper -``` - -### ICS20 - Transfer - -The `key` parameter of the `NewKeeper` function in `modules/apps/transfer/keeper` is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`): - -```diff -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - ics4Wrapper types.ICS4Wrapper, - channelKeeper types.ChannelKeeper, - portKeeper types.PortKeeper, - authKeeper types.AccountKeeper, - bankKeeper types.BankKeeper, - scopedKeeper capabilitykeeper.ScopedKeeper, -) Keeper -``` - -The `amount` parameter of function `GetTransferCoin` in `modules/apps/transfer/types` is now of type `math.Int` (`"cosmossdk.io/math"`): - -```diff -func GetTransferCoin( - portID, channelID, baseDenom string, -- amount sdk.Int -+ amount math.Int -) sdk.Coin -``` - -The `RegisterRESTRoutes` function in `modules/apps/transfer` has been removed. - -### ICS27 - Interchain Accounts - -The `key` and `msgRouter` parameters of the `NewKeeper` functions in - -- `modules/apps/27-interchain-accounts/controller/keeper` -- and `modules/apps/27-interchain-accounts/host/keeper` - -have changed type. The `key` parameter is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`), and the `msgRouter` parameter is now of type `*icatypes.MessageRouter` (where `icatypes` is an import alias for `"github.com/cosmos/ibc-go/v5/modules/apps/27-interchain-accounts/types"`): - -```diff -// NewKeeper creates a new interchain accounts controller Keeper instance -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - ics4Wrapper icatypes.ICS4Wrapper, - channelKeeper icatypes.ChannelKeeper, - portKeeper icatypes.PortKeeper, - scopedKeeper capabilitykeeper.ScopedKeeper, -- msgRouter *baseapp.MsgServiceRouter, -+ msgRouter *icatypes.MessageRouter, -) Keeper -``` - -```diff -// NewKeeper creates a new interchain accounts host Keeper instance -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - channelKeeper icatypes.ChannelKeeper, - portKeeper icatypes.PortKeeper, - accountKeeper icatypes.AccountKeeper, - scopedKeeper capabilitykeeper.ScopedKeeper, -- msgRouter *baseapp.MsgServiceRouter, -+ msgRouter *icatypes.MessageRouter, -) Keeper -``` - -The new `MessageRouter` interface is defined as: - -```go -type MessageRouter interface { - Handler(msg sdk.Msg) baseapp.MsgServiceHandler -} -``` - -The `RegisterRESTRoutes` function in `modules/apps/27-interchain-accounts` has been removed. - -An additional parameter, `ics4Wrapper` has been added to the `host` submodule `NewKeeper` function in `modules/apps/27-interchain-accounts/host/keeper`. -This allows the `host` submodule to correctly unwrap the channel version for channel reopening handshakes in the `OnChanOpenTry` callback. - -```diff -func NewKeeper( - cdc codec.BinaryCodec, - key storetypes.StoreKey, - paramSpace paramtypes.Subspace, -+ ics4Wrapper icatypes.ICS4Wrapper, - channelKeeper icatypes.ChannelKeeper, - portKeeper icatypes.PortKeeper, - accountKeeper icatypes.AccountKeeper, - scopedKeeper icatypes.ScopedKeeper, - msgRouter icatypes.MessageRouter, -) Keeper -``` - -#### Cosmos SDK message handler responses in packet acknowledgement - -The construction of the transaction response of a message execution on the host chain has changed. The `Data` field in the `sdk.TxMsgData` has been deprecated and since Cosmos SDK 0.46 the `MsgResponses` field contains the message handler responses packed into `Any`s. - -For chains on Cosmos SDK 0.45 and below, the message response was constructed like this: - -```go -txMsgData := &sdk.TxMsgData{ - Data: make([]*sdk.MsgData, len(msgs)), -} - -for i, msg := range msgs { - // message validation - - msgResponse, err := k.executeMsg(cacheCtx, msg) - // return if err != nil - - txMsgData.Data[i] = &sdk.MsgData{ - MsgType: sdk.MsgTypeURL(msg), - Data: msgResponse, - } -} - -// emit events - -txResponse, err := proto.Marshal(txMsgData) -// return if err != nil - -return txResponse, nil -``` - -And for chains on Cosmos SDK 0.46 and above, it is now done like this: - -```go -txMsgData := &sdk.TxMsgData{ - MsgResponses: make([]*codectypes.Any, len(msgs)), -} - -for i, msg := range msgs { - // message validation - - any, err := k.executeMsg(cacheCtx, msg) - // return if err != nil - - txMsgData.MsgResponses[i] = any -} - -// emit events - -txResponse, err := proto.Marshal(txMsgData) -// return if err != nil - -return txResponse, nil -``` - -When handling the acknowledgement in the `OnAcknowledgementPacket` callback of a custom ICA controller module, then depending on whether `txMsgData.Data` is empty or not, the logic to handle the message handler response will be different. **Only controller chains on Cosmos SDK 0.46 or above will be able to write the logic needed to handle the response from a host chain on Cosmos SDK 0.46 or above.** - -```go -var ack channeltypes.Acknowledgement -if err := channeltypes.SubModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { - return err -} - -var txMsgData sdk.TxMsgData -if err := proto.Unmarshal(ack.GetResult(), txMsgData); err != nil { - return err -} - -switch len(txMsgData.Data) { -case 0: // for SDK 0.46 and above - for _, msgResponse := range txMsgData.MsgResponses { - // unmarshall msgResponse and execute logic based on the response - } - return nil -default: // for SDK 0.45 and below - for _, msgData := range txMsgData.Data { - // unmarshall msgData and execute logic based on the response - } -} -``` - -See [ADR-03](/architecture/adr-003-ics27-acknowledgement#next-major-version-format) for more information or the [corrresponding documentation about authentication modules](../02-apps/02-interchain-accounts/03-auth-modules.md#onacknowledgementpacket). - -### ICS29 - Fee Middleware - -The `key` parameter of the `NewKeeper` function in `modules/apps/29-fee` is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`): - -```diff -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - ics4Wrapper types.ICS4Wrapper, - channelKeeper types.ChannelKeeper, - portKeeper types.PortKeeper, - authKeeper types.AccountKeeper, - bankKeeper types.BankKeeper, -) Keeper -``` - -The `RegisterRESTRoutes` function in `modules/apps/29-fee` has been removed. - -### IBC testing package - -The `MockIBCApp` type has been renamed to `IBCApp` (and the corresponding constructor function to `NewIBCApp`). This has resulted therefore in: - -- The `IBCApp` field of the `*IBCModule` in `testing/mock` to change its type as well to `*IBCApp`: - -```diff -type IBCModule struct { - appModule *AppModule -- IBCApp *MockIBCApp // base application of an IBC middleware stack -+ IBCApp *IBCApp // base application of an IBC middleware stack -} -``` - -- The `app` parameter to `*NewIBCModule` in `testing/mock` to change its type as well to `*IBCApp`: - -```diff -func NewIBCModule( - appModule *AppModule, -- app *MockIBCApp -+ app *IBCApp -) IBCModule -``` - -The `MockEmptyAcknowledgement` type has been renamed to `EmptyAcknowledgement` (and the corresponding constructor function to `NewEmptyAcknowledgement`). - -The `TestingApp` interface in `testing` has gone through some modifications: - -- The return type of the function `GetStakingKeeper` is not the concrete type `stakingkeeper.Keeper` anymore (where `stakingkeeper` is an import alias for `"github.com/cosmos/cosmos-sdk/x/staking/keeper"`), but it has been changed to the interface `ibctestingtypes.StakingKeeper` (where `ibctestingtypes` is an import alias for `""github.com/cosmos/ibc-go/v5/testing/types"`). See this [PR](https://github.com/cosmos/ibc-go/pull/2028) for more details. The `StakingKeeper` interface is defined as: - -```go -type StakingKeeper interface { - GetHistoricalInfo(ctx sdk.Context, height int64) (stakingtypes.HistoricalInfo, bool) -} -``` - -- The return type of the function `LastCommitID` has changed to `storetypes.CommitID` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`). - -See the following `git diff` for more details: - -```diff -type TestingApp interface { - abci.Application - - // ibc-go additions - GetBaseApp() *baseapp.BaseApp -- GetStakingKeeper() stakingkeeper.Keeper -+ GetStakingKeeper() ibctestingtypes.StakingKeeper - GetIBCKeeper() *keeper.Keeper - GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper - GetTxConfig() client.TxConfig - - // Implemented by SimApp - AppCodec() codec.Codec - - // Implemented by BaseApp -- LastCommitID() sdk.CommitID -+ LastCommitID() storetypes.CommitID - LastBlockHeight() int64 -} -``` - -The `powerReduction` parameter of the function `SetupWithGenesisValSet` in `testing` is now of type `math.Int` (`"cosmossdk.io/math"`): - -```diff -func SetupWithGenesisValSet( - t *testing.T, - valSet *tmtypes.ValidatorSet, - genAccs []authtypes.GenesisAccount, - chainID string, -- powerReduction sdk.Int, -+ powerReduction math.Int, - balances ...banktypes.Balance -) TestingApp -``` - -The `accAmt` parameter of the functions - -- `AddTestAddrsFromPubKeys` , -- `AddTestAddrs` -- and `AddTestAddrsIncremental` - -in `testing/simapp` are now of type `math.Int` (`"cosmossdk.io/math"`): - -```diff -func AddTestAddrsFromPubKeys( - app *SimApp, - ctx sdk.Context, - pubKeys []cryptotypes.PubKey, -- accAmt sdk.Int, -+ accAmt math.Int -) -func addTestAddrs( - app *SimApp, - ctx sdk.Context, - accNum int, -- accAmt sdk.Int, -+ accAmt math.Int, - strategy GenerateAccountStrategy -) []sdk.AccAddress -func AddTestAddrsIncremental( - app *SimApp, - ctx sdk.Context, - accNum int, -- accAmt sdk.Int, -+ accAmt math.Int -) []sdk.AccAddress -``` - -The `RegisterRESTRoutes` function in `testing/mock` has been removed. - -## Relayers - -- No relevant changes were made in this release. - -## IBC Light Clients - -### ICS02 - Client - -The `key` parameter of the `NewKeeper` function in `modules/core/02-client/keeper` is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`): - -```diff -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - sk types.StakingKeeper, - uk types.UpgradeKeeper -) Keeper -``` diff --git a/docs/versioned_docs/version-v6.2.x/04-migrations/07-v5-to-v6.md b/docs/versioned_docs/version-v6.2.x/04-migrations/07-v5-to-v6.md deleted file mode 100644 index 93f955568e3..00000000000 --- a/docs/versioned_docs/version-v6.2.x/04-migrations/07-v5-to-v6.md +++ /dev/null @@ -1,299 +0,0 @@ ---- -title: IBC-Go v5 to v6 -sidebar_label: IBC-Go v5 to v6 -sidebar_position: 7 -slug: /migrations/v5-to-v6 ---- - -# Migrating from ibc-go v5 to v6 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -## Chains - -The `ibc-go/v6` release introduces a new set of migrations for `27-interchain-accounts`. Ownership of ICS27 channel capabilities is transferred from ICS27 authentication modules and will now reside with the ICS27 controller submodule moving forward. - -For chains which contain a custom authentication module using the ICS27 controller submodule this requires a migration function to be included in the chain upgrade handler. A subsequent migration handler is run automatically, asserting the ownership of ICS27 channel capabilities has been transferred successfully. - -This migration is not required for chains which *do not* contain a custom authentication module using the ICS27 controller submodule. - -This migration facilitates the addition of the ICS27 controller submodule `MsgServer` which provides a standardised approach to integrating existing forms of authentication such as `x/gov` and `x/group` provided by the Cosmos SDK. - -For more information please refer to [ADR 009](/architecture/adr-009-v6-ics27-msgserver). - -### Upgrade proposal - -Please refer to [PR #2383](https://github.com/cosmos/ibc-go/pull/2383) for integrating the ICS27 channel capability migration logic or follow the steps outlined below: - -1. Add the upgrade migration logic to chain distribution. This may be, for example, maintained under a package `app/upgrades/v6`. - -```go -package v6 - -import ( - "github.com/cosmos/cosmos-sdk/codec" - storetypes "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" - upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - - v6 "github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts/controller/migrations/v6" -) - -const ( - UpgradeName = "v6" -) - -func CreateUpgradeHandler( - mm *module.Manager, - configurator module.Configurator, - cdc codec.BinaryCodec, - capabilityStoreKey *storetypes.KVStoreKey, - capabilityKeeper *capabilitykeeper.Keeper, - moduleName string, -) upgradetypes.UpgradeHandler { - return func(ctx sdk.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { - if err := v6.MigrateICS27ChannelCapability(ctx, cdc, capabilityStoreKey, capabilityKeeper, moduleName); err != nil { - return nil, err - } - - return mm.RunMigrations(ctx, configurator, vm) - } -} -``` - -2. Set the upgrade handler in `app.go`. The `moduleName` parameter refers to the authentication module's `ScopedKeeper` name. This is the name provided upon instantiation in `app.go` via the [`x/capability` keeper `ScopeToModule(moduleName string)`](https://github.com/cosmos/cosmos-sdk/blob/v0.46.1/x/capability/keeper/keeper.go#L70) method. [See here for an example in `simapp`](https://github.com/cosmos/ibc-go/blob/v5.0.0/testing/simapp/app.go#L304). - -```go -app.UpgradeKeeper.SetUpgradeHandler( - v6.UpgradeName, - v6.CreateUpgradeHandler( - app.mm, - app.configurator, - app.appCodec, - app.keys[capabilitytypes.ModuleName], - app.CapabilityKeeper, - >>>> moduleName <<<<, - ), -) -``` - -## IBC Apps - -### ICS27 - Interchain Accounts - -#### Controller APIs - -In previous releases of ibc-go, chain developers integrating the ICS27 interchain accounts controller functionality were expected to create a custom `Base Application` referred to as an authentication module, see the section [Building an authentication module](../02-apps/02-interchain-accounts/03-auth-modules.md) from the documentation. - -The `Base Application` was intended to be composed with the ICS27 controller submodule `Keeper` and faciliate many forms of message authentication depending on a chain's particular use case. - -Prior to ibc-go v6 the controller submodule exposed only these two functions (to which we will refer as the legacy APIs): - -- [`RegisterInterchainAccount`](https://github.com/cosmos/ibc-go/blob/v5.0.0/modules/apps/27-interchain-accounts/controller/keeper/account.go#L19) -- [`SendTx`](https://github.com/cosmos/ibc-go/blob/v5.0.0/modules/apps/27-interchain-accounts/controller/keeper/relay.go#L18) - -However, these functions have now been deprecated in favour of the new controller submodule `MsgServer` and will be removed in later releases. - -Both APIs remain functional and maintain backwards compatibility in ibc-go v6, however consumers of these APIs are now recommended to follow the message passing paradigm outlined in Cosmos SDK [ADR 031](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-031-msg-service.md) and [ADR 033](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-033-protobuf-inter-module-comm.md). This is facilitated by the Cosmos SDK [`MsgServiceRouter`](https://github.com/cosmos/cosmos-sdk/blob/main/baseapp/msg_service_router.go#L17) and chain developers creating custom application logic can now omit the ICS27 controller submodule `Keeper` from their module and instead depend on message routing. - -Depending on the use case, developers of custom authentication modules face one of three scenarios: - -![auth-module-decision-tree.png](./images/auth-module-decision-tree.png) - -**My authentication module needs to access IBC packet callbacks** - -Application developers that wish to consume IBC packet callbacks and react upon packet acknowledgements **must** continue using the controller submodule's legacy APIs. The authentication modules will not need a `ScopedKeeper` anymore, though, because the channel capability will be claimed by the controller submodule. For example, given an Interchain Accounts authentication module keeper `ICAAuthKeeper`, the authentication module's `ScopedKeeper` (`scopedICAAuthKeeper`) is not needed anymore and can be removed for the argument list of the keeper constructor function, as shown here: - -```diff -app.ICAAuthKeeper = icaauthkeeper.NewKeeper( - appCodec, - keys[icaauthtypes.StoreKey], - app.ICAControllerKeeper, -- scopedICAAuthKeeper, -) -``` - -Please note that the authentication module's `ScopedKeeper` name is still needed as part of the channel capability migration described in section [Upgrade proposal](#upgrade-proposal) above. Therefore the authentication module's `ScopedKeeper` cannot be completely removed from the chain code until the migration has run. - -In the future, the use of the legacy APIs for accessing packet callbacks will be replaced by IBC Actor Callbacks (see [ADR 008](https://github.com/cosmos/ibc-go/pull/1976) for more details) and it will also be possible to access them with the `MsgServiceRouter`. - -**My authentication module does not need access to IBC packet callbacks** - -The authentication module can migrate from using the legacy APIs and it can be composed instead with the `MsgServiceRouter`, so that the authentication module is able to pass messages to the controller submodule's `MsgServer` to register interchain accounts and send packets to the interchain account. For example, given an Interchain Accounts authentication module keeper `ICAAuthKeeper`, the ICS27 controller submodule keeper (`ICAControllerKeeper`) and authentication module scoped keeper (`scopedICAAuthKeeper`) are not needed anymore and can be replaced with the `MsgServiceRouter`, as shown here: - -```diff -app.ICAAuthKeeper = icaauthkeeper.NewKeeper( - appCodec, - keys[icaauthtypes.StoreKey], -- app.ICAControllerKeeper, -- scopedICAAuthKeeper, -+ app.MsgServiceRouter(), -) -``` - -In your authentication module you can route messages to the controller submodule's `MsgServer` instead of using the legacy APIs. For example, for registering an interchain account: - -```diff -- if err := keeper.icaControllerKeeper.RegisterInterchainAccount( -- ctx, -- connectionID, -- owner.String(), -- version, -- ); err != nil { -- return err -- } -+ msg := controllertypes.NewMsgRegisterInterchainAccount( -+ connectionID, -+ owner.String(), -+ version, -+ ) -+ handler := keeper.msgRouter.Handler(msg) -+ res, err := handler(ctx, msg) -+ if err != nil { -+ return err -+ } -``` - -where `controllertypes` is an import alias for `"github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts/controller/types"`. - -In addition, in this use case the authentication module does not need to implement the `IBCModule` interface anymore. - -**I do not need a custom authentication module anymore** - -If your authentication module does not have any extra functionality compared to the default authentication module added in ibc-go v6 (the `MsgServer`), or if you can use a generic authentication module, such as the `x/auth`, `x/gov` or `x/group` modules from the Cosmos SDK (v0.46 and later), then you can remove your authentication module completely and use instead the gRPC endpoints of the `MsgServer` or the CLI added in ibc-go v6. - -Please remember that the authentication module's `ScopedKeeper` name is still needed as part of the channel capability migration described in section [Upgrade proposal](#upgrade-proposal) above. - -#### Host params - -The ICS27 host submodule default params have been updated to include the `AllowAllHostMsgs` wildcard `*`. -This enables execution of any `sdk.Msg` type for ICS27 registered on the host chain `InterfaceRegistry`. - -```diff -// AllowAllHostMsgs holds the string key that allows all message types on interchain accounts host module -const AllowAllHostMsgs = "*" - -... - -// DefaultParams is the default parameter configuration for the host submodule -func DefaultParams() Params { -- return NewParams(DefaultHostEnabled, nil) -+ return NewParams(DefaultHostEnabled, []string{AllowAllHostMsgs}) -} -``` - -#### API breaking changes - -`SerializeCosmosTx` takes in a `[]proto.Message` instead of `[]sdk.Message`. This allows for the serialization of proto messages without requiring the fulfillment of the `sdk.Msg` interface. - -The `27-interchain-accounts` genesis types have been moved to their own package: `modules/apps/27-interchain-acccounts/genesis/types`. -This change facilitates the addition of the ICS27 controller submodule `MsgServer` and avoids cyclic imports. This should have minimal disruption to chain developers integrating `27-interchain-accounts`. - -The ICS27 host submodule `NewKeeper` function in `modules/apps/27-interchain-acccounts/host/keeper` now includes an additional parameter of type `ICS4Wrapper`. -This provides the host submodule with the ability to correctly unwrap channel versions in the event of a channel reopening handshake. - -```diff -func NewKeeper( - cdc codec.BinaryCodec, key storetypes.StoreKey, paramSpace paramtypes.Subspace, -- channelKeeper icatypes.ChannelKeeper, portKeeper icatypes.PortKeeper, -+ ics4Wrapper icatypes.ICS4Wrapper, channelKeeper icatypes.ChannelKeeper, portKeeper icatypes.PortKeeper, - accountKeeper icatypes.AccountKeeper, scopedKeeper icatypes.ScopedKeeper, msgRouter icatypes.MessageRouter, -) Keeper -``` - -### ICS29 - `NewKeeper` API change - -The `NewKeeper` function of ICS29 has been updated to remove the `paramSpace` parameter as it was unused. - -```diff -func NewKeeper( -- cdc codec.BinaryCodec, key storetypes.StoreKey, paramSpace paramtypes.Subspace, -- ics4Wrapper types.ICS4Wrapper, channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, -+ cdc codec.BinaryCodec, key storetypes.StoreKey, -+ ics4Wrapper types.ICS4Wrapper, channelKeeper types.ChannelKeeper, -+ portKeeper types.PortKeeper, authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, -) Keeper { -``` - -### ICS20 - `SendTransfer` is no longer exported - -The `SendTransfer` function of ICS20 has been removed. IBC transfers should now be initiated with `MsgTransfer` and routed to the ICS20 `MsgServer`. - -See below for example: - -```go -if handler := msgRouter.Handler(msgTransfer); handler != nil { - if err := msgTransfer.ValidateBasic(); err != nil { - return nil, err - } - - res, err := handler(ctx, msgTransfer) - if err != nil { - return nil, err - } -} -``` - -### ICS04 - `SendPacket` API change - -The `SendPacket` API has been simplified: - -```diff -// SendPacket is called by a module in order to send an IBC packet on a channel -func (k Keeper) SendPacket( - ctx sdk.Context, - channelCap *capabilitytypes.Capability, -- packet exported.PacketI, --) error { -+ sourcePort string, -+ sourceChannel string, -+ timeoutHeight clienttypes.Height, -+ timeoutTimestamp uint64, -+ data []byte, -+) (uint64, error) { -``` - -Callers no longer need to pass in a pre-constructed packet. -The destination port/channel identifiers and the packet sequence will be determined by core IBC. -`SendPacket` will return the packet sequence. - -### IBC testing package - -The `SendPacket` API has been simplified: - -```diff -// SendPacket is called by a module in order to send an IBC packet on a channel -func (k Keeper) SendPacket( - ctx sdk.Context, - channelCap *capabilitytypes.Capability, -- packet exported.PacketI, --) error { -+ sourcePort string, -+ sourceChannel string, -+ timeoutHeight clienttypes.Height, -+ timeoutTimestamp uint64, -+ data []byte, -+) (uint64, error) { -``` - -Callers no longer need to pass in a pre-constructed packet. `SendPacket` will return the packet sequence. - -## Relayers - -- No relevant changes were made in this release. - -## IBC Light Clients - -- No relevant changes were made in this release. diff --git a/docs/versioned_docs/version-v6.2.x/04-migrations/_category_.json b/docs/versioned_docs/version-v6.2.x/04-migrations/_category_.json deleted file mode 100644 index 95db8e5579e..00000000000 --- a/docs/versioned_docs/version-v6.2.x/04-migrations/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Migrations", - "position": 4, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v6.2.x/04-migrations/images/auth-module-decision-tree.png b/docs/versioned_docs/version-v6.2.x/04-migrations/images/auth-module-decision-tree.png deleted file mode 100644 index dc2c98e6618..00000000000 Binary files a/docs/versioned_docs/version-v6.2.x/04-migrations/images/auth-module-decision-tree.png and /dev/null differ diff --git a/docs/versioned_docs/version-v7.3.x/00-intro.md b/docs/versioned_docs/version-v7.3.x/00-intro.md deleted file mode 100644 index c842dac0022..00000000000 --- a/docs/versioned_docs/version-v7.3.x/00-intro.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -slug: / -sidebar_position: 0 ---- - -# IBC-Go Documentation - -Welcome to the IBC-Go documentation! - -The Inter-Blockchain Communication protocol (IBC) is an end-to-end, connection-oriented, stateful protocol for reliable, ordered, and authenticated communication between heterogeneous blockchains arranged in an unknown and dynamic topology. - -IBC is a protocol that allows blockchains to talk to each other. - -The protocol realizes this interoperability by specifying a set of data structures, abstractions, and semantics that can be implemented by any distributed ledger that satisfies a small set of requirements. - -IBC can be used to build a wide range of cross-chain applications that include token transfers, atomic swaps, multi-chain smart contracts (with or without mutually comprehensible VMs), and data and code sharding of various kinds. diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/01-overview.md b/docs/versioned_docs/version-v7.3.x/01-ibc/01-overview.md deleted file mode 100644 index ba5579fd6f2..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/01-overview.md +++ /dev/null @@ -1,297 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /ibc/overview ---- - - -# Overview - -:::note Synopsis -Learn about IBC, its components, and IBC use cases. -::: - -## What is the Interblockchain Communication Protocol (IBC)? - -This document serves as a guide for developers who want to write their own Inter-Blockchain -Communication protocol (IBC) applications for custom use cases. - -> IBC applications must be written as self-contained modules. - -Due to the modular design of the IBC protocol, IBC -application developers do not need to be concerned with the low-level details of clients, -connections, and proof verification. - -This brief explanation of the lower levels of the -stack gives application developers a broad understanding of the IBC -protocol. Abstraction layer details for channels and ports are most relevant for application developers and describe how to define custom packets and `IBCModule` callbacks. - -The requirements to have your module interact over IBC are: - -- Bind to a port or ports. -- Define your packet data. -- Use the default acknowledgment struct provided by core IBC or optionally define a custom acknowledgment struct. -- Standardize an encoding of the packet data. -- Implement the `IBCModule` interface. - -Read on for a detailed explanation of how to write a self-contained IBC application module. - -## Components Overview - -### [Clients](https://github.com/cosmos/ibc-go/blob/main/modules/core/02-client) - -IBC clients are on-chain light clients. Each light client is identified by a unique client-id. -IBC clients track the consensus states of other blockchains, along with the proof spec necessary to -properly verify proofs against the client's consensus state. A client can be associated with any number -of connections to the counterparty chain. The client identifier is auto generated using the client type -and the global client counter appended in the format: `{client-type}-{N}`. - -A `ClientState` should contain chain specific and light client specific information necessary for verifying updates -and upgrades to the IBC client. The `ClientState` may contain information such as chain-id, latest height, proof specs, -unbonding periods or the status of the light client. The `ClientState` should not contain information that -is specific to a given block at a certain height, this is the function of the `ConsensusState`. Each `ConsensusState` -should be associated with a unique block and should be referenced using a height. IBC clients are given a -client identifier prefixed store to store their associated client state and consensus states along with -any metadata associated with the consensus states. Consensus states are stored using their associated height. - -The supported IBC clients are: - -- [Solo Machine light client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/06-solomachine): Devices such as phones, browsers, or laptops. -- [Tendermint light client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/07-tendermint): The default for Cosmos SDK-based chains. -- [Localhost (loopback) client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/09-localhost): Useful for -testing, simulation, and relaying packets to modules on the same application. - -### IBC Client Heights - -IBC Client Heights are represented by the struct: - -```go -type Height struct { - RevisionNumber uint64 - RevisionHeight uint64 -} -``` - -The `RevisionNumber` represents the revision of the chain that the height is representing. -A revision typically represents a continuous, monotonically increasing range of block-heights. -The `RevisionHeight` represents the height of the chain within the given revision. - -On any reset of the `RevisionHeight`—for example, when hard-forking a Tendermint chain— -the `RevisionNumber` will get incremented. This allows IBC clients to distinguish between a -block-height `n` of a previous revision of the chain (at revision `p`) and block-height `n` of the current -revision of the chain (at revision `e`). - -`Height`s that share the same revision number can be compared by simply comparing their respective `RevisionHeight`s. -`Height`s that do not share the same revision number will only be compared using their respective `RevisionNumber`s. -Thus a height `h` with revision number `e+1` will always be greater than a height `g` with revision number `e`, -**REGARDLESS** of the difference in revision heights. - -Ex: - -```go -Height{RevisionNumber: 3, RevisionHeight: 0} > Height{RevisionNumber: 2, RevisionHeight: 100000000000} -``` - -When a Tendermint chain is running a particular revision, relayers can simply submit headers and proofs with the revision number -given by the chain's `chainID`, and the revision height given by the Tendermint block height. When a chain updates using a hard-fork -and resets its block-height, it is responsible for updating its `chainID` to increment the revision number. -IBC Tendermint clients then verifies the revision number against their `chainID` and treat the `RevisionHeight` as the Tendermint block-height. - -Tendermint chains wishing to use revisions to maintain persistent IBC connections even across height-resetting upgrades must format their `chainID`s -in the following manner: `{chainID}-{revision_number}`. On any height-resetting upgrade, the `chainID` **MUST** be updated with a higher revision number -than the previous value. - -Ex: - -- Before upgrade `chainID`: `gaiamainnet-3` -- After upgrade `chainID`: `gaiamainnet-4` - -Clients that do not require revisions, such as the solo-machine client, simply hardcode `0` into the revision number whenever they -need to return an IBC height when implementing IBC interfaces and use the `RevisionHeight` exclusively. - -Other client-types can implement their own logic to verify the IBC heights that relayers provide in their `Update`, `Misbehavior`, and -`Verify` functions respectively. - -The IBC interfaces expect an `ibcexported.Height` interface, however all clients must use the concrete implementation provided in -`02-client/types` and reproduced above. - -### [Connections](https://github.com/cosmos/ibc-go/blob/main/modules/core/03-connection) - -Connections encapsulate two `ConnectionEnd` objects on two separate blockchains. Each -`ConnectionEnd` is associated with a client of the other blockchain (for example, the counterparty blockchain). -The connection handshake is responsible for verifying that the light clients on each chain are -correct for their respective counterparties. Connections, once established, are responsible for -facilitating all cross-chain verifications of IBC state. A connection can be associated with any -number of channels. - -### [Proofs](https://github.com/cosmos/ibc-go/blob/main/modules/core/23-commitment) and [Paths](https://github.com/cosmos/ibc-go/blob/main/modules/core/24-host) - -In IBC, blockchains do not directly pass messages to each other over the network. Instead, to -communicate, a blockchain commits some state to a specifically defined path that is reserved for a -specific message type and a specific counterparty. For example, for storing a specific connectionEnd as part -of a handshake or a packet intended to be relayed to a module on the counterparty chain. A relayer -process monitors for updates to these paths and relays messages by submitting the data stored -under the path and a proof to the counterparty chain. - -Proofs are passed from core IBC to light-clients as bytes. It is up to light client implementation to interpret these bytes appropriately. - -- The paths that all IBC implementations must use for committing IBC messages is defined in -[ICS-24 Host State Machine Requirements](https://github.com/cosmos/ics/tree/master/spec/core/ics-024-host-requirements). -- The proof format that all implementations must be able to produce and verify is defined in [ICS-23 Proofs](https://github.com/cosmos/ics23) implementation. - -### [Capabilities](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/advanced/10-ocap.md) - -IBC is intended to work in execution environments where modules do not necessarily trust each -other. Thus, IBC must authenticate module actions on ports and channels so that only modules with the -appropriate permissions can use them. - -This module authentication is accomplished using a [dynamic -capability store](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-003-dynamic-capability-store.md). Upon binding to a port or -creating a channel for a module, IBC returns a dynamic capability that the module must claim in -order to use that port or channel. The dynamic capability module prevents other modules from using that port or channel since -they do not own the appropriate capability. - -While this background information is useful, IBC modules do not need to interact at all with -these lower-level abstractions. The relevant abstraction layer for IBC application developers is -that of channels and ports. IBC applications must be written as self-contained **modules**. - -A module on one blockchain can communicate with other modules on other blockchains by sending, -receiving, and acknowledging packets through channels that are uniquely identified by the -`(channelID, portID)` tuple. - -A useful analogy is to consider IBC modules as internet applications on -a computer. A channel can then be conceptualized as an IP connection, with the IBC portID being -analogous to an IP port and the IBC channelID being analogous to an IP address. Thus, a single -instance of an IBC module can communicate on the same port with any number of other modules and -IBC correctly routes all packets to the relevant module using the (channelID, portID tuple). An -IBC module can also communicate with another IBC module over multiple ports, with each -`(portID<->portID)` packet stream being sent on a different unique channel. - -### [Ports](https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port) - -An IBC module can bind to any number of ports. Each port must be identified by a unique `portID`. -Since IBC is designed to be secure with mutually distrusted modules operating on the same ledger, -binding a port returns a dynamic object capability. In order to take action on a particular port -(for example, an open channel with its portID), a module must provide the dynamic object capability to the IBC -handler. This requirement prevents a malicious module from opening channels with ports it does not own. Thus, -IBC modules are responsible for claiming the capability that is returned on `BindPort`. - -### [Channels](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -An IBC channel can be established between two IBC ports. Currently, a port is exclusively owned by a -single module. IBC packets are sent over channels. Just as IP packets contain the destination IP -address and IP port, and the source IP address and source IP port, IBC packets contain -the destination portID and channelID, and the source portID and channelID. This packet structure enables IBC to -correctly route packets to the destination module while allowing modules receiving packets to -know the sender module. - -A channel can be `ORDERED`, where packets from a sending module must be processed by the -receiving module in the order they were sent. Or a channel can be `UNORDERED`, where packets -from a sending module are processed in the order they arrive (might be in a different order than they were sent). - -Modules can choose which channels they wish to communicate over with, thus IBC expects modules to -implement callbacks that are called during the channel handshake. These callbacks can do custom -channel initialization logic. If any callback returns an error, the channel handshake fails. Thus, by -returning errors on callbacks, modules can programmatically reject and accept channels. - -The channel handshake is a 4-step handshake. Briefly, if a given chain A wants to open a channel with -chain B using an already established connection: - -1. chain A sends a `ChanOpenInit` message to signal a channel initialization attempt with chain B. -2. chain B sends a `ChanOpenTry` message to try opening the channel on chain A. -3. chain A sends a `ChanOpenAck` message to mark its channel end status as open. -4. chain B sends a `ChanOpenConfirm` message to mark its channel end status as open. - -If all handshake steps are successful, the channel is opened on both sides. At each step in the handshake, the module -associated with the `ChannelEnd` executes its callback. So -on `ChanOpenInit`, the module on chain A executes its callback `OnChanOpenInit`. - -The channel identifier is auto derived in the format: `channel-{N}` where N is the next sequence to be used. - -Just as ports came with dynamic capabilities, channel initialization returns a dynamic capability -that the module **must** claim so that they can pass in a capability to authenticate channel actions -like sending packets. The channel capability is passed into the callback on the first parts of the -handshake; either `OnChanOpenInit` on the initializing chain or `OnChanOpenTry` on the other chain. - -#### Closing channels - -Closing a channel occurs in 2 handshake steps as defined in [ICS 04](https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics). - -`ChanCloseInit` closes a channel on the executing chain if the channel exists, it is not -already closed and the connection it exists upon is OPEN. Channels can only be closed by a -calling module or in the case of a packet timeout on an ORDERED channel. - -`ChanCloseConfirm` is a response to a counterparty channel executing `ChanCloseInit`. The channel -on the executing chain closes if the channel exists, the channel is not already closed, -the connection the channel exists upon is OPEN and the executing chain successfully verifies -that the counterparty channel has been closed. - -### [Packets](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -Modules communicate with each other by sending packets over IBC channels. All -IBC packets contain the destination `portID` and `channelID` along with the source `portID` and -`channelID`. This packet structure allows modules to know the sender module of a given packet. IBC packets -contain a sequence to optionally enforce ordering. - -IBC packets also contain a `TimeoutHeight` and a `TimeoutTimestamp` that determine the deadline before the receiving module must process a packet. - -Modules send custom application data to each other inside the `Data []byte` field of the IBC packet. -Thus, packet data is opaque to IBC handlers. It is incumbent on a sender module to encode -their application-specific packet information into the `Data` field of packets. The receiver -module must decode that `Data` back to the original application data. - -### [Receipts and Timeouts](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -Since IBC works over a distributed network and relies on potentially faulty relayers to relay messages between ledgers, -IBC must handle the case where a packet does not get sent to its destination in a timely manner or at all. Packets must -specify a non-zero value for timeout height (`TimeoutHeight`) or timeout timestamp (`TimeoutTimestamp` ) after which a packet can no longer be successfully received on the destination chain. - -- The `timeoutHeight` indicates a consensus height on the destination chain after which the packet is no longer be processed, and instead counts as having timed-out. -- The `timeoutTimestamp` indicates a timestamp on the destination chain after which the packet is no longer be processed, and instead counts as having timed-out. - -If the timeout passes without the packet being successfully received, the packet can no longer be -received on the destination chain. The sending module can timeout the packet and take appropriate actions. - -If the timeout is reached, then a proof of packet timeout can be submitted to the original chain. The original chain can then perform -application-specific logic to timeout the packet, perhaps by rolling back the packet send changes (refunding senders any locked funds, etc.). - -- In ORDERED channels, a timeout of a single packet in the channel causes the channel to close. - - - If packet sequence `n` times out, then a packet at sequence `k > n` cannot be received without violating the contract of ORDERED channels that packets are processed in the order that they are sent. - - Since ORDERED channels enforce this invariant, a proof that sequence `n` has not been received on the destination chain by the specified timeout of packet `n` is sufficient to timeout packet `n` and close the channel. - -- In UNORDERED channels, the application-specific timeout logic for that packet is applied and the channel is not closed. - - - Packets can be received in any order. - - - IBC writes a packet receipt for each sequence receives in the UNORDERED channel. This receipt does not contain information; it is simply a marker intended to signify that the UNORDERED channel has received a packet at the specified sequence. - - - To timeout a packet on an UNORDERED channel, a proof is required that a packet receipt **does not exist** for the packet's sequence by the specified timeout. - -For this reason, most modules should use UNORDERED channels as they require fewer liveness guarantees to function effectively for users of that channel. - -### [Acknowledgments](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel) - -Modules can also choose to write application-specific acknowledgments upon processing a packet. Acknowledgments can be done: - -- Synchronously on `OnRecvPacket` if the module processes packets as soon as they are received from IBC module. -- Asynchronously if module processes packets at some later point after receiving the packet. - -This acknowledgment data is opaque to IBC much like the packet `Data` and is treated by IBC as a simple byte string `[]byte`. Receiver modules must encode their acknowledgment so that the sender module can decode it correctly. The encoding must be negotiated between the two parties during version negotiation in the channel handshake. - -The acknowledgment can encode whether the packet processing succeeded or failed, along with additional information that allows the sender module to take appropriate action. - -After the acknowledgment has been written by the receiving chain, a relayer relays the acknowledgment back to the original sender module. - -The original sender module then executes application-specific acknowledgment logic using the contents of the acknowledgment. - -- After an acknowledgement fails, packet-send changes can be rolled back (for example, refunding senders in ICS20). - -- After an acknowledgment is received successfully on the original sender on the chain, the corresponding packet commitment is deleted since it is no longer needed. - -## Further Readings and Specs - -If you want to learn more about IBC, check the following specifications: - -- [IBC specification overview](https://github.com/cosmos/ibc/blob/master/README.md) diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/02-integration.md b/docs/versioned_docs/version-v7.3.x/01-ibc/02-integration.md deleted file mode 100644 index a067f357ef3..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/02-integration.md +++ /dev/null @@ -1,235 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 2 -slug: /ibc/integration ---- - - -# Integration - -:::note Synopsis -Learn how to integrate IBC to your application and send data packets to other chains. -::: - -This document outlines the required steps to integrate and configure the [IBC -module](https://github.com/cosmos/ibc-go/tree/main/modules/core) to your Cosmos SDK application and -send fungible token transfers to other chains. - -## Integrating the IBC module - -Integrating the IBC module to your SDK-based application is straighforward. The general changes can be summarized in the following steps: - -- Add required modules to the `module.BasicManager` -- Define additional `Keeper` fields for the new modules on the `App` type -- Add the module's `StoreKey`s and initialize their `Keeper`s -- Set up corresponding routers and routes for the `ibc` module -- Add the modules to the module `Manager` -- Add modules to `Begin/EndBlockers` and `InitGenesis` -- Update the module `SimulationManager` to enable simulations - -### Module `BasicManager` and `ModuleAccount` permissions - -The first step is to add the following modules to the `BasicManager`: `x/capability`, `x/ibc`, -and `x/ibc-transfer`. After that, we need to grant `Minter` and `Burner` permissions to -the `ibc-transfer` `ModuleAccount` to mint and burn relayed tokens. - -### Integrating light clients - -> Note that from v7 onwards, all light clients have to be explicitly registered in a chain's app.go and follow the steps listed below. - This is in contrast to earlier versions of ibc-go when `07-tendermint` and `06-solomachine` were added out of the box. - -All light clients must be registered with `module.BasicManager` in a chain's app.go file. - -The following code example shows how to register the existing `ibctm.AppModuleBasic{}` light client implementation. - -```diff - -import ( - ... -+ ibctm "github.com/cosmos/ibc-go/v6/modules/light-clients/07-tendermint" - ... -) - -// app.go -var ( - - ModuleBasics = module.NewBasicManager( - // ... - capability.AppModuleBasic{}, - ibc.AppModuleBasic{}, - transfer.AppModuleBasic{}, // i.e ibc-transfer module - - // register light clients on IBC -+ ibctm.AppModuleBasic{}, - ) - - // module account permissions - maccPerms = map[string][]string{ - // other module accounts permissions - // ... - ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, - } -) -``` - -### Application fields - -Then, we need to register the `Keepers` as follows: - -```go -// app.go -type App struct { - // baseapp, keys and subspaces definitions - - // other keepers - // ... - IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly - TransferKeeper ibctransferkeeper.Keeper // for cross-chain fungible token transfers - - // make scoped keepers public for test purposes - ScopedIBCKeeper capabilitykeeper.ScopedKeeper - ScopedTransferKeeper capabilitykeeper.ScopedKeeper - - /// ... - /// module and simulation manager definitions -} -``` - -### Configure the `Keepers` - -During initialization, besides initializing the IBC `Keepers` (for the `x/ibc`, and -`x/ibc-transfer` modules), we need to grant specific capabilities through the capability module -`ScopedKeepers` so that we can authenticate the object-capability permissions for each of the IBC -channels. - -```go -func NewApp(...args) *App { - // define codecs and baseapp - - // add capability keeper and ScopeToModule for ibc module - app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey]) - - // grant capabilities for the ibc and ibc-transfer modules - scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibcexported.ModuleName) - scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) - - // ... other modules keepers - - // Create IBC Keeper - app.IBCKeeper = ibckeeper.NewKeeper( - appCodec, keys[ibcexported.StoreKey], app.GetSubspace(ibcexported.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper, - ) - - // Create Transfer Keepers - app.TransferKeeper = ibctransferkeeper.NewKeeper( - appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName), - app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, app.BankKeeper, scopedTransferKeeper, - ) - transferModule := transfer.NewAppModule(app.TransferKeeper) - - // .. continues -} -``` - -### Register `Routers` - -IBC needs to know which module is bound to which port so that it can route packets to the -appropriate module and call the appropriate callbacks. The port to module name mapping is handled by -IBC's port `Keeper`. However, the mapping from module name to the relevant callbacks is accomplished -by the port -[`Router`](https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port/types/router.go) on the -IBC module. - -Adding the module routes allows the IBC handler to call the appropriate callback when processing a -channel handshake or a packet. - -Currently, a `Router` is static so it must be initialized and set correctly on app initialization. -Once the `Router` has been set, no new routes can be added. - -```go -// app.go -func NewApp(...args) *App { - // .. continuation from above - - // Create static IBC router, add ibc-tranfer module route, then set and seal it - ibcRouter := port.NewRouter() - ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule) - // Setting Router will finalize all routes by sealing router - // No more routes can be added - app.IBCKeeper.SetRouter(ibcRouter) - - // .. continues -``` - -### Module Managers - -In order to use IBC, we need to add the new modules to the module `Manager` and to the `SimulationManager` in case your application supports [simulations](https://github.com/cosmos/cosmos-sdk/blob/main/docs/build/building-modules/14-simulator.md). - -```go -// app.go -func NewApp(...args) *App { - // .. continuation from above - - app.mm = module.NewManager( - // other modules - // ... - capability.NewAppModule(appCodec, *app.CapabilityKeeper), - ibc.NewAppModule(app.IBCKeeper), - transferModule, - ) - - // ... - - app.sm = module.NewSimulationManager( - // other modules - // ... - capability.NewAppModule(appCodec, *app.CapabilityKeeper), - ibc.NewAppModule(app.IBCKeeper), - transferModule, - ) - - // .. continues -``` - -### Application ABCI Ordering - -One addition from IBC is the concept of `HistoricalEntries` which are stored on the staking module. -Each entry contains the historical information for the `Header` and `ValidatorSet` of this chain which is stored -at each height during the `BeginBlock` call. The historical info is required to introspect the -past historical info at any given height in order to verify the light client `ConsensusState` during the -connection handhake. - -```go -// app.go -func NewApp(...args) *App { - // .. continuation from above - - // add staking and ibc modules to BeginBlockers - app.mm.SetOrderBeginBlockers( - // other modules ... - stakingtypes.ModuleName, ibcexported.ModuleName, - ) - - // ... - - // 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. - app.mm.SetOrderInitGenesis( - capabilitytypes.ModuleName, - // other modules ... - ibcexported.ModuleName, ibctransfertypes.ModuleName, - ) - - // .. continues -``` - -:::warning -**IMPORTANT**: The capability module **must** be declared first in `SetOrderInitGenesis` -::: - -That's it! You have now wired up the IBC module and are now able to send fungible tokens across -different chains. If you want to have a broader view of the changes take a look into the SDK's -[`SimApp`](https://github.com/cosmos/ibc-go/blob/main/testing/simapp/app.go). diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/01-apps.md b/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/01-apps.md deleted file mode 100644 index d923b6158c5..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/01-apps.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -title: IBC Applications -sidebar_label: IBC Applications -sidebar_position: 1 -slug: /ibc/apps/apps ---- - - -# IBC Applications - -:::note Synopsis -Learn how to build custom IBC application modules that enable packets to be sent to and received from other IBC-enabled chains. -::: - -This document serves as a guide for developers who want to write their own Inter-blockchain Communication Protocol (IBC) applications for custom use cases. - -Due to the modular design of the IBC protocol, IBC application developers do not need to concern themselves with the low-level details of clients, connections, and proof verification. Nevertheless, an overview of these low-level concepts can be found in [the Overview section](../01-overview.md). -The document goes into detail on the abstraction layer most relevant for application developers (channels and ports), and describes how to define your own custom packets, `IBCModule` callbacks and more to make an application module IBC ready. - -**To have your module interact over IBC you must:** - -- implement the `IBCModule` interface, i.e.: - - channel (opening) handshake callbacks - - channel closing handshake callbacks - - packet callbacks -- bind to a port(s) -- add keeper methods -- define your own packet data and acknowledgement structs as well as how to encode/decode them -- add a route to the IBC router - -The following sections provide a more detailed explanation of how to write an IBC application -module correctly corresponding to the listed steps. - -:::note - -## Pre-requisites Readings - -- [IBC Overview](../01-overview.md)) -- [IBC default integration](../02-integration.md) - -::: - -## Working example - -For a real working example of an IBC application, you can look through the `ibc-transfer` module -which implements everything discussed in this section. - -Here are the useful parts of the module to look at: - -[Binding to transfer -port](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/genesis.go) - -[Sending transfer -packets](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/relay.go) - -[Implementing IBC -callbacks](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/ibc_module.go) diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/02-ibcmodule.md b/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/02-ibcmodule.md deleted file mode 100644 index ec080e71b7a..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/02-ibcmodule.md +++ /dev/null @@ -1,382 +0,0 @@ ---- -title: Implement `IBCModule` interface and callbacks -sidebar_label: Implement `IBCModule` interface and callbacks -sidebar_position: 2 -slug: /ibc/apps/ibcmodule ---- - - -# Implement `IBCModule` interface and callbacks - -:::note Synopsis -Learn how to implement the `IBCModule` interface and all of the callbacks it requires. -::: - -The Cosmos SDK expects all IBC modules to implement the [`IBCModule` -interface](https://github.com/cosmos/ibc-go/tree/main/modules/core/05-port/types/module.go). This interface contains all of the callbacks IBC expects modules to implement. They include callbacks related to channel handshake, closing and packet callbacks (`OnRecvPacket`, `OnAcknowledgementPacket` and `OnTimeoutPacket`). - -```go -// IBCModule implements the ICS26 interface for given the keeper. -// The implementation of the IBCModule interface could for example be in a file called ibc_module.go, -// but ultimately file structure is up to the developer -type IBCModule struct { - keeper keeper.Keeper -} -``` - -Additionally, in the `module.go` file, add the following line: - -```go -var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} - // Add this line - _ porttypes.IBCModule = IBCModule{} -) -``` - -:::note - -## Pre-requisites Readings - -- [IBC Overview](../01-overview.md)) -- [IBC default integration](../02-integration.md) - -::: - -## Channel handshake callbacks - -This section will describe the callbacks that are called during channel handshake execution. Among other things, it will claim channel capabilities passed on from core IBC. For a refresher on capabilities, check [the Overview section](../01-overview.md#capabilities). - -Here are the channel handshake callbacks that modules are expected to implement: - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `checkArguments` and `negotiateAppVersion` functions. - -```go -// Called by IBC Handler on MsgOpenInit -func (im IBCModule) OnChanOpenInit(ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) (string, error) { - // ... do custom initialization logic - - // Use above arguments to determine if we want to abort handshake - // Examples: - // - Abort if order == UNORDERED, - // - Abort if version is unsupported - if err := checkArguments(args); err != nil { - return "", err - } - - // OpenInit must claim the channelCapability that IBC passes into the callback - if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return "", err - } - - return version, nil -} - -// Called by IBC Handler on MsgOpenTry -func (im IBCModule) OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (string, error) { - // ... do custom initialization logic - - // Use above arguments to determine if we want to abort handshake - if err := checkArguments(args); err != nil { - return "", err - } - - // OpenTry must claim the channelCapability that IBC passes into the callback - if err := im.keeper.scopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return err - } - - // Construct application version - // IBC applications must return the appropriate application version - // This can be a simple string or it can be a complex version constructed - // from the counterpartyVersion and other arguments. - // The version returned will be the channel version used for both channel ends. - appVersion := negotiateAppVersion(counterpartyVersion, args) - - return appVersion, nil -} - -// Called by IBC Handler on MsgOpenAck -func (im IBCModule) OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyVersion string, -) error { - if counterpartyVersion != types.Version { - return sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: %s, expected %s", counterpartyVersion, types.Version) - } - - // do custom logic - - return nil -} - -// Called by IBC Handler on MsgOpenConfirm -func (im IBCModule) OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // do custom logic - - return nil -} -``` - -The channel closing handshake will also invoke module callbacks that can return errors to abort the closing handshake. Closing a channel is a 2-step handshake, the initiating chain calls `ChanCloseInit` and the finalizing chain calls `ChanCloseConfirm`. - -```go -// Called by IBC Handler on MsgCloseInit -func (im IBCModule) OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - // ... do custom finalization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} - -// Called by IBC Handler on MsgCloseConfirm -func (im IBCModule) OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // ... do custom finalization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} -``` - -### Channel handshake version negotiation - -Application modules are expected to verify versioning used during the channel handshake procedure. - -- `OnChanOpenInit` will verify that the relayer-chosen parameters - are valid and perform any custom `INIT` logic. - It may return an error if the chosen parameters are invalid - in which case the handshake is aborted. - If the provided version string is non-empty, `OnChanOpenInit` should return - the version string if valid or an error if the provided version is invalid. - **If the version string is empty, `OnChanOpenInit` is expected to - return a default version string representing the version(s) - it supports.** - If there is no default version string for the application, - it should return an error if the provided version is an empty string. -- `OnChanOpenTry` will verify the relayer-chosen parameters along with the - counterparty-chosen version string and perform custom `TRY` logic. - If the relayer-chosen parameters - are invalid, the callback must return an error to abort the handshake. - If the counterparty-chosen version is not compatible with this module's - supported versions, the callback must return an error to abort the handshake. - If the versions are compatible, the try callback must select the final version - string and return it to core IBC. - `OnChanOpenTry` may also perform custom initialization logic. -- `OnChanOpenAck` will error if the counterparty selected version string - is invalid and abort the handshake. It may also perform custom ACK logic. - -Versions must be strings but can implement any versioning structure. If your application plans to -have linear releases then semantic versioning is recommended. If your application plans to release -various features in between major releases then it is advised to use the same versioning scheme -as IBC. This versioning scheme specifies a version identifier and compatible feature set with -that identifier. Valid version selection includes selecting a compatible version identifier with -a subset of features supported by your application for that version. The struct used for this -scheme can be found in [03-connection/types](https://github.com/cosmos/ibc-go/blob/main/modules/core/03-connection/types/version.go#L16). - -Since the version type is a string, applications have the ability to do simple version verification -via string matching or they can use the already impelemented versioning system and pass the proto -encoded version into each handhshake call as necessary. - -ICS20 currently implements basic string matching with a single supported version. - -## Packet callbacks - -Just as IBC expects modules to implement callbacks for channel handshakes, it also expects modules to implement callbacks for handling the packet flow through a channel, as defined in the `IBCModule` interface. - -Once a module A and module B are connected to each other, relayers can start relaying packets and acknowledgements back and forth on the channel. - -![IBC packet flow diagram](./images/packet_flow.png) - -Briefly, a successful packet flow works as follows: - -1. module A sends a packet through the IBC module -2. the packet is received by module B -3. if module B writes an acknowledgement of the packet then module A will process the - acknowledgement -4. if the packet is not successfully received before the timeout, then module A processes the - packet's timeout. - -### Sending packets - -Modules **do not send packets through callbacks**, since the modules initiate the action of sending packets to the IBC module, as opposed to other parts of the packet flow where messages sent to the IBC -module must trigger execution on the port-bound module through the use of callbacks. Thus, to send a packet a module simply needs to call `SendPacket` on the `IBCChannelKeeper`. - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `EncodePacketData(customPacketData)` function. - -```go -// retrieve the dynamic capability for this channel -channelCap := scopedKeeper.GetCapability(ctx, channelCapName) -// Sending custom application packet data -data := EncodePacketData(customPacketData) -// Send packet to IBC, authenticating with channelCap -sequence, err := IBCChannelKeeper.SendPacket( - ctx, - channelCap, - sourcePort, - sourceChannel, - timeoutHeight, - timeoutTimestamp, - data, -) -``` - -::: warning -In order to prevent modules from sending packets on channels they do not own, IBC expects -modules to pass in the correct channel capability for the packet's source channel. -::: - -### Receiving packets - -To handle receiving packets, the module must implement the `OnRecvPacket` callback. This gets -invoked by the IBC module after the packet has been proved valid and correctly processed by the IBC -keepers. Thus, the `OnRecvPacket` callback only needs to worry about making the appropriate state -changes given the packet data without worrying about whether the packet is valid or not. - -Modules may return to the IBC handler an acknowledgement which implements the `Acknowledgement` interface. -The IBC handler will then commit this acknowledgement of the packet so that a relayer may relay the -acknowledgement back to the sender module. - -The state changes that occurred during this callback will only be written if: - -- the acknowledgement was successful as indicated by the `Success()` function of the acknowledgement -- if the acknowledgement returned is nil indicating that an asynchronous process is occurring - -NOTE: Applications which process asynchronous acknowledgements must handle reverting state changes -when appropriate. Any state changes that occurred during the `OnRecvPacket` callback will be written -for asynchronous acknowledgements. - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `DecodePacketData(packet.Data)` function. - -```go -func (im IBCModule) OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, -) ibcexported.Acknowledgement { - // Decode the packet data - packetData := DecodePacketData(packet.Data) - - // do application state changes based on packet data and return the acknowledgement - // NOTE: The acknowledgement will indicate to the IBC handler if the application - // state changes should be written via the `Success()` function. Application state - // changes are only written if the acknowledgement is successful or the acknowledgement - // returned is nil indicating that an asynchronous acknowledgement will occur. - ack := processPacket(ctx, packet, packetData) - - return ack -} -``` - -Reminder, the `Acknowledgement` interface: - -```go -// Acknowledgement defines the interface used to return -// acknowledgements in the OnRecvPacket callback. -type Acknowledgement interface { - Success() bool - Acknowledgement() []byte -} -``` - -### Acknowledging packets - -After a module writes an acknowledgement, a relayer can relay back the acknowledgement to the sender module. The sender module can -then process the acknowledgement using the `OnAcknowledgementPacket` callback. The contents of the -acknowledgement is entirely up to the modules on the channel (just like the packet data); however, it -may often contain information on whether the packet was successfully processed along -with some additional data that could be useful for remediation if the packet processing failed. - -Since the modules are responsible for agreeing on an encoding/decoding standard for packet data and -acknowledgements, IBC will pass in the acknowledgements as `[]byte` to this callback. The callback -is responsible for decoding the acknowledgement and processing it. - -> Note that some of the code below is *pseudo code*, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `DecodeAcknowledgement(acknowledgments)` and `processAck(ack)` functions. - -```go -func (im IBCModule) OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, -) (*sdk.Result, error) { - // Decode acknowledgement - ack := DecodeAcknowledgement(acknowledgement) - - // process ack - res, err := processAck(ack) - return res, err -} -``` - -### Timeout packets - -If the timeout for a packet is reached before the packet is successfully received or the -counterparty channel end is closed before the packet is successfully received, then the receiving -chain can no longer process it. Thus, the sending chain must process the timeout using -`OnTimeoutPacket` to handle this situation. Again the IBC module will verify that the timeout is -indeed valid, so our module only needs to implement the state machine logic for what to do once a -timeout is reached and the packet can no longer be received. - -```go -func (im IBCModule) OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, -) (*sdk.Result, error) { - // do custom timeout logic -} -``` - -### Optional interfaces - -The following interface are optional and MAY be implemented by an IBCModule. - -#### PacketDataUnmarshaler - -The `PacketDataUnmarshaler` interface is defined as follows: - -```go -// PacketDataUnmarshaler defines an optional interface which allows a middleware to -// request the packet data to be unmarshaled by the base application. -type PacketDataUnmarshaler interface { - // UnmarshalPacketData unmarshals the packet data into a concrete type - UnmarshalPacketData([]byte) (interface{}, error) -} -``` - -The implementation of `UnmarshalPacketData` should unmarshal the bytes into the packet data type defined for an IBC stack. -The base application of an IBC stack should unmarshal the bytes into its packet data type, while a middleware may simply defer the call to the underlying application. - -This interface allows middlewares to unmarshal a packet data in order to make use of interfaces the packet data type implements. -For example, the callbacks middleware makes use of this function to access packet data types which implement the `PacketData` and `PacketDataProvider` interfaces. diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/03-bindports.md b/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/03-bindports.md deleted file mode 100644 index a57ec4c6000..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/03-bindports.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -title: Bind ports -sidebar_label: Bind ports -sidebar_position: 3 -slug: /ibc/apps/bindports ---- - -# Bind ports - -:::note Synopsis -Learn what changes to make to bind modules to their ports on initialization. -::: - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: -Currently, ports must be bound on app initialization. In order to bind modules to their respective ports on initialization, the following needs to be implemented: - -> Note that `portID` does not refer to a certain numerical ID, like `localhost:8080` with a `portID` 8080. Rather it refers to the application module the port binds. For IBC Modules built with the Cosmos SDK, it defaults to the module's name and for Cosmwasm contracts it defaults to the contract address. - -1. Add port ID to the `GenesisState` proto definition: - - ```protobuf - message GenesisState { - string port_id = 1; - // other fields - } - ``` - -1. Add port ID as a key to the module store: - - ```go - // x//types/keys.go - const ( - // ModuleName defines the IBC Module name - ModuleName = "moduleName" - - // Version defines the current version the IBC - // module supports - Version = "moduleVersion-1" - - // PortID is the default port id that module binds to - PortID = "portID" - - // ... - ) - ``` - -1. Add port ID to `x//types/genesis.go`: - - ```go - // in x//types/genesis.go - - // DefaultGenesisState returns a GenesisState with "transfer" as the default PortID. - func DefaultGenesisState() *GenesisState { - return &GenesisState{ - PortId: PortID, - // additional k-v fields - } - } - - // Validate performs basic genesis state validation returning an error upon any - // failure. - func (gs GenesisState) Validate() error { - if err := host.PortIdentifierValidator(gs.PortId); err != nil { - return err - } - //addtional validations - - return gs.Params.Validate() - } - ``` - -1. Bind to port(s) in the module keeper's `InitGenesis`: - - ```go - // InitGenesis initializes the ibc-module state and binds to PortID. - func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) { - k.SetPort(ctx, state.PortId) - - // ... - - // Only try to bind to port if it is not already bound, since we may already own - // port capability from capability InitGenesis - if !k.IsBound(ctx, state.PortId) { - // transfer module binds to the transfer port on InitChain - // and claims the returned capability - err := k.BindPort(ctx, state.PortId) - if err != nil { - panic(fmt.Sprintf("could not claim port capability: %v", err)) - } - } - - // ... - } - ``` - - With: - - ```go - // IsBound checks if the module is already bound to the desired port - func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { - _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) - return ok - } - - // BindPort defines a wrapper function for the port Keeper's function in - // order to expose it to module's InitGenesis function - func (k Keeper) BindPort(ctx sdk.Context, portID string) error { - cap := k.portKeeper.BindPort(ctx, portID) - return k.ClaimCapability(ctx, cap, host.PortPath(portID)) - } - ``` - - The module binds to the desired port(s) and returns the capabilities. - - In the above we find reference to keeper methods that wrap other keeper functionality, in the next section the keeper methods that need to be implemented will be defined. diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/04-keeper.md b/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/04-keeper.md deleted file mode 100644 index e359e014f2c..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/04-keeper.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: Keeper -sidebar_label: Keeper -sidebar_position: 4 -slug: /ibc/apps/keeper ---- - -# Keeper - -:::note Synopsis -Learn how to implement the IBC Module keeper. -::: - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: -In the previous sections, on channel handshake callbacks and port binding in `InitGenesis`, a reference was made to keeper methods that need to be implemented when creating a custom IBC module. Below is an overview of how to define an IBC module's keeper. - -> Note that some code has been left out for clarity, to get a full code overview, please refer to [the transfer module's keeper in the ibc-go repo](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/keeper.go). - -```go -// Keeper defines the IBC app module keeper -type Keeper struct { - storeKey sdk.StoreKey - cdc codec.BinaryCodec - paramSpace paramtypes.Subspace - - channelKeeper types.ChannelKeeper - portKeeper types.PortKeeper - scopedKeeper capabilitykeeper.ScopedKeeper - - // ... additional according to custom logic -} - -// NewKeeper creates a new IBC app module Keeper instance -func NewKeeper( - // args -) Keeper { - // ... - - return Keeper{ - cdc: cdc, - storeKey: key, - paramSpace: paramSpace, - - channelKeeper: channelKeeper, - portKeeper: portKeeper, - scopedKeeper: scopedKeeper, - - // ... additional according to custom logic - } -} - -// IsBound checks if the IBC app module is already bound to the desired port -func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { - _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) - return ok -} - -// BindPort defines a wrapper function for the port Keeper's function in -// order to expose it to module's InitGenesis function -func (k Keeper) BindPort(ctx sdk.Context, portID string) error { - cap := k.portKeeper.BindPort(ctx, portID) - return k.ClaimCapability(ctx, cap, host.PortPath(portID)) -} - -// GetPort returns the portID for the IBC app module. Used in ExportGenesis -func (k Keeper) GetPort(ctx sdk.Context) string { - store := ctx.KVStore(k.storeKey) - return string(store.Get(types.PortKey)) -} - -// SetPort sets the portID for the IBC app module. Used in InitGenesis -func (k Keeper) SetPort(ctx sdk.Context, portID string) { - store := ctx.KVStore(k.storeKey) - store.Set(types.PortKey, []byte(portID)) -} - -// AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function -func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool { - return k.scopedKeeper.AuthenticateCapability(ctx, cap, name) -} - -// ClaimCapability allows the IBC app module to claim a capability that core IBC -// passes to it -func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { - return k.scopedKeeper.ClaimCapability(ctx, cap, name) -} - -// ... additional according to custom logic -``` diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/05-packets_acks.md b/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/05-packets_acks.md deleted file mode 100644 index c6bf0e51cfc..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/05-packets_acks.md +++ /dev/null @@ -1,167 +0,0 @@ ---- -title: Define packets and acks -sidebar_label: Define packets and acks -sidebar_position: 5 -slug: /ibc/apps/packets_acks ---- - - -# Define packets and acks - -:::note Synopsis -Learn how to define custom packet and acknowledgement structs and how to encode and decode them. -::: - -:::note - -## Pre-requisites Readings - -- [IBC Overview](../01-overview.md)) -- [IBC default integration](../02-integration.md) - -::: - -## Custom packets - -Modules connected by a channel must agree on what application data they are sending over the -channel, as well as how they will encode/decode it. This process is not specified by IBC as it is up -to each application module to determine how to implement this agreement. However, for most -applications this will happen as a version negotiation during the channel handshake. While more -complex version negotiation is possible to implement inside the channel opening handshake, a very -simple version negotation is implemented in the [ibc-transfer module](https://github.com/cosmos/ibc-go/tree/main/modules/apps/transfer/module.go). - -Thus, a module must define its custom packet data structure, along with a well-defined way to -encode and decode it to and from `[]byte`. - -```go -// Custom packet data defined in application module -type CustomPacketData struct { - // Custom fields ... -} - -EncodePacketData(packetData CustomPacketData) []byte { - // encode packetData to bytes -} - -DecodePacketData(encoded []byte) (CustomPacketData) { - // decode from bytes to packet data -} -``` - -> Note that the `CustomPacketData` struct is defined in the proto definition and then compiled by the protobuf compiler. - -Then a module must encode its packet data before sending it through IBC. - -```go -// retrieve the dynamic capability for this channel -channelCap := scopedKeeper.GetCapability(ctx, channelCapName) -// Sending custom application packet data -data := EncodePacketData(customPacketData) -// Send packet to IBC, authenticating with channelCap -sequence, err := IBCChannelKeeper.SendPacket( - ctx, - channelCap, - sourcePort, - sourceChannel, - timeoutHeight, - timeoutTimestamp, - data, -) -``` - -A module receiving a packet must decode the `PacketData` into a structure it expects so that it can -act on it. - -```go -// Receiving custom application packet data (in OnRecvPacket) -packetData := DecodePacketData(packet.Data) -// handle received custom packet data -``` - -### Optional interfaces - -The following interfaces are optional and MAY be implemented by a custom packet type. -They allow middlewares such as callbacks to access information stored within the packet data. - -#### PacketData interface - -The `PacketData` interface is defined as follows: - -```go -// PacketData defines an optional interface which an application's packet data structure may implement. -type PacketData interface { - // GetPacketSender returns the sender address of the packet data. - // If the packet sender is unknown or undefined, an empty string should be returned. - GetPacketSender(sourcePortID string) string -} -``` - -The implementation of `GetPacketSender` should return the sender of the packet data. -If the packet sender is unknown or undefined, an empty string should be returned. - -This interface is intended to give IBC middlewares access to the packet sender of a packet data type. - -#### PacketDataProvider interface - -The `PacketDataProvider` interface is defined as follows: - -```go -// PacketDataProvider defines an optional interfaces for retrieving custom packet data stored on behalf of another application. -// An existing problem in the IBC middleware design is the inability for a middleware to define its own packet data type and insert packet sender provided information. -// A short term solution was introduced into several application's packet data to utilize a memo field to carry this information on behalf of another application. -// This interfaces standardizes that behaviour. Upon realization of the ability for middleware's to define their own packet data types, this interface will be deprecated and removed with time. -type PacketDataProvider interface { - // GetCustomPacketData returns the packet data held on behalf of another application. - // The name the information is stored under should be provided as the key. - // If no custom packet data exists for the key, nil should be returned. - GetCustomPacketData(key string) interface{} -} -``` - -The implementation of `GetCustomPacketData` should return packet data held on behalf of another application (if present and supported). -If this functionality is not supported, it should return nil. Otherwise it should return the packet data associated with the provided key. - -This interface gives IBC applications access to the packet data information embedded into the base packet data type. -Within transfer and interchain accounts, the embedded packet data is stored within the Memo field. - -Once all IBC applications within an IBC stack are capable of creating/maintaining their own packet data type's, this interface function will be deprecated and removed. - -## Acknowledgements - -Modules may commit an acknowledgement upon receiving and processing a packet in the case of synchronous packet processing. -In the case where a packet is processed at some later point after the packet has been received (asynchronous execution), the acknowledgement -will be written once the packet has been processed by the application which may be well after the packet receipt. - -NOTE: Most blockchain modules will want to use the synchronous execution model in which the module processes and writes the acknowledgement -for a packet as soon as it has been received from the IBC module. - -This acknowledgement can then be relayed back to the original sender chain, which can take action -depending on the contents of the acknowledgement. - -Just as packet data was opaque to IBC, acknowledgements are similarly opaque. Modules must pass and -receive acknowledegments with the IBC modules as byte strings. - -Thus, modules must agree on how to encode/decode acknowledgements. The process of creating an -acknowledgement struct along with encoding and decoding it, is very similar to the packet data -example above. [ICS 04](https://github.com/cosmos/ibc/blob/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope) -specifies a recommended format for acknowledgements. This acknowledgement type can be imported from -[channel types](https://github.com/cosmos/ibc-go/tree/main/modules/core/04-channel/types). - -While modules may choose arbitrary acknowledgement structs, a default acknowledgement types is provided by IBC [here](https://github.com/cosmos/ibc-go/blob/main/proto/ibc/core/channel/v1/channel.proto): - -```protobuf -// Acknowledgement is the recommended acknowledgement format to be used by -// app-specific protocols. -// NOTE: The field numbers 21 and 22 were explicitly chosen to avoid accidental -// conflicts with other protobuf message formats used for acknowledgements. -// The first byte of any message with this format will be the non-ASCII values -// `0xaa` (result) or `0xb2` (error). Implemented as defined by ICS: -// https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope -message Acknowledgement { - // response contains either a result or an error and must be non-empty - oneof response { - bytes result = 21; - string error = 22; - } -} -``` diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/06-routing.md b/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/06-routing.md deleted file mode 100644 index e11b3182e7f..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/06-routing.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Routing -sidebar_label: Routing -sidebar_position: 6 -slug: /ibc/apps/routing ---- - -# Routing - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC default integration](../02-integration.md) - -::: -:::note Synopsis -Learn how to hook a route to the IBC router for the custom IBC module. -::: - -As mentioned above, modules must implement the `IBCModule` interface (which contains both channel -handshake callbacks and packet handling callbacks). The concrete implementation of this interface -must be registered with the module name as a route on the IBC `Router`. - -```go -// app.go -func NewApp(...args) *App { -// ... - -// Create static IBC router, add module routes, then set and seal it -ibcRouter := port.NewRouter() - -ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule) -// Note: moduleCallbacks must implement IBCModule interface -ibcRouter.AddRoute(moduleName, moduleCallbacks) - -// Setting Router will finalize all routes by sealing router -// No more routes can be added -app.IBCKeeper.SetRouter(ibcRouter) - -// ... -} -``` diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/_category_.json b/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/_category_.json deleted file mode 100644 index 4561a95b84c..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Applications", - "position": 3, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/images/packet_flow.png b/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/images/packet_flow.png deleted file mode 100644 index db2d1d314b8..00000000000 Binary files a/docs/versioned_docs/version-v7.3.x/01-ibc/03-apps/images/packet_flow.png and /dev/null differ diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/04-middleware/01-develop.md b/docs/versioned_docs/version-v7.3.x/01-ibc/04-middleware/01-develop.md deleted file mode 100644 index 4403e816f82..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/04-middleware/01-develop.md +++ /dev/null @@ -1,473 +0,0 @@ ---- -title: IBC middleware -sidebar_label: IBC middleware -sidebar_position: 1 -slug: /ibc/middleware/develop ---- - -# IBC middleware - -:::note Synopsis -Learn how to write your own custom middleware to wrap an IBC application, and understand how to hook different middleware to IBC base applications to form different IBC application stacks -:::. - -This document serves as a guide for middleware developers who want to write their own middleware and for chain developers who want to use IBC middleware on their chains. - -IBC applications are designed to be self-contained modules that implement their own application-specific logic through a set of interfaces with the core IBC handlers. These core IBC handlers, in turn, are designed to enforce the correctness properties of IBC (transport, authentication, ordering) while delegating all application-specific handling to the IBC application modules. However, there are cases where some functionality may be desired by many applications, yet not appropriate to place in core IBC. - -Middleware allows developers to define the extensions as separate modules that can wrap over the base application. This middleware can thus perform its own custom logic, and pass data into the application so that it may run its logic without being aware of the middleware's existence. This allows both the application and the middleware to implement its own isolated logic while still being able to run as part of a single packet flow. - -:::note - -## Pre-requisite readings - -- [IBC Overview](../01-overview.md) -- [IBC Integration](../02-integration.md) -- [IBC Application Developer Guide](../03-apps/01-apps.md) - -::: - -## Definitions - -`Middleware`: A self-contained module that sits between core IBC and an underlying IBC application during packet execution. All messages between core IBC and underlying application must flow through middleware, which may perform its own custom logic. - -`Underlying Application`: An underlying application is the application that is directly connected to the middleware in question. This underlying application may itself be middleware that is chained to a base application. - -`Base Application`: A base application is an IBC application that does not contain any middleware. It may be nested by 0 or multiple middleware to form an application stack. - -`Application Stack (or stack)`: A stack is the complete set of application logic (middleware(s) + base application) that gets connected to core IBC. A stack may be just a base application, or it may be a series of middlewares that nest a base application. - -## Create a custom IBC middleware - -IBC middleware will wrap over an underlying IBC application and sits between core IBC and the application. It has complete control in modifying any message coming from IBC to the application, and any message coming from the application to core IBC. Thus, middleware must be completely trusted by chain developers who wish to integrate them, however this gives them complete flexibility in modifying the application(s) they wrap. - -### Interfaces - -```go -// Middleware implements the ICS26 Module interface -type Middleware interface { - porttypes.IBCModule // middleware has acccess to an underlying application which may be wrapped by more middleware - ics4Wrapper: ICS4Wrapper // middleware has access to ICS4Wrapper which may be core IBC Channel Handler or a higher-level middleware that wraps this middleware. -} -``` - -```typescript -// This is implemented by ICS4 and all middleware that are wrapping base application. -// The base application will call `sendPacket` or `writeAcknowledgement` of the middleware directly above them -// which will call the next middleware until it reaches the core IBC handler. -type ICS4Wrapper interface { - SendPacket( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - data []byte, - ) (sequence uint64, err error) - - WriteAcknowledgement( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - packet exported.PacketI, - ack exported.Acknowledgement, - ) error - - GetAppVersion( - ctx sdk.Context, - portID, - channelID string, - ) (string, bool) -} -``` - -### Implement `IBCModule` interface and callbacks - -The `IBCModule` is a struct that implements the [ICS-26 interface (`porttypes.IBCModule`)](https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port/types/module.go#L11-L106). It is recommended to separate these callbacks into a separate file `ibc_module.go`. As will be mentioned in the [integration section](02-integration.md), this struct should be different than the struct that implements `AppModule` in case the middleware maintains its own internal state and processes separate SDK messages. - -The middleware must have access to the underlying application, and be called before during all ICS-26 callbacks. It may execute custom logic during these callbacks, and then call the underlying application's callback. Middleware **may** choose not to call the underlying application's callback at all. Though these should generally be limited to error cases. - -In the case where the IBC middleware expects to speak to a compatible IBC middleware on the counterparty chain, they must use the channel handshake to negotiate the middleware version without interfering in the version negotiation of the underlying application. - -Middleware accomplishes this by formatting the version in a JSON-encoded string containing the middleware version and the application version. The application version may as well be a JSON-encoded string, possibly including further middleware and app versions, if the application stack consists of multiple milddlewares wrapping a base application. The format of the version is specified in ICS-30 as the following: - -```json -{ - "": "", - "app_version": "" -} -``` - -The `` key in the JSON struct should be replaced by the actual name of the key for the corresponding middleware (e.g. `fee_version`). - -During the handshake callbacks, the middleware can unmarshal the version string and retrieve the middleware and application versions. It can do its negotiation logic on ``, and pass the `` to the underlying application. - -The middleware should simply pass the capability in the callback arguments along to the underlying application so that it may be claimed by the base application. The base application will then pass the capability up the stack in order to authenticate an outgoing packet/acknowledgement. - -In the case where the middleware wishes to send a packet or acknowledgment without the involvement of the underlying application, it should be given access to the same `scopedKeeper` as the base application so that it can retrieve the capabilities by itself. - -### Handshake callbacks - -#### `OnChanOpenInit` - -```go -func (im IBCModule) OnChanOpenInit( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) (string, error) { - if version != "" { - // try to unmarshal JSON-encoded version string and pass - // the app-specific version to app callback. - // otherwise, pass version directly to app callback. - metadata, err := Unmarshal(version) - if err != nil { - // Since it is valid for fee version to not be specified, - // the above middleware version may be for another middleware. - // Pass the entire version string onto the underlying application. - return im.app.OnChanOpenInit( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - version, - ) - } - else { - metadata = { - // set middleware version to default value - MiddlewareVersion: defaultMiddlewareVersion, - // allow application to return its default version - AppVersion: "", - } - } - - doCustomLogic() - - // if the version string is empty, OnChanOpenInit is expected to return - // a default version string representing the version(s) it supports - appVersion, err := im.app.OnChanOpenInit( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - metadata.AppVersion, // note we only pass app version here - ) - if err != nil { - return "", err - } - - version := constructVersion(metadata.MiddlewareVersion, appVersion) - - return version, nil -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L34-L82) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnChanOpenTry` - -```go -func OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (string, error) { - // try to unmarshal JSON-encoded version string and pass - // the app-specific version to app callback. - // otherwise, pass version directly to app callback. - cpMetadata, err := Unmarshal(counterpartyVersion) - if err != nil { - return app.OnChanOpenTry( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - counterpartyVersion, - ) - } - - doCustomLogic() - - // Call the underlying application's OnChanOpenTry callback. - // The try callback must select the final app-specific version string and return it. - appVersion, err := app.OnChanOpenTry( - ctx, - order, - connectionHops, - portID, - channelID, - channelCap, - counterparty, - cpMetadata.AppVersion, // note we only pass counterparty app version here - ) - if err != nil { - return "", err - } - - // negotiate final middleware version - middlewareVersion := negotiateMiddlewareVersion(cpMetadata.MiddlewareVersion) - version := constructVersion(middlewareVersion, appVersion) - - return version, nil -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L84-L124) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnChanOpenAck` - -```go -func OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyChannelID string, - counterpartyVersion string, -) error { - // try to unmarshal JSON-encoded version string and pass - // the app-specific version to app callback. - // otherwise, pass version directly to app callback. - cpMetadata, err = UnmarshalJSON(counterpartyVersion) - if err != nil { - return app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) - } - - if !isCompatible(cpMetadata.MiddlewareVersion) { - return error - } - doCustomLogic() - - // call the underlying application's OnChanOpenTry callback - return app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, cpMetadata.AppVersion) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L126-L152) an example implementation of this callback for the ICS29 Fee Middleware module. - -### `OnChanOpenConfirm` - -```go -func OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - doCustomLogic() - - return app.OnChanOpenConfirm(ctx, portID, channelID) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L154-L162) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnChanCloseInit` - -```go -func OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - doCustomLogic() - - return app.OnChanCloseInit(ctx, portID, channelID) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L164-L187) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnChanCloseConfirm` - -```go -func OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - doCustomLogic() - - return app.OnChanCloseConfirm(ctx, portID, channelID) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L189-L212) an example implementation of this callback for the ICS29 Fee Middleware module. - -**NOTE**: Middleware that does not need to negotiate with a counterparty middleware on the remote stack will not implement the version unmarshalling and negotiation, and will simply perform its own custom logic on the callbacks without relying on the counterparty behaving similarly. - -### Packet callbacks - -The packet callbacks just like the handshake callbacks wrap the application's packet callbacks. The packet callbacks are where the middleware performs most of its custom logic. The middleware may read the packet flow data and perform some additional packet handling, or it may modify the incoming data before it reaches the underlying application. This enables a wide degree of usecases, as a simple base application like token-transfer can be transformed for a variety of usecases by combining it with custom middleware. - -#### `OnRecvPacket` - -```go -func OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) ibcexported.Acknowledgement { - doCustomLogic(packet) - - ack := app.OnRecvPacket(ctx, packet, relayer) - - doCustomLogic(ack) // middleware may modify outgoing ack - return ack -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L214-L237) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnAcknowledgementPacket` - -```go -func OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - relayer sdk.AccAddress, -) error { - doCustomLogic(packet, ack) - - return app.OnAcknowledgementPacket(ctx, packet, ack, relayer) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L239-L292) an example implementation of this callback for the ICS29 Fee Middleware module. - -#### `OnTimeoutPacket` - -```go -func OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) error { - doCustomLogic(packet) - - return app.OnTimeoutPacket(ctx, packet, relayer) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L294-L334) an example implementation of this callback for the ICS29 Fee Middleware module. - -### ICS-4 wrappers - -Middleware must also wrap ICS-4 so that any communication from the application to the `channelKeeper` goes through the middleware first. Similar to the packet callbacks, the middleware may modify outgoing acknowledgements and packets in any way it wishes. - -#### `SendPacket` - -```go -func SendPacket( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - appData []byte, -) { - // middleware may modify data - data = doCustomLogic(appData) - - return ics4Keeper.SendPacket( - ctx, - chanCap, - sourcePort, - sourceChannel, - timeoutHeight, - timeoutTimestamp, - data, - ) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L336-L343) an example implementation of this function for the ICS29 Fee Middleware module. - -#### `WriteAcknowledgement` - -```go -// only called for async acks -func WriteAcknowledgement( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - packet exported.PacketI, - ack exported.Acknowledgement, -) { - // middleware may modify acknowledgement - ack_bytes = doCustomLogic(ack) - - return ics4Keeper.WriteAcknowledgement(packet, ack_bytes) -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L345-L353) an example implementation of this function for the ICS29 Fee Middleware module. - -#### `GetAppVersion` - -```go -// middleware must return the underlying application version -func GetAppVersion( - ctx sdk.Context, - portID, - channelID string, -) (string, bool) { - version, found := ics4Keeper.GetAppVersion(ctx, portID, channelID) - if !found { - return "", false - } - - if !MiddlewareEnabled { - return version, true - } - - // unwrap channel version - metadata, err := Unmarshal(version) - if err != nil { - panic(fmt.Errof("unable to unmarshal version: %w", err)) - } - - return metadata.AppVersion, true -} - -// middleware must return the underlying application version -func GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { - version, found := ics4Keeper.GetAppVersion(ctx, portID, channelID) - if !found { - return "", false - } - - if !MiddlewareEnabled { - return version, true - } - - // unwrap channel version - metadata, err := Unmarshal(version) - if err != nil { - panic(fmt.Errof("unable to unmarshal version: %w", err)) - } - - return metadata.AppVersion, true -} -``` - -See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L355-L358) an example implementation of this function for the ICS29 Fee Middleware module. diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/04-middleware/02-integration.md b/docs/versioned_docs/version-v7.3.x/01-ibc/04-middleware/02-integration.md deleted file mode 100644 index 7bda98b5f88..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/04-middleware/02-integration.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: Integrating IBC middleware into a chain -sidebar_label: Integrating IBC middleware into a chain -sidebar_position: 2 -slug: /ibc/middleware/integration ---- - - -# Integrating IBC middleware into a chain - -Learn how to integrate IBC middleware(s) with a base application to your chain. The following document only applies for Cosmos SDK chains. - -If the middleware is maintaining its own state and/or processing SDK messages, then it should create and register its SDK module **only once** with the module manager in `app.go`. - -All middleware must be connected to the IBC router and wrap over an underlying base IBC application. An IBC application may be wrapped by many layers of middleware, only the top layer middleware should be hooked to the IBC router, with all underlying middlewares and application getting wrapped by it. - -The order of middleware **matters**, function calls from IBC to the application travel from top-level middleware to the bottom middleware and then to the application. Function calls from the application to IBC goes through the bottom middleware in order to the top middleware and then to core IBC handlers. Thus the same set of middleware put in different orders may produce different effects. - -## Example integration - -```go -// app.go - -// middleware 1 and middleware 3 are stateful middleware, -// perhaps implementing separate sdk.Msg and Handlers -mw1Keeper := mw1.NewKeeper(storeKey1) -mw3Keeper := mw3.NewKeeper(storeKey3) - -// Only create App Module **once** and register in app module -// if the module maintains independent state and/or processes sdk.Msgs -app.moduleManager = module.NewManager( - ... - mw1.NewAppModule(mw1Keeper), - mw3.NewAppModule(mw3Keeper), - transfer.NewAppModule(transferKeeper), - custom.NewAppModule(customKeeper) -) - -mw1IBCModule := mw1.NewIBCModule(mw1Keeper) -mw2IBCModule := mw2.NewIBCModule() // middleware2 is stateless middleware -mw3IBCModule := mw3.NewIBCModule(mw3Keeper) - -scopedKeeperTransfer := capabilityKeeper.NewScopedKeeper("transfer") -scopedKeeperCustom1 := capabilityKeeper.NewScopedKeeper("custom1") -scopedKeeperCustom2 := capabilityKeeper.NewScopedKeeper("custom2") - -// NOTE: IBC Modules may be initialized any number of times provided they use a separate -// scopedKeeper and underlying port. - -// initialize base IBC applications -// if you want to create two different stacks with the same base application, -// they must be given different scopedKeepers and assigned different ports. -transferIBCModule := transfer.NewIBCModule(transferKeeper) -customIBCModule1 := custom.NewIBCModule(customKeeper, "portCustom1") -customIBCModule2 := custom.NewIBCModule(customKeeper, "portCustom2") - -// create IBC stacks by combining middleware with base application -// NOTE: since middleware2 is stateless it does not require a Keeper -// stack 1 contains mw1 -> mw3 -> transfer -stack1 := mw1.NewIBCMiddleware(mw3.NewIBCMiddleware(transferIBCModule, mw3Keeper), mw1Keeper) -// stack 2 contains mw3 -> mw2 -> custom1 -stack2 := mw3.NewIBCMiddleware(mw2.NewIBCMiddleware(customIBCModule1), mw3Keeper) -// stack 3 contains mw2 -> mw1 -> custom2 -stack3 := mw2.NewIBCMiddleware(mw1.NewIBCMiddleware(customIBCModule2, mw1Keeper)) - -// associate each stack with the moduleName provided by the underlying scopedKeeper -ibcRouter := porttypes.NewRouter() -ibcRouter.AddRoute("transfer", stack1) -ibcRouter.AddRoute("custom1", stack2) -ibcRouter.AddRoute("custom2", stack3) -app.IBCKeeper.SetRouter(ibcRouter) -``` diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/04-middleware/_category_.json b/docs/versioned_docs/version-v7.3.x/01-ibc/04-middleware/_category_.json deleted file mode 100644 index 6596fe16c13..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/04-middleware/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Middleware", - "position": 4, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/05-upgrades/00-intro.md b/docs/versioned_docs/version-v7.3.x/01-ibc/05-upgrades/00-intro.md deleted file mode 100644 index d97ac898277..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/05-upgrades/00-intro.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: Upgrading IBC Chains Overview -sidebar_label: Overview -sidebar_position: 0 -slug: /ibc/upgrades/intro ---- - -### Upgrading IBC Chains Overview - -This directory contains information on how to upgrade an IBC chain without breaking counterparty clients and connections. - -IBC-connnected chains must be able to upgrade without breaking connections to other chains. Otherwise there would be a massive disincentive towards upgrading and disrupting high-value IBC connections, thus preventing chains in the IBC ecosystem from evolving and improving. Many chain upgrades may be irrelevant to IBC, however some upgrades could potentially break counterparty clients if not handled correctly. Thus, any IBC chain that wishes to perform a IBC-client-breaking upgrade must perform an IBC upgrade in order to allow counterparty clients to securely upgrade to the new light client. - -1. The [quick-guide](./01-quick-guide.md) describes how IBC-connected chains can perform client-breaking upgrades and how relayers can securely upgrade counterparty clients using the SDK. -2. The [developer-guide](./02-developer-guide.md) is a guide for developers intending to develop IBC client implementations with upgrade functionality. diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/05-upgrades/01-quick-guide.md b/docs/versioned_docs/version-v7.3.x/01-ibc/05-upgrades/01-quick-guide.md deleted file mode 100644 index 7a541c50244..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/05-upgrades/01-quick-guide.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: How to Upgrade IBC Chains and their Clients -sidebar_label: How to Upgrade IBC Chains and their Clients -sidebar_position: 1 -slug: /ibc/upgrades/quick-guide ---- - - -# How to Upgrade IBC Chains and their Clients - -:::note Synopsis -Learn how to upgrade your chain and counterparty clients. -::: - -The information in this doc for upgrading chains is relevant to SDK chains. However, the guide for counterparty clients is relevant to any Tendermint client that enables upgrades. - -## IBC Client Breaking Upgrades - -IBC-connected chains must perform an IBC upgrade if their upgrade will break counterparty IBC clients. The current IBC protocol supports upgrading tendermint chains for a specific subset of IBC-client-breaking upgrades. Here is the exhaustive list of IBC client-breaking upgrades and whether the IBC protocol currently supports such upgrades. - -IBC currently does **NOT** support unplanned upgrades. All of the following upgrades must be planned and committed to in advance by the upgrading chain, in order for counterparty clients to maintain their connections securely. - -Note: Since upgrades are only implemented for Tendermint clients, this doc only discusses upgrades on Tendermint chains that would break counterparty IBC Tendermint Clients. - -1. Changing the Chain-ID: **Supported** -2. Changing the UnbondingPeriod: **Partially Supported**, chains may increase the unbonding period with no issues. However, decreasing the unbonding period may irreversibly break some counterparty clients. Thus, it is **not recommended** that chains reduce the unbonding period. -3. Changing the height (resetting to 0): **Supported**, so long as chains remember to increment the revision number in their chain-id. -4. Changing the ProofSpecs: **Supported**, this should be changed if the proof structure needed to verify IBC proofs is changed across the upgrade. Ex: Switching from an IAVL store, to a SimpleTree Store -5. Changing the UpgradePath: **Supported**, this might involve changing the key under which upgraded clients and consensus states are stored in the upgrade store, or even migrating the upgrade store itself. -6. Migrating the IBC store: **Unsupported**, as the IBC store location is negotiated by the connection. -7. Upgrading to a backwards compatible version of IBC: Supported -8. Upgrading to a non-backwards compatible version of IBC: **Unsupported**, as IBC version is negotiated on connection handshake. -9. Changing the Tendermint LightClient algorithm: **Partially Supported**. Changes to the light client algorithm that do not change the ClientState or ConsensusState struct may be supported, provided that the counterparty is also upgraded to support the new light client algorithm. Changes that require updating the ClientState and ConsensusState structs themselves are theoretically possible by providing a path to translate an older ClientState struct into the new ClientState struct; however this is not currently implemented. - -### Step-by-Step Upgrade Process for SDK chains - -If the IBC-connected chain is conducting an upgrade that will break counterparty clients, it must ensure that the upgrade is first supported by IBC using the list above and then execute the upgrade process described below in order to prevent counterparty clients from breaking. - -1. Create a 02-client [`UpgradeProposal`](https://github.com/cosmos/ibc-go/blob/v7.3.0/proto/ibc/core/client/v1/client.proto#L58-L77) with an `UpgradePlan` and a new IBC ClientState in the `UpgradedClientState` field. Note that the `UpgradePlan` must specify an upgrade height **only** (no upgrade time), and the `ClientState` should only include the fields common to all valid clients and zero out any client-customizable fields (such as TrustingPeriod). -2. Vote on and pass the `UpgradeProposal` - -Upon the `UpgradeProposal` passing, the upgrade module will commit the UpgradedClient under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedClient`. On the block right before the upgrade height, the upgrade module will also commit an initial consensus state for the next chain under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedConsState`. - -Once the chain reaches the upgrade height and halts, a relayer can upgrade the counterparty clients to the last block of the old chain. They can then submit the proofs of the `UpgradedClient` and `UpgradedConsensusState` against this last block and upgrade the counterparty client. - -### Step-by-Step Upgrade Process for Relayers Upgrading Counterparty Clients - -Once the upgrading chain has committed to upgrading, relayers must wait till the chain halts at the upgrade height before upgrading counterparty clients. This is because chains may reschedule or cancel upgrade plans before they occur. Thus, relayers must wait till the chain reaches the upgrade height and halts before they can be sure the upgrade will take place. - -Thus, the upgrade process for relayers trying to upgrade the counterparty clients is as follows: - -1. Wait for the upgrading chain to reach the upgrade height and halt -2. Query a full node for the proofs of `UpgradedClient` and `UpgradedConsensusState` at the last height of the old chain. -3. Update the counterparty client to the last height of the old chain using the `UpdateClient` msg. -4. Submit an `UpgradeClient` msg to the counterparty chain with the `UpgradedClient`, `UpgradedConsensusState` and their respective proofs. -5. Submit an `UpdateClient` msg to the counterparty chain with a header from the new upgraded chain. - -The Tendermint client on the counterparty chain will verify that the upgrading chain did indeed commit to the upgraded client and upgraded consensus state at the upgrade height (since the upgrade height is included in the key). If the proofs are verified against the upgrade height, then the client will upgrade to the new client while retaining all of its client-customized fields. Thus, it will retain its old TrustingPeriod, TrustLevel, MaxClockDrift, etc; while adopting the new chain-specified fields such as UnbondingPeriod, ChainId, UpgradePath, etc. Note, this can lead to an invalid client since the old client-chosen fields may no longer be valid given the new chain-chosen fields. Upgrading chains should try to avoid these situations by not altering parameters that can break old clients. For an example, see the UnbondingPeriod example in the supported upgrades section. - -The upgraded consensus state will serve purely as a basis of trust for future `UpdateClientMsgs` and will not contain a consensus root to perform proof verification against. Thus, relayers must submit an `UpdateClientMsg` with a header from the new chain so that the connection can be used for proof verification again. diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/05-upgrades/02-developer-guide.md b/docs/versioned_docs/version-v7.3.x/01-ibc/05-upgrades/02-developer-guide.md deleted file mode 100644 index fb99db691a9..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/05-upgrades/02-developer-guide.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: IBC Client Developer Guide to Upgrades -sidebar_label: IBC Client Developer Guide to Upgrades -sidebar_position: 2 -slug: /ibc/upgrades/developer-guide ---- - - -# IBC Client Developer Guide to Upgrades - -:::note Synopsis -Learn how to implement upgrade functionality for your custom IBC client. -::: - -Please see the section [Handling upgrades](../../03-light-clients/01-developer-guide/05-upgrades.md) from the light client developer guide for more information. diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/05-upgrades/03-genesis-restart.md b/docs/versioned_docs/version-v7.3.x/01-ibc/05-upgrades/03-genesis-restart.md deleted file mode 100644 index 1119dd1ffad..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/05-upgrades/03-genesis-restart.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: Genesis Restart Upgrades -sidebar_label: Genesis Restart Upgrades -sidebar_position: 3 -slug: /ibc/upgrades/genesis-restart ---- - - -# Genesis Restart Upgrades - -:::note Synopsis -Learn how to upgrade your chain and counterparty clients using genesis restarts. -::: - -**NOTE**: Regular genesis restarts are currently unsupported by relayers! - -## IBC Client Breaking Upgrades - -IBC client breaking upgrades are possible using genesis restarts. -It is highly recommended to use the in-place migrations instead of a genesis restart. -Genesis restarts should be used sparingly and as backup plans. - -Genesis restarts still require the usage of an IBC upgrade proposal in order to correctly upgrade counterparty clients. - -### Step-by-Step Upgrade Process for SDK Chains - -If the IBC-connected chain is conducting an upgrade that will break counterparty clients, it must ensure that the upgrade is first supported by IBC using the [IBC Client Breaking Upgrade List](./01-quick-guide.md#ibc-client-breaking-upgrades) and then execute the upgrade process described below in order to prevent counterparty clients from breaking. - -1. Create a 02-client [`UpgradeProposal`](https://github.com/cosmos/ibc-go/blob/v7.3.0/proto/ibc/core/client/v1/client.proto#L58-L77) with an `UpgradePlan` and a new IBC ClientState in the `UpgradedClientState` field. Note that the `UpgradePlan` must specify an upgrade height **only** (no upgrade time), and the `ClientState` should only include the fields common to all valid clients and zero out any client-customizable fields (such as TrustingPeriod). -2. Vote on and pass the `UpgradeProposal` -3. Halt the node after successful upgrade. -4. Export the genesis file. -5. Swap to the new binary. -6. Run migrations on the genesis file. -7. Remove the `UpgradeProposal` plan from the genesis file. This may be done by migrations. -8. Change desired chain-specific fields (chain id, unbonding period, etc). This may be done by migrations. -8. Reset the node's data. -9. Start the chain. - -Upon the `UpgradeProposal` passing, the upgrade module will commit the UpgradedClient under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedClient`. On the block right before the upgrade height, the upgrade module will also commit an initial consensus state for the next chain under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedConsState`. - -Once the chain reaches the upgrade height and halts, a relayer can upgrade the counterparty clients to the last block of the old chain. They can then submit the proofs of the `UpgradedClient` and `UpgradedConsensusState` against this last block and upgrade the counterparty client. - -#### Step-by-Step Upgrade Process for Relayers Upgrading Counterparty Clients - -These steps are identical to the regular [IBC client breaking upgrade process](./01-quick-guide.md#step-by-step-upgrade-process-for-relayers-upgrading-counterparty-clients). - -### Non-IBC Client Breaking Upgrades - -While ibc-go supports genesis restarts which do not break IBC clients, relayers do not support this upgrade path. -Here is a tracking issue on [Hermes](https://github.com/informalsystems/ibc-rs/issues/1152). -Please do not attempt a regular genesis restarts unless you have a tool to update counterparty clients correctly. diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/05-upgrades/_category_.json b/docs/versioned_docs/version-v7.3.x/01-ibc/05-upgrades/_category_.json deleted file mode 100644 index 7c3191d2ce9..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/05-upgrades/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Upgrades", - "position": 5, - "link": { "type": "doc", "id": "intro" } -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/06-proposals.md b/docs/versioned_docs/version-v7.3.x/01-ibc/06-proposals.md deleted file mode 100644 index 3c9279a8658..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/06-proposals.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -title: Governance Proposals -sidebar_label: Governance Proposals -sidebar_position: 6 -slug: /ibc/proposals ---- - -# Governance Proposals - -In uncommon situations, a highly valued client may become frozen due to uncontrollable -circumstances. A highly valued client might have hundreds of channels being actively used. -Some of those channels might have a significant amount of locked tokens used for ICS 20. - -If the one third of the validator set of the chain the client represents decides to collude, -they can sign off on two valid but conflicting headers each signed by the other one third -of the honest validator set. The light client can now be updated with two valid, but conflicting -headers at the same height. The light client cannot know which header is trustworthy and therefore -evidence of such misbehaviour is likely to be submitted resulting in a frozen light client. - -Frozen light clients cannot be updated under any circumstance except via a governance proposal. -Since a quorum of validators can sign arbitrary state roots which may not be valid executions -of the state machine, a governance proposal has been added to ease the complexity of unfreezing -or updating clients which have become "stuck". Without this mechanism, validator sets would need -to construct a state root to unfreeze the client. Unfreezing clients, re-enables all of the channels -built upon that client. This may result in recovery of otherwise lost funds. - -Tendermint light clients may become expired if the trusting period has passed since their -last update. This may occur if relayers stop submitting headers to update the clients. - -An unplanned upgrade by the counterparty chain may also result in expired clients. If the counterparty -chain undergoes an unplanned upgrade, there may be no commitment to that upgrade signed by the validator -set before the chain-id changes. In this situation, the validator set of the last valid update for the -light client is never expected to produce another valid header since the chain-id has changed, which will -ultimately lead the on-chain light client to become expired. - -In the case that a highly valued light client is frozen, expired, or rendered non-updateable, a -governance proposal may be submitted to update this client, known as the subject client. The -proposal includes the client identifier for the subject and the client identifier for a substitute -client. Light client implementations may implement custom updating logic, but in most cases, -the subject will be updated to the latest consensus state of the substitute client, if the proposal passes. -The substitute client is used as a "stand in" while the subject is on trial. It is best practice to create -a substitute client *after* the subject has become frozen to avoid the substitute from also becoming frozen. -An active substitute client allows headers to be submitted during the voting period to prevent accidental expiry -once the proposal passes. - -*note* two of these parameters: `AllowUpdateAfterExpiry` and `AllowUpdateAfterMisbehavior` have been deprecated, and will both be set to `false` upon upgrades even if they were previously set to `true`. These parameters will no longer play a role in restricting a client upgrade. Please see ADR026 for more details. - -## How to recover an expired client with a governance proposal - -See also the relevant documentation: [ADR-026, IBC client recovery mechanisms](/architecture/adr-026-ibc-client-recovery-mechanisms) - -> **Who is this information for?** -> Although technically anyone can submit the governance proposal to recover an expired client, often it will be **relayer operators** (at least coordinating the submission). - -### Preconditions - -- The chain is updated with ibc-go >= v1.1.0. -- There exists an active client (with a known client identifier) for the same counterparty chain as the expired client. -- The governance deposit. - -## Steps - -### Step 1 - -Check if the client is attached to the expected `chain-id`. For example, for an expired Tendermint client representing the Akash chain the client state looks like this on querying the client state: - -```text -{ - client_id: 07-tendermint-146 - client_state: - '@type': /ibc.lightclients.tendermint.v1.ClientState - allow_update_after_expiry: true - allow_update_after_misbehaviour: true - chain_id: akashnet-2 -} -``` - -The client is attached to the expected Akash `chain-id`. Note that although the parameters (`allow_update_after_expiry` and `allow_update_after_misbehaviour`) exist to signal intent, these parameters have been deprecated and will not enforce any checks on the revival of client. See ADR-026 for more context on this deprecation. - -### Step 2 - -If the chain has been updated to ibc-go >= v1.1.0, anyone can submit the governance proposal to recover the client by executing this via CLI. - -> Note that the Cosmos SDK has updated how governance proposals are submitted in SDK v0.46, now requiring to pass a .json proposal file - -- From SDK v0.46.x onwards - - ```bash - tx gov submit-proposal [path-to-proposal-json] - ``` - - where `proposal.json` contains: - - ```json - { - "messages": [ - { - "@type": "/ibc.core.client.v1.ClientUpdateProposal", - "title": "title_string", - "description": "description_string", - "subject_client_id": "expired_client_id_string", - "substitute_client_id": "active_client_id_string" - } - ], - "metadata": "", - "deposit": "10stake" - } - ``` - - Alternatively there's a legacy command (that is no longer recommended though): - - ```bash - tx gov submit-legacy-proposal update-client - ``` - -- Until SDK v0.45.x - - ```bash - tx gov submit-proposal update-client - ``` - -The `` identifier is the proposed client to be updated. This client must be either frozen or expired. - -The `` represents a substitute client. It carries all the state for the client which may be updated. It must have identical client and chain parameters to the client which may be updated (except for latest height, frozen height, and chain ID). It should be continually updated during the voting period. - -After this, all that remains is deciding who funds the governance deposit and ensuring the governance proposal passes. If it does, the client on trial will be updated to the latest state of the substitute. - -## Important considerations - -Please note that from v1.0.0 of ibc-go it will not be allowed for transactions to go to expired clients anymore, so please update to at least this version to prevent similar issues in the future. - -Please also note that if the client on the other end of the transaction is also expired, that client will also need to update. This process updates only one client. diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/07-relayer.md b/docs/versioned_docs/version-v7.3.x/01-ibc/07-relayer.md deleted file mode 100644 index f40e9e671a3..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/07-relayer.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: Relayer -sidebar_label: Relayer -sidebar_position: 7 -slug: /ibc/relayer ---- - -# Relayer - -:::note - -## Pre-requisite readings - -- [IBC Overview](01-overview.md) -- [Events](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/advanced/08-events.md) - -::: - -## Events - -Events are emitted for every transaction processed by the base application to indicate the execution -of some logic clients may want to be aware of. This is extremely useful when relaying IBC packets. -Any message that uses IBC will emit events for the corresponding TAO logic executed as defined in -the [IBC events document](/events/events). - -In the SDK, it can be assumed that for every message there is an event emitted with the type `message`, -attribute key `action`, and an attribute value representing the type of message sent -(`channel_open_init` would be the attribute value for `MsgChannelOpenInit`). If a relayer queries -for transaction events, it can split message events using this event Type/Attribute Key pair. - -The Event Type `message` with the Attribute Key `module` may be emitted multiple times for a single -message due to application callbacks. It can be assumed that any TAO logic executed will result in -a module event emission with the attribute value `ibc_` (02-client emits `ibc_client`). - -### Subscribing with Tendermint - -Calling the Tendermint RPC method `Subscribe` via [Tendermint's Websocket](https://docs.tendermint.com/main/rpc/) will return events using -Tendermint's internal representation of them. Instead of receiving back a list of events as they -were emitted, Tendermint will return the type `map[string][]string` which maps a string in the -form `.` to `attribute_value`. This causes extraction of the event -ordering to be non-trivial, but still possible. - -A relayer should use the `message.action` key to extract the number of messages in the transaction -and the type of IBC transactions sent. For every IBC transaction within the string array for -`message.action`, the necessary information should be extracted from the other event fields. If -`send_packet` appears at index 2 in the value for `message.action`, a relayer will need to use the -value at index 2 of the key `send_packet.packet_sequence`. This process should be repeated for each -piece of information needed to relay a packet. - -## Example Implementations - -- [Golang Relayer](https://github.com/cosmos/relayer) -- [Hermes](https://github.com/informalsystems/ibc-rs/tree/master/crates/relayer) diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/08-proto-docs.md b/docs/versioned_docs/version-v7.3.x/01-ibc/08-proto-docs.md deleted file mode 100644 index 7d479513398..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/08-proto-docs.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Protobuf Documentation -sidebar_label: Protobuf Documentation -sidebar_position: 8 -slug: /ibc/proto-docs ---- - - -# Protobuf documentation - -See [ibc-go Buf Protobuf documentation](https://buf.build/cosmos/ibc/tags/main). diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/09-roadmap.md b/docs/versioned_docs/version-v7.3.x/01-ibc/09-roadmap.md deleted file mode 100644 index 94fa7e376ef..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/09-roadmap.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -title: Roadmap -sidebar_label: Roadmap -sidebar_position: 9 -slug: /roadmap/roadmap ---- - -# Roadmap ibc-go - -*Lastest update: December 21st, 2022* - -This document endeavours to inform the wider IBC community about plans and priorities for work on ibc-go by the team at Interchain GmbH. It is intended to broadly inform all users of ibc-go, including developers and operators of IBC, relayer, chain and wallet applications. - -This roadmap should be read as a high-level guide, rather than a commitment to schedules and deliverables. The degree of specificity is inversely proportional to the timeline. We will update this document periodically to reflect the status and plans. For the latest expected release timelines, please check [here](https://github.com/cosmos/ibc-go/wiki/Release-timeline). - -## v7.0.0 - -### 02-client refactor - -This refactor will make the development of light clients easier. The ibc-go implementation will finally align with the spec and light clients will be required to set their own client and consensus states. This will allow more flexibility for light clients to manage their own internal storage and do batch updates. See [ADR 006](/architecture/adr-006-02-client-refactor) for more information. - -Follow the progress with the [beta](https://github.com/cosmos/ibc-go/milestone/25) and [RC](https://github.com/cosmos/ibc-go/milestone/27) milestones or in the [project board](https://github.com/orgs/cosmos/projects/7/views/14). - -### Upgrade Cosmos SDK v0.47 - -Follow the progress with the [milestone](https://github.com/cosmos/ibc-go/milestone/36). - -### Add `authz` support to 20-transfer - -Authz goes cross chain: users can grant permission for their tokens to be transferred to another chain on their behalf. See [this issue](https://github.com/cosmos/ibc-go/issues/2431) for more details. - -## v7.1.0 - -Because it is so important to have an ibc-go release compatible with the latest Cosmos SDK release, a couple of features will take a little longer and be released in [v7.1.0](https://github.com/cosmos/ibc-go/milestone/37). - -### Localhost connection - -This feature will add support for applications on a chain to communicate with applications on the same chain using the existing standard interface to communicate with applications on remote chains. This is a powerful UX improvement, particularly for those users interested in interacting with multiple smart contracts on a single chain through one interface. - -For more details, see the design proposal and discussion [here](https://github.com/cosmos/ibc-go/discussions/2191). - -A special shout out to Strangelove for their substantial contribution on this feature. - -### Support for Wasm light clients - -We will add support for Wasm light clients. The first Wasm client developed with ibc-go/v7 02-client refactor and stored as Wasm bytecode will be the GRANDPA light client used for Cosmos x Substrate IBC connections. This feature will be used also for a NEAR light client in the future. - -This feature was developed by Composable and Strangelove but will be upstreamed into ibc-go. - -## v8.0.0 - -### Channel upgradability - -Channel upgradability will allow chains to renegotiate an existing channel to take advantage of new features without having to create a new channel, thus preserving all existing packet state processed on the channel. - -Follow the progress with the [alpha milestone](https://github.com/cosmos/ibc-go/milestone/29) or the [project board](https://github.com/orgs/cosmos/projects/7/views/17). - -### Path unwinding - -This feature will allow tokens with non-native denoms to be sent back automatically to their native chains before being sent to a final destination chain. This will allow tokens to reach a final destination with the least amount possible of hops from their native chain. - -For more details, see this [discussion](https://github.com/cosmos/ibc/discussions/824). - ---- - -This roadmap is also available as a [project board](https://github.com/orgs/cosmos/projects/7/views/25). - -For the latest expected release timelines, please check [here](https://github.com/cosmos/ibc-go/wiki/Release-timeline). - -For the latest information on the progress of the work or the decisions made that might influence the roadmap, please follow our [engineering updates](https://github.com/cosmos/ibc-go/wiki/Engineering-updates). - ---- - -**Note**: release version numbers may be subject to change. diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/10-troubleshooting.md b/docs/versioned_docs/version-v7.3.x/01-ibc/10-troubleshooting.md deleted file mode 100644 index 0504a993b17..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/10-troubleshooting.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: Troubleshooting -sidebar_label: Troubleshooting -sidebar_position: 10 -slug: /ibc/troubleshooting ---- - -# Troubleshooting - -## Unauthorized client states - -If it is being reported that a client state is unauthorized, this is due to the client type not being present -in the [`AllowedClients`](https://github.com/cosmos/ibc-go/blob/v6.0.0/modules/core/02-client/types/client.pb.go#L345) array. - -Unless the client type is present in this array, all usage of clients of this type will be prevented. diff --git a/docs/versioned_docs/version-v7.3.x/01-ibc/_category_.json b/docs/versioned_docs/version-v7.3.x/01-ibc/_category_.json deleted file mode 100644 index 066f3af93b1..00000000000 --- a/docs/versioned_docs/version-v7.3.x/01-ibc/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Using IBC-Go", - "position": 1, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/01-overview.md b/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/01-overview.md deleted file mode 100644 index 7e257d1e805..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/01-overview.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /apps/transfer/overview ---- - -# Overview - -:::note Synopsis -Learn about what the token Transfer module is -::: - -## What is the Transfer module? - -Transfer is the Cosmos SDK implementation of the [ICS-20](https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer) protocol, which enables cross-chain fungible token transfers. - -## Concepts - -### Acknowledgements - -ICS20 uses the recommended acknowledgement format as specified by [ICS 04](https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope). - -A successful receive of a transfer packet will result in a Result Acknowledgement being written -with the value `[]byte{byte(1)}` in the `Response` field. - -An unsuccessful receive of a transfer packet will result in an Error Acknowledgement being written -with the error message in the `Response` field. - -### Denomination trace - -The denomination trace corresponds to the information that allows a token to be traced back to its -origin chain. It contains a sequence of port and channel identifiers ordered from the most recent to -the oldest in the timeline of transfers. - -This information is included on the token denomination field in the form of a hash to prevent an -unbounded denomination length. For example, the token `transfer/channelToA/uatom` will be displayed -as `ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2`. - -Each send to any chain other than the one it was previously received from is a movement forwards in -the token's timeline. This causes trace to be added to the token's history and the destination port -and destination channel to be prefixed to the denomination. In these instances the sender chain is -acting as the "source zone". When the token is sent back to the chain it previously received from, the -prefix is removed. This is a backwards movement in the token's timeline and the sender chain is -acting as the "sink zone". - -It is strongly recommended to read the full details of [ADR 001: Coin Source Tracing](/architecture/adr-001-coin-source-tracing) to understand the implications and context of the IBC token representations. - -## UX suggestions for clients - -For clients (wallets, exchanges, applications, block explorers, etc) that want to display the source of the token, it is recommended to use the following alternatives for each of the cases below: - -### Direct connection - -If the denomination trace contains a single identifier prefix pair (as in the example above), then -the easiest way to retrieve the chain and light client identifier is to map the trace information -directly. In summary, this requires querying the channel from the denomination trace identifiers, -and then the counterparty client state using the counterparty port and channel identifiers from the -retrieved channel. - -A general pseudo algorithm would look like the following: - -1. Query the full denomination trace. -2. Query the channel with the `portID/channelID` pair, which corresponds to the first destination of the - token. -3. Query the client state using the identifiers pair. Note that this query will return a `"Not -Found"` response if the current chain is not connected to this channel. -4. Retrieve the client identifier or chain identifier from the client state (eg: on - Tendermint clients) and store it locally. - -Using the gRPC gateway client service the steps above would be, with a given IBC token `ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2` stored on `chainB`: - -1. `GET /ibc/apps/transfer/v1/denom_traces/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2` -> `{"path": "transfer/channelToA", "base_denom": "uatom"}` -2. `GET /ibc/apps/transfer/v1/channels/channelToA/ports/transfer/client_state"` -> `{"client_id": "clientA", "chain-id": "chainA", ...}` -3. `GET /ibc/apps/transfer/v1/channels/channelToA/ports/transfer"` -> `{"channel_id": "channelToA", port_id": "transfer", counterparty: {"channel_id": "channelToB", port_id": "transfer"}, ...}` -4. `GET /ibc/apps/transfer/v1/channels/channelToB/ports/transfer/client_state" -> {"client_id": "clientB", "chain-id": "chainB", ...}` - -Then, the token transfer chain path for the `uatom` denomination would be: `chainA` -> `chainB`. - -### Multiple hops - -The multiple channel hops case applies when the token has passed through multiple chains between the original source and final destination chains. - -The IBC protocol doesn't know the topology of the overall network (i.e connections between chains and identifier names between them). For this reason, in the multiple hops case, a particular chain in the timeline of the individual transfers can't query the chain and client identifiers of the other chains. - -Take for example the following sequence of transfers `A -> B -> C` for an IBC token, with a final prefix path (trace info) of `transfer/channelChainC/transfer/channelChainB`. What the paragraph above means is that even in the case that chain `C` is directly connected to chain `A`, querying the port and channel identifiers that chain `B` uses to connect to chain `A` (eg: `transfer/channelChainA`) can be completely different from the one that chain `C` uses to connect to chain `A` (eg: `transfer/channelToChainA`). - -Thus the proposed solution for clients that the IBC team recommends are the following: - -- **Connect to all chains**: Connecting to all the chains in the timeline would allow clients to - perform the queries outlined in the [direct connection](#direct-connection) section to each - relevant chain. By repeatedly following the port and channel denomination trace transfer timeline, - clients should always be able to find all the relevant identifiers. This comes at the tradeoff - that the client must connect to nodes on each of the chains in order to perform the queries. -- **Relayer as a Service (RaaS)**: A longer term solution is to use/create a relayer service that - could map the denomination trace to the chain path timeline for each token (i.e `origin chain -> -chain #1 -> ... -> chain #(n-1) -> final chain`). These services could provide merkle proofs in - order to allow clients to optionally verify the path timeline correctness for themselves by - running light clients. If the proofs are not verified, they should be considered as trusted third - parties services. Additionally, client would be advised in the future to use RaaS that support the - largest number of connections between chains in the ecosystem. Unfortunately, none of the existing - public relayers (in [Golang](https://github.com/cosmos/relayer) and - [Rust](https://github.com/informalsystems/ibc-rs)), provide this service to clients. - -:::tip -The only viable alternative for clients (at the time of writing) to tokens with multiple connection hops, is to connect to all chains directly and perform relevant queries to each of them in the sequence. -::: - -## Locked funds - -In some [exceptional cases](/architecture/adr-026-ibc-client-recovery-mechanisms#exceptional-cases), a client state associated with a given channel cannot be updated. This causes that funds from fungible tokens in that channel will be permanently locked and thus can no longer be transferred. - -To mitigate this, a client update governance proposal can be submitted to update the frozen client -with a new valid header. Once the proposal passes the client state will be unfrozen and the funds -from the associated channels will then be unlocked. This mechanism only applies to clients that -allow updates via governance, such as Tendermint clients. - -In addition to this, it's important to mention that a token must be sent back along the exact route -that it took originally in order to return it to its original form on the source chain (eg: the -Cosmos Hub for the `uatom`). Sending a token back to the same chain across a different channel will -**not** move the token back across its timeline. If a channel in the chain history closes before the -token can be sent back across that channel, then the token will not be returnable to its original -form. - -## Security considerations - -For safety, no other module must be capable of minting tokens with the `ibc/` prefix. The IBC -transfer module needs a subset of the denomination space that only it can create tokens in. diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/02-state.md b/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/02-state.md deleted file mode 100644 index 916e99b46c3..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/02-state.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: State -sidebar_label: State -sidebar_position: 2 -slug: /apps/transfer/state ---- - -# State - -The IBC transfer application module keeps state of the port to which the module is binded and the denomination trace information as outlined in [ADR 001](/architecture/adr-001-coin-source-tracing). - -- `Port`: `0x01 -> ProtocolBuffer(string)` -- `DenomTrace`: `0x02 | []bytes(traceHash) -> ProtocolBuffer(DenomTrace)` diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/03-state-transitions.md b/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/03-state-transitions.md deleted file mode 100644 index 7c73b8da21c..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/03-state-transitions.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: State Transitions -sidebar_label: State Transitions -sidebar_position: 3 -slug: /apps/transfer/state-transitions ---- - -# State transitions - -## Send fungible tokens - -A successful fungible token send has two state transitions depending if the transfer is a movement forward or backwards in the token's timeline: - -1. Sender chain is the source chain, *i.e* a transfer to any chain other than the one it was previously received from is a movement forwards in the token's timeline. This results in the following state transitions: - - - The coins are transferred to an escrow address (i.e locked) on the sender chain. - - The coins are transferred to the receiving chain through IBC TAO logic. - -2. Sender chain is the sink chain, *i.e* the token is sent back to the chain it previously received from. This is a backwards movement in the token's timeline. This results in the following state transitions: - - - The coins (vouchers) are burned on the sender chain. - - The coins are transferred to the receiving chain through IBC TAO logic. - -## Receive fungible tokens - -A successful fungible token receive has two state transitions depending if the transfer is a movement forward or backwards in the token's timeline: - -1. Receiver chain is the source chain. This is a backwards movement in the token's timeline. This results in the following state transitions: - - - The leftmost port and channel identifier pair is removed from the token denomination prefix. - - The tokens are unescrowed and sent to the receiving address. - -2. Receiver chain is the sink chain. This is a movement forwards in the token's timeline. This results in the following state transitions: - - - Token vouchers are minted by prefixing the destination port and channel identifiers to the trace information. - - The receiving chain stores the new trace information in the store (if not set already). - - The vouchers are sent to the receiving address. diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/04-messages.md b/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/04-messages.md deleted file mode 100644 index 483384a09fe..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/04-messages.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: Messages -sidebar_label: Messages -sidebar_position: 4 -slug: /apps/transfer/messages ---- - -# Messages - -## `MsgTransfer` - -A fungible token cross chain transfer is achieved by using the `MsgTransfer`: - -```go -type MsgTransfer struct { - SourcePort string - SourceChannel string - Token sdk.Coin - Sender string - Receiver string - TimeoutHeight ibcexported.Height - TimeoutTimestamp uint64 - Memo string -} -``` - -This message is expected to fail if: - -- `SourcePort` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). -- `SourceChannel` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -- `Token` is invalid (denom is invalid or amount is negative) - - `Token.Amount` is not positive. - - `Token.Denom` is not a valid IBC denomination as per [ADR 001 - Coin Source Tracing](/architecture/adr-001-coin-source-tracing). -- `Sender` is empty. -- `Receiver` is empty. -- `TimeoutHeight` and `TimeoutTimestamp` are both zero. - -This message will send a fungible token to the counterparty chain represented by the counterparty Channel End connected to the Channel End with the identifiers `SourcePort` and `SourceChannel`. - -The denomination provided for transfer should correspond to the same denomination represented on this chain. The prefixes will be added as necessary upon by the receiving chain. - -### Memo - -The memo field was added to allow applications and users to attach metadata to transfer packets. The field is optional and may be left empty. When it is used to attach metadata for a particular middleware, the memo field should be represented as a json object where different middlewares use different json keys. - -For example, the following memo field is used by the [callbacks middleware](../../04-middleware/02-callbacks/01-overview.md) to attach a source callback to a transfer packet: - -```jsonc -{ - "src_callback": { - "address": "callbackAddressString", - // optional - "gas_limit": "userDefinedGasLimitString", - } -} -``` - -You can find more information about other applications that use the memo field in the [chain registry](https://github.com/cosmos/chain-registry/blob/master/_memo_keys/ICS20_memo_keys.json). diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/05-events.md b/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/05-events.md deleted file mode 100644 index 888b26a959a..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/05-events.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Events -sidebar_label: Events -sidebar_position: 5 -slug: /apps/transfer/events ---- - - -# Events - -## `MsgTransfer` - -| Type | Attribute Key | Attribute Value | -|--------------|---------------|-----------------| -| ibc_transfer | sender | {sender} | -| ibc_transfer | receiver | {receiver} | -| message | action | transfer | -| message | module | transfer | - -## `OnRecvPacket` callback - -| Type | Attribute Key | Attribute Value | -|-----------------------|---------------|-----------------| -| fungible_token_packet | module | transfer | -| fungible_token_packet | sender | {sender} | -| fungible_token_packet | receiver | {receiver} | -| fungible_token_packet | denom | {denom} | -| fungible_token_packet | amount | {amount} | -| fungible_token_packet | success | {ackSuccess} | -| fungible_token_packet | memo | {memo} | -| denomination_trace | trace_hash | {hex_hash} | - -## `OnAcknowledgePacket` callback - -| Type | Attribute Key | Attribute Value | -|-----------------------|-----------------|-------------------| -| fungible_token_packet | module | transfer | -| fungible_token_packet | sender | {sender} | -| fungible_token_packet | receiver | {receiver} | -| fungible_token_packet | denom | {denom} | -| fungible_token_packet | amount | {amount} | -| fungible_token_packet | memo | {memo} | -| fungible_token_packet | acknowledgement | {ack.String()} | -| fungible_token_packet | success | error | {ack.Response} | - -## `OnTimeoutPacket` callback - -| Type | Attribute Key | Attribute Value | -|-----------------------|-----------------|-----------------| -| fungible_token_packet | module | transfer | -| fungible_token_packet | refund_receiver | {receiver} | -| fungible_token_packet | denom | {denom} | -| fungible_token_packet | amount | {amount} | -| fungible_token_packet | memo | {memo} | diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/06-metrics.md b/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/06-metrics.md deleted file mode 100644 index 104e5b4d3bc..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/06-metrics.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: Metrics -sidebar_label: Metrics -sidebar_position: 6 -slug: /apps/transfer/metrics ---- - - -# Metrics - -The IBC transfer application module exposes the following set of [metrics](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/advanced/09-telemetry.md). - -| Metric | Description | Unit | Type | -|:--------------------------------|:------------------------------------------------------------------------------------------|:----------------|:--------| -| `tx_msg_ibc_transfer` | The total amount of tokens transferred via IBC in a `MsgTransfer` (source or sink chain) | token | gauge | -| `ibc_transfer_packet_receive` | The total amount of tokens received in a `FungibleTokenPacketData` (source or sink chain) | token | gauge | -| `ibc_transfer_send` | Total number of IBC transfers sent from a chain (source or sink) | transfer | counter | -| `ibc_transfer_receive` | Total number of IBC transfers received to a chain (source or sink) | transfer | counter | diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/07-params.md b/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/07-params.md deleted file mode 100644 index f3d55f7388f..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/07-params.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: Params -sidebar_label: Params -sidebar_position: 7 -slug: /apps/transfer/params ---- - - -# Parameters - -The IBC transfer application module contains the following parameters: - -| Key | Type | Default Value | -|------------------|------|---------------| -| `SendEnabled` | bool | `true` | -| `ReceiveEnabled` | bool | `true` | - -## `SendEnabled` - -The transfers enabled parameter controls send cross-chain transfer capabilities for all fungible tokens. - -To prevent a single token from being transferred from the chain, set the `SendEnabled` parameter to `true` and then, depending on the Cosmos SDK version, do one of the following: - -- For Cosmos SDK v0.46.x or earlier, set the bank module's [`SendEnabled` parameter](https://github.com/cosmos/cosmos-sdk/blob/release/v0.46.x/x/bank/spec/05_params.md#sendenabled) for the denomination to `false`. -- For Cosmos SDK versions above v0.46.x, set the bank module's `SendEnabled` entry for the denomination to `false` using `MsgSetSendEnabled` as a governance proposal. - -## `ReceiveEnabled` - -The transfers enabled parameter controls receive cross-chain transfer capabilities for all fungible tokens. - -To prevent a single token from being transferred to the chain, set the `ReceiveEnabled` parameter to `true` and then, depending on the Cosmos SDK version, do one of the following: - -- For Cosmos SDK v0.46.x or earlier, set the bank module's [`SendEnabled` parameter](https://github.com/cosmos/cosmos-sdk/blob/release/v0.46.x/x/bank/spec/05_params.md#sendenabled) for the denomination to `false`. -- For Cosmos SDK versions above v0.46.x, set the bank module's `SendEnabled` entry for the denomination to `false` using `MsgSetSendEnabled` as a governance proposal. diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/08-authorizations.md b/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/08-authorizations.md deleted file mode 100644 index 0519e63d556..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/08-authorizations.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: Authorizations -sidebar_label: Authorizations -sidebar_position: 8 -slug: /apps/transfer/authorizations ---- - - -# `TransferAuthorization` - -`TransferAuthorization` implements the `Authorization` interface for `ibc.applications.transfer.v1.MsgTransfer`. It allows a granter to grant a grantee the privilege to submit `MsgTransfer` on its behalf. Please see the [Cosmos SDK docs](https://docs.cosmos.network/v0.47/modules/authz) for more details on granting privileges via the `x/authz` module. - -More specifically, the granter allows the grantee to transfer funds that belong to the granter over a specified channel. - -For the specified channel, the granter must be able to specify a spend limit of a specific denomination they wish to allow the grantee to be able to transfer. - -The granter may be able to specify the list of addresses that they allow to receive funds. If empty, then all addresses are allowed. - -It takes: - -- a `SourcePort` and a `SourceChannel` which together comprise the unique transfer channel identifier over which authorized funds can be transferred. - -- a `SpendLimit` that specifies the maximum amount of tokens the grantee can transfer. The `SpendLimit` is updated as the tokens are transfered, unless the sentinel value of the maximum value for a 256-bit unsigned integer (i.e. 2^256 - 1) is used for the amount, in which case the `SpendLimit` will not be updated (please be aware that using this sentinel value will grant the grantee the privilege to transfer **all** the tokens of a given denomination available at the granter's account). The helper function `UnboundedSpendLimit` in the `types` package of the `transfer` module provides the sentinel value that can be used. This `SpendLimit` may also be updated to increase or decrease the limit as the granter wishes. - -- an `AllowList` list that specifies the list of addresses that are allowed to receive funds. If this list is empty, then all addresses are allowed to receive funds from the `TransferAuthorization`. - -Setting a `TransferAuthorization` is expected to fail if: - -- the spend limit is nil -- the denomination of the spend limit is an invalid coin type -- the source port ID is invalid -- the source channel ID is invalid -- there are duplicate entries in the `AllowList` - -Below is the `TransferAuthorization` message: - -```go -func NewTransferAuthorization(allocations ...Allocation) *TransferAuthorization { - return &TransferAuthorization{ - Allocations: allocations, - } -} - -type Allocation struct { - // the port on which the packet will be sent - SourcePort string - // the channel by which the packet will be sent - SourceChannel string - // spend limitation on the channel - SpendLimit sdk.Coins - // allow list of receivers, an empty allow list permits any receiver address - AllowList []string -} - -``` diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/09-client.md b/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/09-client.md deleted file mode 100644 index 2ba2a877518..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/09-client.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: Client -sidebar_label: Client -sidebar_position: 9 -slug: /apps/transfer/client ---- - - -# Client - -## CLI - -A user can query and interact with the `transfer` module using the CLI. Use the `--help` flag to discover the available commands: - -### Query - -The `query` commands allow users to query `transfer` state. - -```shell -simd query ibc-transfer --help -``` - -#### `total-escrow` - -The `total-escrow` command allows users to query the total amount in escrow for a particular coin denomination regardless of the transfer channel from where the coins were sent out. - -```shell -simd query ibc-transfer total-escrow [denom] [flags] -``` - -Example: - -```shell -simd query ibc-transfer total-escrow samoleans -``` - -Example Output: - -```shell -amount: "100" -``` - -## gRPC - -A user can query the `transfer` module using gRPC endpoints. - -### `TotalEscrowForDenom` - -The `TotalEscrowForDenom` endpoint allows users to query the total amount in escrow for a particular coin denomination regardless of the transfer channel from where the coins were sent out. - -```shell -ibc.applications.transfer.v1.Query/TotalEscrowForDenom -``` - -Example: - -```shell -grpcurl -plaintext \ - -d '{"denom":"samoleans"}' \ - localhost:9090 \ - ibc.applications.transfer.v1.Query/TotalEscrowForDenom -``` - -Example output: - -```shell -{ - "amount": "100" -} -``` diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/_category_.json b/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/_category_.json deleted file mode 100644 index d643a498cdf..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/01-transfer/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Transfer", - "position": 1, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/01-overview.md b/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/01-overview.md deleted file mode 100644 index 2582aa0cb90..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/01-overview.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /apps/interchain-accounts/overview ---- - - -# Overview - -:::note Synopsis -Learn about what the Interchain Accounts module is -::: - -## What is the Interchain Accounts module? - -Interchain Accounts is the Cosmos SDK implementation of the ICS-27 protocol, which enables cross-chain account management built upon IBC. - -- How does an interchain account differ from a regular account? - -Regular accounts use a private key to sign transactions. Interchain Accounts are instead controlled programmatically by counterparty chains via IBC packets. - -## Concepts - -`Host Chain`: The chain where the interchain account is registered. The host chain listens for IBC packets from a controller chain which should contain instructions (e.g. Cosmos SDK messages) for which the interchain account will execute. - -`Controller Chain`: The chain registering and controlling an account on a host chain. The controller chain sends IBC packets to the host chain to control the account. - -`Interchain Account`: An account on a host chain created using the ICS-27 protocol. An interchain account has all the capabilities of a normal account. However, rather than signing transactions with a private key, a controller chain will send IBC packets to the host chain which signals what transactions the interchain account should execute. - -`Authentication Module`: A custom application module on the controller chain that uses the Interchain Accounts module to build custom logic for the creation & management of interchain accounts. It can be either an IBC application module using the [legacy API](10-legacy/03-keeper-api.md), or a regular Cosmos SDK application module sending messages to the controller submodule's `MsgServer` (this is the recommended approach from ibc-go v6 if access to packet callbacks is not needed). Please note that the legacy API will eventually be removed and IBC applications will not be able to use them in later releases. - -## SDK security model - -SDK modules on a chain are assumed to be trustworthy. For example, there are no checks to prevent an untrustworthy module from accessing the bank keeper. - -The implementation of ICS-27 in ibc-go uses this assumption in its security considerations. - -The implementation assumes other IBC application modules will not bind to ports within the ICS-27 namespace. diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/02-development.md b/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/02-development.md deleted file mode 100644 index 4b640e2b10c..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/02-development.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: Development Use Cases -sidebar_label: Development Use Cases -sidebar_position: 2 -slug: /apps/interchain-accounts/development ---- - - -# Development use cases - -The initial version of Interchain Accounts allowed for the controller submodule to be extended by providing it with an underlying application which would handle all packet callbacks. -That functionality is now being deprecated in favor of alternative approaches. -This document will outline potential use cases and redirect each use case to the appropriate documentation. - -## Custom authentication - -Interchain accounts may be associated with alternative types of authentication relative to the traditional public/private key signing. -If you wish to develop or use Interchain Accounts with a custom authentication module and do not need to execute custom logic on the packet callbacks, we recommend you use ibc-go v6 or greater and that your custom authentication module interacts with the controller submodule via the [`MsgServer`](05-messages.md). - -If you wish to consume and execute custom logic in the packet callbacks, then please read the section [Packet callbacks](#packet-callbacks) below. - -## Redirection to a smart contract - -It may be desirable to allow smart contracts to control an interchain account. -To faciliate such an action, the controller submodule may be provided an underlying application which redirects to smart contract callers. -An improved design has been suggested in [ADR 008](https://github.com/cosmos/ibc-go/pull/1976) which performs this action via middleware. - -Implementors of this use case are recommended to follow the ADR 008 approach. -The underlying application may continue to be used as a short term solution for ADR 008 and the [legacy API](03-auth-modules.md#registerinterchainaccount) should continue to be utilized in such situations. - -## Packet callbacks - -If a developer requires access to packet callbacks for their use case, then they have the following options: - -1. Write a smart contract which is connected via an ADR 008 or equivalent IBC application (recommended). -2. Use the controller's underlying application to implement packet callback logic. - -In the first case, the smart contract should use the [`MsgServer`](05-messages.md). - -In the second case, the underlying application should use the [legacy API](10-legacy/03-keeper-api.md). diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/03-auth-modules.md b/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/03-auth-modules.md deleted file mode 100644 index 46bc9f7e2dd..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/03-auth-modules.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: Authentication Modules -sidebar_label: Authentication Modules -sidebar_position: 3 -slug: /apps/interchain-accounts/auth-modules ---- - - -# Building an authentication module - -:::note Synopsis -Authentication modules enable application developers to perform custom logic when interacting with the Interchain Accounts controller sumbmodule's `MsgServer`. -::: - -The controller submodule is used for account registration and packet sending. It executes only logic required of all controllers of interchain accounts. The type of authentication used to manage the interchain accounts remains unspecified. There may exist many different types of authentication which are desirable for different use cases. Thus the purpose of the authentication module is to wrap the controller submodule with custom authentication logic. - -In ibc-go, authentication modules can communicate with the controller submodule by passing messages through `baseapp`'s `MsgServiceRouter`. To implement an authentication module, the `IBCModule` interface need not be fulfilled; it is only required to fulfill Cosmos SDK's `AppModuleBasic` interface, just like any regular Cosmos SDK application module. - -The authentication module must: - -- Authenticate interchain account owners. -- Track the associated interchain account address for an owner. -- Send packets on behalf of an owner (after authentication). - -## Integration into `app.go` file - -To integrate the authentication module into your chain, please follow the steps outlined in [`app.go` integration](04-integration.md#example-integration). diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/04-integration.md b/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/04-integration.md deleted file mode 100644 index 373ff3ce5bf..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/04-integration.md +++ /dev/null @@ -1,199 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 4 -slug: /apps/interchain-accounts/integration ---- - - -# Integration - -:::note Synopsis -Learn how to integrate Interchain Accounts host and controller functionality to your chain. The following document only applies for Cosmos SDK chains. -::: - -The Interchain Accounts module contains two submodules. Each submodule has its own IBC application. The Interchain Accounts module should be registered as an `AppModule` in the same way all SDK modules are registered on a chain, but each submodule should create its own `IBCModule` as necessary. A route should be added to the IBC router for each submodule which will be used. - -Chains who wish to support ICS-27 may elect to act as a host chain, a controller chain or both. Disabling host or controller functionality may be done statically by excluding the host or controller submodule entirely from the `app.go` file or it may be done dynamically by taking advantage of the on-chain parameters which enable or disable the host or controller submodules. - -Interchain Account authentication modules (both custom or generic, such as the `x/gov`, `x/group` or `x/auth` Cosmos SDK modules) can send messages to the controller submodule's [`MsgServer`](05-messages.md) to register interchain accounts and send packets to the interchain account. To accomplish this, the authentication module needs to be composed with `baseapp`'s `MsgServiceRouter`. - -![ica-v6.png](./images/ica-v6.png) - -## Example integration - -```go -// app.go - -// Register the AppModule for the Interchain Accounts module and the authentication module -// Note: No `icaauth` exists, this must be substituted with an actual Interchain Accounts authentication module -ModuleBasics = module.NewBasicManager( - ... - ica.AppModuleBasic{}, - icaauth.AppModuleBasic{}, - ... -) - -... - -// Add module account permissions for the Interchain Accounts module -// Only necessary for host chain functionality -// Each Interchain Account created on the host chain is derived from the module account created -maccPerms = map[string][]string{ - ... - icatypes.ModuleName: nil, -} - -... - -// Add Interchain Accounts Keepers for each submodule used and the authentication module -// If a submodule is being statically disabled, the associated Keeper does not need to be added. -type App struct { - ... - - ICAControllerKeeper icacontrollerkeeper.Keeper - ICAHostKeeper icahostkeeper.Keeper - ICAAuthKeeper icaauthkeeper.Keeper - - ... -} - -... - -// Create store keys for each submodule Keeper and the authentication module -keys := sdk.NewKVStoreKeys( - ... - icacontrollertypes.StoreKey, - icahosttypes.StoreKey, - icaauthtypes.StoreKey, - ... -) - -... - -// Create the scoped keepers for each submodule keeper and authentication keeper -scopedICAControllerKeeper := app.CapabilityKeeper.ScopeToModule(icacontrollertypes.SubModuleName) -scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icahosttypes.SubModuleName) -scopedICAAuthKeeper := app.CapabilityKeeper.ScopeToModule(icaauthtypes.ModuleName) - -... - -// Create the Keeper for each submodule -app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( - appCodec, keys[icacontrollertypes.StoreKey], app.GetSubspace(icacontrollertypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - scopedICAControllerKeeper, app.MsgServiceRouter(), -) -app.ICAHostKeeper = icahostkeeper.NewKeeper( - appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), -) - -// Create Interchain Accounts AppModule -icaModule := ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper) - -// Create your Interchain Accounts authentication module -app.ICAAuthKeeper = icaauthkeeper.NewKeeper(appCodec, keys[icaauthtypes.StoreKey], app.MsgServiceRouter()) - -// ICA auth AppModule -icaAuthModule := icaauth.NewAppModule(appCodec, app.ICAAuthKeeper) - -// Create controller IBC application stack and host IBC module as desired -icaControllerStack := icacontroller.NewIBCMiddleware(nil, app.ICAControllerKeeper) -icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - -// Register host and authentication routes -ibcRouter. - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icahosttypes.SubModuleName, icaHostIBCModule) -... - -// Register Interchain Accounts and authentication module AppModule's -app.moduleManager = module.NewManager( - ... - icaModule, - icaAuthModule, -) - -... - -// Add Interchain Accounts to begin blocker logic -app.moduleManager.SetOrderBeginBlockers( - ... - icatypes.ModuleName, - ... -) - -// Add Interchain Accounts to end blocker logic -app.moduleManager.SetOrderEndBlockers( - ... - icatypes.ModuleName, - ... -) - -// Add Interchain Accounts module InitGenesis logic -app.moduleManager.SetOrderInitGenesis( - ... - icatypes.ModuleName, - ... -) - -// initParamsKeeper init params keeper and its subspaces -func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) paramskeeper.Keeper { - ... - paramsKeeper.Subspace(icahosttypes.SubModuleName) - paramsKeeper.Subspace(icacontrollertypes.SubModuleName) - ... -} -``` - -If no custom athentication module is needed and a generic Cosmos SDK authentication module can be used, then from the sample integration code above all references to `ICAAuthKeeper` and `icaAuthModule` can be removed. That's it, the following code would not be needed: - -```go -// Create your Interchain Accounts authentication module -app.ICAAuthKeeper = icaauthkeeper.NewKeeper(appCodec, keys[icaauthtypes.StoreKey], app.MsgServiceRouter()) - -// ICA auth AppModule -icaAuthModule := icaauth.NewAppModule(appCodec, app.ICAAuthKeeper) -``` - -### Using submodules exclusively - -As described above, the Interchain Accounts application module is structured to support the ability of exclusively enabling controller or host functionality. -This can be achieved by simply omitting either controller or host `Keeper` from the Interchain Accounts `NewAppModule` constructor function, and mounting only the desired submodule via the `IBCRouter`. -Alternatively, submodules can be enabled and disabled dynamically using [on-chain parameters](06-parameters.md). - -The following snippets show basic examples of statically disabling submodules using `app.go`. - -#### Disabling controller chain functionality - -```go -// Create Interchain Accounts AppModule omitting the controller keeper -icaModule := ica.NewAppModule(nil, &app.ICAHostKeeper) - -// Create host IBC Module -icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - -// Register host route -ibcRouter.AddRoute(icahosttypes.SubModuleName, icaHostIBCModule) -``` - -#### Disabling host chain functionality - -```go -// Create Interchain Accounts AppModule omitting the host keeper -icaModule := ica.NewAppModule(&app.ICAControllerKeeper, nil) - - -// Optionally instantiate your custom authentication module if needed, or not otherwise -... - -// Create controller IBC application stack -icaControllerStack := icacontroller.NewIBCMiddleware(nil, app.ICAControllerKeeper) - -// Register controller route -ibcRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) -``` diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/05-messages.md b/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/05-messages.md deleted file mode 100644 index 0c29e7364c5..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/05-messages.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: Messages -sidebar_label: Messages -sidebar_position: 5 -slug: /apps/interchain-accounts/messages ---- - - -# Messages - -## `MsgRegisterInterchainAccount` - -An Interchain Accounts channel handshake can be initated using `MsgRegisterInterchainAccount`: - -```go -type MsgRegisterInterchainAccount struct { - Owner string - ConnectionID string - Version string -} -``` - -This message is expected to fail if: - -- `Owner` is an empty string. -- `ConnectionID` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). - -This message will construct a new `MsgChannelOpenInit` on chain and route it to the core IBC message server to initiate the opening step of the channel handshake. - -The controller submodule will generate a new port identifier and claim the associated port capability. The caller is expected to provide an appropriate application version string. For example, this may be an ICS-27 JSON encoded [`Metadata`](https://github.com/cosmos/ibc-go/blob/v6.0.0/proto/ibc/applications/interchain_accounts/v1/metadata.proto#L11) type or an ICS-29 JSON encoded [`Metadata`](https://github.com/cosmos/ibc-go/blob/v6.0.0/proto/ibc/applications/fee/v1/metadata.proto#L11) type with a nested application version. -If the `Version` string is omitted, the controller submodule will construct a default version string in the `OnChanOpenInit` handshake callback. - -```go -type MsgRegisterInterchainAccountResponse struct { - ChannelID string - PortID string -} -``` - -The `ChannelID` and `PortID` are returned in the message response. - -## `MsgSendTx` - -An Interchain Accounts transaction can be executed on a remote host chain by sending a `MsgSendTx` from the corresponding controller chain: - -```go -type MsgSendTx struct { - Owner string - ConnectionID string - PacketData InterchainAccountPacketData - RelativeTimeout uint64 -} -``` - -This message is expected to fail if: - -- `Owner` is an empty string. -- `ConnectionID` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -- `PacketData` contains an `UNSPECIFIED` type enum, the length of `Data` bytes is zero or the `Memo` field exceeds 256 characters in length. -- `RelativeTimeout` is zero. - -This message will create a new IBC packet with the provided `PacketData` and send it via the channel associated with the `Owner` and `ConnectionID`. -The `PacketData` is expected to contain a list of serialized `[]sdk.Msg` in the form of `CosmosTx`. Please note the signer field of each `sdk.Msg` must be the interchain account address. -When the packet is relayed to the host chain, the `PacketData` is unmarshalled and the messages are authenticated and executed. - -```go -type MsgSendTxResponse struct { - Sequence uint64 -} -``` - -The packet `Sequence` is returned in the message response. - -## Atomicity - -As the Interchain Accounts module supports the execution of multiple transactions using the Cosmos SDK `Msg` interface, it provides the same atomicity guarantees as Cosmos SDK-based applications, leveraging the [`CacheMultiStore`](https://docs.cosmos.network/main/learn/advanced/store#cachemultistore) architecture provided by the [`Context`](https://docs.cosmos.network/main/learn/advanced/context.html) type. - -This provides atomic execution of transactions when using Interchain Accounts, where state changes are only committed if all `Msg`s succeed. diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/06-parameters.md b/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/06-parameters.md deleted file mode 100644 index 9e01bb75ec2..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/06-parameters.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -title: Parameters -sidebar_label: Parameters -sidebar_position: 6 -slug: /apps/interchain-accounts/parameters ---- - - -# Parameters - -The Interchain Accounts module contains the following on-chain parameters, logically separated for each distinct submodule: - -## Controller Submodule Parameters - -| Key | Type | Default Value | -|------------------------|------|---------------| -| `ControllerEnabled` | bool | `true` | - -### ControllerEnabled - -The `ControllerEnabled` parameter controls a chains ability to service ICS-27 controller specific logic. This includes the sending of Interchain Accounts packet data as well as the following ICS-26 callback handlers: - -- `OnChanOpenInit` -- `OnChanOpenAck` -- `OnChanCloseConfirm` -- `OnAcknowledgementPacket` -- `OnTimeoutPacket` - -## Host Submodule Parameters - -| Key | Type | Default Value | -|------------------------|----------|---------------| -| `HostEnabled` | bool | `true` | -| `AllowMessages` | []string | `["*"]` | - -### HostEnabled - -The `HostEnabled` parameter controls a chains ability to service ICS-27 host specific logic. This includes the following ICS-26 callback handlers: - -- `OnChanOpenTry` -- `OnChanOpenConfirm` -- `OnChanCloseConfirm` -- `OnRecvPacket` - -### AllowMessages - -The `AllowMessages` parameter provides the ability for a chain to limit the types of messages or transactions that hosted interchain accounts are authorized to execute by defining an allowlist using the Protobuf message type URL format. - -For example, a Cosmos SDK-based chain that elects to provide hosted Interchain Accounts with the ability of governance voting and staking delegations will define its parameters as follows: - -```json -"params": { - "host_enabled": true, - "allow_messages": ["/cosmos.staking.v1beta1.MsgDelegate", "/cosmos.gov.v1beta1.MsgVote"] -} -``` - -There is also a special wildcard `"*"` value which allows any type of message to be executed by the interchain account. This must be the only value in the `allow_messages` array. - -```json -"params": { - "host_enabled": true, - "allow_messages": ["*"] -} -``` diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/07-tx-encoding.md b/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/07-tx-encoding.md deleted file mode 100644 index 5be03af2f8e..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/07-tx-encoding.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: Transaction Encoding -sidebar_label: Transaction Encoding -sidebar_position: 7 -slug: /apps/interchain-accounts/tx-encoding ---- - -# Transaction Encoding - -When orchestrating an interchain account transaction, which comprises multiple `sdk.Msg` objects represented as `Any` types, the transactions must be encoded as bytes within [`InterchainAccountPacketData`](https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/interchain_accounts/v1/packet.proto#L21-L26). - -```protobuf -// InterchainAccountPacketData is comprised of a raw transaction, type of transaction and optional memo field. -message InterchainAccountPacketData { - Type type = 1; - bytes data = 2; - string memo = 3; -} -``` - -The `data` field must be encoded as a [`CosmosTx`](https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/interchain_accounts/v1/packet.proto#L28-L31). - -```protobuf -// CosmosTx contains a list of sdk.Msg's. It should be used when sending transactions to an SDK host chain. -message CosmosTx { - repeated google.protobuf.Any messages = 1; -} -``` - -The encoding method for `CosmosTx` is determined during the channel handshake process. If the channel version [metadata's `encoding` field](https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/interchain_accounts/v1/metadata.proto#L22) is marked as `proto3`, then `CosmosTx` undergoes protobuf encoding. Conversely, if the field is set to `proto3json`, then [proto3 json](https://protobuf.dev/programming-guides/proto3/#json) encoding takes place, which generates a JSON representation of the protobuf message. - -## Protobuf Encoding - -Protobuf encoding serves as the standard encoding process for `CosmosTx`. This occurs if the channel handshake initiates with an empty channel version metadata or if the `encoding` field explicitly denotes `proto3`. In Golang, the protobuf encoding procedure utilizes the `proto.Marshal` function. Every protobuf autogenerated Golang type comes equipped with a `Marshal` method that can be employed to encode the message. - -## (Protobuf) JSON Encoding - -The proto3 JSON encoding presents an alternative encoding technique for `CosmosTx`. It is selected if the channel handshake begins with the channel version metadata `encoding` field labeled as `proto3json`. In Golang, the Proto3 canonical encoding in JSON is implemented by the `"github.com/cosmos/gogoproto/jsonpb"` package. Within Cosmos SDK, the `ProtoCodec` structure implements the `JSONCodec` interface, leveraging the `jsonpb` package. This method generates a JSON format as follows: - -```json -{ - "messages": [ - { - "@type": "/cosmos.bank.v1beta1.MsgSend", - "from_address": "cosmos1...", - "to_address": "cosmos1...", - "amount": [ - { - "denom": "uatom", - "amount": "1000000" - } - ] - } - ] -} -``` - -Here, the `"messages"` array is populated with transactions. Each transaction is represented as a JSON object with the `@type` field denoting the transaction type and the remaining fields representing the transaction's attributes. diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/08-client.md b/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/08-client.md deleted file mode 100644 index c7c50d09d82..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/08-client.md +++ /dev/null @@ -1,183 +0,0 @@ ---- -title: Client -sidebar_label: Client -sidebar_position: 8 -slug: /apps/interchain-accounts/client ---- - -# Client - -## CLI - -A user can query and interact with the Interchain Accounts module using the CLI. Use the `--help` flag to discover the available commands: - -```shell -simd query interchain-accounts --help -``` - -> Please not that this section does not document all the available commands, but only the ones that deserved extra documentation that was not possible to fit in the command line documentation. - -### Controller - -A user can query and interact with the controller submodule. - -#### Query - -The `query` commands allow users to query the controller submodule. - -```shell -simd query interchain-accounts controller --help -``` - -#### Transactions - -The `tx` commands allow users to interact with the controller submodule. - -```shell -simd tx interchain-accounts controller --help -``` - -#### `send-tx` - -The `send-tx` command allows users to send a transaction on the provided connection to be executed using an interchain account on the host chain. - -```shell -simd tx interchain-accounts controller send-tx [connection-id] [path/to/packet_msg.json] -``` - -Example: - -```shell -simd tx interchain-accounts controller send-tx connection-0 packet-data.json --from cosmos1.. -``` - -See below for example contents of `packet-data.json`. The CLI handler will unmarshal the following into `InterchainAccountPacketData` appropriately. - -```json -{ - "type":"TYPE_EXECUTE_TX", - "data":"CqIBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEoEBCkFjb3Ntb3MxNWNjc2hobXAwZ3N4MjlxcHFxNmc0em1sdG5udmdteXU5dWV1YWRoOXkybmM1emowc3psczVndGRkehItY29zbW9zMTBoOXN0YzV2Nm50Z2V5Z2Y1eGY5NDVuanFxNWgzMnI1M3VxdXZ3Gg0KBXN0YWtlEgQxMDAw", - "memo":"" -} -``` - -Note the `data` field is a base64 encoded byte string as per the tx encoding agreed upon during the channel handshake. - -A helper CLI is provided in the host submodule which can be used to generate the packet data JSON using the counterparty chain's binary. See the [`generate-packet-data` command](#generate-packet-data) for an example. - -### Host - -A user can query and interact with the host submodule. - -#### Query - -The `query` commands allow users to query the host submodule. - -```shell -simd query interchain-accounts host --help -``` - -#### Transactions - -The `tx` commands allow users to interact with the controller submodule. - -```shell -simd tx interchain-accounts host --help -``` - -##### `generate-packet-data` - -The `generate-packet-data` command allows users to generate protobuf or proto3 JSON encoded interchain accounts packet data for input message(s). The packet data can then be used with the controller submodule's [`send-tx` command](#send-tx). The `--encoding` flag can be uesd to specify the encoding format (value must be either `proto3` or `proto3json`); if not specified, the default will be `proto3`. The `--memo` flag can be used to include a memo string in the interchain accounts packet data. - -```shell -simd tx interchain-accounts host generate-packet-data [message] -``` - -Example: - -```shell -simd tx interchain-accounts host generate-packet-data '[{ - "@type":"/cosmos.bank.v1beta1.MsgSend", - "from_address":"cosmos15ccshhmp0gsx29qpqq6g4zmltnnvgmyu9ueuadh9y2nc5zj0szls5gtddz", - "to_address":"cosmos10h9stc5v6ntgeygf5xf945njqq5h32r53uquvw", - "amount": [ - { - "denom": "stake", - "amount": "1000" - } - ] -}]' --memo memo -``` - -The command accepts a single `sdk.Msg` or a list of `sdk.Msg`s that will be encoded into the outputs `data` field. - -Example output: - -```json -{ - "type":"TYPE_EXECUTE_TX", - "data":"CqIBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEoEBCkFjb3Ntb3MxNWNjc2hobXAwZ3N4MjlxcHFxNmc0em1sdG5udmdteXU5dWV1YWRoOXkybmM1emowc3psczVndGRkehItY29zbW9zMTBoOXN0YzV2Nm50Z2V5Z2Y1eGY5NDVuanFxNWgzMnI1M3VxdXZ3Gg0KBXN0YWtlEgQxMDAw", - "memo":"memo" -} -``` - -## gRPC - -A user can query the interchain account module using gRPC endpoints. - -### Controller - -A user can query the controller submodule using gRPC endpoints. - -#### `InterchainAccount` - -The `InterchainAccount` endpoint allows users to query the controller submodule for the interchain account address for a given owner on a particular connection. - -```shell -ibc.applications.interchain_accounts.controller.v1.Query/InterchainAccount -``` - -Example: - -```shell -grpcurl -plaintext \ - -d '{"owner":"cosmos1..","connection_id":"connection-0"}' \ - localhost:9090 \ - ibc.applications.interchain_accounts.controller.v1.Query/InterchainAccount -``` - -#### `Params` - -The `Params` endpoint users to query the current controller submodule parameters. - -```shell -ibc.applications.interchain_accounts.controller.v1.Query/Params -``` - -Example: - -```shell -grpcurl -plaintext \ - localhost:9090 \ - ibc.applications.interchain_accounts.controller.v1.Query/Params -``` - -### Host - -A user can query the host submodule using gRPC endpoints. - -#### `Params` - -The `Params` endpoint users to query the current host submodule parameters. - -```shell -ibc.applications.interchain_accounts.host.v1.Query/Params -``` - -Example: - -```shell -grpcurl -plaintext \ - localhost:9090 \ - ibc.applications.interchain_accounts.host.v1.Query/Params -``` diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/09-active-channels.md b/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/09-active-channels.md deleted file mode 100644 index 2aedeb8a42f..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/09-active-channels.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Active Channels -sidebar_label: Active Channels -sidebar_position: 9 -slug: /apps/interchain-accounts/active-channels ---- - -# Understanding Active Channels - -The Interchain Accounts module uses [ORDERED channels](https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#ordering) to maintain the order of transactions when sending packets from a controller to a host chain. A limitation when using ORDERED channels is that when a packet times out the channel will be closed. - -In the case of a channel closing, a controller chain needs to be able to regain access to the interchain account registered on this channel. `Active Channels` enable this functionality. - -When an Interchain Account is registered using `MsgRegisterInterchainAccount`, a new channel is created on a particular port. During the `OnChanOpenAck` and `OnChanOpenConfirm` steps (on controller & host chain respectively) the `Active Channel` for this interchain account is stored in state. - -It is possible to create a new channel using the same controller chain portID if the previously set `Active Channel` is now in a `CLOSED` state. This channel creation can be initialized programatically by sending a new `MsgChannelOpenInit` message like so: - -```go -msg := channeltypes.NewMsgChannelOpenInit(portID, string(versionBytes), channeltypes.ORDERED, []string{connectionID}, icatypes.HostPortID, authtypes.NewModuleAddress(icatypes.ModuleName).String()) -handler := keeper.msgRouter.Handler(msg) -res, err := handler(ctx, msg) -if err != nil { - return err -} -``` - -Alternatively, any relayer operator may initiate a new channel handshake for this interchain account once the previously set `Active Channel` is in a `CLOSED` state. This is done by initiating the channel handshake on the controller chain using the same portID associated with the interchain account in question. - -It is important to note that once a channel has been opened for a given interchain account, new channels can not be opened for this account until the currently set `Active Channel` is set to `CLOSED`. - -## Future improvements - -Future versions of the ICS-27 protocol and the Interchain Accounts module will likely use a new channel type that provides ordering of packets without the channel closing in the event of a packet timing out, thus removing the need for `Active Channels` entirely. -The following is a list of issues which will provide the infrastructure to make this possible: - -- [IBC Channel Upgrades](https://github.com/cosmos/ibc-go/issues/1599) -- [Implement ORDERED_ALLOW_TIMEOUT logic in 04-channel](https://github.com/cosmos/ibc-go/issues/1661) -- [Add ORDERED_ALLOW_TIMEOUT as supported ordering in 03-connection](https://github.com/cosmos/ibc-go/issues/1662) -- [Allow ICA channels to be opened as ORDERED_ALLOW_TIMEOUT](https://github.com/cosmos/ibc-go/issues/1663) diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/10-legacy/01-auth-modules.md b/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/10-legacy/01-auth-modules.md deleted file mode 100644 index 70cc36b8a69..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/10-legacy/01-auth-modules.md +++ /dev/null @@ -1,274 +0,0 @@ ---- -title: Authentication Modules -sidebar_label: Authentication Modules -sidebar_position: 1 -slug: /apps/interchain-accounts/legacy/auth-modules ---- - - -# Building an authentication module - -## Deprecation Notice - -**This document is deprecated and will be removed in future releases**. - -:::note Synopsis -Authentication modules play the role of the `Base Application` as described in [ICS-30 IBC Middleware](https://github.com/cosmos/ibc/tree/master/spec/app/ics-030-middleware), and enable application developers to perform custom logic when working with the Interchain Accounts controller API. -::: - -The controller submodule is used for account registration and packet sending. It executes only logic required of all controllers of interchain accounts. The type of authentication used to manage the interchain accounts remains unspecified. There may exist many different types of authentication which are desirable for different use cases. Thus the purpose of the authentication module is to wrap the controller submodule with custom authentication logic. - -In ibc-go, authentication modules are connected to the controller chain via a middleware stack. The controller submodule is implemented as [middleware](https://github.com/cosmos/ibc/tree/master/spec/app/ics-030-middleware) and the authentication module is connected to the controller submodule as the base application of the middleware stack. To implement an authentication module, the `IBCModule` interface must be fulfilled. By implementing the controller submodule as middleware, any amount of authentication modules can be created and connected to the controller submodule without writing redundant code. - -The authentication module must: - -- Authenticate interchain account owners. -- Track the associated interchain account address for an owner. -- Send packets on behalf of an owner (after authentication). - -> Please note that since ibc-go v6 the channel capability is claimed by the controller submodule and therefore it is not required for authentication modules to claim the capability in the `OnChanOpenInit` callback. When the authentication module sends packets on the channel created for the associated interchain account it can pass a `nil` capability to the legacy function `SendTx` of the controller keeper (see section [`SendTx`](03-keeper-api.md#sendtx) for more information). - -## `IBCModule` implementation - -The following `IBCModule` callbacks must be implemented with appropriate custom logic: - -```go -// OnChanOpenInit implements the IBCModule interface -func (im IBCModule) OnChanOpenInit( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) (string, error) { - // since ibc-go v6 the authentication module *must not* claim the channel capability on OnChanOpenInit - - // perform custom logic - - return version, nil -} - -// OnChanOpenAck implements the IBCModule interface -func (im IBCModule) OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyVersion string, -) error { - // perform custom logic - - return nil -} - -// OnChanCloseConfirm implements the IBCModule interface -func (im IBCModule) OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // perform custom logic - - return nil -} - -// OnAcknowledgementPacket implements the IBCModule interface -func (im IBCModule) OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - relayer sdk.AccAddress, -) error { - // perform custom logic - - return nil -} - -// OnTimeoutPacket implements the IBCModule interface. -func (im IBCModule) OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) error { - // perform custom logic - - return nil -} -``` - -The following functions must be defined to fulfill the `IBCModule` interface, but they will never be called by the controller submodule so they may error or panic. That is because in Interchain Accounts, the channel handshake is always initiated on the controller chain and packets are always sent to the host chain and never to the controller chain. - -```go -// OnChanOpenTry implements the IBCModule interface -func (im IBCModule) OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (string, error) { - panic("UNIMPLEMENTED") -} - -// OnChanOpenConfirm implements the IBCModule interface -func (im IBCModule) OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - panic("UNIMPLEMENTED") -} - -// OnChanCloseInit implements the IBCModule interface -func (im IBCModule) OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - panic("UNIMPLEMENTED") -} - -// OnRecvPacket implements the IBCModule interface. A successful acknowledgement -// is returned if the packet data is succesfully decoded and the receive application -// logic returns without error. -func (im IBCModule) OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) ibcexported.Acknowledgement { - panic("UNIMPLEMENTED") -} -``` - -## `OnAcknowledgementPacket` - -Controller chains will be able to access the acknowledgement written into the host chain state once a relayer relays the acknowledgement. -The acknowledgement bytes contain either the response of the execution of the message(s) on the host chain or an error. They will be passed to the auth module via the `OnAcknowledgementPacket` callback. Auth modules are expected to know how to decode the acknowledgement. - -If the controller chain is connected to a host chain using the host module on ibc-go, it may interpret the acknowledgement bytes as follows: - -Begin by unmarshaling the acknowledgement into `sdk.TxMsgData`: - -```go -var ack channeltypes.Acknowledgement -if err := channeltypes.SubModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { - return err -} - -txMsgData := &sdk.TxMsgData{} -if err := proto.Unmarshal(ack.GetResult(), txMsgData); err != nil { - return err -} -``` - -If the `txMsgData.Data` field is non nil, the host chain is using SDK version <= v0.45. -The auth module should interpret the `txMsgData.Data` as follows: - -```go -switch len(txMsgData.Data) { -case 0: - // see documentation below for SDK 0.46.x or greater -default: - for _, msgData := range txMsgData.Data { - if err := handler(msgData); err != nil { - return err - } - } -... -} -``` - -A handler will be needed to interpret what actions to perform based on the message type sent. -A router could be used, or more simply a switch statement. - -```go -func handler(msgData sdk.MsgData) error { -switch msgData.MsgType { -case sdk.MsgTypeURL(&banktypes.MsgSend{}): - msgResponse := &banktypes.MsgSendResponse{} - if err := proto.Unmarshal(msgData.Data, msgResponse}; err != nil { - return err - } - - handleBankSendMsg(msgResponse) - -case sdk.MsgTypeURL(&stakingtypes.MsgDelegate{}): - msgResponse := &stakingtypes.MsgDelegateResponse{} - if err := proto.Unmarshal(msgData.Data, msgResponse}; err != nil { - return err - } - - handleStakingDelegateMsg(msgResponse) - -case sdk.MsgTypeURL(&transfertypes.MsgTransfer{}): - msgResponse := &transfertypes.MsgTransferResponse{} - if err := proto.Unmarshal(msgData.Data, msgResponse}; err != nil { - return err - } - - handleIBCTransferMsg(msgResponse) - -default: - return -} -``` - -If the `txMsgData.Data` is empty, the host chain is using SDK version > v0.45. -The auth module should interpret the `txMsgData.Responses` as follows: - -```go -... -// switch statement from above -case 0: - for _, any := range txMsgData.MsgResponses { - if err := handleAny(any); err != nil { - return err - } - } -} -``` - -A handler will be needed to interpret what actions to perform based on the type URL of the Any. -A router could be used, or more simply a switch statement. -It may be possible to deduplicate logic between `handler` and `handleAny`. - -```go -func handleAny(any *codectypes.Any) error { -switch any.TypeURL { -case banktypes.MsgSend: - msgResponse, err := unpackBankMsgSendResponse(any) - if err != nil { - return err - } - - handleBankSendMsg(msgResponse) - -case stakingtypes.MsgDelegate: - msgResponse, err := unpackStakingDelegateResponse(any) - if err != nil { - return err - } - - handleStakingDelegateMsg(msgResponse) - - case transfertypes.MsgTransfer: - msgResponse, err := unpackIBCTransferMsgResponse(any) - if err != nil { - return err - } - - handleIBCTransferMsg(msgResponse) - -default: - return -} -``` - -## Integration into `app.go` file - -To integrate the authentication module into your chain, please follow the steps outlined in [`app.go` integration](02-integration.md#example-integration). diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/10-legacy/02-integration.md b/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/10-legacy/02-integration.md deleted file mode 100644 index 90a645aaabd..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/10-legacy/02-integration.md +++ /dev/null @@ -1,201 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 2 -slug: /apps/interchain-accounts/legacy/integration ---- - - -# Integration - -## Deprecation Notice - -**This document is deprecated and will be removed in future releases**. - -:::note Synopsis -Learn how to integrate Interchain Accounts host and controller functionality to your chain. The following document only applies for Cosmos SDK chains. -::: - -The Interchain Accounts module contains two submodules. Each submodule has its own IBC application. The Interchain Accounts module should be registered as an `AppModule` in the same way all SDK modules are registered on a chain, but each submodule should create its own `IBCModule` as necessary. A route should be added to the IBC router for each submodule which will be used. - -Chains who wish to support ICS-27 may elect to act as a host chain, a controller chain or both. Disabling host or controller functionality may be done statically by excluding the host or controller module entirely from the `app.go` file or it may be done dynamically by taking advantage of the on-chain parameters which enable or disable the host or controller submodules. - -Interchain Account authentication modules are the base application of a middleware stack. The controller submodule is the middleware in this stack. - -![ica-pre-v6.png](./images/ica-pre-v6.png) - -> Please note that since ibc-go v6 the channel capability is claimed by the controller submodule and therefore it is not required for authentication modules to claim the capability in the `OnChanOpenInit` callback. Therefore the custom authentication module does not need a scoped keeper anymore. - -## Example integration - -```go -// app.go - -// Register the AppModule for the Interchain Accounts module and the authentication module -// Note: No `icaauth` exists, this must be substituted with an actual Interchain Accounts authentication module -ModuleBasics = module.NewBasicManager( - ... - ica.AppModuleBasic{}, - icaauth.AppModuleBasic{}, - ... -) - -... - -// Add module account permissions for the Interchain Accounts module -// Only necessary for host chain functionality -// Each Interchain Account created on the host chain is derived from the module account created -maccPerms = map[string][]string{ - ... - icatypes.ModuleName: nil, -} - -... - -// Add Interchain Accounts Keepers for each submodule used and the authentication module -// If a submodule is being statically disabled, the associated Keeper does not need to be added. -type App struct { - ... - - ICAControllerKeeper icacontrollerkeeper.Keeper - ICAHostKeeper icahostkeeper.Keeper - ICAAuthKeeper icaauthkeeper.Keeper - - ... -} - -... - -// Create store keys for each submodule Keeper and the authentication module -keys := sdk.NewKVStoreKeys( - ... - icacontrollertypes.StoreKey, - icahosttypes.StoreKey, - icaauthtypes.StoreKey, - ... -) - -... - -// Create the scoped keepers for each submodule keeper and authentication keeper -scopedICAControllerKeeper := app.CapabilityKeeper.ScopeToModule(icacontrollertypes.SubModuleName) -scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icahosttypes.SubModuleName) - -... - -// Create the Keeper for each submodule -app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( - appCodec, keys[icacontrollertypes.StoreKey], app.GetSubspace(icacontrollertypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - scopedICAControllerKeeper, app.MsgServiceRouter(), -) -app.ICAHostKeeper = icahostkeeper.NewKeeper( - appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), -) - -// Create Interchain Accounts AppModule -icaModule := ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper) - -// Create your Interchain Accounts authentication module -app.ICAAuthKeeper = icaauthkeeper.NewKeeper(appCodec, keys[icaauthtypes.StoreKey], app.ICAControllerKeeper) - -// ICA auth AppModule -icaAuthModule := icaauth.NewAppModule(appCodec, app.ICAAuthKeeper) - -// ICA auth IBC Module -icaAuthIBCModule := icaauth.NewIBCModule(app.ICAAuthKeeper) - -// Create controller IBC application stack and host IBC module as desired -icaControllerStack := icacontroller.NewIBCMiddleware(icaAuthIBCModule, app.ICAControllerKeeper) -icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - -// Register host and authentication routes -ibcRouter. - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icahosttypes.SubModuleName, icaHostIBCModule). - AddRoute(icaauthtypes.ModuleName, icaControllerStack) // Note, the authentication module is routed to the top level of the middleware stack - -... - -// Register Interchain Accounts and authentication module AppModule's -app.moduleManager = module.NewManager( - ... - icaModule, - icaAuthModule, -) - -... - -// Add fee middleware to begin blocker logic -app.moduleManager.SetOrderBeginBlockers( - ... - icatypes.ModuleName, - ... -) - -// Add fee middleware to end blocker logic -app.moduleManager.SetOrderEndBlockers( - ... - icatypes.ModuleName, - ... -) - -// Add Interchain Accounts module InitGenesis logic -app.moduleManager.SetOrderInitGenesis( - ... - icatypes.ModuleName, - ... -) - -// initParamsKeeper init params keeper and its subspaces -func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) paramskeeper.Keeper { - ... - paramsKeeper.Subspace(icahosttypes.SubModuleName) - paramsKeeper.Subspace(icacontrollertypes.SubModuleName) - ... -``` - -## Using submodules exclusively - -As described above, the Interchain Accounts application module is structured to support the ability of exclusively enabling controller or host functionality. -This can be achieved by simply omitting either controller or host `Keeper` from the Interchain Accounts `NewAppModule` constructor function, and mounting only the desired submodule via the `IBCRouter`. -Alternatively, submodules can be enabled and disabled dynamically using [on-chain parameters](../06-parameters.md). - -The following snippets show basic examples of statically disabling submodules using `app.go`. - -### Disabling controller chain functionality - -```go -// Create Interchain Accounts AppModule omitting the controller keeper -icaModule := ica.NewAppModule(nil, &app.ICAHostKeeper) - -// Create host IBC Module -icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - -// Register host route -ibcRouter.AddRoute(icahosttypes.SubModuleName, icaHostIBCModule) -``` - -### Disabling host chain functionality - -```go -// Create Interchain Accounts AppModule omitting the host keeper -icaModule := ica.NewAppModule(&app.ICAControllerKeeper, nil) - -// Create your Interchain Accounts authentication module, setting up the Keeper, AppModule and IBCModule appropriately -app.ICAAuthKeeper = icaauthkeeper.NewKeeper(appCodec, keys[icaauthtypes.StoreKey], app.ICAControllerKeeper) -icaAuthModule := icaauth.NewAppModule(appCodec, app.ICAAuthKeeper) -icaAuthIBCModule := icaauth.NewIBCModule(app.ICAAuthKeeper) - -// Create controller IBC application stack -icaControllerStack := icacontroller.NewIBCMiddleware(icaAuthIBCModule, app.ICAControllerKeeper) - -// Register controller and authentication routes -ibcRouter. - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icaauthtypes.ModuleName, icaControllerStack) // Note, the authentication module is routed to the top level of the middleware stack -``` diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/10-legacy/03-keeper-api.md b/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/10-legacy/03-keeper-api.md deleted file mode 100644 index 252c7eaf7ff..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/10-legacy/03-keeper-api.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -title: Keeper API -sidebar_label: Keeper API -sidebar_position: 3 -slug: /apps/interchain-accounts/legacy/keeper-api ---- - - -# Keeper API - -## Deprecation Notice - -**This document is deprecated and will be removed in future releases**. - -The controller submodule keeper exposes two legacy functions that allow respectively for custom authentication modules to register interchain accounts and send packets to the interchain account. - -## `RegisterInterchainAccount` - -The authentication module can begin registering interchain accounts by calling `RegisterInterchainAccount`: - -```go -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, connectionID, owner.String(), version); err != nil { - return err -} - -return nil -``` - -The `version` argument is used to support ICS-29 fee middleware for relayer incentivization of ICS-27 packets. Consumers of the `RegisterInterchainAccount` are expected to build the appropriate JSON encoded version string themselves and pass it accordingly. If an empty string is passed in the `version` argument, then the version will be initialized to a default value in the `OnChanOpenInit` callback of the controller's handler, so that channel handshake can proceed. - -The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, controllerConnectionID, owner.String(), string(appVersion)); err != nil { - return err -} -``` - -Similarly, if the application stack is configured to route through ICS-29 fee middleware and a fee enabled channel is desired, construct the appropriate ICS-29 `Metadata` type: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -feeMetadata := feetypes.Metadata{ - AppVersion: string(appVersion), - FeeVersion: feetypes.Version, -} - -feeEnabledVersion, err := feetypes.ModuleCdc.MarshalJSON(&feeMetadata) -if err != nil { - return err -} - -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, controllerConnectionID, owner.String(), string(feeEnabledVersion)); err != nil { - return err -} -``` - -## `SendTx` - -The authentication module can attempt to send a packet by calling `SendTx`: - -```go -// Authenticate owner -// perform custom logic - -// Construct controller portID based on interchain account owner address -portID, err := icatypes.NewControllerPortID(owner.String()) -if err != nil { - return err -} - -// Obtain data to be sent to the host chain. -// In this example, the owner of the interchain account would like to send a bank MsgSend to the host chain. -// The appropriate serialization function should be called. The host chain must be able to deserialize the transaction. -// If the host chain is using the ibc-go host module, `SerializeCosmosTx` should be used. -msg := &banktypes.MsgSend{FromAddress: fromAddr, ToAddress: toAddr, Amount: amt} -data, err := icatypes.SerializeCosmosTx(keeper.cdc, []proto.Message{msg}) -if err != nil { - return err -} - -// Construct packet data -packetData := icatypes.InterchainAccountPacketData{ - Type: icatypes.EXECUTE_TX, - Data: data, -} - -// Obtain timeout timestamp -// An appropriate timeout timestamp must be determined based on the usage of the interchain account. -// If the packet times out, the channel will be closed requiring a new channel to be created. -timeoutTimestamp := obtainTimeoutTimestamp() - -// Send the interchain accounts packet, returning the packet sequence -// A nil channel capability can be passed, since the controller submodule (and not the authentication module) -// claims the channel capability since ibc-go v6. -seq, err = keeper.icaControllerKeeper.SendTx(ctx, nil, portID, packetData, timeoutTimestamp) -``` - -The data within an `InterchainAccountPacketData` must be serialized using a format supported by the host chain. -If the host chain is using the ibc-go host chain submodule, `SerializeCosmosTx` should be used. If the `InterchainAccountPacketData.Data` is serialized using a format not supported by the host chain, the packet will not be successfully received. diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/10-legacy/_category_.json b/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/10-legacy/_category_.json deleted file mode 100644 index 70500795bf8..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/10-legacy/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Legacy", - "position": 10, - "link": null -} diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/10-legacy/images/ica-pre-v6.png b/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/10-legacy/images/ica-pre-v6.png deleted file mode 100644 index acd00d1294b..00000000000 Binary files a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/10-legacy/images/ica-pre-v6.png and /dev/null differ diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/_category_.json b/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/_category_.json deleted file mode 100644 index 5ac86ce8ff6..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Interchain Accounts", - "position": 2, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/images/ica-v6.png b/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/images/ica-v6.png deleted file mode 100644 index 0ffa707c981..00000000000 Binary files a/docs/versioned_docs/version-v7.3.x/02-apps/02-interchain-accounts/images/ica-v6.png and /dev/null differ diff --git a/docs/versioned_docs/version-v7.3.x/02-apps/_category_.json b/docs/versioned_docs/version-v7.3.x/02-apps/_category_.json deleted file mode 100644 index fa5fbf0ac9a..00000000000 --- a/docs/versioned_docs/version-v7.3.x/02-apps/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "IBC Application Modules", - "position": 2, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/01-overview.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/01-overview.md deleted file mode 100644 index b31210d60c0..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/01-overview.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /ibc/light-clients/overview ---- - -# Overview - -:::note Synopsis -Learn how to build IBC light client modules and fulfill the interfaces required to integrate with core IBC. -::: - -:::note - -## Pre-requisite readings - -- [IBC Overview](../../01-ibc/01-overview.md) -- [IBC Transport, Authentication, and Ordering Layer - Clients](https://tutorials.cosmos.network/academy/3-ibc/4-clients.html) -- [ICS-002 Client Semantics](https://github.com/cosmos/ibc/tree/main/spec/core/ics-002-client-semantics) - -::: - -IBC uses light clients in order to provide trust-minimized interoperability between sovereign blockchains. Light clients operate under a strict set of rules which provide security guarantees for state updates and facilitate the ability to verify the state of a remote blockchain using merkle proofs. - -The following aims to provide a high level IBC light client module developer guide. Access to IBC light clients are gated by the core IBC `MsgServer` which utilizes the abstractions set by the `02-client` submodule to call into a light client module. A light client module developer is only required to implement a set interfaces as defined in the `modules/core/exported` package of ibc-go. - -A light client module developer should be concerned with three main interfaces: - -- [`ClientState`](#clientstate) encapsulates the light client implementation and its semantics. -- [`ConsensusState`](#consensusstate) tracks consensus data used for verification of client updates, misbehaviour detection and proof verification of counterparty state. -- [`ClientMessage`](#clientmessage) used for submitting block headers for client updates and submission of misbehaviour evidence using conflicting headers. - -Throughout this guide the `07-tendermint` light client module may be referred to as a reference example. - -## Concepts and vocabulary - -### `ClientState` - -`ClientState` is a term used to define the data structure which encapsulates opaque light client state. The `ClientState` contains all the information needed to verify a `ClientMessage` and perform membership and non-membership proof verification of counterparty state. This includes properties that refer to the remote state machine, the light client type and the specific light client instance. - -For example: - -- Constraints used for client updates. -- Constraints used for misbehaviour detection. -- Constraints used for state verification. -- Constraints used for client upgrades. - -The `ClientState` type maintained within the light client module *must* implement the [`ClientState`](https://github.com/cosmos/ibc-go/tree/02-client-refactor-beta1/modules/core/exported/client.go#L36) interface defined in `core/modules/exported/client.go`. -The methods which make up this interface are detailed at a more granular level in the [ClientState section of this guide](02-client-state.md). - -Please refer to the `07-tendermint` light client module's [`ClientState` definition](https://github.com/cosmos/ibc-go/tree/02-client-refactor-beta1/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L18) containing information such as chain ID, status, latest height, unbonding period and proof specifications. - -### `ConsensusState` - -`ConsensusState` is a term used to define the data structure which encapsulates consensus data at a particular point in time, i.e. a unique height or sequence number of a state machine. There must exist a single trusted `ConsensusState` for each height. `ConsensusState` generally contains a trusted root, validator set information and timestamp. - -For example, the `ConsensusState` of the `07-tendermint` light client module defines a trusted root which is used by the `ClientState` to perform verification of membership and non-membership commitment proofs, as well as the next validator set hash used for verifying headers can be trusted in client updates. - -The `ConsensusState` type maintained within the light client module *must* implement the [`ConsensusState`](https://github.com/cosmos/ibc-go/tree/02-client-refactor-beta1/modules/core/exported/client.go#L134) interface defined in `modules/core/exported/client.go`. -The methods which make up this interface are detailed at a more granular level in the [`ConsensusState` section of this guide](03-consensus-state.md). - -### `Height` - -`Height` defines a monotonically increasing sequence number which provides ordering of consensus state data persisted through client updates. -IBC light client module developers are expected to use the [concrete type](https://github.com/cosmos/ibc-go/tree/02-client-refactor-beta1/proto/ibc/core/client/v1/client.proto#L89) provided by the `02-client` submodule. This implements the expectations required by the [`Height`](https://github.com/cosmos/ibc-go/blob/02-client-refactor-beta1/modules/core/exported/client.go#L157) interface defined in `modules/core/exported/client.go`. - -### `ClientMessage` - -`ClientMessage` refers to the interface type [`ClientMessage`](https://github.com/cosmos/ibc-go/tree/02-client-refactor-beta1/modules/core/exported/client.go#L148) used for performing updates to a `ClientState` stored on chain. -This may be any concrete type which produces a change in state to the IBC client when verified. - -The following are considered as valid update scenarios: - -- A block header which when verified inserts a new `ConsensusState` at a unique height. -- A batch of block headers which when verified inserts `N` `ConsensusState` instances for `N` unique heights. -- Evidence of misbehaviour provided by two conflicting block headers. - -Learn more in the [Handling update and misbehaviour](04-updates-and-misbehaviour.md) section. diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/02-client-state.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/02-client-state.md deleted file mode 100644 index 09ec21209ef..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/02-client-state.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -title: Client State interface -sidebar_label: Client State interface -sidebar_position: 2 -slug: /ibc/light-clients/client-state ---- - - -# Implementing the `ClientState` interface - -Learn how to implement the [`ClientState`](https://github.com/cosmos/ibc-go/blob/v6.0.0/modules/core/exported/client.go#L40) interface. This list of methods described here does not include all methods of the interface. Some methods are explained in detail in the relevant sections of the guide. - -## `ClientType` method - -`ClientType` should return a unique string identifier of the light client. This will be used when generating a client identifier. -The format is created as follows: `ClientType-{N}` where `{N}` is the unique global nonce associated with a specific client. - -## `GetLatestHeight` method - -`GetLatestHeight` should return the latest block height that the client state represents. - -## `Validate` method - -`Validate` should validate every client state field and should return an error if any value is invalid. The light client -implementer is in charge of determining which checks are required. See the [Tendermint light client implementation](https://github.com/cosmos/ibc-go/blob/v6.0.0/modules/light-clients/07-tendermint/types/client_state.go#L101) as a reference. - -## `Status` method - -`Status` must return the status of the client. - -- An `Active` status indicates that clients are allowed to process packets. -- A `Frozen` status indicates that misbehaviour was detected in the counterparty chain and the client is not allowed to be used. -- An `Expired` status indicates that a client is not allowed to be used because it was not updated for longer than the trusting period. -- An `Unknown` status indicates that there was an error in determining the status of a client. - -All possible `Status` types can be found [here](https://github.com/cosmos/ibc-go/blob/v6.0.0/modules/core/exported/client.go#L26-L36). - -This field is returned in the response of the gRPC [`ibc.core.client.v1.Query/ClientStatus`](https://github.com/cosmos/ibc-go/blob/v6.0.0/modules/core/02-client/types/query.pb.go#L665) endpoint. - -## `ZeroCustomFields` method - -`ZeroCustomFields` should return a copy of the light client with all client customizable fields with their zero value. It should not mutate the fields of the light client. -This method is used when [scheduling upgrades](https://github.com/cosmos/ibc-go/blob/v6.0.0/modules/core/02-client/keeper/proposal.go#L89). Upgrades are used to upgrade chain specific fields. -In the tendermint case, this may be the chain ID or the unbonding period. -For more information about client upgrades see the [Handling upgrades](05-upgrades.md) section. - -## `GetTimestampAtHeight` method - -`GetTimestampAtHeight` must return the timestamp for the consensus state associated with the provided height. -This value is used to facilitate timeouts by checking the packet timeout timestamp against the returned value. - -## `Initialize` method - -Clients must validate the initial consensus state, and set the initial client state and consensus state in the provided client store. -Clients may also store any necessary client-specific metadata. - -`Initialize` is called when a [client is created](https://github.com/cosmos/ibc-go/blob/main/modules/core/02-client/keeper/client.go#L32). - -## `VerifyMembership` method - -`VerifyMembership` must verify the existence of a value at a given commitment path at the specified height. For more information about membership proofs -see the [Existence and non-existence proofs section](06-proofs.md). - -## `VerifyNonMembership` method - -`VerifyNonMembership` must verify the absence of a value at a given commitment path at a specified height. For more information about non-membership proofs -see the [Existence and non-existence proofs section](06-proofs.md). - -## `VerifyClientMessage` method - -`VerifyClientMessage` must verify a `ClientMessage`. A `ClientMessage` could be a `Header`, `Misbehaviour`, or batch update. -It must handle each type of `ClientMessage` appropriately. Calls to `CheckForMisbehaviour`, `UpdateState`, and `UpdateStateOnMisbehaviour` -will assume that the content of the `ClientMessage` has been verified and can be trusted. An error should be returned -if the ClientMessage fails to verify. - -## `CheckForMisbehaviour` method - -Checks for evidence of a misbehaviour in `Header` or `Misbehaviour` type. It assumes the `ClientMessage` -has already been verified. diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/03-consensus-state.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/03-consensus-state.md deleted file mode 100644 index e9598c3e8d5..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/03-consensus-state.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: Consensus State interface -sidebar_label: Consensus State interface -sidebar_position: 3 -slug: /ibc/light-clients/consensus-state ---- - - -# Implementing the `ConsensusState` interface - -A `ConsensusState` is the snapshot of the counterparty chain, that an IBC client uses to verify proofs (e.g. a block). - -The further development of multiple types of IBC light clients and the difficulties presented by this generalization problem (see [ADR-006](https://github.com/cosmos/ibc-go/blob/main/docs/architecture/adr-006-02-client-refactor.md) for more information about this historical context) led to the design decision of each client keeping track of and set its own `ClientState` and `ConsensusState`, as well as the simplification of client `ConsensusState` updates through the generalized `ClientMessage` interface. - -The below [`ConsensusState`](https://github.com/cosmos/ibc-go/blob/main/modules/core/exported/client.go#L134) interface is a generalized interface for the types of information a `ConsensusState` could contain. For a reference `ConsensusState` implementation, please see the [Tendermint light client `ConsensusState`](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/07-tendermint/consensus_state.go). - -## `ClientType` method - -This is the type of client consensus. It should be the same as the `ClientType` return value for the [corresponding `ClientState` implementation](02-client-state.md). - -## `GetTimestamp` method - -`GetTimestamp` should return the timestamp (in nanoseconds) of the consensus state snapshot. - -## `ValidateBasic` method - -`ValidateBasic` should validate every consensus state field and should return an error if any value is invalid. The light client implementer is in charge of determining which checks are required. diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/04-updates-and-misbehaviour.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/04-updates-and-misbehaviour.md deleted file mode 100644 index 7d3d50d107c..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/04-updates-and-misbehaviour.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -title: Handling Updates and Misbehaviour -sidebar_label: Handling Updates and Misbehaviour -sidebar_position: 4 -slug: /ibc/light-clients/updates-and-misbehaviour ---- - - -# Handling `ClientMessage`s: updates and misbehaviour - -As mentioned before in the documentation about [implementing the `ConsensusState` interface](03-consensus-state.md), [`ClientMessage`](https://github.com/cosmos/ibc-go/blob/main/modules/core/exported/client.go#L145) is an interface used to update an IBC client. This update may be performed by: - -- a single header -- a batch of headers -- evidence of misbehaviour, -- or any type which when verified produces a change to the consensus state of the IBC client. - -This interface has been purposefully kept generic in order to give the maximum amount of flexibility to the light client implementer. - -## Implementing the `ClientMessage` interface - -Find the `ClientMessage`interface in `modules/core/exported`: - -```go -type ClientMessage interface { - proto.Message - - ClientType() string - ValidateBasic() error -} -``` - -The `ClientMessage` will be passed to the client to be used in [`UpdateClient`](https://github.com/cosmos/ibc-go/blob/57da75a70145409247e85365b64a4b2fc6ddad2f/modules/core/02-client/keeper/client.go#L53), which retrieves the `ClientState` by client ID (available in `MsgUpdateClient`). This `ClientState` implements the [`ClientState` interface](02-client-state.md) for its specific consenus type (e.g. Tendermint). - -`UpdateClient` will then handle a number of cases including misbehaviour and/or updating the consensus state, utilizing the specific methods defined in the relevant `ClientState`. - -```go -VerifyClientMessage(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg ClientMessage) error -CheckForMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg ClientMessage) bool -UpdateStateOnMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg ClientMessage) -UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg ClientMessage) []Height -``` - -## Handling updates and misbehaviour - -The functions for handling updates to a light client and evidence of misbehaviour are all found in the [`ClientState`](https://github.com/cosmos/ibc-go/blob/v6.0.0/modules/core/exported/client.go#L40) interface, and will be discussed below. - -> It is important to note that `Misbehaviour` in this particular context is referring to misbehaviour on the chain level intended to fool the light client. This will be defined by each light client. - -## `VerifyClientMessage` - -`VerifyClientMessage` must verify a `ClientMessage`. A `ClientMessage` could be a `Header`, `Misbehaviour`, or batch update. To understand how to implement a `ClientMessage`, please refer to the [Implementing the `ClientMessage` interface](#implementing-the-clientmessage-interface) section. - -It must handle each type of `ClientMessage` appropriately. Calls to `CheckForMisbehaviour`, `UpdateState`, and `UpdateStateOnMisbehaviour` will assume that the content of the `ClientMessage` has been verified and can be trusted. An error should be returned if the `ClientMessage` fails to verify. - -For an example of a `VerifyClientMessage` implementation, please check the [Tendermint light client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/07-tendermint/update.go#L20). - -## `CheckForMisbehaviour` - -Checks for evidence of a misbehaviour in `Header` or `Misbehaviour` type. It assumes the `ClientMessage` has already been verified. - -For an example of a `CheckForMisbehaviour` implementation, please check the [Tendermint light client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/07-tendermint/misbehaviour_handle.go#L18). - -> The Tendermint light client [defines `Misbehaviour`](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/07-tendermint/misbehaviour.go) as two different types of situations: a situation where two conflicting `Header`s with the same height have been submitted to update a client's `ConsensusState` within the same trusting period, or that the two conflicting `Header`s have been submitted at different heights but the consensus states are not in the correct monotonic time ordering (BFT time violation). More explicitly, updating to a new height must have a timestamp greater than the previous consensus state, or, if inserting a consensus at a past height, then time must be less than those heights which come after and greater than heights which come before. - -## `UpdateStateOnMisbehaviour` - -`UpdateStateOnMisbehaviour` should perform appropriate state changes on a client state given that misbehaviour has been detected and verified. This method should only be called when misbehaviour is detected, as it does not perform any misbehaviour checks. Notably, it should freeze the client so that calling the `Status` function on the associated client state no longer returns `Active`. - -For an example of a `UpdateStateOnMisbehaviour` implementation, please check the [Tendermint light client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/07-tendermint/update.go#L197). - -## `UpdateState` - -`UpdateState` updates and stores as necessary any associated information for an IBC client, such as the `ClientState` and corresponding `ConsensusState`. It should perform a no-op on duplicate updates. - -It assumes the `ClientMessage` has already been verified. - -For an example of a `UpdateState` implementation, please check the [Tendermint light client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/07-tendermint/update.go#L131). - -## Putting it all together - -The `02-client` `Keeper` module in ibc-go offers a reference as to how these functions will be used to [update the client](https://github.com/cosmos/ibc-go/blob/main/modules/core/02-client/keeper/client.go#L48). - -```go -if err := clientState.VerifyClientMessage(clientMessage); err != nil { - return err -} - -foundMisbehaviour := clientState.CheckForMisbehaviour(clientMessage) -if foundMisbehaviour { - clientState.UpdateStateOnMisbehaviour(clientMessage) - // emit misbehaviour event - return -} - -clientState.UpdateState(clientMessage) // expects no-op on duplicate header - // emit update event - return -} diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/05-upgrades.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/05-upgrades.md deleted file mode 100644 index ec0cfc243fa..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/05-upgrades.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Handling Upgrades -sidebar_label: Handling Upgrades -sidebar_position: 5 -slug: /ibc/light-clients/upgrades ---- - - -# Handling upgrades - -It is vital that high-value IBC clients can upgrade along with their underlying chains to avoid disruption to the IBC ecosystem. Thus, IBC client developers will want to implement upgrade functionality to enable clients to maintain connections and channels even across chain upgrades. - -## Implementing `VerifyUpgradeAndUpdateState` - -The IBC protocol allows client implementations to provide a path to upgrading clients given the upgraded `ClientState`, upgraded `ConsensusState` and proofs for each. This path is provided in the `VerifyUpgradeAndUpdateState` method: - -```go -// NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last height committed by the current revision. Clients are responsible for ensuring that the planned last height of the current revision is somehow encoded in the proof verification process. -// This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty may be cancelled or modified before the last planned height. -// If the upgrade is verified, the upgraded client and consensus states must be set in the client store. -func (cs ClientState) VerifyUpgradeAndUpdateState( - ctx sdk.Context, - cdc codec.BinaryCodec, - store sdk.KVStore, - newClient ClientState, - newConsState ConsensusState, - proofUpgradeClient, - proofUpgradeConsState []byte, -) error -``` - -> Please refer to the [Tendermint light client implementation](https://github.com/cosmos/ibc-go/blob/02-client-refactor-beta1/modules/light-clients/07-tendermint/upgrade.go#L27) as an example for implementation. - -It is important to note that light clients **must** handle all management of client and consensus states including the setting of updated `ClientState` and `ConsensusState` in the client store. This can include verifying that the submitted upgraded `ClientState` is of a valid `ClientState` type, that the height of the upgraded client is not greater than the height of the current client (in order to preserve BFT monotonic time), or that certain parameters which should not be changed have not been altered in the upgraded `ClientState`. - -Developers must ensure that the `MsgUpgradeClient` does not pass until the last height of the old chain has been committed, and after the chain upgrades, the `MsgUpgradeClient` should pass once and only once on all counterparty clients. - -### Upgrade path - -Clients should have **prior knowledge of the merkle path** that the upgraded client and upgraded consensus states will use. The height at which the upgrade has occurred should also be encoded in the proof. -> The Tendermint client implementation accomplishes this by including an `UpgradePath` in the `ClientState` itself, which is used along with the upgrade height to construct the merkle path under which the client state and consensus state are committed. - -## Chain specific vs client specific client parameters - -Developers should maintain the distinction between client parameters that are uniform across every valid light client of a chain (chain-chosen parameters), and client parameters that are customizable by each individual client (client-chosen parameters); since this distinction is necessary to implement the `ZeroCustomFields` method in the [`ClientState` interface](02-client-state.md): - -```go -// Utility function that zeroes out any client customizable fields in client state -// Ledger enforced fields are maintained while all custom fields are zero values -// Used to verify upgrades -func (cs ClientState) ZeroCustomFields() ClientState -``` - -Developers must ensure that the new client adopts all of the new client parameters that must be uniform across every valid light client of a chain (chain-chosen parameters), while maintaining the client parameters that are customizable by each individual client (client-chosen parameters) from the previous version of the client. `ZeroCustomFields` is a useful utility function to ensure only chain specific fields are updated during upgrades. - -## Security - -Upgrades must adhere to the IBC Security Model. IBC does not rely on the assumption of honest relayers for correctness. Thus users should not have to rely on relayers to maintain client correctness and security (though honest relayers must exist to maintain relayer liveness). While relayers may choose any set of client parameters while creating a new `ClientState`, this still holds under the security model since users can always choose a relayer-created client that suits their security and correctness needs or create a client with their desired parameters if no such client exists. - -However, when upgrading an existing client, one must keep in mind that there are already many users who depend on this client's particular parameters. **We cannot give the upgrading relayer free choice over these parameters once they have already been chosen. This would violate the security model** since users who rely on the client would have to rely on the upgrading relayer to maintain the same level of security. - -Thus, developers must make sure that their upgrade mechanism allows clients to upgrade the chain-specified parameters whenever a chain upgrade changes these parameters (examples in the Tendermint client include `UnbondingPeriod`, `TrustingPeriod`, `ChainID`, `UpgradePath`, etc), while ensuring that the relayer submitting the `MsgUpgradeClient` cannot alter the client-chosen parameters that the users are relying upon (examples in Tendermint client include `TrustLevel`, `MaxClockDrift`, etc). The previous paragraph discusses how `ZeroCustomFields` helps achieve this. - -### Document potential client parameter conflicts during upgrades - -Counterparty clients can upgrade securely by using all of the chain-chosen parameters from the chain-committed `UpgradedClient` and preserving all of the old client-chosen parameters. This enables chains to securely upgrade without relying on an honest relayer, however it can in some cases lead to an invalid final `ClientState` if the new chain-chosen parameters clash with the old client-chosen parameter. This can happen in the Tendermint client case if the upgrading chain lowers the `UnbondingPeriod` (chain-chosen) to a duration below that of a counterparty client's `TrustingPeriod` (client-chosen). Such cases should be clearly documented by developers, so that chains know which upgrades should be avoided to prevent this problem. The final upgraded client should also be validated in `VerifyUpgradeAndUpdateState` before returning to ensure that the client does not upgrade to an invalid `ClientState`. diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/06-proofs.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/06-proofs.md deleted file mode 100644 index c5a651d0dea..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/06-proofs.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Existence/Non-Existence Proofs -sidebar_label: Existence/Non-Existence Proofs -sidebar_position: 6 -slug: /ibc/light-clients/proofs ---- - - -# Existence and non-existence proofs - -IBC uses merkle proofs in order to verify the state of a remote counterparty state machine given a trusted root, and [ICS-23](https://github.com/cosmos/ics23/tree/master/go) is a general approach for verifying merkle trees which is used in ibc-go. - -Currently, all Cosmos SDK modules contain their own stores, which maintain the state of the application module in an IAVL (immutable AVL) binary merkle tree format. Specifically with regard to IBC, core IBC maintains its own IAVL store, and IBC apps (e.g. transfer) maintain their own dedicated stores. The Cosmos SDK multistore therefore creates a simple merkle tree of all of these IAVL trees, and from each of these individual IAVL tree root hashes it derives a root hash for the application state tree as a whole (the `AppHash`). - -For the purposes of ibc-go, there are two types of proofs which are important: existence and non-existence proofs, terms which have been used interchangeably with membership and non-membership proofs. For the purposes of this guide, we will stick with "existence" and "non-existence". - -## Existence proofs - -Existence proofs are used in IBC transactions which involve verification of counterparty state for transactions which will result in the writing of provable state. For example, this includes verification of IBC store state for handshakes and packets. - -Put simply, existence proofs prove that a particular key and value exists in the tree. Under the hood, an IBC existence proof comprises of two proofs: an IAVL proof that the key exists in IBC store/IBC root hash, and a proof that the IBC root hash exists in the multistore root hash. - -## Non-existence proofs - -Non-existence proofs verify the absence of data stored within counterparty state and are used to prove that a key does NOT exist in state. As stated above, these types of proofs can be used to timeout packets by proving that the counterparty has not written a packet receipt into the store, meaning that a token transfer has NOT successfully occurred. - -Some trees (e.g. SMT) may have a sentinel empty child for non-existent keys. In this case, the ICS-23 proof spec should include this `EmptyChild` so that ICS-23 handles the non-existence proof correctly. - -In some cases, there is a necessity to "mock" non-existence proofs if the counterparty does not have ability to prove absence. Since the verification method is designed to give complete control to client implementations, clients can support chains that do not provide absence proofs by verifying the existence of a non-empty sentinel `ABSENCE` value. In these special cases, the proof provided will be an ICS-23 `Existence` proof, and the client will verify that the `ABSENCE` value is stored under the given path for the given height. - -## State verification methods: `VerifyMembership` and `VerifyNonMembership` - -The state verification functions for all IBC data types have been consolidated into two generic methods, `VerifyMembership` and `VerifyNonMembership`. - -From the [`ClientState` interface definition](https://github.com/cosmos/ibc-go/blob/e650be91614ced7be687c30eb42714787a3bbc59/modules/core/exported/client.go#L68-L91), we find: - -```go -VerifyMembership( - ctx sdk.Context, - clientStore sdk.KVStore, - cdc codec.BinaryCodec, - height Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - proof []byte, - path Path, - value []byte, -) error - -// VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. -// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). -VerifyNonMembership( - ctx sdk.Context, - clientStore sdk.KVStore, - cdc codec.BinaryCodec, - height Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - proof []byte, - path Path, -) error -``` - -Both are expected to be provided with a standardised key path, `exported.Path`, as defined in [ICS-24 host requirements](https://github.com/cosmos/ibc/tree/main/spec/core/ics-024-host-requirements). Membership verification requires callers to provide the value marshalled as `[]byte`. Delay period values should be zero for non-packet processing verification. A zero proof height is now allowed by core IBC and may be passed into `VerifyMembership` and `VerifyNonMembership`. Light clients are responsible for returning an error if a zero proof height is invalid behaviour. - -Please refer to the [ICS-23 implementation](https://github.com/cosmos/ibc-go/blob/e093d85b533ab3572b32a7de60b88a0816bed4af/modules/core/23-commitment/types/merkle.go#L131-L205) for a concrete example. diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/07-proposals.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/07-proposals.md deleted file mode 100644 index 069342bd5ec..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/07-proposals.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: Handling Proposals -sidebar_label: Handling Proposals -sidebar_position: 7 -slug: /ibc/light-clients/proposals ---- - - -# Handling proposals - -It is possible to update the client with the state of the substitute client through a governance proposal. [This type of governance proposal](https://ibc.cosmos.network/main/ibc/proposals.html) is typically used to recover an expired or frozen client, as it can recover the entire state and therefore all existing channels built on top of the client. `CheckSubstituteAndUpdateState` should be implemented to handle the proposal. - -## Implementing `CheckSubstituteAndUpdateState` - -In the [`ClientState`interface](https://github.com/cosmos/ibc-go/blob/e650be91614ced7be687c30eb42714787a3bbc59/modules/core/exported/client.go), we find: - -```go -// CheckSubstituteAndUpdateState must verify that the provided substitute may be used to update the subject client. -// The light client must set the updated client and consensus states within the clientStore for the subject client. -CheckSubstituteAndUpdateState( - ctx sdk.Context, - cdc codec.BinaryCodec, - subjectClientStore, - substituteClientStore sdk.KVStore, - substituteClient ClientState) - error -``` - -Prior to updating, this function must verify that: - -- the substitute client is the same type as the subject client. For a reference implementation, please see the [Tendermint light client](https://github.com/cosmos/ibc-go/blob/02-client-refactor-beta1/modules/light-clients/07-tendermint/proposal_handle.go#L32). -- the provided substitute may be used to update the subject client. This may mean that certain parameters must remain unaltered. For example, a [valid substitute Tendermint light client](https://github.com/cosmos/ibc-go/blob/02-client-refactor-beta1/modules/light-clients/07-tendermint/proposal_handle.go#L84) must NOT change the chain ID, trust level, max clock drift, unbonding period, proof specs or upgrade path. Please note that `AllowUpdateAfterMisbehaviour` and `AllowUpdateAfterExpiry` have been deprecated (see ADR 026 for more information). - -After these checks are performed, the function must [set the updated client and consensus states](https://github.com/cosmos/ibc-go/blob/02-client-refactor-beta1/modules/light-clients/07-tendermint/proposal_handle.go#L77) within the client store for the subject client. - -Please refer to the [Tendermint light client implementation](https://github.com/cosmos/ibc-go/blob/02-client-refactor-beta1/modules/light-clients/07-tendermint/proposal_handle.go#L27) for reference. diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/08-genesis.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/08-genesis.md deleted file mode 100644 index b3f730259b7..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/08-genesis.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: Handling Genesis -sidebar_label: Handling Genesis -sidebar_position: 8 -slug: /ibc/light-clients/genesis ---- - - -# Genesis metadata - -:::note Synopsis -Learn how to implement the `ExportMetadata` interface -::: - -## Pre-requisite readings - -- [Cosmos SDK module genesis](https://docs.cosmos.network/v0.47/building-modules/genesis) - -`ClientState` instances are provided their own isolated and namespaced client store upon initialisation. `ClientState` implementations may choose to store any amount of arbitrary metadata in order to verify counterparty consensus state and perform light client updates correctly. - -The `ExportMetadata` method of the [`ClientState` interface](https://github.com/cosmos/ibc-go/blob/e650be91614ced7be687c30eb42714787a3bbc59/modules/core/exported/client.go) provides light client modules with the ability to persist metadata in genesis exports. - -```go -ExportMetadata(clientStore sdk.KVStore) []GenesisMetadata -``` - -`ExportMetadata` is provided the client store and returns an array of `GenesisMetadata`. For maximum flexibility, `GenesisMetadata` is defined as a simple interface containing two distinct `Key` and `Value` accessor methods. - -```go -type GenesisMetadata interface { - // return store key that contains metadata without clientID-prefix - GetKey() []byte - // returns metadata value - GetValue() []byte -} -``` - -This allows `ClientState` instances to retrieve and export any number of key-value pairs which are maintained within the store in their raw `[]byte` form. - -When a chain is started with a `genesis.json` file which contains `ClientState` metadata (for example, when performing manual upgrades using an exported `genesis.json`) the `02-client` submodule of core IBC will handle setting the key-value pairs within their respective client stores. [See `02-client` `InitGenesis`](https://github.com/cosmos/ibc-go/blob/02-client-refactor-beta1/modules/core/02-client/genesis.go#L18-L22). - -Please refer to the [Tendermint light client implementation](https://github.com/cosmos/ibc-go/blob/02-client-refactor-beta1/modules/light-clients/07-tendermint/genesis.go#L12) for an example. diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/09-setup.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/09-setup.md deleted file mode 100644 index 9b5c33abccd..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/09-setup.md +++ /dev/null @@ -1,135 +0,0 @@ ---- -title: Setup -sidebar_label: Setup -sidebar_position: 9 -slug: /ibc/light-clients/setup ---- - - -# Setup - -:::note Synopsis -Learn how to configure light client modules and create clients using core IBC and the `02-client` submodule. -::: - -A last step to finish the development of the light client, is to implement the `AppModuleBasic` interface to allow it to be added to the chain's `app.go` alongside other light client types the chain enables. - -Finally, a succinct rundown is given of the remaining steps to make the light client operational, getting the light client type passed through governance and creating the clients. - -## Configuring a light client module - -An IBC light client module must implement the [`AppModuleBasic`](https://github.com/cosmos/cosmos-sdk/blob/main/types/module/module.go#L50) interface in order to register its concrete types against the core IBC interfaces defined in `modules/core/exported`. This is accomplished via the `RegisterInterfaces` method which provides the light client module with the opportunity to register codec types using the chain's `InterfaceRegistry`. Please refer to the [`07-tendermint` codec registration](https://github.com/cosmos/ibc-go/blob/02-client-refactor-beta1/modules/light-clients/07-tendermint/codec.go#L11). - -The `AppModuleBasic` interface may also be leveraged to install custom CLI handlers for light client module users. Light client modules can safely no-op for interface methods which it does not wish to implement. - -Please refer to the [core IBC documentation](../../01-ibc/02-integration.md#integrating-light-clients) for how to configure additional light client modules alongside `07-tendermint` in `app.go`. - -See below for an example of the `07-tendermint` implementation of `AppModuleBasic`. - -```go -var _ module.AppModuleBasic = AppModuleBasic{} - -// AppModuleBasic defines the basic application module used by the tendermint light client. -// Only the RegisterInterfaces function needs to be implemented. All other function perform -// a no-op. -type AppModuleBasic struct{} - -// Name returns the tendermint module name. -func (AppModuleBasic) Name() string { - return ModuleName -} - -// RegisterLegacyAminoCodec performs a no-op. The Tendermint client does not support amino. -func (AppModuleBasic) RegisterLegacyAminoCodec(*codec.LegacyAmino) {} - -// RegisterInterfaces registers module concrete types into protobuf Any. This allows core IBC -// to unmarshal tendermint light client types. -func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { - RegisterInterfaces(registry) -} - -// DefaultGenesis performs a no-op. Genesis is not supported for the tendermint light client. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { - return nil -} - -// ValidateGenesis performs a no-op. Genesis is not supported for the tendermint light cilent. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { - return nil -} - -// RegisterGRPCGatewayRoutes performs a no-op. -func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) {} - -// GetTxCmd performs a no-op. Please see the 02-client cli commands. -func (AppModuleBasic) GetTxCmd() *cobra.Command { - return nil -} - -// GetQueryCmd performs a no-op. Please see the 02-client cli commands. -func (AppModuleBasic) GetQueryCmd() *cobra.Command { - return nil -} -``` - -## Creating clients - -A client is created by executing a new `MsgCreateClient` transaction composed with a valid `ClientState` and initial `ConsensusState` encoded as protobuf `Any`s. -Generally, this is performed by an off-chain process known as an [IBC relayer](https://github.com/cosmos/ibc/tree/main/spec/relayer/ics-018-relayer-algorithms) however, this is not a strict requirement. - -See below for a list of IBC relayer implementations: - -- [cosmos/relayer](https://github.com/cosmos/relayer) -- [informalsystems/hermes](https://github.com/informalsystems/hermes) -- [confio/ts-relayer](https://github.com/confio/ts-relayer) - -Stateless checks are performed within the [`ValidateBasic`](https://github.com/cosmos/ibc-go/blob/02-client-refactor-beta1/modules/core/02-client/types/msgs.go#L48) method of `MsgCreateClient`. - -```protobuf -// MsgCreateClient defines a message to create an IBC client -message MsgCreateClient { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - // light client state - google.protobuf.Any client_state = 1 [(gogoproto.moretags) = "yaml:\"client_state\""]; - // consensus state associated with the client that corresponds to a given - // height. - google.protobuf.Any consensus_state = 2 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; - // signer address - string signer = 3; -} -``` - -Leveraging protobuf `Any` encoding allows core IBC to [unpack](https://github.com/cosmos/ibc-go/blob/02-client-refactor-beta1/modules/core/keeper/msg_server.go#L28-L36) both the `ClientState` and `ConsensusState` into their respective interface types registered previously using the light client module's `RegisterInterfaces` method. - -Within the `02-client` submodule, the [`ClientState` is then initialized](https://github.com/cosmos/ibc-go/blob/02-client-refactor-beta1/modules/core/02-client/keeper/client.go#L30-L34) with its own isolated key-value store, namespaced using a unique client identifier. - -In order to successfully create an IBC client using a new client type, it [must be supported](https://github.com/cosmos/ibc-go/blob/02-client-refactor-beta1/modules/core/02-client/keeper/client.go#L18-L24). Light client support in IBC is gated by on-chain governance. The allow list may be updated by submitting a new governance proposal to update the `02-client` parameter `AllowedClients`. - - -See below for example: - -```shell -%s tx gov submit-proposal param-change --from= -``` - -where `proposal.json` contains: - -```json -{ - "title": "IBC Clients Param Change", - "description": "Update allowed clients", - "changes": [ - { - "subspace": "ibc", - "key": "AllowedClients", - "value": ["06-solomachine", "07-tendermint", "0x-new-client"] - } - ], - "deposit": "1000stake" -} -``` diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/_category_.json b/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/_category_.json deleted file mode 100644 index 9be9c3c3a08..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/01-developer-guide/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Developer Guide", - "position": 1, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/02-solomachine/01-solomachine.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/02-solomachine/01-solomachine.md deleted file mode 100644 index 883d9ec8beb..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/02-solomachine/01-solomachine.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: Solomachine -sidebar_label: Solomachine -sidebar_position: 1 -slug: /ibc/light-clients/solomachine/solomachine ---- - - -# `solomachine` - -## Abstract - -This paper defines the implementation of the ICS06 protocol on the Cosmos SDK. For the general -specification please refer to the [ICS06 Specification](https://github.com/cosmos/ibc/tree/master/spec/client/ics-006-solo-machine-client). - -This implementation of a solo machine light client supports single and multi-signature public -keys. The client is capable of handling public key updates by header and governance proposals. -The light client is capable of processing client misbehaviour. Proofs of the counterparty state -are generated by the solo machine client by signing over the desired state with a certain sequence, -diversifier, and timestamp. - -## Contents - -1. **[Concepts](02-concepts.md)** -2. **[State](03-state.md)** -3. **[State Transitions](04-state_transitions.md)** diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/02-solomachine/02-concepts.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/02-solomachine/02-concepts.md deleted file mode 100644 index 3791e20a185..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/02-solomachine/02-concepts.md +++ /dev/null @@ -1,168 +0,0 @@ ---- -title: Concepts -sidebar_label: Concepts -sidebar_position: 2 -slug: /ibc/light-clients/solomachine/concepts ---- - - -# Concepts - -## Client State - -The `ClientState` for a solo machine light client stores the latest sequence, the frozen sequence, -the latest consensus state, and client flag indicating if the client should be allowed to be updated -after a governance proposal. - -If the client is not frozen then the frozen sequence is 0. - -## Consensus State - -The consensus states stores the public key, diversifier, and timestamp of the solo machine light client. - -The diversifier is used to prevent accidental misbehaviour if the same public key is used across -different chains with the same client identifier. It should be unique to the chain the light client -is used on. - -## Public Key - -The public key can be a single public key or a multi-signature public key. The public key type used -must fulfill the tendermint public key interface (this will become the SDK public key interface in the -near future). The public key must be registered on the application codec otherwise encoding/decoding -errors will arise. The public key stored in the consensus state is represented as a protobuf `Any`. -This allows for flexibility in what other public key types can be supported in the future. - -## Counterparty Verification - -The solo machine light client can verify counterparty client state, consensus state, connection state, -channel state, packet commitments, packet acknowledgements, packet receipt absence, -and the next sequence receive. At the end of each successful verification call the light -client sequence number will be incremented. - -Successful verification requires the current public key to sign over the proof. - -## Proofs - -A solo machine proof should verify that the solomachine public key signed -over some specified data. The format for generating marshaled proofs for -the SDK's implementation of solo machine is as follows: - -1. Construct the data using the associated protobuf definition and marshal it. - -For example: - -```go -data := &ClientStateData{ - Path: []byte(path.String()), - ClientState: any, -} - -dataBz, err := cdc.Marshal(data) -``` - -The helper functions `...DataBytes()` in [proof.go](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/06-solomachine/proof.go) handle this -functionality. - -2. Construct the `SignBytes` and marshal it. - -For example: - -```go -signBytes := &SignBytes{ - Sequence: sequence, - Timestamp: timestamp, - Diversifier: diversifier, - DataType: CLIENT, - Data: dataBz, -} - -signBz, err := cdc.Marshal(signBytes) -``` - -The helper functions `...SignBytes()` in [proof.go](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/06-solomachine/proof.go) handle this functionality. -The `DataType` field is used to disambiguate what type of data was signed to prevent potential -proto encoding overlap. - -3. Sign the sign bytes. Embed the signatures into either `SingleSignatureData` or `MultiSignatureData`. -Convert the `SignatureData` to proto and marshal it. - -For example: - -```go -sig, err := key.Sign(signBz) -sigData := &signing.SingleSignatureData{ - Signature: sig, -} - -protoSigData := signing.SignatureDataToProto(sigData) -bz, err := cdc.Marshal(protoSigData) -``` - -4. Construct a `TimestampedSignatureData` and marshal it. The marshaled result can be passed in -as the proof parameter to the verification functions. - -For example: - -```go -timestampedSignatureData := &solomachine.TimestampedSignatureData{ - SignatureData: sigData, - Timestamp: solomachine.Time, -} - -proof, err := cdc.Marshal(timestampedSignatureData) -``` - -NOTE: At the end of this process, the sequence associated with the key needs to be updated. -The sequence must be incremented each time proof is generated. - -## Updates By Header - -An update by a header will only succeed if: - -- the header provided is parseable to solo machine header -- the header sequence matches the current sequence -- the header timestamp is greater than or equal to the consensus state timestamp -- the currently registered public key generated the proof - -If the update is successful: - -- the public key is updated -- the diversifier is updated -- the timestamp is updated -- the sequence is incremented by 1 -- the new consensus state is set in the client state - -## Updates By Proposal - -An update by a governance proposal will only succeed if: - -- the substitute provided is parseable to solo machine client state -- the new consensus state public key does not equal the current consensus state public key - -If the update is successful: - -- the subject client state is updated to the substitute client state -- the subject consensus state is updated to the substitute consensus state -- the client is unfrozen (if it was previously frozen) - -NOTE: Previously, `AllowUpdateAfterProposal` was used to signal the update/recovery options for the solo machine client. However, this has now been deprecated because a code migration can overwrite the client and consensus states regardless of the value of this parameter. If governance would vote to overwrite a client or consensus state, it is likely that governance would also be willing to perform a code migration to do the same. - -## Misbehaviour - -Misbehaviour handling will only succeed if: - -- the misbehaviour provided is parseable to solo machine misbehaviour -- the client is not already frozen -- the current public key signed over two unique data messages at the same sequence and diversifier. - -If the misbehaviour is successfully processed: - -- the client is frozen by setting the frozen sequence to the misbehaviour sequence - -NOTE: Misbehaviour processing is data processing order dependent. A misbehaving solo machine -could update to a new public key to prevent being frozen before misbehaviour is submitted. - -## Upgrades - -Upgrades to solo machine light clients are not supported since an entirely different type of -public key can be set using normal client updates. diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/02-solomachine/03-state.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/02-solomachine/03-state.md deleted file mode 100644 index 90d017473c3..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/02-solomachine/03-state.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: State -sidebar_label: State -sidebar_position: 3 -slug: /ibc/light-clients/solomachine/state ---- - - -# State - -The solo machine light client will only store consensus states for each update by a header -or a governance proposal. The latest client state is also maintained in the store. diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/02-solomachine/04-state_transitions.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/02-solomachine/04-state_transitions.md deleted file mode 100644 index 8b4154b3903..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/02-solomachine/04-state_transitions.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: State Transitions -sidebar_label: State Transitions -sidebar_position: 4 -slug: /ibc/light-clients/solomachine/state_transitions ---- - - -# State Transitions - -## Client State Verification Functions - -Successful state verification by a solo machine light client will result in: - -- the sequence being incremented by 1. - -## Update By Header - -A successful update of a solo machine light client by a header will result in: - -- the public key being updated to the new public key provided by the header. -- the diversifier being updated to the new diviersifier provided by the header. -- the timestamp being updated to the new timestamp provided by the header. -- the sequence being incremented by 1 -- the consensus state being updated (consensus state stores the public key, diversifier, and timestamp) - -## Update By Governance Proposal - -A successful update of a solo machine light client by a governance proposal will result in: - -- the client state being updated to the substitute client state -- the consensus state being updated to the substitute consensus state (consensus state stores the public key, diversifier, and timestamp) -- the frozen sequence being set to zero (client is unfrozen if it was previously frozen). - -## Upgrade - -Client udgrades are not supported for the solo machine light client. No state transition occurs. - -## Misbehaviour - -Successful misbehaviour processing of a solo machine light client will result in: - -- the frozen sequence being set to the sequence the misbehaviour occurred at diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/02-solomachine/_category_.json b/docs/versioned_docs/version-v7.3.x/03-light-clients/02-solomachine/_category_.json deleted file mode 100644 index c78281ce778..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/02-solomachine/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Solomachine", - "position": 2, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/03-localhost/01-overview.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/03-localhost/01-overview.md deleted file mode 100644 index 0ec579664c1..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/03-localhost/01-overview.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /ibc/light-clients/localhost/overview ---- - - -# `09-localhost` - -## Overview - -:::note Synopsis -Learn about the 09-localhost light client module. -::: - -The 09-localhost light client module implements a localhost loopback client with the ability to send and receive IBC packets to and from the same state machine. - -### Context - -In a multichain environment, application developers will be used to developing cross-chain applications through IBC. From their point of view, whether or not they are interacting with multiple modules on the same chain or on different chains should not matter. The localhost client module enables a unified interface to interact with different applications on a single chain, using the familiar IBC application layer semantics. - -### Implementation - -There exists a [single sentinel `ClientState`](03-client-state.md) instance with the client identifier `09-localhost`. - -To supplement this, a [sentinel `ConnectionEnd` is stored in core IBC](04-connection.md) state with the connection identifier `connection-localhost`. This enables IBC applications to create channels directly on top of the sentinel connection which leverage the 09-localhost loopback functionality. - -[State verification](05-state-verification.md) for channel state in handshakes or processing packets is reduced in complexity, the `09-localhost` client can simply compare bytes stored under the standardized key paths. - -### Localhost vs *regular* client - -The localhost client aims to provide a unified approach to interacting with applications on a single chain, as the IBC application layer provides for cross-chain interactions. To achieve this unified interface though, there are a number of differences under the hood compared to a 'regular' IBC client (excluding `06-solomachine` and `09-localhost` itself). - -The table below lists some important differences: - -| | Regular client | Localhost | -| -------------------------------------------- | --------------------------------------------------------------------------- | --------- | -| Number of clients | Many instances of a client *type* corresponding to different counterparties | A single sentinel client with the client identifier `09-localhost`| -| Client creation | Relayer (permissionless) | `ClientState` is instantiated in the `InitGenesis` handler of the 02-client submodule in core IBC | -| Client updates | Relayer submits headers using `MsgUpdateClient` | Latest height is updated periodically through the ABCI [`BeginBlock`](https://docs.cosmos.network/v0.47/building-modules/beginblock-endblock) interface of the 02-client submodule in core IBC | -| Number of connections | Many connections, 1 (or more) per client | A single sentinel connection with the connection identifier `connection-localhost` | -| Connection creation | Connection handshake, provided underlying client | Sentinel `ConnectionEnd` is created and set in store in the `InitGenesis` handler of the 03-connection submodule in core IBC | -| Counterparty | Underlying client, representing another chain | Client with identifier `09-localhost` in same chain | -| `VerifyMembership` and `VerifyNonMembership` | Performs proof verification using consensus state roots | Performs state verification using key-value lookups in the core IBC store | -| Integration | Expected to register codec types using the `AppModuleBasic` interface | Registers codec types within the core IBC module | diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/03-localhost/02-integration.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/03-localhost/02-integration.md deleted file mode 100644 index fb15df16a29..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/03-localhost/02-integration.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 2 -slug: /ibc/light-clients/localhost/integration ---- - - -# Integration - -The 09-localhost light client module registers codec types within the core IBC module. This differs from other light client module implementations which are expected to register codec types using the `AppModuleBasic` interface. - -The localhost client is added to the 02-client submodule param [`allowed_clients`](https://github.com/cosmos/ibc-go/blob/v7.0.0-rc0/proto/ibc/core/client/v1/client.proto#L102) by default in ibc-go. - -```go -var ( - // DefaultAllowedClients are the default clients for the AllowedClients parameter. - DefaultAllowedClients = []string{exported.Solomachine, exported.Tendermint, exported.Localhost} -) -``` diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/03-localhost/03-client-state.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/03-localhost/03-client-state.md deleted file mode 100644 index 5f0a990412e..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/03-localhost/03-client-state.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: ClientState -sidebar_label: ClientState -sidebar_position: 3 -slug: /ibc/light-clients/localhost/client-state ---- - - -# `ClientState` - -The 09-localhost `ClientState` maintains a single field used to track the latest sequence of the state machine i.e. the height of the blockchain. - -```go -type ClientState struct { - // the latest height of the blockchain - LatestHeight clienttypes.Height -} -``` - -The 09-localhost `ClientState` is instantiated in the `InitGenesis` handler of the 02-client submodule in core IBC. -It calls `CreateLocalhostClient`, declaring a new `ClientState` and initializing it with its own client prefixed store. - -```go -func (k Keeper) CreateLocalhostClient(ctx sdk.Context) error { - var clientState localhost.ClientState - return clientState.Initialize(ctx, k.cdc, k.ClientStore(ctx, exported.LocalhostClientID), nil) -} -``` - -It is possible to disable the localhost client by removing the `09-localhost` entry from the `allowed_clients` list through governance. - -## Client updates - -The latest height is updated periodically through the ABCI [`BeginBlock`](https://docs.cosmos.network/v0.47/building-modules/beginblock-endblock) interface of the 02-client submodule in core IBC. - -[See `BeginBlocker` in abci.go.](https://github.com/cosmos/ibc-go/blob/09-localhost/modules/core/02-client/abci.go#L12) - -```go -func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { - // ... - - if clientState, found := k.GetClientState(ctx, exported.Localhost); found { - if k.GetClientStatus(ctx, clientState, exported.Localhost) == exported.Active { - k.UpdateLocalhostClient(ctx, clientState) - } - } -} -``` - -The above calls into the the 09-localhost `UpdateState` method of the `ClientState` . -It retrieves the current block height from the application context and sets the `LatestHeight` of the 09-localhost client. - -```go -func (cs ClientState) UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg exported.ClientMessage) []exported.Height { - height := clienttypes.GetSelfHeight(ctx) - cs.LatestHeight = height - - clientStore.Set(host.ClientStateKey(), clienttypes.MustMarshalClientState(cdc, &cs)) - - return []exported.Height{height} -} -``` - -Note that the 09-localhost `ClientState` is not updated through the 02-client interface leveraged by conventional IBC light clients. diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/03-localhost/04-connection.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/03-localhost/04-connection.md deleted file mode 100644 index 48c2854a75a..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/03-localhost/04-connection.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: Connection -sidebar_label: Connection -sidebar_position: 4 -slug: /ibc/light-clients/localhost/connection ---- - - -# Localhost connections - -The 09-localhost light client module integrates with core IBC through a single sentinel localhost connection. -The sentinel `ConnectionEnd` is stored by default in the core IBC store. - -This enables channel handshakes to be initiated out of the box by supplying the localhost connection identifier (`connection-localhost`) in the `connectionHops` parameter of `MsgChannelOpenInit`. - -The `ConnectionEnd` is created and set in store via the `InitGenesis` handler of the 03-connection submodule in core IBC. -The `ConnectionEnd` and its `Counterparty` both reference the `09-localhost` client identifier, and share the localhost connection identifier `connection-localhost`. - -```go -// CreateSentinelLocalhostConnection creates and sets the sentinel localhost connection end in the IBC store. -func (k Keeper) CreateSentinelLocalhostConnection(ctx sdk.Context) { - counterparty := types.NewCounterparty(exported.LocalhostClientID, exported.LocalhostConnectionID, commitmenttypes.NewMerklePrefix(k.GetCommitmentPrefix().Bytes())) - connectionEnd := types.NewConnectionEnd(types.OPEN, exported.LocalhostClientID, counterparty, types.ExportedVersionsToProto(types.GetCompatibleVersions()), 0) - - k.SetConnection(ctx, exported.LocalhostConnectionID, connectionEnd) -} -``` - -Note that connection handshakes are disallowed when using the `09-localhost` client type. diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/03-localhost/05-state-verification.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/03-localhost/05-state-verification.md deleted file mode 100644 index c039d241a72..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/03-localhost/05-state-verification.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: State Verification -sidebar_label: State Verification -sidebar_position: 5 -slug: /ibc/light-clients/localhost/state-verification ---- - - -# State verification - -The localhost client handles state verification through the `ClientState` interface methods `VerifyMembership` and `VerifyNonMembership` by performing read-only operations directly on the core IBC store. - -When verifying channel state in handshakes or processing packets the `09-localhost` client can simply compare bytes stored under the standardized key paths defined by [ICS-24](https://github.com/cosmos/ibc/tree/main/spec/core/ics-024-host-requirements). - -For existence proofs via `VerifyMembership` the 09-localhost client will retrieve the value stored under the provided key path and compare it against the value provided by the caller. In contrast, non-existence proofs via `VerifyNonMembership` assert the absence of a value at the provided key path. - -Relayers are expected to provide a sentinel proof when sending IBC messages. Submission of nil or empty proofs is disallowed in core IBC messaging. -The 09-localhost light client module defines a `SentinelProof` as a single byte. Localhost client state verification will fail if the sentintel proof value is not provided. - -```go -var SentinelProof = []byte{0x01} -``` diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/03-localhost/_category_.json b/docs/versioned_docs/version-v7.3.x/03-light-clients/03-localhost/_category_.json deleted file mode 100644 index 484c8801e3b..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/03-localhost/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Localhost", - "position": 3, - "link": null -} diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/_category_.json b/docs/versioned_docs/version-v7.3.x/03-light-clients/_category_.json deleted file mode 100644 index 8e1f221f353..00000000000 --- a/docs/versioned_docs/version-v7.3.x/03-light-clients/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "IBC Light Clients", - "position": 3, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/01-overview.md b/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/01-overview.md deleted file mode 100644 index b1e85bfb9eb..00000000000 --- a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/01-overview.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /middleware/ics29-fee/overview ---- - -# Overview - -:::note Synopsis -Learn about what the Fee Middleware module is, and how to build custom modules that utilize the Fee Middleware functionality -::: - -## What is the Fee Middleware module? - -IBC does not depend on relayer operators for transaction verification. However, the relayer infrastructure ensures liveness of the Interchain network — operators listen for packets sent through channels opened between chains, and perform the vital service of ferrying these packets (and proof of the transaction on the sending chain/receipt on the receiving chain) to the clients on each side of the channel. - -Though relaying is permissionless and completely decentralized and accessible, it does come with operational costs. Running full nodes to query transaction proofs and paying for transaction fees associated with IBC packets are two of the primary cost burdens which have driven the overall discussion on **a general, in-protocol incentivization mechanism for relayers**. - -Initially, a [simple proposal](https://github.com/cosmos/ibc/pull/577/files) was created to incentivize relaying on ICS20 token transfers on the destination chain. However, the proposal was specific to ICS20 token transfers and would have to be reimplemented in this format on every other IBC application module. - -After much discussion, the proposal was expanded to a [general incentivisation design](https://github.com/cosmos/ibc/tree/master/spec/app/ics-029-fee-payment) that can be adopted by any ICS application protocol as [middleware](../../01-ibc/04-middleware/01-develop.md). - -## Concepts - -ICS29 fee payments in this middleware design are built on the assumption that sender chains are the source of incentives — the chain on which packets are incentivized is the chain that distributes fees to relayer operators. However, as part of the IBC packet flow, messages have to be submitted on both sender and destination chains. This introduces the requirement of a mapping of relayer operator's addresses on both chains. - -To achieve the stated requirements, the **fee middleware module has two main groups of functionality**: - -- Registering of relayer addresses associated with each party involved in relaying the packet on the source chain. This registration process can be automated on start up of relayer infrastructure and happens only once, not every packet flow. - - This is described in the [Fee distribution section](04-fee-distribution.md). - -- Escrowing fees by any party which will be paid out to each rightful party on completion of the packet lifecycle. - - This is described in the [Fee messages section](03-msgs.md). - -We complete the introduction by giving a list of definitions of relevant terminolgy. - -`Forward relayer`: The relayer that submits the `MsgRecvPacket` message for a given packet (on the destination chain). - -`Reverse relayer`: The relayer that submits the `MsgAcknowledgement` message for a given packet (on the source chain). - -`Timeout relayer`: The relayer that submits the `MsgTimeout` or `MsgTimeoutOnClose` messages for a given packet (on the source chain). - -`Payee`: The account address on the source chain to be paid on completion of the packet lifecycle. The packet lifecycle on the source chain completes with the receipt of a `MsgTimeout`/`MsgTimeoutOnClose` or a `MsgAcknowledgement`. - -`Counterparty payee`: The account address to be paid on completion of the packet lifecycle on the destination chain. The package lifecycle on the destination chain completes with a successful `MsgRecvPacket`. - -`Refund address`: The address of the account paying for the incentivization of packet relaying. The account is refunded timeout fees upon successful acknowledgement. In the event of a packet timeout, both acknowledgement and receive fees are refunded. - -## Known Limitations - -The first version of fee payments middleware will only support incentivisation of new channels, however, channel upgradeability will enable incentivisation of all existing channels. diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/02-integration.md b/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/02-integration.md deleted file mode 100644 index 4fa2909e316..00000000000 --- a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/02-integration.md +++ /dev/null @@ -1,174 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 2 -slug: /middleware/ics29-fee/integration ---- - - -# Integration - -:::note Synopsis -Learn how to configure the Fee Middleware module with IBC applications. The following document is intended for developers building on top of the Cosmos SDK and only applies for Cosmos SDK chains. -::: - -## Pre-requisite Readings - -- [IBC middleware development](../../01-ibc/04-middleware/01-develop.md) -- [IBC middleware integration](../../01-ibc/04-middleware/02-integration.md) - -The Fee Middleware module, as the name suggests, plays the role of an IBC middleware and as such must be configured by chain developers to route and handle IBC messages correctly. -For Cosmos SDK chains this setup is done via the `app/app.go` file, where modules are constructed and configured in order to bootstrap the blockchain application. - -## Example integration of the Fee Middleware module - -```go -// app.go - -// Register the AppModule for the fee middleware module -ModuleBasics = module.NewBasicManager( - ... - ibcfee.AppModuleBasic{}, - ... -) - -... - -// Add module account permissions for the fee middleware module -maccPerms = map[string][]string{ - ... - ibcfeetypes.ModuleName: nil, -} - -... - -// Add fee middleware Keeper -type App struct { - ... - - IBCFeeKeeper ibcfeekeeper.Keeper - - ... -} - -... - -// Create store keys -keys := sdk.NewKVStoreKeys( - ... - ibcfeetypes.StoreKey, - ... -) - -... - -app.IBCFeeKeeper = ibcfeekeeper.NewKeeper( - appCodec, keys[ibcfeetypes.StoreKey], - app.IBCKeeper.ChannelKeeper, // may be replaced with IBC middleware - app.IBCKeeper.ChannelKeeper, - &app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, -) - - -// See the section below for configuring an application stack with the fee middleware module - -... - -// Register fee middleware AppModule -app.moduleManager = module.NewManager( - ... - ibcfee.NewAppModule(app.IBCFeeKeeper), -) - -... - -// Add fee middleware to begin blocker logic -app.moduleManager.SetOrderBeginBlockers( - ... - ibcfeetypes.ModuleName, - ... -) - -// Add fee middleware to end blocker logic -app.moduleManager.SetOrderEndBlockers( - ... - ibcfeetypes.ModuleName, - ... -) - -// Add fee middleware to init genesis logic -app.moduleManager.SetOrderInitGenesis( - ... - ibcfeetypes.ModuleName, - ... -) -``` - -## Configuring an application stack with Fee Middleware - -As mentioned in [IBC middleware development](../../01-ibc/04-middleware/01-develop.md) an application stack may be composed of many or no middlewares that nest a base application. -These layers form the complete set of application logic that enable developers to build composable and flexible IBC application stacks. -For example, an application stack may be just a single base application like `transfer`, however, the same application stack composed with `29-fee` will nest the `transfer` base application -by wrapping it with the Fee Middleware module. - -### Transfer - -See below for an example of how to create an application stack using `transfer` and `29-fee`. -The following `transferStack` is configured in `app/app.go` and added to the IBC `Router`. -The in-line comments describe the execution flow of packets between the application stack and IBC core. - -```go -// Create Transfer Stack -// SendPacket, since it is originating from the application to core IBC: -// transferKeeper.SendPacket -> fee.SendPacket -> channel.SendPacket - -// RecvPacket, message that originates from core IBC and goes down to app, the flow is the other way -// channel.RecvPacket -> fee.OnRecvPacket -> transfer.OnRecvPacket - -// transfer stack contains (from top to bottom): -// - IBC Fee Middleware -// - Transfer - -// create IBC module from bottom to top of stack -var transferStack porttypes.IBCModule -transferStack = transfer.NewIBCModule(app.TransferKeeper) -transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) - -// Add transfer stack to IBC Router -ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) -``` - -### Interchain Accounts - -See below for an example of how to create an application stack using `27-interchain-accounts` and `29-fee`. -The following `icaControllerStack` and `icaHostStack` are configured in `app/app.go` and added to the IBC `Router` with the associated authentication module. -The in-line comments describe the execution flow of packets between the application stack and IBC core. - -```go -// Create Interchain Accounts Stack -// SendPacket, since it is originating from the application to core IBC: -// icaAuthModuleKeeper.SendTx -> icaController.SendPacket -> fee.SendPacket -> channel.SendPacket - -// initialize ICA module with mock module as the authentication module on the controller side -var icaControllerStack porttypes.IBCModule -icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp("", scopedICAMockKeeper)) -app.ICAAuthModule = icaControllerStack.(ibcmock.IBCModule) -icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) -icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) - -// RecvPacket, message that originates from core IBC and goes down to app, the flow is: -// channel.RecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket - -var icaHostStack porttypes.IBCModule -icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) -icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) - -// Add authentication module, controller and host to IBC router -ibcRouter. - // the ICA Controller middleware needs to be explicitly added to the IBC Router because the - // ICA controller module owns the port capability for ICA. The ICA authentication module - // owns the channel capability. - AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack) - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icahosttypes.SubModuleName, icaHostStack). -``` diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/03-msgs.md b/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/03-msgs.md deleted file mode 100644 index 10b9ed94491..00000000000 --- a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/03-msgs.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: Fee Messages -sidebar_label: Fee Messages -sidebar_position: 3 -slug: /middleware/ics29-fee/msgs ---- - - -# Fee messages - -:::note Synopsis -Learn about the different ways to pay for fees, how the fees are paid out and what happens when not enough escrowed fees are available for payout -::: - -## Escrowing fees - -The fee middleware module exposes two different ways to pay fees for relaying IBC packets: - -1. `MsgPayPacketFee`, which enables the escrowing of fees for a packet at the next sequence send and should be combined into one `MultiMsgTx` with the message that will be paid for. - - Note that the `Relayers` field has been set up to allow for an optional whitelist of relayers permitted to receive this fee, however, this feature has not yet been enabled at this time. - - ```go - type MsgPayPacketFee struct{ - // fee encapsulates the recv, ack and timeout fees associated with an IBC packet - Fee Fee - // the source port unique identifier - SourcePortId string - // the source channel unique identifer - SourceChannelId string - // account address to refund fee if necessary - Signer string - // optional list of relayers permitted to the receive packet fee - Relayers []string - } - ``` - - The `Fee` message contained in this synchronous fee payment method configures different fees which will be paid out for `MsgRecvPacket`, `MsgAcknowledgement`, and `MsgTimeout`/`MsgTimeoutOnClose`. - - ```go - type Fee struct { - RecvFee types.Coins - AckFee types.Coins - TimeoutFee types.Coins - } - ``` - - The diagram below shows the `MultiMsgTx` with the `MsgTransfer` coming from a token transfer message, along with `MsgPayPacketFee`. - - ![msgpaypacket.png](./images/msgpaypacket.png) - -2. `MsgPayPacketFeeAsync`, which enables the asynchronous escrowing of fees for a specified packet: - - Note that a packet can be 'topped up' multiple times with additional fees of any coin denomination by broadcasting multiple `MsgPayPacketFeeAsync` messages. - - ```go - type MsgPayPacketFeeAsync struct { - // unique packet identifier comprised of the channel ID, port ID and sequence - PacketId channeltypes.PacketId - // the packet fee associated with a particular IBC packet - PacketFee PacketFee - } - ``` - - where the `PacketFee` also specifies the `Fee` to be paid as well as the refund address for fees which are not paid out - - ```go - type PacketFee struct { - Fee Fee - RefundAddress string - Relayers []string - } - ``` - -The diagram below shows how multiple `MsgPayPacketFeeAsync` can be broadcasted asynchronously. Escrowing of the fee associated with a packet can be carried out by any party because ICS-29 does not dictate a particular fee payer. In fact, chains can choose to simply not expose this fee payment to end users at all and rely on a different module account or even the community pool as the source of relayer incentives. - -![paypacketfeeasync.png](./images/paypacketfeeasync.png) - -Please see our [wiki](https://github.com/cosmos/ibc-go/wiki/Fee-enabled-fungible-token-transfers) for example flows on how to use these messages to incentivise a token transfer channel using a CLI. - -## Paying out the escrowed fees - -Following diagram takes a look at the packet flow for an incentivized token transfer and investigates the several scenario's for paying out the escrowed fees. We assume that the relayers have registered their counterparty address, detailed in the [Fee distribution section](04-fee-distribution.md). - -![feeflow.png](./images/feeflow.png) - -- In the case of a successful transaction, `RecvFee` will be paid out to the designated counterparty payee address which has been registered on the receiver chain and sent back with the `MsgAcknowledgement`, `AckFee` will be paid out to the relayer address which has submitted the `MsgAcknowledgement` on the sending chain (or the registered payee in case one has been registered for the relayer address), and `TimeoutFee` will be reimbursed to the account which escrowed the fee. -- In case of a timeout transaction, `RecvFee` and `AckFee` will be reimbursed. The `TimeoutFee` will be paid to the `Timeout Relayer` (who submits the timeout message to the source chain). - -> Please note that fee payments are built on the assumption that sender chains are the source of incentives — the chain that sends the packets is the same chain where fee payments will occur -- please see the [Fee distribution section](04-fee-distribution.md) to understand the flow for registering payee and counterparty payee (fee receiving) addresses. - -## A locked fee middleware module - -The fee middleware module can become locked if the situation arises that the escrow account for the fees does not have sufficient funds to pay out the fees which have been escrowed for each packet. *This situation indicates a severe bug.* In this case, the fee module will be locked until manual intervention fixes the issue. - -> A locked fee module will simply skip fee logic and continue on to the underlying packet flow. A channel with a locked fee module will temporarily function as a fee disabled channel, and the locking of a fee module will not affect the continued flow of packets over the channel. diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/04-fee-distribution.md b/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/04-fee-distribution.md deleted file mode 100644 index 9cfd4f3e5a6..00000000000 --- a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/04-fee-distribution.md +++ /dev/null @@ -1,114 +0,0 @@ ---- -title: Fee Distribution -sidebar_label: Fee Distribution -sidebar_position: 4 -slug: /middleware/ics29-fee/fee-distribution ---- - - -# Fee distribution - -:::note Synopsis -Learn about payee registration for the distribution of packet fees. The following document is intended for relayer operators. -::: - -## Pre-requisite readings - -- [Fee Middleware](01-overview.md) - -Packet fees are divided into 3 distinct amounts in order to compensate relayer operators for packet relaying on fee enabled IBC channels. - -- `RecvFee`: The sum of all packet receive fees distributed to a payee for successful execution of `MsgRecvPacket`. -- `AckFee`: The sum of all packet acknowledgement fees distributed to a payee for successful execution of `MsgAcknowledgement`. -- `TimeoutFee`: The sum of all packet timeout fees distributed to a payee for successful execution of `MsgTimeout`. - -## Register a counterparty payee address for forward relaying - -As mentioned in [ICS29 Concepts](01-overview.md#concepts), the forward relayer describes the actor who performs the submission of `MsgRecvPacket` on the destination chain. -Fee distribution for incentivized packet relays takes place on the packet source chain. - -> Relayer operators are expected to register a counterparty payee address, in order to be compensated accordingly with `RecvFee`s upon completion of a packet lifecycle. - -The counterparty payee address registered on the destination chain is encoded into the packet acknowledgement and communicated as such to the source chain for fee distribution. -**If a counterparty payee is not registered for the forward relayer on the destination chain, the escrowed fees will be refunded upon fee distribution.** - -### Relayer operator actions? - -A transaction must be submitted **to the destination chain** including a `CounterpartyPayee` address of an account on the source chain. -The transaction must be signed by the `Relayer`. - -Note: If a module account address is used as the `CounterpartyPayee` but the module has been set as a blocked address in the `BankKeeper`, the refunding to the module account will fail. This is because many modules use invariants to compare internal tracking of module account balances against the actual balance of the account stored in the `BankKeeper`. If a token transfer to the module account occurs without going through this module and updating the account balance of the module on the `BankKeeper`, then invariants may break and unknown behaviour could occur depending on the module implementation. Therefore, if it is desirable to use a module account that is currently blocked, the module developers should be consulted to gauge to possibility of removing the module account from the blocked list. - -```go -type MsgRegisterCounterpartyPayee struct { - // unique port identifier - PortId string - // unique channel identifier - ChannelId string - // the relayer address - Relayer string - // the counterparty payee address - CounterpartyPayee string -} -``` - -> This message is expected to fail if: -> -> - `PortId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). -> - `ChannelId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -> - `Relayer` is an invalid address (see [Cosmos SDK Addresses](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/beginner/03-accounts.md#addresses)). -> - `CounterpartyPayee` is empty. - -See below for an example CLI command: - -```bash -simd tx ibc-fee register-counterparty-payee transfer channel-0 \ -cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh \ -osmo1v5y0tz01llxzf4c2afml8s3awue0ymju22wxx2 \ ---from cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh -``` - -## Register an alternative payee address for reverse and timeout relaying - -As mentioned in [ICS29 Concepts](01-overview.md#concepts), the reverse relayer describes the actor who performs the submission of `MsgAcknowledgement` on the source chain. -Similarly the timeout relayer describes the actor who performs the submission of `MsgTimeout` (or `MsgTimeoutOnClose`) on the source chain. - -> Relayer operators **may choose** to register an optional payee address, in order to be compensated accordingly with `AckFee`s and `TimeoutFee`s upon completion of a packet life cycle. - -If a payee is not registered for the reverse or timeout relayer on the source chain, then fee distribution assumes the default behaviour, where fees are paid out to the relayer account which delivers `MsgAcknowledgement` or `MsgTimeout`/`MsgTimeoutOnClose`. - -### Relayer operator actions - -A transaction must be submitted **to the source chain** including a `Payee` address of an account on the source chain. -The transaction must be signed by the `Relayer`. - -Note: If a module account address is used as the `Payee` it is recommended to [turn off invariant checks](https://github.com/cosmos/ibc-go/blob/71d7480c923f4227453e8a80f51be01ae7ee845e/testing/simapp/app.go#L659) for that module. - -```go -type MsgRegisterPayee struct { - // unique port identifier - PortId string - // unique channel identifier - ChannelId string - // the relayer address - Relayer string - // the payee address - Payee string -} -``` - -> This message is expected to fail if: -> -> - `PortId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). -> - `ChannelId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -> - `Relayer` is an invalid address (see [Cosmos SDK Addresses](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/beginner/03-accounts.md#addresses)). -> - `Payee` is an invalid address (see [Cosmos SDK Addresses](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/beginner/03-accounts.md#addresses)). - -See below for an example CLI command: - -```bash -simd tx ibc-fee register-payee transfer channel-0 \ -cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh \ -cosmos153lf4zntqt33a4v0sm5cytrxyqn78q7kz8j8x5 \ ---from cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh -``` diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/05-events.md b/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/05-events.md deleted file mode 100644 index eddb296b70c..00000000000 --- a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/05-events.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: Events -sidebar_label: Events -sidebar_position: 5 -slug: /middleware/ics29-fee/events ---- - - -# Events - -:::note Synopsis -An overview of all events related to ICS-29 -::: - -## `MsgPayPacketFee`, `MsgPayPacketFeeAsync` - -| Type | Attribute Key | Attribute Value | -| ----------------------- | --------------- | --------------- | -| incentivized_ibc_packet | port_id | {portID} | -| incentivized_ibc_packet | channel_id | {channelID} | -| incentivized_ibc_packet | packet_sequence | {sequence} | -| incentivized_ibc_packet | recv_fee | {recvFee} | -| incentivized_ibc_packet | ack_fee | {ackFee} | -| incentivized_ibc_packet | timeout_fee | {timeoutFee} | -| message | module | fee-ibc | - -## `RegisterPayee` - -| Type | Attribute Key | Attribute Value | -| -------------- | ------------- | --------------- | -| register_payee | relayer | {relayer} | -| register_payee | payee | {payee} | -| register_payee | channel_id | {channelID} | -| message | module | fee-ibc | - -## `RegisterCounterpartyPayee` - -| Type | Attribute Key | Attribute Value | -| --------------------------- | ------------------ | ------------------- | -| register_counterparty_payee | relayer | {relayer} | -| register_counterparty_payee | counterparty_payee | {counterpartyPayee} | -| register_counterparty_payee | channel_id | {channelID} | -| message | module | fee-ibc | diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/06-end-users.md b/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/06-end-users.md deleted file mode 100644 index fbea38d0ded..00000000000 --- a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/06-end-users.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: End Users -sidebar_label: End Users -sidebar_position: 6 -slug: /middleware/ics29-fee/end-users ---- - - -# For end users - -:::note Synopsis -Learn how to incentivize IBC packets using the ICS29 Fee Middleware module. -::: - -## Pre-requisite readings - -- [Fee Middleware](01-overview.md) - -## Summary - -Different types of end users: - -- CLI users who want to manually incentivize IBC packets -- Client developers - -The Fee Middleware module allows end users to add a 'tip' to each IBC packet which will incentivize relayer operators to relay packets between chains. gRPC endpoints are exposed for client developers as well as a simple CLI for manually incentivizing IBC packets. - -## CLI Users - -For an in depth guide on how to use the ICS29 Fee Middleware module using the CLI please take a look at the [wiki](https://github.com/cosmos/ibc-go/wiki/Fee-enabled-fungible-token-transfers#asynchronous-incentivization-of-a-fungible-token-transfer) on the `ibc-go` repo. - -## Client developers - -Client developers can read more about the relevant ICS29 message types in the [Fee messages section](03-msgs.md). - -[CosmJS](https://github.com/cosmos/cosmjs) is a useful client library for signing and broadcasting Cosmos SDK messages. diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/_category_.json b/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/_category_.json deleted file mode 100644 index ddca8d29da6..00000000000 --- a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Fee Middleware", - "position": 1, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/images/feeflow.png b/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/images/feeflow.png deleted file mode 100644 index ba02071f4d8..00000000000 Binary files a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/images/feeflow.png and /dev/null differ diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/images/msgpaypacket.png b/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/images/msgpaypacket.png deleted file mode 100644 index 1bd5deb01fd..00000000000 Binary files a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/images/msgpaypacket.png and /dev/null differ diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/images/paypacketfeeasync.png b/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/images/paypacketfeeasync.png deleted file mode 100644 index 27c486a6f82..00000000000 Binary files a/docs/versioned_docs/version-v7.3.x/04-middleware/01-ics29-fee/images/paypacketfeeasync.png and /dev/null differ diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/01-overview.md b/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/01-overview.md deleted file mode 100644 index 70eefc31e7d..00000000000 --- a/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/01-overview.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 1 -slug: /middleware/callbacks/overview ---- - -# Overview - -Learn about what the Callbacks Middleware is, and how to build custom modules that utilize the Callbacks Middleware functionality {synopsis} - -## What is the Callbacks Middleware? - -IBC was designed with callbacks between core IBC and IBC applications. IBC apps would send a packet to core IBC, and receive a callback on every step of that packet's lifecycle. This allows IBC applications to be built on top of core IBC, and to be able to execute custom logic on packet lifecycle events (e.g. unescrow tokens for ICS-20). - -This setup worked well for off-chain users interacting with IBC applications. However, we are now seeing the desire for secondary applications (e.g. smart contracts, modules) to call into IBC apps as part of their state machine logic and then do some actions on packet lifecycle events. - -The Callbacks Middleware allows for this functionality by allowing the packets of the underlying IBC applications to register callbacks to secondary applications for lifecycle events. These callbacks are then executed by the Callbacks Middleware when the corresponding packet lifecycle event occurs. - -After much discussion, the design was expanded to [an ADR](/architecture/adr-008-app-caller-cbs), and the Callbacks Middleware is an implementation of that ADR. - -## Concepts - -Callbacks Middleware was built with smart contracts in mind, but can be used by any secondary application that wants to allow IBC packets to call into it. Think of the Callbacks Middleware as a bridge between core IBC and a secondary application. - -We have the following definitions: - -- `Underlying IBC application`: The IBC application that is wrapped by the Callbacks Middleware. This is the IBC application that is actually sending and receiving packet lifecycle events from core IBC. For example, the transfer module, or the ICA controller submodule. -- `IBC Actor`: IBC Actor is an on-chain or off-chain entity that can initiate a packet on the underlying IBC application. For example, a smart contract, an off-chain user, or a module that sends a transfer packet are all IBC Actors. -- `Secondary application`: The application that is being called into by the Callbacks Middleware for packet lifecycle events. This is the application that is receiving the callback directly from the Callbacks Middleware module. For example, the `x/wasm` module. -- `Callback Actor`: The on-chain smart contract or module that is registered to receive callbacks from the secondary application. For example, a Wasm smart contract (gatekeeped by the `x/wasm` module). Note that the Callback Actor is not necessarily the same as the IBC Actor. For example, an off-chain user can initiate a packet on the underlying IBC application, but the Callback Actor could be a smart contract. The secondary application may want to check that the IBC Actor is allowed to call into the Callback Actor, for example, by checking that the IBC Actor is the same as the Callback Actor. -- `Callback Address`: Address of the Callback Actor. This is the address that the secondary application will call into when a packet lifecycle event occurs. For example, the address of the Wasm smart contract. -- `Maximum gas limit`: The maximum amount of gas that the Callbacks Middleware will allow the secondary application to use when it executes its custom logic. -- `User defined gas limit`: The amount of gas that the IBC Actor wants to allow the secondary application to use when it executes its custom logic. This is the gas limit that the IBC Actor specifies when it sends a packet to the underlying IBC application. This cannot be greater than the maximum gas limit. - -Think of the secondary application as a bridge between the Callbacks Middleware and the Callback Actor. The secondary application is responsible for executing the custom logic of the Callback Actor when a packet lifecycle event occurs. The secondary application is also responsible for checking that the IBC Actor is allowed to call into the Callback Actor. - -Note that it is possible that the IBC Actor, Secondary Application, and Callback Actor are all the same entity. In which case, the Callback Address should be the secondary application's module address. - -The following diagram shows how a typical `RecvPacket`, `AcknowledgementPacket`, and `TimeoutPacket` execution flow would look like: -![callbacks-middleware](./images/callbackflow.svg) - -And the following diagram shows how a typical `SendPacket` and `WriteAcknowledgement` execution flow would look like: -![callbacks-middleware](./images/ics4-callbackflow.svg) - -## Known Limitations - -- Callbacks are always executed after the underlying IBC application has executed its logic. -- Maximum gas limit is hardcoded manually during wiring. It requires a coordinated upgrade to change the maximum gas limit. -- The receive packet callback does not pass the relayer address to the secondary application. This is so that we can use the same callback for both synchronous and asynchronous acknowledgements. -- The receive packet callback does not pass IBC Actor's address, this is because the IBC Actor lives in the counterparty chain and cannot be trusted. diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/02-integration.md b/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/02-integration.md deleted file mode 100644 index 3796c559e40..00000000000 --- a/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/02-integration.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: Integration -sidebar_label: Integration -sidebar_position: 2 -slug: /middleware/callbacks/integration ---- - -# Integration - -Learn how to integrate the callbacks middleware with IBC applications. The following document is intended for developers building on top of the Cosmos SDK and only applies for Cosmos SDK chains. {synopsis} - -The callbacks middleware is a minimal and stateless implementation of the IBC middleware interface. It does not have a keeper, nor does it store any state. It simply routes IBC middleware messages to the appropriate callback function, which is implemented by the secondary application. Therefore, it doesn't need to be registered as a module, nor does it need to be added to the module manager. It only needs to be added to the IBC application stack. - -## Pre-requisite Readings - -- [IBC middleware development](../../01-ibc/04-middleware/01-develop.md) -- [IBC middleware integration](../../01-ibc/04-middleware/02-integration.md) - -The callbacks middleware, as the name suggests, plays the role of an IBC middleware and as such must be configured by chain developers to route and handle IBC messages correctly. -For Cosmos SDK chains this setup is done via the `app/app.go` file, where modules are constructed and configured in order to bootstrap the blockchain application. - -## Configuring an application stack with the callbacks middleware - -As mentioned in [IBC middleware development](../../01-ibc/04-middleware/01-develop.md) an application stack may be composed of many or no middlewares that nest a base application. -These layers form the complete set of application logic that enable developers to build composable and flexible IBC application stacks. -For example, an application stack may just be a single base application like `transfer`, however, the same application stack composed with `29-fee` and `callbacks` will nest the `transfer` base application twice by wrapping it with the Fee Middleware module and then callbacks middleware. - -The callbacks middleware also **requires** a secondary application that will receive the callbacks to implement the [`ContractKeeper`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/apps/callbacks/types/expected_keepers.go#L11-L83). Since the wasm module does not yet support the callbacks middleware, we will use the `mockContractKeeper` module in the examples below. You should replace this with a module that implements `ContractKeeper`. - -### Transfer - -See below for an example of how to create an application stack using `transfer`, `29-fee`, and `callbacks`. Feel free to omit the `29-fee` middleware if you do not want to use it. -The following `transferStack` is configured in `app/app.go` and added to the IBC `Router`. -The in-line comments describe the execution flow of packets between the application stack and IBC core. - -```go -// Create Transfer Stack -// SendPacket, since it is originating from the application to core IBC: -// transferKeeper.SendPacket -> callbacks.SendPacket -> fee.SendPacket -> channel.SendPacket - -// RecvPacket, message that originates from core IBC and goes down to app, the flow is the other way -// channel.RecvPacket -> callbacks.OnRecvPacket -> fee.OnRecvPacket -> transfer.OnRecvPacket - -// transfer stack contains (from top to bottom): -// - IBC Callbacks Middleware -// - IBC Fee Middleware -// - Transfer - -// create IBC module from bottom to top of stack -var transferStack porttypes.IBCModule -transferStack = transfer.NewIBCModule(app.TransferKeeper) -transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) -// maxCallbackGas is a hard-coded value that is passed to the callbacks middleware -transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCFeeKeeper, app.MockContractKeeper, maxCallbackGas) -// Since the callbacks middleware itself is an ics4wrapper, it needs to be passed to the transfer keeper -app.TransferKeeper.WithICS4Wrapper(transferStack.(porttypes.ICS4Wrapper)) - -// Add transfer stack to IBC Router -ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) -``` - -::: warning -The usage of `WithICS4Wrapper` after `transferStack`'s configuration is critical! It allows the callbacks middleware to do `SendPacket` callbacks and asynchronous `ReceivePacket` callbacks. You must do this regardless of whether you are using the `29-fee` middleware or not. -::: - -### Interchain Accounts Controller - -```go -// Create Interchain Accounts Stack -// SendPacket, since it is originating from the application to core IBC: -// icaControllerKeeper.SendTx -> callbacks.SendPacket -> fee.SendPacket -> channel.SendPacket - -var icaControllerStack porttypes.IBCModule -icaControllerStack = icacontroller.NewIBCMiddleware(nil, app.ICAControllerKeeper) -icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) -// maxCallbackGas is a hard-coded value that is passed to the callbacks middleware -icaControllerStack = ibccallbacks.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper, app.MockContractKeeper, maxCallbackGas) -// Since the callbacks middleware itself is an ics4wrapper, it needs to be passed to the ica controller keeper -app.ICAControllerKeeper.WithICS4Wrapper(icaControllerStack.(porttypes.ICS4Wrapper)) - -// RecvPacket, message that originates from core IBC and goes down to app, the flow is: -// channel.RecvPacket -> callbacks.OnRecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket - -var icaHostStack porttypes.IBCModule -icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) -icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) - -// Add ICA host and controller to IBC router ibcRouter. -AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). -AddRoute(icahosttypes.SubModuleName, icaHostStack). -``` - -::: warning -The usage of `WithICS4Wrapper` here is also critical! -::: diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/03-interfaces.md b/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/03-interfaces.md deleted file mode 100644 index 0c05b1bb27b..00000000000 --- a/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/03-interfaces.md +++ /dev/null @@ -1,151 +0,0 @@ ---- -title: Interfaces -sidebar_label: Interfaces -sidebar_position: 3 -slug: /middleware/callbacks/interfaces ---- - -# Interfaces - -The callbacks middleware requires certain interfaces to be implemented by the underlying IBC applications and the secondary application. If you're simply wiring up the callbacks middleware to an existing IBC application stack and a secondary application such as `icacontroller` and `x/wasm`, you can skip this section. - -## Interfaces for developing the Underlying IBC Application - -### `PacketDataUnmarshaler` - -```go -// PacketDataUnmarshaler defines an optional interface which allows a middleware to -// request the packet data to be unmarshaled by the base application. -type PacketDataUnmarshaler interface { - // UnmarshalPacketData unmarshals the packet data into a concrete type - UnmarshalPacketData([]byte) (interface{}, error) -} -``` - -The callbacks middleware **requires** the underlying ibc application to implement the [`PacketDataUnmarshaler`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/core/05-port/types/module.go#L142-L147) interface so that it can unmarshal the packet data bytes into the appropriate packet data type. This allows usage of interface functions implemented by the packet data type. The packet data type is expected to implement the `PacketDataProvider` interface (see section below), which is used to parse the callback data that is currently stored in the packet memo field for `transfer` and `ica` packets as a JSON string. See its implementation in the [`transfer`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/apps/transfer/ibc_module.go#L303-L313) and [`icacontroller`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/apps/27-interchain-accounts/controller/ibc_middleware.go#L258-L268) modules for reference. - -If the underlying application is a middleware itself, then it can implement this interface by simply passing the function call to its underlying application. See its implementation in the [`fee middleware`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/apps/29-fee/ibc_middleware.go#L368-L378) for reference. - -### `PacketDataProvider` - -```go -// PacketDataProvider defines an optional interfaces for retrieving custom packet data stored on behalf of another application. -// An existing problem in the IBC middleware design is the inability for a middleware to define its own packet data type and insert packet sender provided information. -// A short term solution was introduced into several application's packet data to utilize a memo field to carry this information on behalf of another application. -// This interfaces standardizes that behaviour. Upon realization of the ability for middleware's to define their own packet data types, this interface will be deprecated and removed with time. -type PacketDataProvider interface { - // GetCustomPacketData returns the packet data held on behalf of another application. - // The name the information is stored under should be provided as the key. - // If no custom packet data exists for the key, nil should be returned. - GetCustomPacketData(key string) interface{} -} -``` - -The callbacks middleware also **requires** the underlying ibc application's packet data type to implement the [`PacketDataProvider`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/core/exported/packet.go#L43-L52) interface. This interface is used to retrieve the callback data from the packet data (using the memo field in the case of `transfer` and `ica`). For example, see its implementation in the [`transfer`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/apps/transfer/types/packet.go#L85-L105) module. - -Since middlewares do not have packet types, they do not need to implement this interface. - -### `PacketData` - -```go -// PacketData defines an optional interface which an application's packet data structure may implement. -type PacketData interface { - // GetPacketSender returns the sender address of the packet data. - // If the packet sender is unknown or undefined, an empty string should be returned. - GetPacketSender(sourcePortID string) string -} -``` - -[`PacketData`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/core/exported/packet.go#L36-L41) is an optional interface that can be implemented by the underlying ibc application's packet data type. It is used to retrieve the packet sender address from the packet data. The callbacks middleware uses this interface to retrieve the packet sender address and pass it to the callback function during a source callback. If this interface is not implemented, then the callbacks middleware passes and empty string as the sender address. For example, see its implementation in the [`transfer`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/apps/transfer/types/packet.go#L74-L83) and [`ica`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/apps/27-interchain-accounts/types/packet.go#L78-L92) module. - -This interface was added so that secondary applications can retrieve the packet sender address to perform custom authorization logic if needed. - -Since middlewares do not have packet types, they do not need to implement this interface. - -## Interfaces for developing the Secondary Application - -### `ContractKeeper` - -The callbacks middleware requires the secondary application to implement the [`ContractKeeper`](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/apps/callbacks/types/expected_keepers.go#L11-L83) interface. The contract keeper will be invoked at each step of the packet lifecycle. When a packet is sent, if callback information is provided, the contract keeper will be invoked via the `IBCSendPacketCallback`. This allows the contract keeper to prevent packet sends when callback information is provided, for example if the sender is unauthroized to perform callbacks on the given information. If the packet send is successful, the contract keeper on the destination (if present) will be invoked when a packet has been received and the acknowledgement is written, this will occur via `IBCReceivePacketCallback`. At the end of the packet lifecycle, when processing acknowledgements or timeouts, the source contract keeper will be invoked either via `IBCOnAcknowledgementPacket` or `IBCOnTimeoutPacket`. Once a packet has been sent, each step of the packet lifecycle can be processed given that a relayer sets the gas limit to be more than or equal to the required `CommitGasLimit`. State changes performed in the callback will only be committed upon successful execution. - -```go -// ContractKeeper defines the entry points exposed to the VM module which invokes a smart contract -type ContractKeeper interface { - // IBCSendPacketCallback is called in the source chain when a PacketSend is executed. The - // packetSenderAddress is determined by the underlying module, and may be empty if the sender is - // unknown or undefined. The contract is expected to handle the callback within the user defined - // gas limit, and handle any errors, or panics gracefully. - // This entry point is called with a cached context. If an error is returned, then the changes in - // this context will not be persisted, and the error will be propagated to the underlying IBC - // application, resulting in a packet send failure. - // - // Implementations are provided with the packetSenderAddress and MAY choose to use this to perform - // validation on the origin of a given packet. It is recommended to perform the same validation - // on all source chain callbacks (SendPacket, AcknowledgementPacket, TimeoutPacket). This - // defensively guards against exploits due to incorrectly wired SendPacket ordering in IBC stacks. - IBCSendPacketCallback( - cachedCtx sdk.Context, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - packetData []byte, - contractAddress, - packetSenderAddress string, - ) error - // IBCOnAcknowledgementPacketCallback is called in the source chain when a packet acknowledgement - // is received. The packetSenderAddress is determined by the underlying module, and may be empty if - // the sender is unknown or undefined. The contract is expected to handle the callback within the - // user defined gas limit, and handle any errors, or panics gracefully. - // This entry point is called with a cached context. If an error is returned, then the changes in - // this context will not be persisted, but the packet lifecycle will not be blocked. - // - // Implementations are provided with the packetSenderAddress and MAY choose to use this to perform - // validation on the origin of a given packet. It is recommended to perform the same validation - // on all source chain callbacks (SendPacket, AcknowledgementPacket, TimeoutPacket). This - // defensively guards against exploits due to incorrectly wired SendPacket ordering in IBC stacks. - IBCOnAcknowledgementPacketCallback( - cachedCtx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - relayer sdk.AccAddress, - contractAddress, - packetSenderAddress string, - ) error - // IBCOnTimeoutPacketCallback is called in the source chain when a packet is not received before - // the timeout height. The packetSenderAddress is determined by the underlying module, and may be - // empty if the sender is unknown or undefined. The contract is expected to handle the callback - // within the user defined gas limit, and handle any error, out of gas, or panics gracefully. - // This entry point is called with a cached context. If an error is returned, then the changes in - // this context will not be persisted, but the packet lifecycle will not be blocked. - // - // Implementations are provided with the packetSenderAddress and MAY choose to use this to perform - // validation on the origin of a given packet. It is recommended to perform the same validation - // on all source chain callbacks (SendPacket, AcknowledgementPacket, TimeoutPacket). This - // defensively guards against exploits due to incorrectly wired SendPacket ordering in IBC stacks. - IBCOnTimeoutPacketCallback( - cachedCtx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, - contractAddress, - packetSenderAddress string, - ) error - // IBCReceivePacketCallback is called in the destination chain when a packet acknowledgement is written. - // The contract is expected to handle the callback within the user defined gas limit, and handle any errors, - // out of gas, or panics gracefully. - // This entry point is called with a cached context. If an error is returned, then the changes in - // this context will not be persisted, but the packet lifecycle will not be blocked. - IBCReceivePacketCallback( - cachedCtx sdk.Context, - packet ibcexported.PacketI, - ack ibcexported.Acknowledgement, - contractAddress string, - ) error -} -``` - -These are the callback entry points exposed to the secondary application. The secondary application is expected to execute its custom logic within these entry points. The callbacks middleware will handle the execution of these callbacks and revert the state if needed. - -:::tip -Note that the source callback entry points are provided with the `packetSenderAddress` and MAY choose to use this to perform validation on the origin of a given packet. It is recommended to perform the same validation on all source chain callbacks (SendPacket, AcknowledgePacket, TimeoutPacket). This defensively guards against exploits due to incorrectly wired SendPacket ordering in IBC stacks. -::: diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/04-events.md b/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/04-events.md deleted file mode 100644 index c7711100fb7..00000000000 --- a/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/04-events.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Events -sidebar_label: Events -sidebar_position: 4 -slug: /middleware/callbacks/events ---- - -# Events - -An overview of all events related to the callbacks middleware. There are two types of events, `"ibc_src_callback"` and `"ibc_dest_callback"`. - -## Shared Attributes - -Both of these event types share the following attributes: - -| **Attribute Key** | **Attribute Values** | **Optional** | -|:-------------------------:|:---------------------------------------------------------------------------------------:|:------------------:| -| module | "ibccallbacks" | | -| callback_type | **One of**: "send_packet", "acknowledgement_packet", "timeout_packet", "receive_packet" | | -| callback_address | string | | -| callback_exec_gas_limit | string (parsed from uint64) | | -| callback_commit_gas_limit | string (parsed from uint64) | | -| packet_sequence | string (parsed from uint64) | | -| callback_result | **One of**: "success", "failure" | | -| callback_error | string (parsed from callback err) | Yes, if err != nil | - -## `ibc_src_callback` Attributes - -| **Attribute Key** | **Attribute Values** | -|:------------------:|:------------------------:| -| packet_src_port | string (sourcePortID) | -| packet_src_channel | string (sourceChannelID) | - -## `ibc_dest_callback` Attributes - -| **Attribute Key** | **Attribute Values** | -|:-------------------:|:------------------------:| -| packet_dest_port | string (destPortID) | -| packet_dest_channel | string (destChannelID) | diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/05-end-users.md b/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/05-end-users.md deleted file mode 100644 index f2500ae3c05..00000000000 --- a/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/05-end-users.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: End Users -sidebar_label: End Users -sidebar_position: 5 -slug: /middleware/callbacks/end-users ---- - -# Usage - -This section explains how to use the callbacks middleware from the perspective of an IBC Actor. Callbacks middleware provides two types of callbacks: - -- Source callbacks: - - `SendPacket` callback - - `OnAcknowledgementPacket` callback - - `OnTimeoutPacket` callback -- Destination callbacks: - - `ReceivePacket` callback - -For a given channel, the source callbacks are supported if the source chain has the callbacks middleware wired up in the channel's IBC stack. Similarly, the destination callbacks are supported if the destination chain has the callbacks middleware wired up in the channel's IBC stack. - -::: tip -Callbacks are always executed after the packet has been processed by the underlying IBC module. -::: - -::: warning -If the underlying application module is doing an asynchronous acknowledgement on packet receive (for example, if the [packet forward middleware](https://github.com/cosmos/ibc-apps/tree/main/middleware/packet-forward-middleware) is in the stack, and is being used by this packet), then the callbacks middleware will execute the `ReceivePacket` callback after the acknowledgement has been received. -::: - -## Source Callbacks - -Source callbacks are natively supported in the following ibc modules (if they are wrapped by the callbacks middleware): - -- `transfer` -- `icacontroller` - -To have your source callbacks be processed by the callbacks middleware, you must set the memo in the application's packet data to the following format: - -```jsonc -{ - "src_callback": { - "address": "callbackAddressString", - // optional - "gas_limit": "userDefinedGasLimitString", - } -} -``` - -## Destination Callbacks - -Destination callbacks are natively only supported in the transfer module. Note that wrapping icahost is not supported. This is because icahost should be able to execute an arbitrary transaction anyway, and can call contracts or modules directly. - -To have your destination callbacks processed by the callbacks middleware, you must set the memo in the application's packet data to the following format: - -```jsonc -{ - "dest_callback": { - "address": "callbackAddressString", - // optional - "gas_limit": "userDefinedGasLimitString", - } -} -``` - -Note that a packet can have both a source and destination callback. - -```jsonc -{ - "src_callback": { - "address": "callbackAddressString", - // optional - "gas_limit": "userDefinedGasLimitString", - }, - "dest_callback": { - "address": "callbackAddressString", - // optional - "gas_limit": "userDefinedGasLimitString", - } -} -``` - -# User Defined Gas Limit - -User defined gas limit was added for the following reasons: - -- To prevent callbacks from blocking packet lifecycle. -- To prevent relayers from being able to DOS the callback execution by sending a packet with a low amount of gas. - -::: tip -There is a chain wide parameter that sets the maximum gas limit that a user can set for a callback. This is to prevent a user from setting a gas limit that is too high for relayers. If the `"gas_limit"` is not set in the packet memo, then the maximum gas limit is used. -::: - -These goals are achieved by creating a minimum gas amount required for callback execution. If the relayer provides at least the minimum gas limit for the callback execution, then the packet lifecycle will not be blocked if the callback runs out of gas during execution, and the callback cannot be retried. If the relayer does not provided the minimum amount of gas and the callback executions runs out of gas, the entire tx is reverted and it may be executed again. - -::: tip -`SendPacket` callback is always reverted if the callback execution fails or returns an error for any reason. This is so that the packet is not sent if the callback execution fails. -::: diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/06-gas.md b/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/06-gas.md deleted file mode 100644 index d9637c58344..00000000000 --- a/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/06-gas.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: Gas Management -sidebar_label: Gas Management -sidebar_position: 6 -slug: /middleware/callbacks/gas ---- - -# Gas Management - -## Overview - -Executing arbitrary code on a chain can be arbitrarily expensive. In general, a callback may consume infinite gas (think of a callback that loops forever). This is problematic for a few reasons: - -- It can block the packet lifecycle. -- It can be used to consume all of the relayer's funds and gas. -- A relayer can DOS the callback execution by sending a packet with a low amount of gas. - -To prevent these, the callbacks middleware introduces two gas limits: a chain wide gas limit (`maxCallbackGas`) and a user defined gas limit. - -### Chain Wide Gas Limit - -Since the callbacks middleware does not have a keeper, it does not use a governance parameter to set the chain wide gas limit. Instead, the chain wide gas limit is passed in as a parameter to the callbacks middleware during initialization. - -```go -// app.go - -maxCallbackGas := uint64(1_000_000) - -var transferStack porttypes.IBCModule -transferStack = transfer.NewIBCModule(app.TransferKeeper) -transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) -transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCFeeKeeper, app.MockContractKeeper, maxCallbackGas) -// Since the callbacks middleware itself is an ics4wrapper, it needs to be passed to the transfer keeper -app.TransferKeeper.WithICS4Wrapper(transferStack.(porttypes.ICS4Wrapper)) - -// Add transfer stack to IBC Router -ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) -``` - -### User Defined Gas Limit - -The user defined gas limit is set by the IBC Actor during packet creation. The user defined gas limit is set in the packet memo. If the user defined gas limit is not set or if the user defined gas limit is greater than the chain wide gas limit, then the chain wide gas limit is used as the user defined gas limit. - -```jsonc -{ - "src_callback": { - "address": "callbackAddressString", - // optional - "gas_limit": "userDefinedGasLimitString", - }, - "dest_callback": { - "address": "callbackAddressString", - // optional - "gas_limit": "userDefinedGasLimitString", - } -} -``` - -## Gas Limit Enforcement - -During a callback execution, there are three types of gas limits that are enforced: - -- User defined gas limit -- Chain wide gas limit -- Context gas limit (amount of gas that the relayer has left for this execution) - -Chain wide gas limit is used as a maximum to the user defined gas limit as explained in the [previous section](#user-defined-gas-limit). It may also be used as a default value if no user gas limit is provided. Therefore, we can ignore the chain wide gas limit for the rest of this section and work with the minimum of the chain wide gas limit and user defined gas limit. This minimum is called the commit gas limit. - -The gas limit enforcement is done by executing the callback inside a cached context with a new gas meter. The gas meter is initialized with the minimum of the commit gas limit and the context gas limit. This minimum is called the execution gas limit. We say that retries are allowed if `context gas limit < commit gas limit`. Otherwise, we say that retries are not allowed. - -If the callback execution fails due to an out of gas error, then the middleware checks if retries are allowed. If retries are not allowed, then it recovers from the out of gas error, consumes execution gas limit from the original context, and continues with the packet life cycle. If retries are allowed, then it panics with an out of gas error to revert the entire tx. The packet can then be submitted again with a higher gas limit. The out of gas panic descriptor is shown below. - -```go -fmt.Sprintf("ibc %s callback out of gas; commitGasLimit: %d", callbackType, callbackData.CommitGasLimit)} -``` - -If the callback execution does not fail due to an out of gas error then the callbacks middleware does not block the packet life cycle regardless of whether retries are allowed or not. diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/_category_.json b/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/_category_.json deleted file mode 100644 index 06ae30acec9..00000000000 --- a/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Callbacks Middleware", - "position": 2, - "link": null -} diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/images/callbackflow.svg b/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/images/callbackflow.svg deleted file mode 100644 index 2323889b7c9..00000000000 --- a/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/images/callbackflow.svg +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/images/ics4-callbackflow.svg b/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/images/ics4-callbackflow.svg deleted file mode 100644 index 032a83f7662..00000000000 --- a/docs/versioned_docs/version-v7.3.x/04-middleware/02-callbacks/images/ics4-callbackflow.svg +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/versioned_docs/version-v7.3.x/04-middleware/_category_.json b/docs/versioned_docs/version-v7.3.x/04-middleware/_category_.json deleted file mode 100644 index 72f60663bf3..00000000000 --- a/docs/versioned_docs/version-v7.3.x/04-middleware/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "IBC Middleware Modules", - "position": 4, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v7.3.x/05-migrations/01-support-denoms-with-slashes.md b/docs/versioned_docs/version-v7.3.x/05-migrations/01-support-denoms-with-slashes.md deleted file mode 100644 index 54bbd96227e..00000000000 --- a/docs/versioned_docs/version-v7.3.x/05-migrations/01-support-denoms-with-slashes.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: Support transfer of coins whose base denom contains slashes -sidebar_label: Support transfer of coins whose base denom contains slashes -sidebar_position: 1 -slug: /migrations/support-denoms-with-slashes ---- -# Migrating from not supporting base denoms with slashes to supporting base denoms with slashes - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -This document is necessary when chains are upgrading from a version that does not support base denoms with slashes (e.g. v3.0.0) to a version that does (e.g. v3.2.0). All versions of ibc-go smaller than v1.5.0 for the v1.x release line, v2.3.0 for the v2.x release line, and v3.1.0 for the v3.x release line do **NOT** support IBC token transfers of coins whose base denoms contain slashes. Therefore the in-place of genesis migration described in this document are required when upgrading. - -If a chain receives coins of a base denom with slashes before it upgrades to supporting it, the receive may pass however the trace information will be incorrect. - -E.g. If a base denom of `testcoin/testcoin/testcoin` is sent to a chain that does not support slashes in the base denom, the receive will be successful. However, the trace information stored on the receiving chain will be: `Trace: "transfer/{channel-id}/testcoin/testcoin", BaseDenom: "testcoin"`. - -This incorrect trace information must be corrected when the chain does upgrade to fully supporting denominations with slashes. - -To do so, chain binaries should include a migration script that will run when the chain upgrades from not supporting base denominations with slashes to supporting base denominations with slashes. - -## Chains - -### ICS20 - Transfer - -The transfer module will now support slashes in base denoms, so we must iterate over current traces to check if any of them are incorrectly formed and correct the trace information. - -### Upgrade Proposal - -```go -app.UpgradeKeeper.SetUpgradeHandler("MigrateTraces", - func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - // transfer module consensus version has been bumped to 2 - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) - -``` - -This is only necessary if there are denom traces in the store with incorrect trace information from previously received coins that had a slash in the base denom. However, it is recommended that any chain upgrading to support base denominations with slashes runs this code for safety. - -For a more detailed sample, please check out the code changes in [this pull request](https://github.com/cosmos/ibc-go/pull/1680). - -### Genesis Migration - -If the chain chooses to add support for slashes in base denoms via genesis export, then the trace information must be corrected during genesis migration. - -The migration code required may look like: - -```go -func migrateGenesisSlashedDenomsUpgrade(appState genutiltypes.AppMap, clientCtx client.Context, genDoc *tmtypes.GenesisDoc) (genutiltypes.AppMap, error) { - if appState[ibctransfertypes.ModuleName] != nil { - transferGenState := &ibctransfertypes.GenesisState{} - clientCtx.Codec.MustUnmarshalJSON(appState[ibctransfertypes.ModuleName], transferGenState) - - substituteTraces := make([]ibctransfertypes.DenomTrace, len(transferGenState.DenomTraces)) - for i, dt := range transferGenState.DenomTraces { - // replace all previous traces with the latest trace if validation passes - // note most traces will have same value - newTrace := ibctransfertypes.ParseDenomTrace(dt.GetFullDenomPath()) - - if err := newTrace.Validate(); err != nil { - substituteTraces[i] = dt - } else { - substituteTraces[i] = newTrace - } - } - - transferGenState.DenomTraces = substituteTraces - - // delete old genesis state - delete(appState, ibctransfertypes.ModuleName) - - // set new ibc transfer genesis state - appState[ibctransfertypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(transferGenState) - } - - return appState, nil -} -``` - -For a more detailed sample, please check out the code changes in [this pull request](https://github.com/cosmos/ibc-go/pull/1528). diff --git a/docs/versioned_docs/version-v7.3.x/05-migrations/02-sdk-to-v1.md b/docs/versioned_docs/version-v7.3.x/05-migrations/02-sdk-to-v1.md deleted file mode 100644 index f979034e272..00000000000 --- a/docs/versioned_docs/version-v7.3.x/05-migrations/02-sdk-to-v1.md +++ /dev/null @@ -1,195 +0,0 @@ ---- -title: SDK v0.43 to IBC-Go v1 -sidebar_label: SDK v0.43 to IBC-Go v1 -sidebar_position: 2 -slug: /migrations/sdk-to-v1 ---- -# Migrating to ibc-go - -This file contains information on how to migrate from the IBC module contained in the SDK 0.41.x and 0.42.x lines to the IBC module in the ibc-go repository based on the 0.44 SDK version. - -## Import Changes - -The most obvious changes is import name changes. We need to change: - -- applications -> apps -- cosmos-sdk/x/ibc -> ibc-go - -On my GNU/Linux based machine I used the following commands, executed in order: - -```bash -grep -RiIl 'cosmos-sdk\/x\/ibc\/applications' | xargs sed -i 's/cosmos-sdk\/x\/ibc\/applications/ibc-go\/modules\/apps/g' -``` - -```bash -grep -RiIl 'cosmos-sdk\/x\/ibc' | xargs sed -i 's/cosmos-sdk\/x\/ibc/ibc-go\/modules/g' -``` - -ref: [explanation of the above commands](https://www.internalpointers.com/post/linux-find-and-replace-text-multiple-files) - -Executing these commands out of order will cause issues. - -Feel free to use your own method for modifying import names. - -NOTE: Updating to the `v0.44.0` SDK release and then running `go mod tidy` will cause a downgrade to `v0.42.0` in order to support the old IBC import paths. -Update the import paths before running `go mod tidy`. - -## Chain Upgrades - -Chains may choose to upgrade via an upgrade proposal or genesis upgrades. Both in-place store migrations and genesis migrations are supported. - -**WARNING**: Please read at least the quick guide for [IBC client upgrades](../01-ibc/05-upgrades/00-intro.md) before upgrading your chain. It is highly recommended you do not change the chain-ID during an upgrade, otherwise you must follow the IBC client upgrade instructions. - -Both in-place store migrations and genesis migrations will: - -- migrate the solo machine client state from v1 to v2 protobuf definitions -- prune all solo machine consensus states -- prune all expired tendermint consensus states - -Chains must set a new connection parameter during either in place store migrations or genesis migration. The new parameter, max expected block time, is used to enforce packet processing delays on the receiving end of an IBC packet flow. Checkout the [docs](https://github.com/cosmos/ibc-go/blob/release/v1.0.x/docs/ibc/proto-docs.md#params-2) for more information. - -### In-Place Store Migrations - -The new chain binary will need to run migrations in the upgrade handler. The fromVM (previous module version) for the IBC module should be 1. This will allow migrations to be run for IBC updating the version from 1 to 2. - -Ex: - -```go -app.UpgradeKeeper.SetUpgradeHandler("my-upgrade-proposal", - func(ctx sdk.Context, _ upgradetypes.Plan, _ module.VersionMap) (module.VersionMap, error) { - // set max expected block time parameter. Replace the default with your expected value - // https://github.com/cosmos/ibc-go/blob/release/v1.0.x/docs/ibc/proto-docs.md#params-2 - app.IBCKeeper.ConnectionKeeper.SetParams(ctx, ibcconnectiontypes.DefaultParams()) - - fromVM := map[string]uint64{ - ... // other modules - "ibc": 1, - ... - } - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) - -``` - -### Genesis Migrations - -To perform genesis migrations, the following code must be added to your existing migration code. - -```go -// add imports as necessary -import ( - ibcv100 "github.com/cosmos/ibc-go/modules/core/legacy/v100" - ibchost "github.com/cosmos/ibc-go/modules/core/24-host" -) - -... - -// add in migrate cmd function -// expectedTimePerBlock is a new connection parameter -// https://github.com/cosmos/ibc-go/blob/release/v1.0.x/docs/ibc/proto-docs.md#params-2 -newGenState, err = ibcv100.MigrateGenesis(newGenState, clientCtx, *genDoc, expectedTimePerBlock) -if err != nil { - return err -} -``` - -**NOTE:** The genesis chain-id, time and height MUST be updated before migrating IBC, otherwise the tendermint consensus state will not be pruned. - -## IBC Keeper Changes - -The IBC Keeper now takes in the Upgrade Keeper. Please add the chains' Upgrade Keeper after the Staking Keeper: - -```diff - // Create IBC Keeper - app.IBCKeeper = ibckeeper.NewKeeper( -- appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, scopedIBCKeeper, -+ appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper, - ) - -``` - -## Proposals - -### UpdateClientProposal - -The `UpdateClient` has been modified to take in two client-identifiers and one initial height. Please see the [documentation](../01-ibc/06-proposals.md) for more information. - -### UpgradeProposal - -A new IBC proposal type has been added, `UpgradeProposal`. This handles an IBC (breaking) Upgrade. -The previous `UpgradedClientState` field in an Upgrade `Plan` has been deprecated in favor of this new proposal type. - -### Proposal Handler Registration - -The `ClientUpdateProposalHandler` has been renamed to `ClientProposalHandler`. -It handles both `UpdateClientProposal`s and `UpgradeProposal`s. - -Add this import: - -```diff -+ ibcclienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" -``` - -Please ensure the governance module adds the correct route: - -```diff -- AddRoute(ibchost.RouterKey, ibcclient.NewClientUpdateProposalHandler(app.IBCKeeper.ClientKeeper)) -+ AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)) -``` - -NOTE: Simapp registration was incorrect in the 0.41.x releases. The `UpdateClient` proposal handler should be registered with the router key belonging to `ibc-go/core/02-client/types` -as shown in the diffs above. - -### Proposal CLI Registration - -Please ensure both proposal type CLI commands are registered on the governance module by adding the following arguments to `gov.NewAppModuleBasic()`: - -Add the following import: - -```diff -+ ibcclientclient "github.com/cosmos/ibc-go/modules/core/02-client/client" -``` - -Register the cli commands: - -```diff - gov.NewAppModuleBasic( - paramsclient.ProposalHandler, distrclient.ProposalHandler, upgradeclient.ProposalHandler, upgradeclient.CancelProposalHandler, -+ ibcclientclient.UpdateClientProposalHandler, ibcclientclient.UpgradeProposalHandler, - ), -``` - -REST routes are not supported for these proposals. - -## Proto file changes - -The gRPC querier service endpoints have changed slightly. The previous files used `v1beta1` gRPC route, this has been updated to `v1`. - -The solo machine has replaced the FrozenSequence uint64 field with a IsFrozen boolean field. The package has been bumped from `v1` to `v2` - -## IBC callback changes - -### OnRecvPacket - -Application developers need to update their `OnRecvPacket` callback logic. - -The `OnRecvPacket` callback has been modified to only return the acknowledgement. The acknowledgement returned must implement the `Acknowledgement` interface. The acknowledgement should indicate if it represents a successful processing of a packet by returning true on `Success()` and false in all other cases. A return value of false on `Success()` will result in all state changes which occurred in the callback being discarded. More information can be found in the [documentation](../01-ibc/03-apps/02-ibcmodule.md#receiving-packets). - -The `OnRecvPacket`, `OnAcknowledgementPacket`, and `OnTimeoutPacket` callbacks are now passed the `sdk.AccAddress` of the relayer who relayed the IBC packet. Applications may use or ignore this information. - -## IBC Event changes - -The `packet_data` attribute has been deprecated in favor of `packet_data_hex`, in order to provide standardized encoding/decoding of packet data in events. While the `packet_data` event still exists, all relayers and IBC Event consumers are strongly encouraged to switch over to using `packet_data_hex` as soon as possible. - -The `packet_ack` attribute has also been deprecated in favor of `packet_ack_hex` for the same reason stated above. All relayers and IBC Event consumers are strongly encouraged to switch over to using `packet_ack_hex` as soon as possible. - -The `consensus_height` attribute has been removed in the Misbehaviour event emitted. IBC clients no longer have a frozen height and misbehaviour does not necessarily have an associated height. - -## Relevant SDK changes - -- (codec) [\#9226](https://github.com/cosmos/cosmos-sdk/pull/9226) Rename codec interfaces and methods, to follow a general Go interfaces: - - `codec.Marshaler` → `codec.Codec` (this defines objects which serialize other objects) - - `codec.BinaryMarshaler` → `codec.BinaryCodec` - - `codec.JSONMarshaler` → `codec.JSONCodec` - - Removed `BinaryBare` suffix from `BinaryCodec` methods (`MarshalBinaryBare`, `UnmarshalBinaryBare`, ...) - - Removed `Binary` infix from `BinaryCodec` methods (`MarshalBinaryLengthPrefixed`, `UnmarshalBinaryLengthPrefixed`, ...) diff --git a/docs/versioned_docs/version-v7.3.x/05-migrations/03-v1-to-v2.md b/docs/versioned_docs/version-v7.3.x/05-migrations/03-v1-to-v2.md deleted file mode 100644 index 577ddf995bf..00000000000 --- a/docs/versioned_docs/version-v7.3.x/05-migrations/03-v1-to-v2.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: IBC-Go v1 to v2 -sidebar_label: IBC-Go v1 to v2 -sidebar_position: 3 -slug: /migrations/v1-to-v2 ---- -# Migrating from ibc-go v1 to v2 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -```go -github.com/cosmos/ibc-go -> github.com/cosmos/ibc-go/v2 -``` - -## Chains - -- No relevant changes were made in this release. - -## IBC Apps - -A new function has been added to the app module interface: - -```go -// NegotiateAppVersion performs application version negotiation given the provided channel ordering, connectionID, portID, counterparty and proposed version. - // An error is returned if version negotiation cannot be performed. For example, an application module implementing this interface - // may decide to return an error in the event of the proposed version being incompatible with it's own - NegotiateAppVersion( - ctx sdk.Context, - order channeltypes.Order, - connectionID string, - portID string, - counterparty channeltypes.Counterparty, - proposedVersion string, - ) (version string, err error) -} -``` - -This function should perform application version negotiation and return the negotiated version. If the version cannot be negotiated, an error should be returned. This function is only used on the client side. - -### sdk.Result removed - -sdk.Result has been removed as a return value in the application callbacks. Previously it was being discarded by core IBC and was thus unused. - -## Relayers - -A new gRPC has been added to 05-port, `AppVersion`. It returns the negotiated app version. This function should be used for the `ChanOpenTry` channel handshake step to decide upon the application version which should be set in the channel. - -## IBC Light Clients - -- No relevant changes were made in this release. diff --git a/docs/versioned_docs/version-v7.3.x/05-migrations/04-v2-to-v3.md b/docs/versioned_docs/version-v7.3.x/05-migrations/04-v2-to-v3.md deleted file mode 100644 index d32237692ae..00000000000 --- a/docs/versioned_docs/version-v7.3.x/05-migrations/04-v2-to-v3.md +++ /dev/null @@ -1,186 +0,0 @@ ---- -title: IBC-Go v2 to v3 -sidebar_label: IBC-Go v2 to v3 -sidebar_position: 4 -slug: /migrations/v2-to-v3 ---- -# Migrating from ibc-go v2 to v3 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -```go -github.com/cosmos/ibc-go/v2 -> github.com/cosmos/ibc-go/v3 -``` - -No genesis or in-place migrations are required when upgrading from v1 or v2 of ibc-go. - -## Chains - -### ICS20 - -The `transferkeeper.NewKeeper(...)` now takes in an ICS4Wrapper. -The ICS4Wrapper should be the IBC Channel Keeper unless ICS 20 is being connected to a middleware application. - -### ICS27 - -ICS27 Interchain Accounts has been added as a supported IBC application of ibc-go. -Please see the [ICS27 documentation](../02-apps/02-interchain-accounts/01-overview.md) for more information. - -### Upgrade Proposal - -If the chain will adopt ICS27, it must set the appropriate params during the execution of the upgrade handler in `app.go`: - -```go -app.UpgradeKeeper.SetUpgradeHandler("v3", - func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - // set the ICS27 consensus version so InitGenesis is not run - fromVM[icatypes.ModuleName] = icamodule.ConsensusVersion() - - // create ICS27 Controller submodule params - controllerParams := icacontrollertypes.Params{ - ControllerEnabled: true, - } - - // create ICS27 Host submodule params - hostParams := icahosttypes.Params{ - HostEnabled: true, - AllowMessages: []string{"/cosmos.bank.v1beta1.MsgSend", ...}, - } - - // initialize ICS27 module - icamodule.InitModule(ctx, controllerParams, hostParams) - - ... - - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) - -``` - -The host and controller submodule params only need to be set if the chain integrates those submodules. -For example, if a chain chooses not to integrate a controller submodule, it may pass empty params into `InitModule`. - -#### Add `StoreUpgrades` for ICS27 module - -For ICS27 it is also necessary to [manually add store upgrades](https://docs.cosmos.network/main/learn/advanced/upgrade#add-storeupgrades-for-new-modules) for the new ICS27 module and then configure the store loader to apply those upgrades in `app.go`: - -```go -if upgradeInfo.Name == "v3" && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { - storeUpgrades := store.StoreUpgrades{ - Added: []string{icacontrollertypes.StoreKey, icahosttypes.StoreKey}, - } - - app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) -} -``` - -This ensures that the new module's stores are added to the multistore before the migrations begin. -The host and controller submodule keys only need to be added if the chain integrates those submodules. -For example, if a chain chooses not to integrate a controller submodule, it does not need to add the controller key to the `Added` field. - -### Genesis migrations - -If the chain will adopt ICS27 and chooses to upgrade via a genesis export, then the ICS27 parameters must be set during genesis migration. - -The migration code required may look like: - -```go - controllerGenesisState := icatypes.DefaultControllerGenesis() - // overwrite parameters as desired - controllerGenesisState.Params = icacontrollertypes.Params{ - ControllerEnabled: true, - } - - hostGenesisState := icatypes.DefaultHostGenesis() - // overwrite parameters as desired - hostGenesisState.Params = icahosttypes.Params{ - HostEnabled: true, - AllowMessages: []string{"/cosmos.bank.v1beta1.MsgSend", ...}, - } - - icaGenesisState := icatypes.NewGenesisState(controllerGenesisState, hostGenesisState) - - // set new ics27 genesis state - appState[icatypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(icaGenesisState) -``` - -### Ante decorator - -The field of type `channelkeeper.Keeper` in the `AnteDecorator` structure has been replaced with a field of type `*keeper.Keeper`: - -```diff -type AnteDecorator struct { -- k channelkeeper.Keeper -+ k *keeper.Keeper -} - -- func NewAnteDecorator(k channelkeeper.Keeper) AnteDecorator { -+ func NewAnteDecorator(k *keeper.Keeper) AnteDecorator { - return AnteDecorator{k: k} -} -``` - -## IBC Apps - -### `OnChanOpenTry` must return negotiated application version - -The `OnChanOpenTry` application callback has been modified. -The return signature now includes the application version. -IBC applications must perform application version negoitation in `OnChanOpenTry` using the counterparty version. -The negotiated application version then must be returned in `OnChanOpenTry` to core IBC. -Core IBC will set this version in the TRYOPEN channel. - -### `OnChanOpenAck` will take additional `counterpartyChannelID` argument - -The `OnChanOpenAck` application callback has been modified. -The arguments now include the counterparty channel id. - -### `NegotiateAppVersion` removed from `IBCModule` interface - -Previously this logic was handled by the `NegotiateAppVersion` function. -Relayers would query this function before calling `ChanOpenTry`. -Applications would then need to verify that the passed in version was correct. -Now applications will perform this version negotiation during the channel handshake, thus removing the need for `NegotiateAppVersion`. - -### Channel state will not be set before application callback - -The channel handshake logic has been reorganized within core IBC. -Channel state will not be set in state after the application callback is performed. -Applications must rely only on the passed in channel parameters instead of querying the channel keeper for channel state. - -### IBC application callbacks moved from `AppModule` to `IBCModule` - -Previously, IBC module callbacks were apart of the `AppModule` type. -The recommended approach is to create an `IBCModule` type and move the IBC module callbacks from `AppModule` to `IBCModule` in a separate file `ibc_module.go`. - -The mock module go API has been broken in this release by applying the above format. -The IBC module callbacks have been moved from the mock modules `AppModule` into a new type `IBCModule`. - -As apart of this release, the mock module now supports middleware testing. Please see the [README](https://github.com/cosmos/ibc-go/blob/v7.0.0/testing/README.md#middleware-testing) for more information. - -Please review the [mock](https://github.com/cosmos/ibc-go/blob/v7.0.0/testing/mock/ibc_module.go) and [transfer](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/apps/transfer/ibc_module.go) modules as examples. Additionally, [simapp](https://github.com/cosmos/ibc-go/blob/v7.0.0/testing/simapp/app.go) provides an example of how `IBCModule` types should now be added to the IBC router in favour of `AppModule`. - -### IBC testing package - -`TestChain`s are now created with chainID's beginning from an index of 1. Any calls to `GetChainID(0)` will now fail. Please increment all calls to `GetChainID` by 1. - -## Relayers - -`AppVersion` gRPC has been removed. -The `version` string in `MsgChanOpenTry` has been deprecated and will be ignored by core IBC. -Relayers no longer need to determine the version to use on the `ChanOpenTry` step. -IBC applications will determine the correct version using the counterparty version. - -## IBC Light Clients - -The `GetProofSpecs` function has been removed from the `ClientState` interface. This function was previously unused by core IBC. Light clients which don't use this function may remove it. diff --git a/docs/versioned_docs/version-v7.3.x/05-migrations/05-v3-to-v4.md b/docs/versioned_docs/version-v7.3.x/05-migrations/05-v3-to-v4.md deleted file mode 100644 index 067d8738e68..00000000000 --- a/docs/versioned_docs/version-v7.3.x/05-migrations/05-v3-to-v4.md +++ /dev/null @@ -1,160 +0,0 @@ ---- -title: IBC-Go v3 to v4 -sidebar_label: IBC-Go v3 to v4 -sidebar_position: 5 -slug: /migrations/v3-to-v4 ---- -# Migrating from ibc-go v3 to v4 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -```go -github.com/cosmos/ibc-go/v3 -> github.com/cosmos/ibc-go/v4 -``` - -No genesis or in-place migrations required when upgrading from v1 or v2 of ibc-go. - -## Chains - -### ICS27 - Interchain Accounts - -The controller submodule implements now the 05-port `Middleware` interface instead of the 05-port `IBCModule` interface. Chains that integrate the controller submodule, need to create it with the `NewIBCMiddleware` constructor function. For example: - -```diff -- icacontroller.NewIBCModule(app.ICAControllerKeeper, icaAuthIBCModule) -+ icacontroller.NewIBCMiddleware(icaAuthIBCModule, app.ICAControllerKeeper) -``` - -where `icaAuthIBCModule` is the Interchain Accounts authentication IBC Module. - -### ICS29 - Fee Middleware - -The Fee Middleware module, as the name suggests, plays the role of an IBC middleware and as such must be configured by chain developers to route and handle IBC messages correctly. - -Please read the Fee Middleware [integration documentation](https://ibc.cosmos.network/main/middleware/ics29-fee/integration.html) for an in depth guide on how to congfigure the module correctly in order to incentivize IBC packets. - -Take a look at the following diff for an [example setup](https://github.com/cosmos/ibc-go/pull/1432/files#diff-d18972debee5e64f16e40807b2ae112ddbe609504a93ea5e1c80a5d489c3a08aL366) of how to incentivize ics27 channels. - -### Migration to fix support for base denoms with slashes - -As part of [v1.5.0](https://github.com/cosmos/ibc-go/releases/tag/v1.5.0), [v2.3.0](https://github.com/cosmos/ibc-go/releases/tag/v2.3.0) and [v3.1.0](https://github.com/cosmos/ibc-go/releases/tag/v3.1.0) some [migration handler code sample was documented](./01-support-denoms-with-slashes.md#upgrade-proposal) that needs to run in order to correct the trace information of coins transferred using ICS20 whose base denom contains slashes. - -Based on feedback from the community we add now an improved solution to run the same migration that does not require copying a large piece of code over from the migration document, but instead requires only adding a one-line upgrade handler. - -If the chain will migrate to supporting base denoms with slashes, it must set the appropriate params during the execution of the upgrade handler in `app.go`: - -```go -app.UpgradeKeeper.SetUpgradeHandler("MigrateTraces", - func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - // transfer module consensus version has been bumped to 2 - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }) - -``` - -If a chain receives coins of a base denom with slashes before it upgrades to supporting it, the receive may pass however the trace information will be incorrect. - -E.g. If a base denom of `testcoin/testcoin/testcoin` is sent to a chain that does not support slashes in the base denom, the receive will be successful. However, the trace information stored on the receiving chain will be: `Trace: "transfer/{channel-id}/testcoin/testcoin", BaseDenom: "testcoin"`. - -This incorrect trace information must be corrected when the chain does upgrade to fully supporting denominations with slashes. - -## IBC Apps - -### ICS03 - Connection - -Crossing hellos have been removed from 03-connection handshake negotiation. -`PreviousConnectionId` in `MsgConnectionOpenTry` has been deprecated and is no longer used by core IBC. - -`NewMsgConnectionOpenTry` no longer takes in the `PreviousConnectionId` as crossing hellos are no longer supported. A non-empty `PreviousConnectionId` will fail basic validation for this message. - -### ICS04 - Channel - -The `WriteAcknowledgement` API now takes the `exported.Acknowledgement` type instead of passing in the acknowledgement byte array directly. -This is an API breaking change and as such IBC application developers will have to update any calls to `WriteAcknowledgement`. - -The `OnChanOpenInit` application callback has been modified. -The return signature now includes the application version as detailed in the latest IBC [spec changes](https://github.com/cosmos/ibc/pull/629). - -The `NewErrorAcknowledgement` method signature has changed. -It now accepts an `error` rather than a `string`. This was done in order to prevent accidental state changes. -All error acknowledgements now contain a deterministic ABCI code and error message. It is the responsibility of the application developer to emit error details in events. - -Crossing hellos have been removed from 04-channel handshake negotiation. -IBC Applications no longer need to account from already claimed capabilities in the `OnChanOpenTry` callback. The capability provided by core IBC must be able to be claimed with error. -`PreviousChannelId` in `MsgChannelOpenTry` has been deprecated and is no longer used by core IBC. - -`NewMsgChannelOpenTry` no longer takes in the `PreviousChannelId` as crossing hellos are no longer supported. A non-empty `PreviousChannelId` will fail basic validation for this message. - -### ICS27 - Interchain Accounts - -The `RegisterInterchainAccount` API has been modified to include an additional `version` argument. This change has been made in order to support ICS29 fee middleware, for relayer incentivization of ICS27 packets. -Consumers of the `RegisterInterchainAccount` are now expected to build the appropriate JSON encoded version string themselves and pass it accordingly. -This should be constructed within the interchain accounts authentication module which leverages the APIs exposed via the interchain accounts `controllerKeeper`. If an empty string is passed in the `version` argument, then the version will be initialized to a default value in the `OnChanOpenInit` callback of the controller's handler, so that channel handshake can proceed. - -The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, msg.Owner, string(appVersion)); err != nil { - return err -} -``` - -Similarly, if the application stack is configured to route through ICS29 fee middleware and a fee enabled channel is desired, construct the appropriate ICS29 `Metadata` type: - -```go -icaMetadata := icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: controllerConnectionID, - HostConnectionId: hostConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, -} - -appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) -if err != nil { - return err -} - -feeMetadata := feetypes.Metadata{ - AppVersion: string(appVersion), - FeeVersion: feetypes.Version, -} - -feeEnabledVersion, err := feetypes.ModuleCdc.MarshalJSON(&feeMetadata) -if err != nil { - return err -} - -if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, msg.Owner, string(feeEnabledVersion)); err != nil { - return err -} -``` - -## Relayers - -When using the `DenomTrace` gRPC, the full IBC denomination with the `ibc/` prefix may now be passed in. - -Crossing hellos are no longer supported by core IBC for 03-connection and 04-channel. The handshake should be completed in the logical 4 step process (INIT, TRY, ACK, CONFIRM). diff --git a/docs/versioned_docs/version-v7.3.x/05-migrations/06-v4-to-v5.md b/docs/versioned_docs/version-v7.3.x/05-migrations/06-v4-to-v5.md deleted file mode 100644 index dfeefc2802b..00000000000 --- a/docs/versioned_docs/version-v7.3.x/05-migrations/06-v4-to-v5.md +++ /dev/null @@ -1,441 +0,0 @@ ---- -title: IBC-Go v4 to v5 -sidebar_label: IBC-Go v4 to v5 -sidebar_position: 6 -slug: /migrations/v4-to-v5 ---- - -# Migrating from v4 to v5 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- [Chains](#chains) -- [IBC Apps](#ibc-apps) -- [Relayers](#relayers) -- [IBC Light Clients](#ibc-light-clients) - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -```go -github.com/cosmos/ibc-go/v4 -> github.com/cosmos/ibc-go/v5 -``` - -## Chains - -### Ante decorator - -The `AnteDecorator` type in `core/ante` has been renamed to `RedundantRelayDecorator` (and the corresponding constructor function to `NewRedundantRelayDecorator`). Therefore in the function that creates the instance of the `sdk.AnteHandler` type (e.g. `NewAnteHandler`) the change would be like this: - -```diff -func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { - // parameter validation - - anteDecorators := []sdk.AnteDecorator{ - // other ante decorators -- ibcante.NewAnteDecorator(opts.IBCkeeper), -+ ibcante.NewRedundantRelayDecorator(options.IBCKeeper), - } - - return sdk.ChainAnteDecorators(anteDecorators...), nil -} -``` - -The `AnteDecorator` was actually renamed twice, but in [this PR](https://github.com/cosmos/ibc-go/pull/1820) you can see the changes made for the final rename. - -## IBC Apps - -### Core - -The `key` parameter of the `NewKeeper` function in `modules/core/keeper` is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`): - -```diff -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - stakingKeeper clienttypes.StakingKeeper, - upgradeKeeper clienttypes.UpgradeKeeper, - scopedKeeper capabilitykeeper.ScopedKeeper, -) *Keeper -``` - -The `RegisterRESTRoutes` function in `modules/core` has been removed. - -### ICS03 - Connection - -The `key` parameter of the `NewKeeper` function in `modules/core/03-connection/keeper` is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`): - -```diff -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - ck types.ClientKeeper -) Keeper -``` - -### ICS04 - Channel - -The function `NewPacketId` in `modules/core/04-channel/types` has been renamed to `NewPacketID`: - -```diff -- func NewPacketId( -+ func NewPacketID( - portID, - channelID string, - seq uint64 -) PacketId -``` - -The `key` parameter of the `NewKeeper` function in `modules/core/04-channel/keeper` is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`): - -```diff -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - clientKeeper types.ClientKeeper, - connectionKeeper types.ConnectionKeeper, - portKeeper types.PortKeeper, - scopedKeeper capabilitykeeper.ScopedKeeper, -) Keeper -``` - -### ICS20 - Transfer - -The `key` parameter of the `NewKeeper` function in `modules/apps/transfer/keeper` is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`): - -```diff -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - ics4Wrapper types.ICS4Wrapper, - channelKeeper types.ChannelKeeper, - portKeeper types.PortKeeper, - authKeeper types.AccountKeeper, - bankKeeper types.BankKeeper, - scopedKeeper capabilitykeeper.ScopedKeeper, -) Keeper -``` - -The `amount` parameter of function `GetTransferCoin` in `modules/apps/transfer/types` is now of type `math.Int` (`"cosmossdk.io/math"`): - -```diff -func GetTransferCoin( - portID, channelID, baseDenom string, -- amount sdk.Int -+ amount math.Int -) sdk.Coin -``` - -The `RegisterRESTRoutes` function in `modules/apps/transfer` has been removed. - -### ICS27 - Interchain Accounts - -The `key` and `msgRouter` parameters of the `NewKeeper` functions in - -- `modules/apps/27-interchain-accounts/controller/keeper` -- and `modules/apps/27-interchain-accounts/host/keeper` - -have changed type. The `key` parameter is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`), and the `msgRouter` parameter is now of type `*icatypes.MessageRouter` (where `icatypes` is an import alias for `"github.com/cosmos/ibc-go/v5/modules/apps/27-interchain-accounts/types"`): - -```diff -// NewKeeper creates a new interchain accounts controller Keeper instance -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - ics4Wrapper icatypes.ICS4Wrapper, - channelKeeper icatypes.ChannelKeeper, - portKeeper icatypes.PortKeeper, - scopedKeeper capabilitykeeper.ScopedKeeper, -- msgRouter *baseapp.MsgServiceRouter, -+ msgRouter *icatypes.MessageRouter, -) Keeper -``` - -```diff -// NewKeeper creates a new interchain accounts host Keeper instance -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - channelKeeper icatypes.ChannelKeeper, - portKeeper icatypes.PortKeeper, - accountKeeper icatypes.AccountKeeper, - scopedKeeper capabilitykeeper.ScopedKeeper, -- msgRouter *baseapp.MsgServiceRouter, -+ msgRouter *icatypes.MessageRouter, -) Keeper -``` - -The new `MessageRouter` interface is defined as: - -```go -type MessageRouter interface { - Handler(msg sdk.Msg) baseapp.MsgServiceHandler -} -``` - -The `RegisterRESTRoutes` function in `modules/apps/27-interchain-accounts` has been removed. - -An additional parameter, `ics4Wrapper` has been added to the `host` submodule `NewKeeper` function in `modules/apps/27-interchain-accounts/host/keeper`. -This allows the `host` submodule to correctly unwrap the channel version for channel reopening handshakes in the `OnChanOpenTry` callback. - -```diff -func NewKeeper( - cdc codec.BinaryCodec, - key storetypes.StoreKey, - paramSpace paramtypes.Subspace, -+ ics4Wrapper icatypes.ICS4Wrapper, - channelKeeper icatypes.ChannelKeeper, - portKeeper icatypes.PortKeeper, - accountKeeper icatypes.AccountKeeper, - scopedKeeper icatypes.ScopedKeeper, - msgRouter icatypes.MessageRouter, -) Keeper -``` - -#### Cosmos SDK message handler responses in packet acknowledgement - -The construction of the transaction response of a message execution on the host chain has changed. The `Data` field in the `sdk.TxMsgData` has been deprecated and since Cosmos SDK 0.46 the `MsgResponses` field contains the message handler responses packed into `Any`s. - -For chains on Cosmos SDK 0.45 and below, the message response was constructed like this: - -```go -txMsgData := &sdk.TxMsgData{ - Data: make([]*sdk.MsgData, len(msgs)), -} - -for i, msg := range msgs { - // message validation - - msgResponse, err := k.executeMsg(cacheCtx, msg) - // return if err != nil - - txMsgData.Data[i] = &sdk.MsgData{ - MsgType: sdk.MsgTypeURL(msg), - Data: msgResponse, - } -} - -// emit events - -txResponse, err := proto.Marshal(txMsgData) -// return if err != nil - -return txResponse, nil -``` - -And for chains on Cosmos SDK 0.46 and above, it is now done like this: - -```go -txMsgData := &sdk.TxMsgData{ - MsgResponses: make([]*codectypes.Any, len(msgs)), -} - -for i, msg := range msgs { - // message validation - - any, err := k.executeMsg(cacheCtx, msg) - // return if err != nil - - txMsgData.MsgResponses[i] = any -} - -// emit events - -txResponse, err := proto.Marshal(txMsgData) -// return if err != nil - -return txResponse, nil -``` - -When handling the acknowledgement in the `OnAcknowledgementPacket` callback of a custom ICA controller module, then depending on whether `txMsgData.Data` is empty or not, the logic to handle the message handler response will be different. **Only controller chains on Cosmos SDK 0.46 or above will be able to write the logic needed to handle the response from a host chain on Cosmos SDK 0.46 or above.** - -```go -var ack channeltypes.Acknowledgement -if err := channeltypes.SubModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { - return err -} - -var txMsgData sdk.TxMsgData -if err := proto.Unmarshal(ack.GetResult(), txMsgData); err != nil { - return err -} - -switch len(txMsgData.Data) { -case 0: // for SDK 0.46 and above - for _, msgResponse := range txMsgData.MsgResponses { - // unmarshall msgResponse and execute logic based on the response - } - return nil -default: // for SDK 0.45 and below - for _, msgData := range txMsgData.Data { - // unmarshall msgData and execute logic based on the response - } -} -``` - -See [ADR-03](/architecture/adr-003-ics27-acknowledgement#next-major-version-format) for more information or the [corrresponding documentation about authentication modules](../02-apps/02-interchain-accounts/03-auth-modules.md#onacknowledgementpacket). - -### ICS29 - Fee Middleware - -The `key` parameter of the `NewKeeper` function in `modules/apps/29-fee` is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`): - -```diff -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - ics4Wrapper types.ICS4Wrapper, - channelKeeper types.ChannelKeeper, - portKeeper types.PortKeeper, - authKeeper types.AccountKeeper, - bankKeeper types.BankKeeper, -) Keeper -``` - -The `RegisterRESTRoutes` function in `modules/apps/29-fee` has been removed. - -### IBC testing package - -The `MockIBCApp` type has been renamed to `IBCApp` (and the corresponding constructor function to `NewIBCApp`). This has resulted therefore in: - -- The `IBCApp` field of the `*IBCModule` in `testing/mock` to change its type as well to `*IBCApp`: - -```diff -type IBCModule struct { - appModule *AppModule -- IBCApp *MockIBCApp // base application of an IBC middleware stack -+ IBCApp *IBCApp // base application of an IBC middleware stack -} -``` - -- The `app` parameter to `*NewIBCModule` in `testing/mock` to change its type as well to `*IBCApp`: - -```diff -func NewIBCModule( - appModule *AppModule, -- app *MockIBCApp -+ app *IBCApp -) IBCModule -``` - -The `MockEmptyAcknowledgement` type has been renamed to `EmptyAcknowledgement` (and the corresponding constructor function to `NewEmptyAcknowledgement`). - -The `TestingApp` interface in `testing` has gone through some modifications: - -- The return type of the function `GetStakingKeeper` is not the concrete type `stakingkeeper.Keeper` anymore (where `stakingkeeper` is an import alias for `"github.com/cosmos/cosmos-sdk/x/staking/keeper"`), but it has been changed to the interface `ibctestingtypes.StakingKeeper` (where `ibctestingtypes` is an import alias for `""github.com/cosmos/ibc-go/v5/testing/types"`). See this [PR](https://github.com/cosmos/ibc-go/pull/2028) for more details. The `StakingKeeper` interface is defined as: - -```go -type StakingKeeper interface { - GetHistoricalInfo(ctx sdk.Context, height int64) (stakingtypes.HistoricalInfo, bool) -} -``` - -- The return type of the function `LastCommitID` has changed to `storetypes.CommitID` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`). - -See the following `git diff` for more details: - -```diff -type TestingApp interface { - abci.Application - - // ibc-go additions - GetBaseApp() *baseapp.BaseApp -- GetStakingKeeper() stakingkeeper.Keeper -+ GetStakingKeeper() ibctestingtypes.StakingKeeper - GetIBCKeeper() *keeper.Keeper - GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper - GetTxConfig() client.TxConfig - - // Implemented by SimApp - AppCodec() codec.Codec - - // Implemented by BaseApp -- LastCommitID() sdk.CommitID -+ LastCommitID() storetypes.CommitID - LastBlockHeight() int64 -} -``` - -The `powerReduction` parameter of the function `SetupWithGenesisValSet` in `testing` is now of type `math.Int` (`"cosmossdk.io/math"`): - -```diff -func SetupWithGenesisValSet( - t *testing.T, - valSet *tmtypes.ValidatorSet, - genAccs []authtypes.GenesisAccount, - chainID string, -- powerReduction sdk.Int, -+ powerReduction math.Int, - balances ...banktypes.Balance -) TestingApp -``` - -The `accAmt` parameter of the functions - -- `AddTestAddrsFromPubKeys` , -- `AddTestAddrs` -- and `AddTestAddrsIncremental` - -in `testing/simapp` are now of type `math.Int` (`"cosmossdk.io/math"`): - -```diff -func AddTestAddrsFromPubKeys( - app *SimApp, - ctx sdk.Context, - pubKeys []cryptotypes.PubKey, -- accAmt sdk.Int, -+ accAmt math.Int -) -func addTestAddrs( - app *SimApp, - ctx sdk.Context, - accNum int, -- accAmt sdk.Int, -+ accAmt math.Int, - strategy GenerateAccountStrategy -) []sdk.AccAddress -func AddTestAddrsIncremental( - app *SimApp, - ctx sdk.Context, - accNum int, -- accAmt sdk.Int, -+ accAmt math.Int -) []sdk.AccAddress -``` - -The `RegisterRESTRoutes` function in `testing/mock` has been removed. - -## Relayers - -- No relevant changes were made in this release. - -## IBC Light Clients - -### ICS02 - Client - -The `key` parameter of the `NewKeeper` function in `modules/core/02-client/keeper` is now of type `storetypes.StoreKey` (where `storetypes` is an import alias for `"github.com/cosmos/cosmos-sdk/store/types"`): - -```diff -func NewKeeper( - cdc codec.BinaryCodec, -- key sdk.StoreKey, -+ key storetypes.StoreKey, - paramSpace paramtypes.Subspace, - sk types.StakingKeeper, - uk types.UpgradeKeeper -) Keeper -``` diff --git a/docs/versioned_docs/version-v7.3.x/05-migrations/07-v5-to-v6.md b/docs/versioned_docs/version-v7.3.x/05-migrations/07-v5-to-v6.md deleted file mode 100644 index 93f955568e3..00000000000 --- a/docs/versioned_docs/version-v7.3.x/05-migrations/07-v5-to-v6.md +++ /dev/null @@ -1,299 +0,0 @@ ---- -title: IBC-Go v5 to v6 -sidebar_label: IBC-Go v5 to v6 -sidebar_position: 7 -slug: /migrations/v5-to-v6 ---- - -# Migrating from ibc-go v5 to v6 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -## Chains - -The `ibc-go/v6` release introduces a new set of migrations for `27-interchain-accounts`. Ownership of ICS27 channel capabilities is transferred from ICS27 authentication modules and will now reside with the ICS27 controller submodule moving forward. - -For chains which contain a custom authentication module using the ICS27 controller submodule this requires a migration function to be included in the chain upgrade handler. A subsequent migration handler is run automatically, asserting the ownership of ICS27 channel capabilities has been transferred successfully. - -This migration is not required for chains which *do not* contain a custom authentication module using the ICS27 controller submodule. - -This migration facilitates the addition of the ICS27 controller submodule `MsgServer` which provides a standardised approach to integrating existing forms of authentication such as `x/gov` and `x/group` provided by the Cosmos SDK. - -For more information please refer to [ADR 009](/architecture/adr-009-v6-ics27-msgserver). - -### Upgrade proposal - -Please refer to [PR #2383](https://github.com/cosmos/ibc-go/pull/2383) for integrating the ICS27 channel capability migration logic or follow the steps outlined below: - -1. Add the upgrade migration logic to chain distribution. This may be, for example, maintained under a package `app/upgrades/v6`. - -```go -package v6 - -import ( - "github.com/cosmos/cosmos-sdk/codec" - storetypes "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" - upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - - v6 "github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts/controller/migrations/v6" -) - -const ( - UpgradeName = "v6" -) - -func CreateUpgradeHandler( - mm *module.Manager, - configurator module.Configurator, - cdc codec.BinaryCodec, - capabilityStoreKey *storetypes.KVStoreKey, - capabilityKeeper *capabilitykeeper.Keeper, - moduleName string, -) upgradetypes.UpgradeHandler { - return func(ctx sdk.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { - if err := v6.MigrateICS27ChannelCapability(ctx, cdc, capabilityStoreKey, capabilityKeeper, moduleName); err != nil { - return nil, err - } - - return mm.RunMigrations(ctx, configurator, vm) - } -} -``` - -2. Set the upgrade handler in `app.go`. The `moduleName` parameter refers to the authentication module's `ScopedKeeper` name. This is the name provided upon instantiation in `app.go` via the [`x/capability` keeper `ScopeToModule(moduleName string)`](https://github.com/cosmos/cosmos-sdk/blob/v0.46.1/x/capability/keeper/keeper.go#L70) method. [See here for an example in `simapp`](https://github.com/cosmos/ibc-go/blob/v5.0.0/testing/simapp/app.go#L304). - -```go -app.UpgradeKeeper.SetUpgradeHandler( - v6.UpgradeName, - v6.CreateUpgradeHandler( - app.mm, - app.configurator, - app.appCodec, - app.keys[capabilitytypes.ModuleName], - app.CapabilityKeeper, - >>>> moduleName <<<<, - ), -) -``` - -## IBC Apps - -### ICS27 - Interchain Accounts - -#### Controller APIs - -In previous releases of ibc-go, chain developers integrating the ICS27 interchain accounts controller functionality were expected to create a custom `Base Application` referred to as an authentication module, see the section [Building an authentication module](../02-apps/02-interchain-accounts/03-auth-modules.md) from the documentation. - -The `Base Application` was intended to be composed with the ICS27 controller submodule `Keeper` and faciliate many forms of message authentication depending on a chain's particular use case. - -Prior to ibc-go v6 the controller submodule exposed only these two functions (to which we will refer as the legacy APIs): - -- [`RegisterInterchainAccount`](https://github.com/cosmos/ibc-go/blob/v5.0.0/modules/apps/27-interchain-accounts/controller/keeper/account.go#L19) -- [`SendTx`](https://github.com/cosmos/ibc-go/blob/v5.0.0/modules/apps/27-interchain-accounts/controller/keeper/relay.go#L18) - -However, these functions have now been deprecated in favour of the new controller submodule `MsgServer` and will be removed in later releases. - -Both APIs remain functional and maintain backwards compatibility in ibc-go v6, however consumers of these APIs are now recommended to follow the message passing paradigm outlined in Cosmos SDK [ADR 031](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-031-msg-service.md) and [ADR 033](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-033-protobuf-inter-module-comm.md). This is facilitated by the Cosmos SDK [`MsgServiceRouter`](https://github.com/cosmos/cosmos-sdk/blob/main/baseapp/msg_service_router.go#L17) and chain developers creating custom application logic can now omit the ICS27 controller submodule `Keeper` from their module and instead depend on message routing. - -Depending on the use case, developers of custom authentication modules face one of three scenarios: - -![auth-module-decision-tree.png](./images/auth-module-decision-tree.png) - -**My authentication module needs to access IBC packet callbacks** - -Application developers that wish to consume IBC packet callbacks and react upon packet acknowledgements **must** continue using the controller submodule's legacy APIs. The authentication modules will not need a `ScopedKeeper` anymore, though, because the channel capability will be claimed by the controller submodule. For example, given an Interchain Accounts authentication module keeper `ICAAuthKeeper`, the authentication module's `ScopedKeeper` (`scopedICAAuthKeeper`) is not needed anymore and can be removed for the argument list of the keeper constructor function, as shown here: - -```diff -app.ICAAuthKeeper = icaauthkeeper.NewKeeper( - appCodec, - keys[icaauthtypes.StoreKey], - app.ICAControllerKeeper, -- scopedICAAuthKeeper, -) -``` - -Please note that the authentication module's `ScopedKeeper` name is still needed as part of the channel capability migration described in section [Upgrade proposal](#upgrade-proposal) above. Therefore the authentication module's `ScopedKeeper` cannot be completely removed from the chain code until the migration has run. - -In the future, the use of the legacy APIs for accessing packet callbacks will be replaced by IBC Actor Callbacks (see [ADR 008](https://github.com/cosmos/ibc-go/pull/1976) for more details) and it will also be possible to access them with the `MsgServiceRouter`. - -**My authentication module does not need access to IBC packet callbacks** - -The authentication module can migrate from using the legacy APIs and it can be composed instead with the `MsgServiceRouter`, so that the authentication module is able to pass messages to the controller submodule's `MsgServer` to register interchain accounts and send packets to the interchain account. For example, given an Interchain Accounts authentication module keeper `ICAAuthKeeper`, the ICS27 controller submodule keeper (`ICAControllerKeeper`) and authentication module scoped keeper (`scopedICAAuthKeeper`) are not needed anymore and can be replaced with the `MsgServiceRouter`, as shown here: - -```diff -app.ICAAuthKeeper = icaauthkeeper.NewKeeper( - appCodec, - keys[icaauthtypes.StoreKey], -- app.ICAControllerKeeper, -- scopedICAAuthKeeper, -+ app.MsgServiceRouter(), -) -``` - -In your authentication module you can route messages to the controller submodule's `MsgServer` instead of using the legacy APIs. For example, for registering an interchain account: - -```diff -- if err := keeper.icaControllerKeeper.RegisterInterchainAccount( -- ctx, -- connectionID, -- owner.String(), -- version, -- ); err != nil { -- return err -- } -+ msg := controllertypes.NewMsgRegisterInterchainAccount( -+ connectionID, -+ owner.String(), -+ version, -+ ) -+ handler := keeper.msgRouter.Handler(msg) -+ res, err := handler(ctx, msg) -+ if err != nil { -+ return err -+ } -``` - -where `controllertypes` is an import alias for `"github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts/controller/types"`. - -In addition, in this use case the authentication module does not need to implement the `IBCModule` interface anymore. - -**I do not need a custom authentication module anymore** - -If your authentication module does not have any extra functionality compared to the default authentication module added in ibc-go v6 (the `MsgServer`), or if you can use a generic authentication module, such as the `x/auth`, `x/gov` or `x/group` modules from the Cosmos SDK (v0.46 and later), then you can remove your authentication module completely and use instead the gRPC endpoints of the `MsgServer` or the CLI added in ibc-go v6. - -Please remember that the authentication module's `ScopedKeeper` name is still needed as part of the channel capability migration described in section [Upgrade proposal](#upgrade-proposal) above. - -#### Host params - -The ICS27 host submodule default params have been updated to include the `AllowAllHostMsgs` wildcard `*`. -This enables execution of any `sdk.Msg` type for ICS27 registered on the host chain `InterfaceRegistry`. - -```diff -// AllowAllHostMsgs holds the string key that allows all message types on interchain accounts host module -const AllowAllHostMsgs = "*" - -... - -// DefaultParams is the default parameter configuration for the host submodule -func DefaultParams() Params { -- return NewParams(DefaultHostEnabled, nil) -+ return NewParams(DefaultHostEnabled, []string{AllowAllHostMsgs}) -} -``` - -#### API breaking changes - -`SerializeCosmosTx` takes in a `[]proto.Message` instead of `[]sdk.Message`. This allows for the serialization of proto messages without requiring the fulfillment of the `sdk.Msg` interface. - -The `27-interchain-accounts` genesis types have been moved to their own package: `modules/apps/27-interchain-acccounts/genesis/types`. -This change facilitates the addition of the ICS27 controller submodule `MsgServer` and avoids cyclic imports. This should have minimal disruption to chain developers integrating `27-interchain-accounts`. - -The ICS27 host submodule `NewKeeper` function in `modules/apps/27-interchain-acccounts/host/keeper` now includes an additional parameter of type `ICS4Wrapper`. -This provides the host submodule with the ability to correctly unwrap channel versions in the event of a channel reopening handshake. - -```diff -func NewKeeper( - cdc codec.BinaryCodec, key storetypes.StoreKey, paramSpace paramtypes.Subspace, -- channelKeeper icatypes.ChannelKeeper, portKeeper icatypes.PortKeeper, -+ ics4Wrapper icatypes.ICS4Wrapper, channelKeeper icatypes.ChannelKeeper, portKeeper icatypes.PortKeeper, - accountKeeper icatypes.AccountKeeper, scopedKeeper icatypes.ScopedKeeper, msgRouter icatypes.MessageRouter, -) Keeper -``` - -### ICS29 - `NewKeeper` API change - -The `NewKeeper` function of ICS29 has been updated to remove the `paramSpace` parameter as it was unused. - -```diff -func NewKeeper( -- cdc codec.BinaryCodec, key storetypes.StoreKey, paramSpace paramtypes.Subspace, -- ics4Wrapper types.ICS4Wrapper, channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, -+ cdc codec.BinaryCodec, key storetypes.StoreKey, -+ ics4Wrapper types.ICS4Wrapper, channelKeeper types.ChannelKeeper, -+ portKeeper types.PortKeeper, authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, -) Keeper { -``` - -### ICS20 - `SendTransfer` is no longer exported - -The `SendTransfer` function of ICS20 has been removed. IBC transfers should now be initiated with `MsgTransfer` and routed to the ICS20 `MsgServer`. - -See below for example: - -```go -if handler := msgRouter.Handler(msgTransfer); handler != nil { - if err := msgTransfer.ValidateBasic(); err != nil { - return nil, err - } - - res, err := handler(ctx, msgTransfer) - if err != nil { - return nil, err - } -} -``` - -### ICS04 - `SendPacket` API change - -The `SendPacket` API has been simplified: - -```diff -// SendPacket is called by a module in order to send an IBC packet on a channel -func (k Keeper) SendPacket( - ctx sdk.Context, - channelCap *capabilitytypes.Capability, -- packet exported.PacketI, --) error { -+ sourcePort string, -+ sourceChannel string, -+ timeoutHeight clienttypes.Height, -+ timeoutTimestamp uint64, -+ data []byte, -+) (uint64, error) { -``` - -Callers no longer need to pass in a pre-constructed packet. -The destination port/channel identifiers and the packet sequence will be determined by core IBC. -`SendPacket` will return the packet sequence. - -### IBC testing package - -The `SendPacket` API has been simplified: - -```diff -// SendPacket is called by a module in order to send an IBC packet on a channel -func (k Keeper) SendPacket( - ctx sdk.Context, - channelCap *capabilitytypes.Capability, -- packet exported.PacketI, --) error { -+ sourcePort string, -+ sourceChannel string, -+ timeoutHeight clienttypes.Height, -+ timeoutTimestamp uint64, -+ data []byte, -+) (uint64, error) { -``` - -Callers no longer need to pass in a pre-constructed packet. `SendPacket` will return the packet sequence. - -## Relayers - -- No relevant changes were made in this release. - -## IBC Light Clients - -- No relevant changes were made in this release. diff --git a/docs/versioned_docs/version-v7.3.x/05-migrations/08-v6-to-v7.md b/docs/versioned_docs/version-v7.3.x/05-migrations/08-v6-to-v7.md deleted file mode 100644 index 6e43fb6ba72..00000000000 --- a/docs/versioned_docs/version-v7.3.x/05-migrations/08-v6-to-v7.md +++ /dev/null @@ -1,357 +0,0 @@ ---- -title: IBC-Go v6 to v7 -sidebar_label: IBC-Go v6 to v7 -sidebar_position: 8 -slug: /migrations/v6-to-v7 ---- -# Migrating from ibc-go v6 to v7 - -This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. -Any changes that must be done by a user of ibc-go should be documented here. - -There are four sections based on the four potential user groups of this document: - -- Chains -- IBC Apps -- Relayers -- IBC Light Clients - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated to bump the version number on major releases. - -## Chains - -Chains will perform automatic migrations to remove existing localhost clients and to migrate the solomachine to v3 of the protobuf definition. - -An optional upgrade handler has been added to prune expired tendermint consensus states. It may be used during any upgrade (from v7 onwards). -Add the following to the function call to the upgrade handler in `app/app.go`, to perform the optional state pruning. - -```go -import ( - // ... - ibctmmigrations "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint/migrations" -) - -// ... - -app.UpgradeKeeper.SetUpgradeHandler( - upgradeName, - func(ctx sdk.Context, _ upgradetypes.Plan, _ module.VersionMap) (module.VersionMap, error) { - // prune expired tendermint consensus states to save storage space - _, err := ibctmmigrations.PruneExpiredConsensusStates(ctx, app.Codec, app.IBCKeeper.ClientKeeper) - if err != nil { - return nil, err - } - - return app.mm.RunMigrations(ctx, app.configurator, fromVM) - }, -) -``` - -Checkout the logs to see how many consensus states are pruned. - -### Light client registration - -Chains must explicitly register the types of any light client modules it wishes to integrate. - -#### Tendermint registration - -To register the tendermint client, modify the `app.go` file to include the tendermint `AppModuleBasic`: - -```diff -import ( - // ... -+ ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" -) - -// ... - -ModuleBasics = module.NewBasicManager( - ... - ibc.AppModuleBasic{}, -+ ibctm.AppModuleBasic{}, - ... -) -``` - -It may be useful to reference the [PR](https://github.com/cosmos/ibc-go/pull/2825) which added the `AppModuleBasic` for the tendermint client. - -#### Solo machine registration - -To register the solo machine client, modify the `app.go` file to include the solo machine `AppModuleBasic`: - -```diff -import ( - // ... -+ solomachine "github.com/cosmos/ibc-go/v7/modules/light-clients/06-solomachine" -) - -// ... - -ModuleBasics = module.NewBasicManager( - ... - ibc.AppModuleBasic{}, -+ solomachine.AppModuleBasic{}, - ... -) -``` - -It may be useful to reference the [PR](https://github.com/cosmos/ibc-go/pull/2826) which added the `AppModuleBasic` for the solo machine client. - -### Testing package API - -The `SetChannelClosed` utility method in `testing/endpoint.go` has been updated to `SetChannelState`, which will take a `channeltypes.State` argument so that the `ChannelState` can be set to any of the possible channel states. - -## IBC Apps - -- No relevant changes were made in this release. - -## Relayers - -- No relevant changes were made in this release. - -## IBC Light Clients - -### `ClientState` interface changes - -The `VerifyUpgradeAndUpdateState` function has been modified. The client state and consensus state return values have been removed. - -Light clients **must** handle all management of client and consensus states including the setting of updated client state and consensus state in the client store. - -The `Initialize` method is now expected to set the initial client state, consensus state and any client-specific metadata in the provided store upon client creation. - -The `CheckHeaderAndUpdateState` method has been split into 4 new methods: - -- `VerifyClientMessage` verifies a `ClientMessage`. A `ClientMessage` could be a `Header`, `Misbehaviour`, or batch update. Calls to `CheckForMisbehaviour`, `UpdateState`, and `UpdateStateOnMisbehaviour` will assume that the content of the `ClientMessage` has been verified and can be trusted. An error should be returned if the `ClientMessage` fails to verify. - -- `CheckForMisbehaviour` checks for evidence of a misbehaviour in `Header` or `Misbehaviour` types. - -- `UpdateStateOnMisbehaviour` performs appropriate state changes on a `ClientState` given that misbehaviour has been detected and verified. - -- `UpdateState` updates and stores as necessary any associated information for an IBC client, such as the `ClientState` and corresponding `ConsensusState`. An error is returned if `ClientMessage` is of type `Misbehaviour`. Upon successful update, a list containing the updated consensus state height is returned. - -The `CheckMisbehaviourAndUpdateState` function has been removed from `ClientState` interface. This functionality is now encapsulated by the usage of `VerifyClientMessage`, `CheckForMisbehaviour`, `UpdateStateOnMisbehaviour`. - -The function `GetTimestampAtHeight` has been added to the `ClientState` interface. It should return the timestamp for a consensus state associated with the provided height. - -Prior to ibc-go/v7 the `ClientState` interface defined a method for each data type which was being verified in the counterparty state store. -The state verification functions for all IBC data types have been consolidated into two generic methods, `VerifyMembership` and `VerifyNonMembership`. -Both are expected to be provided with a standardised key path, `exported.Path`, as defined in [ICS 24 host requirements](https://github.com/cosmos/ibc/tree/main/spec/core/ics-024-host-requirements). Membership verification requires callers to provide the marshalled value `[]byte`. Delay period values should be zero for non-packet processing verification. A zero proof height is now allowed by core IBC and may be passed into `VerifyMembership` and `VerifyNonMembership`. Light clients are responsible for returning an error if a zero proof height is invalid behaviour. - -See below for an example of how ibc-go now performs channel state verification. - -```go -merklePath := commitmenttypes.NewMerklePath(host.ChannelPath(portID, channelID)) -merklePath, err := commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) -if err != nil { - return err -} - -channelEnd, ok := channel.(channeltypes.Channel) -if !ok { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "invalid channel type %T", channel) -} - -bz, err := k.cdc.Marshal(&channelEnd) -if err != nil { - return err -} - -if err := clientState.VerifyMembership( - ctx, clientStore, k.cdc, height, - 0, 0, // skip delay period checks for non-packet processing verification - proof, merklePath, bz, -); err != nil { - return sdkerrors.Wrapf(err, "failed channel state verification for client (%s)", clientID) -} -``` - -### `Header` and `Misbehaviour` - -`exported.Header` and `exported.Misbehaviour` interface types have been merged and renamed to `ClientMessage` interface. - -`GetHeight` function has been removed from `exported.Header` and thus is not included in the `ClientMessage` interface - -### `ConsensusState` - -The `GetRoot` function has been removed from consensus state interface since it was not used by core IBC. - -### Client keeper - -Keeper function `CheckMisbehaviourAndUpdateState` has been removed since function `UpdateClient` can now handle updating `ClientState` on `ClientMessage` type which can be any `Misbehaviour` implementations. - -### SDK message - -`MsgSubmitMisbehaviour` is deprecated since `MsgUpdateClient` can now submit a `ClientMessage` type which can be any `Misbehaviour` implementations. - -The field `header` in `MsgUpdateClient` has been renamed to `client_message`. - -## Solomachine - -The `06-solomachine` client implementation has been simplified in ibc-go/v7. In-place store migrations have been added to migrate solomachine clients from `v2` to `v3`. - -### `ClientState` - -The `ClientState` protobuf message definition has been updated to remove the deprecated `bool` field `allow_update_after_proposal`. - -```diff -message ClientState { - option (gogoproto.goproto_getters) = false; - - uint64 sequence = 1; - bool is_frozen = 2 [(gogoproto.moretags) = "yaml:\"is_frozen\""]; - ConsensusState consensus_state = 3 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; -- bool allow_update_after_proposal = 4 [(gogoproto.moretags) = "yaml:\"allow_update_after_proposal\""]; -} -``` - -### `Header` and `Misbehaviour` - -The `06-solomachine` protobuf message `Header` has been updated to remove the `sequence` field. This field was seen as redundant as the implementation can safely rely on the `sequence` value maintained within the `ClientState`. - -```diff -message Header { - option (gogoproto.goproto_getters) = false; - -- uint64 sequence = 1; -- uint64 timestamp = 2; -- bytes signature = 3; -- google.protobuf.Any new_public_key = 4 [(gogoproto.moretags) = "yaml:\"new_public_key\""]; -- string new_diversifier = 5 [(gogoproto.moretags) = "yaml:\"new_diversifier\""]; -+ uint64 timestamp = 1; -+ bytes signature = 2; -+ google.protobuf.Any new_public_key = 3 [(gogoproto.moretags) = "yaml:\"new_public_key\""]; -+ string new_diversifier = 4 [(gogoproto.moretags) = "yaml:\"new_diversifier\""]; -} -``` - -Similarly, the `Misbehaviour` protobuf message has been updated to remove the `client_id` field. - -```diff -message Misbehaviour { - option (gogoproto.goproto_getters) = false; - -- string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; -- uint64 sequence = 2; -- SignatureAndData signature_one = 3 [(gogoproto.moretags) = "yaml:\"signature_one\""]; -- SignatureAndData signature_two = 4 [(gogoproto.moretags) = "yaml:\"signature_two\""]; -+ uint64 sequence = 1; -+ SignatureAndData signature_one = 2 [(gogoproto.moretags) = "yaml:\"signature_one\""]; -+ SignatureAndData signature_two = 3 [(gogoproto.moretags) = "yaml:\"signature_two\""]; -} -``` - -### `SignBytes` - -Most notably, the `SignBytes` protobuf definition has been modified to replace the `data_type` field with a new field, `path`. The `path` field is defined as `bytes` and represents a serialized [ICS-24](https://github.com/cosmos/ibc/tree/main/spec/core/ics-024-host-requirements) standardized key path under which the `data` is stored. - -```diff -message SignBytes { - option (gogoproto.goproto_getters) = false; - - uint64 sequence = 1; - uint64 timestamp = 2; - string diversifier = 3; -- DataType data_type = 4 [(gogoproto.moretags) = "yaml:\"data_type\""]; -+ bytes path = 4; - bytes data = 5; -} -``` - -The `DataType` enum and all associated data types have been removed, greatly reducing the number of message definitions and complexity in constructing the `SignBytes` message type. Likewise, solomachine implementations must now use the serialized `path` value when constructing `SignatureAndData` for signature verification of `SignBytes` data. - -```diff -message SignatureAndData { - option (gogoproto.goproto_getters) = false; - - bytes signature = 1; -- DataType data_type = 2 [(gogoproto.moretags) = "yaml:\"data_type\""]; -+ bytes path = 2; - bytes data = 3; - uint64 timestamp = 4; -} -``` - -For more information, please refer to [ADR-007](https://github.com/cosmos/ibc-go/blob/02-client-refactor-beta1/docs/architecture/adr-007-solomachine-signbytes.md). - -### IBC module constants - -IBC module constants have been moved from the `host` package to the `exported` package. Any usages will need to be updated. - -```diff -import ( - // ... -- host "github.com/cosmos/ibc-go/v7/modules/core/24-host" -+ ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" - // ... -) - -- host.ModuleName -+ ibcexported.ModuleName - -- host.StoreKey -+ ibcexported.StoreKey - -- host.QuerierRoute -+ ibcexported.QuerierRoute - -- host.RouterKey -+ ibcexported.RouterKey -``` - -## Upgrading to Cosmos SDK 0.47 - -The following should be considered as complementary to [Cosmos SDK v0.47 UPGRADING.md](https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc2/UPGRADING.md). - -### Protobuf - -Protobuf code generation, linting and formatting have been updated to leverage the `ghcr.io/cosmos/proto-builder:0.11.5` docker container. IBC protobuf definitions are now packaged and published to [buf.build/cosmos/ibc](https://buf.build/cosmos/ibc) via CI workflows. The `third_party/proto` directory has been removed in favour of dependency management using [buf.build](https://docs.buf.build/introduction). - -### App modules - -Legacy APIs of the `AppModule` interface have been removed from ibc-go modules. For example, for - -```diff -- // Route implements the AppModule interface -- func (am AppModule) Route() sdk.Route { -- return sdk.Route{} -- } -- -- // QuerierRoute implements the AppModule interface -- func (AppModule) QuerierRoute() string { -- return types.QuerierRoute -- } -- -- // LegacyQuerierHandler implements the AppModule interface -- func (am AppModule) LegacyQuerierHandler(*codec.LegacyAmino) sdk.Querier { -- return nil -- } -- -- // ProposalContents doesn't return any content functions for governance proposals. -- func (AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalContent { -- return nil -- } -``` - -### Imports - -Imports for ics23 have been updated as the repository have been migrated from confio to cosmos. - -```diff -import ( - // ... -- ics23 "github.com/confio/ics23/go" -+ ics23 "github.com/cosmos/ics23/go" - // ... -) -``` - -Imports for gogoproto have been updated. - -```diff -import ( - // ... -- "github.com/gogo/protobuf/proto" -+ "github.com/cosmos/gogoproto/proto" - // ... -) -``` diff --git a/docs/versioned_docs/version-v7.3.x/05-migrations/09-v7-to-v7_1.md b/docs/versioned_docs/version-v7.3.x/05-migrations/09-v7-to-v7_1.md deleted file mode 100644 index 9cb18bdf1d3..00000000000 --- a/docs/versioned_docs/version-v7.3.x/05-migrations/09-v7-to-v7_1.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: IBC-Go v7 to v7.1 -sidebar_label: IBC-Go v7 to v7.1 -sidebar_position: 9 -slug: /migrations/v7-to-v7_1 ---- -# Migrating from v7 to v7.1 - -This guide provides instructions for migrating to version `v7.1.0` of ibc-go. - -There are four sections based on the four potential user groups of this document: - -- [Migrating from v7 to v7.1](#migrating-from-v7-to-v71) - - [Chains](#chains) - - [IBC Apps](#ibc-apps) - - [Relayers](#relayers) - - [IBC Light Clients](#ibc-light-clients) - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated on major version releases. - -## Chains - -### 09-localhost migration - -In the previous release of ibc-go, the localhost `v1` light client module was deprecated and removed. The ibc-go `v7.1.0` release introduces `v2` of the 09-localhost light client module. - -An [automatic migration handler](https://github.com/cosmos/ibc-go/blob/v7.2.0/modules/core/module.go#L127-L145) is configured in the core IBC module to set the localhost `ClientState` and sentinel `ConnectionEnd` in state. - -In order to use the 09-localhost client chains must update the `AllowedClients` parameter in the 02-client submodule of core IBC. This can be configured directly in the application upgrade handler or alternatively updated via the legacy governance parameter change proposal. -We **strongly** recommend chains to perform this action so that intra-ledger communication can be carried out using the familiar IBC interfaces. - -See the upgrade handler code sample provided below or [follow this link](https://github.com/cosmos/ibc-go/blob/v7.2.0/testing/simapp/upgrades/upgrades.go#L85) for the upgrade handler used by the ibc-go simapp. - -```go -func CreateV7LocalhostUpgradeHandler( - mm *module.Manager, - configurator module.Configurator, - clientKeeper clientkeeper.Keeper, -) upgradetypes.UpgradeHandler { - return func(ctx sdk.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { - // explicitly update the IBC 02-client params, adding the localhost client type - params := clientKeeper.GetParams(ctx) - params.AllowedClients = append(params.AllowedClients, exported.Localhost) - clientKeeper.SetParams(ctx, params) - - return mm.RunMigrations(ctx, configurator, vm) - } -} -``` - -### Transfer migration - -An [automatic migration handler](https://github.com/cosmos/ibc-go/blob/v7.2.0/modules/apps/transfer/module.go#L111-L113) is configured in the transfer module to set the total amount in escrow for all denominations of coins that have been sent out. For each denomination a state entry is added with the total amount of coins in escrow regardless of the channel from which they were transferred. - -## IBC Apps - -- No relevant changes were made in this release. - -## Relayers - -The event attribute `packet_connection` (`connectiontypes.AttributeKeyConnection`) has been deprecated. -Please use the `connection_id` attribute (`connectiontypes.AttributeKeyConnectionID`) which is emitted by all channel events. -Only send packet, receive packet, write acknowledgement, and acknowledge packet events used `packet_connection` previously. - -## IBC Light Clients - -- No relevant changes were made in this release. diff --git a/docs/versioned_docs/version-v7.3.x/05-migrations/10-v7_2-to-v7_3.md b/docs/versioned_docs/version-v7.3.x/05-migrations/10-v7_2-to-v7_3.md deleted file mode 100644 index ff5de70e8df..00000000000 --- a/docs/versioned_docs/version-v7.3.x/05-migrations/10-v7_2-to-v7_3.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: IBC-Go v7.2 to v7.3 -sidebar_label: IBC-Go v7.2 to v7.3 -sidebar_position: 10 -slug: /migrations/v7_2-to-v7_3 ---- -# Migrating from v7.2 to v7.3 - -This guide provides instructions for migrating to version `v7.3.0` of ibc-go. - -There are four sections based on the four potential user groups of this document: - -- [Migrating from v7.2 to v7.3](#migrating-from-v72-to-v73) - - [Chains](#chains) - - [IBC Apps](#ibc-apps) - - [Relayers](#relayers) - - [IBC Light Clients](#ibc-light-clients) - -**Note:** ibc-go supports golang semantic versioning and therefore all imports must be updated on major version releases. - -## Chains - -- No relevant changes were made in this release. - -## IBC Apps - -A set of interfaces have been added that IBC applications may optionally implement. Developers interested in integrating their applications with the [callbacks middleware](../04-middleware/02-callbacks/01-overview.md) should implement these interfaces so that the callbacks middleware can retrieve the desired callback addresses on the source and destination chains and execute actions on packet lifecycle events. The interfaces are [`PacketDataUnmarshaler`](https://github.com/cosmos/ibc-go/blob/v7.3.0-rc1/modules/core/05-port/types/module.go#L142-L147), [`PacketDataProvider`](https://github.com/cosmos/ibc-go/blob/v7.3.0-rc1/modules/core/exported/packet.go#L43-L52) and [`PacketData`](https://github.com/cosmos/ibc-go/blob/v7.3.0-rc1/modules/core/exported/packet.go#L36-L41). - -Sample implementations are available for reference. For `transfer`: - -- [`PacketDataUnmarshaler`](https://github.com/cosmos/ibc-go/blob/v7.3.0-rc1/modules/apps/transfer/ibc_module.go#L303-L313), -- [`PacketDataProvider`](https://github.com/cosmos/ibc-go/blob/v7.3.0-rc1/modules/apps/transfer/types/packet.go#L85-L105) -- and [`PacketData`](https://github.com/cosmos/ibc-go/blob/v7.3.0-rc1/modules/apps/transfer/types/packet.go#L74-L83). - -For `27-interchain-accounts`: - -- [`PacketDataUnmarshaler`](https://github.com/cosmos/ibc-go/blob/v7.3.0-rc1/modules/apps/27-interchain-accounts/controller/ibc_middleware.go#L258-L268), -- [`PacketDataProvider`](https://github.com/cosmos/ibc-go/blob/v7.3.0-rc1/modules/apps/27-interchain-accounts/types/packet.go#L94-L114) -- and [`PacketData`](https://github.com/cosmos/ibc-go/blob/v7.3.0-rc1/modules/apps/27-interchain-accounts/types/packet.go#L78-L92). - -## Relayers - -- No relevant changes were made in this release. - -## IBC Light Clients - -### 06-solomachine - -Solo machines are now expected to sign data on a path that 1) does not include a connection prefix (e.g `ibc`) and 2) does not escape any characters. See PR [#4429](https://github.com/cosmos/ibc-go/pull/4429) for more details. We recommend **NOT** using the solo machine light client of versions lower than v7.3.0. diff --git a/docs/versioned_docs/version-v7.3.x/05-migrations/_category_.json b/docs/versioned_docs/version-v7.3.x/05-migrations/_category_.json deleted file mode 100644 index 21f91f851a4..00000000000 --- a/docs/versioned_docs/version-v7.3.x/05-migrations/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Migrations", - "position": 5, - "link": null -} \ No newline at end of file diff --git a/docs/versioned_docs/version-v7.3.x/05-migrations/images/auth-module-decision-tree.png b/docs/versioned_docs/version-v7.3.x/05-migrations/images/auth-module-decision-tree.png deleted file mode 100644 index dc2c98e6618..00000000000 Binary files a/docs/versioned_docs/version-v7.3.x/05-migrations/images/auth-module-decision-tree.png and /dev/null differ diff --git a/docs/versioned_sidebars/version-v4.4.x-sidebars.json b/docs/versioned_sidebars/version-v4.4.x-sidebars.json deleted file mode 100644 index 0402558cb33..00000000000 --- a/docs/versioned_sidebars/version-v4.4.x-sidebars.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "defaultSidebar": [ - { - "type": "autogenerated", - "dirName": "." - }, - { - "type": "category", - "label": "Resources", - "collapsed": false, - "items": [ - { - "type": "link", - "label": "IBC Specification", - "href": "https://github.com/cosmos/ibc" - }, - { - "type": "link", - "label": "Protobuf Documentation", - "href": "https://buf.build/cosmos/ibc/docs/main" - }, - { - "type": "link", - "label": "Tutorials", - "href": "https://tutorials.cosmos.network" - }, - { - "type": "link", - "label": "Awesome Cosmos", - "href": "https://github.com/cosmos/awesome-cosmos" - } - ] - } - ] -} diff --git a/docs/versioned_sidebars/version-v5.3.x-sidebars.json b/docs/versioned_sidebars/version-v5.3.x-sidebars.json deleted file mode 100644 index 0402558cb33..00000000000 --- a/docs/versioned_sidebars/version-v5.3.x-sidebars.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "defaultSidebar": [ - { - "type": "autogenerated", - "dirName": "." - }, - { - "type": "category", - "label": "Resources", - "collapsed": false, - "items": [ - { - "type": "link", - "label": "IBC Specification", - "href": "https://github.com/cosmos/ibc" - }, - { - "type": "link", - "label": "Protobuf Documentation", - "href": "https://buf.build/cosmos/ibc/docs/main" - }, - { - "type": "link", - "label": "Tutorials", - "href": "https://tutorials.cosmos.network" - }, - { - "type": "link", - "label": "Awesome Cosmos", - "href": "https://github.com/cosmos/awesome-cosmos" - } - ] - } - ] -} diff --git a/docs/versioned_sidebars/version-v6.2.x-sidebars.json b/docs/versioned_sidebars/version-v6.2.x-sidebars.json deleted file mode 100644 index 0402558cb33..00000000000 --- a/docs/versioned_sidebars/version-v6.2.x-sidebars.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "defaultSidebar": [ - { - "type": "autogenerated", - "dirName": "." - }, - { - "type": "category", - "label": "Resources", - "collapsed": false, - "items": [ - { - "type": "link", - "label": "IBC Specification", - "href": "https://github.com/cosmos/ibc" - }, - { - "type": "link", - "label": "Protobuf Documentation", - "href": "https://buf.build/cosmos/ibc/docs/main" - }, - { - "type": "link", - "label": "Tutorials", - "href": "https://tutorials.cosmos.network" - }, - { - "type": "link", - "label": "Awesome Cosmos", - "href": "https://github.com/cosmos/awesome-cosmos" - } - ] - } - ] -} diff --git a/docs/versioned_sidebars/version-v7.3.x-sidebars.json b/docs/versioned_sidebars/version-v7.3.x-sidebars.json deleted file mode 100644 index 0402558cb33..00000000000 --- a/docs/versioned_sidebars/version-v7.3.x-sidebars.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "defaultSidebar": [ - { - "type": "autogenerated", - "dirName": "." - }, - { - "type": "category", - "label": "Resources", - "collapsed": false, - "items": [ - { - "type": "link", - "label": "IBC Specification", - "href": "https://github.com/cosmos/ibc" - }, - { - "type": "link", - "label": "Protobuf Documentation", - "href": "https://buf.build/cosmos/ibc/docs/main" - }, - { - "type": "link", - "label": "Tutorials", - "href": "https://tutorials.cosmos.network" - }, - { - "type": "link", - "label": "Awesome Cosmos", - "href": "https://github.com/cosmos/awesome-cosmos" - } - ] - } - ] -} diff --git a/docs/versions.json b/docs/versions.json deleted file mode 100644 index 1f02d1906c5..00000000000 --- a/docs/versions.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - "v7.3.x", - "v6.2.x", - "v5.3.x", - "v4.4.x" -] diff --git a/go.mod b/go.mod index 3d0d4596a50..6909013a623 100644 --- a/go.mod +++ b/go.mod @@ -2,36 +2,38 @@ go 1.21 module github.com/cosmos/ibc-go/v8 +retract [v8.0.0, v8.1.1] // contains ASA-2024-007 vulnerability + require ( - cosmossdk.io/api v0.7.3 + cosmossdk.io/api v0.7.4 cosmossdk.io/client/v2 v2.0.0-beta.1 cosmossdk.io/core v0.11.0 cosmossdk.io/errors v1.0.1 cosmossdk.io/log v1.3.1 cosmossdk.io/math v1.3.0 - cosmossdk.io/store v1.0.2 + cosmossdk.io/store v1.1.0 cosmossdk.io/tools/confix v0.1.0 cosmossdk.io/x/circuit v0.1.0 cosmossdk.io/x/evidence v0.1.0 cosmossdk.io/x/feegrant v0.1.0 - cosmossdk.io/x/tx v0.13.1 + cosmossdk.io/x/tx v0.13.2 cosmossdk.io/x/upgrade v0.1.0 - github.com/cometbft/cometbft v0.38.5 + github.com/cometbft/cometbft v0.38.7 github.com/cosmos/cosmos-db v1.0.2 - github.com/cosmos/cosmos-proto v1.0.0-beta.4 - github.com/cosmos/cosmos-sdk v0.50.5 - github.com/cosmos/gogoproto v1.4.11 + github.com/cosmos/cosmos-proto v1.0.0-beta.5 + github.com/cosmos/cosmos-sdk v0.50.6 + github.com/cosmos/gogoproto v1.4.12 github.com/cosmos/ibc-go/modules/capability v1.0.0 github.com/cosmos/ics23/go v0.10.0 github.com/golang/protobuf v1.5.4 github.com/grpc-ecosystem/grpc-gateway v1.16.0 - github.com/hashicorp/go-metrics v0.5.1 + github.com/hashicorp/go-metrics v0.5.3 github.com/spf13/cast v1.6.0 github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.18.2 github.com/stretchr/testify v1.9.0 - google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 - google.golang.org/grpc v1.62.0 + google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de + google.golang.org/grpc v1.63.2 google.golang.org/protobuf v1.33.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -57,7 +59,7 @@ require ( 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/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cockroachdb/apd/v2 v2.0.2 // indirect github.com/cockroachdb/errors v1.11.1 // indirect @@ -69,7 +71,7 @@ require ( 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 v1.0.1 // indirect + github.com/cosmos/iavl v1.1.2 // indirect github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect github.com/creachadair/atomicfile v0.3.1 // indirect github.com/creachadair/tomledit v0.0.24 // indirect @@ -133,7 +135,7 @@ require ( 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.8.12 // indirect + github.com/linxGnu/grocksdb v1.8.14 // 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 @@ -146,13 +148,13 @@ require ( github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect github.com/oklog/run v1.1.0 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect - github.com/petermattis/goid v0.0.0-20230904192822-1876fd5063bc // indirect + github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.18.0 // indirect - github.com/prometheus/client_model v0.6.0 // indirect - github.com/prometheus/common v0.47.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect + github.com/prometheus/client_golang v1.19.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.52.2 // indirect + github.com/prometheus/procfs v0.13.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/rs/cors v1.8.3 // indirect @@ -178,19 +180,19 @@ require ( go.opentelemetry.io/otel/metric v1.22.0 // indirect go.opentelemetry.io/otel/trace v1.22.0 // indirect go.uber.org/multierr v1.10.0 // indirect - golang.org/x/crypto v0.19.0 // indirect - golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect - golang.org/x/net v0.21.0 // indirect - golang.org/x/oauth2 v0.16.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.17.0 // indirect - golang.org/x/term v0.17.0 // indirect + golang.org/x/crypto v0.22.0 // indirect + golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/api v0.162.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c // indirect + google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect diff --git a/go.sum b/go.sum index c36667be184..78a856773e8 100644 --- a/go.sum +++ b/go.sum @@ -184,8 +184,8 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cosmossdk.io/api v0.7.3 h1:V815i8YOwOAQa1rLCsSMjVG5Gnzs02JLq+l7ks8s1jk= -cosmossdk.io/api v0.7.3/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= +cosmossdk.io/api v0.7.4 h1:sPo8wKwCty1lht8kgL3J7YL1voJywP3YWuA5JKkBz30= +cosmossdk.io/api v0.7.4/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= cosmossdk.io/client/v2 v2.0.0-beta.1 h1:XkHh1lhrLYIT9zKl7cIOXUXg2hdhtjTPBUfqERNA1/Q= cosmossdk.io/client/v2 v2.0.0-beta.1/go.mod h1:JEUSu9moNZQ4kU3ir1DKD5eU4bllmAexrGWjmb9k8qU= cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s= @@ -200,8 +200,8 @@ cosmossdk.io/log v1.3.1 h1:UZx8nWIkfbbNEWusZqzAx3ZGvu54TZacWib3EzUYmGI= cosmossdk.io/log v1.3.1/go.mod h1:2/dIomt8mKdk6vl3OWJcPk2be3pGOS8OQaLUM/3/tCM= cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE= cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k= -cosmossdk.io/store v1.0.2 h1:lSg5BTvJBHUDwswNNyeh4K/CbqiHER73VU4nDNb8uk0= -cosmossdk.io/store v1.0.2/go.mod h1:EFtENTqVTuWwitGW1VwaBct+yDagk7oG/axBMPH+FXs= +cosmossdk.io/store v1.1.0 h1:LnKwgYMc9BInn9PhpTFEQVbL9UK475G2H911CGGnWHk= +cosmossdk.io/store v1.1.0/go.mod h1:oZfW/4Fc/zYqu3JmQcQdUJ3fqu5vnYTn3LZFFy8P8ng= cosmossdk.io/tools/confix v0.1.0 h1:2OOZTtQsDT5e7P3FM5xqM0bPfluAxZlAwxqaDmYBE+E= cosmossdk.io/tools/confix v0.1.0/go.mod h1:TdXKVYs4gEayav5wM+JHT+kTU2J7fozFNqoVaN+8CdY= cosmossdk.io/x/circuit v0.1.0 h1:IAej8aRYeuOMritczqTlljbUVHq1E85CpBqaCTwYgXs= @@ -210,8 +210,8 @@ cosmossdk.io/x/evidence v0.1.0 h1:J6OEyDl1rbykksdGynzPKG5R/zm6TacwW2fbLTW4nCk= cosmossdk.io/x/evidence v0.1.0/go.mod h1:hTaiiXsoiJ3InMz1uptgF0BnGqROllAN8mwisOMMsfw= cosmossdk.io/x/feegrant v0.1.0 h1:c7s3oAq/8/UO0EiN1H5BIjwVntujVTkYs35YPvvrdQk= cosmossdk.io/x/feegrant v0.1.0/go.mod h1:4r+FsViJRpcZif/yhTn+E0E6OFfg4n0Lx+6cCtnZElU= -cosmossdk.io/x/tx v0.13.1 h1:Mg+EMp67Pz+NukbJqYxuo8uRp7N/a9uR+oVS9pONtj8= -cosmossdk.io/x/tx v0.13.1/go.mod h1:CBCU6fsRVz23QGFIQBb1DNX2DztJCf3jWyEkHY2nJQ0= +cosmossdk.io/x/tx v0.13.2 h1:Kh90UH30bhnnUdJH+CmWLyaH8IKdY6BBGY3EkdOk82o= +cosmossdk.io/x/tx v0.13.2/go.mod h1:yhPokDCfXVIuAtyp49IFlWB5YAXUgD7Zek+ZHwsHzvU= cosmossdk.io/x/upgrade v0.1.0 h1:z1ZZG4UL9ICTNbJDYZ6jOnF9GdEK9wyoEFi4BUScHXE= cosmossdk.io/x/upgrade v0.1.0/go.mod h1:/6jjNGbiPCNtmA1N+rBtP601sr0g4ZXuj3yC6ClPCGY= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= @@ -292,8 +292,8 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA 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/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= @@ -335,8 +335,8 @@ github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/cometbft/cometbft v0.38.5 h1:4lOcK5VTPrfbLOhNHmPYe6c7eDXHtBdMCQuKbAfFJdU= -github.com/cometbft/cometbft v0.38.5/go.mod h1:0tqKin+KQs8zDwzYD8rPHzSBIDNPuB4NrwwGDNb/hUg= +github.com/cometbft/cometbft v0.38.7 h1:ULhIOJ9+LgSy6nLekhq9ae3juX3NnQUMMPyVdhZV6Hk= +github.com/cometbft/cometbft v0.38.7/go.mod h1:HIyf811dFMI73IE0F7RrnY/Fr+d1+HuJAgtkEpQjCMY= github.com/cometbft/cometbft-db v0.9.1 h1:MIhVX5ja5bXNHF8EYrThkG9F7r9kSfv8BX4LWaxWJ4M= github.com/cometbft/cometbft-db v0.9.1/go.mod h1:iliyWaoV0mRwBJoizElCwwRA9Tf7jZJOURcRZF9m60U= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= @@ -351,19 +351,19 @@ 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-db v1.0.2 h1:hwMjozuY1OlJs/uh6vddqnk9j7VamLv+0DBlbEXbAKs= github.com/cosmos/cosmos-db v1.0.2/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= -github.com/cosmos/cosmos-proto v1.0.0-beta.4 h1:aEL7tU/rLOmxZQ9z4i7mzxcLbSCY48OdY7lIWTLG7oU= -github.com/cosmos/cosmos-proto v1.0.0-beta.4/go.mod h1:oeB+FyVzG3XrQJbJng0EnV8Vljfk9XvTIpGILNU/9Co= -github.com/cosmos/cosmos-sdk v0.50.5 h1:MOEi+DKYgW67YaPgB+Pf+nHbD3V9S/ayitRKJYLfGIA= -github.com/cosmos/cosmos-sdk v0.50.5/go.mod h1:oV/k6GJgXV9QPoM2fsYDPPsyPBgQbdotv532O6Mz1OQ= +github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= +github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= +github.com/cosmos/cosmos-sdk v0.50.6 h1:efR3MsvMHX5sxS3be+hOobGk87IzlZbSpsI2x/Vw3hk= +github.com/cosmos/cosmos-sdk v0.50.6/go.mod h1:lVkRY6cdMJ0fG3gp8y4hFrsKZqF4z7y0M2UXFb9Yt40= 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.11 h1:LZcMHrx4FjUgrqQSWeaGC1v/TeuVFqSLa43CC6aWR2g= -github.com/cosmos/gogoproto v1.4.11/go.mod h1:/g39Mh8m17X8Q/GDEs5zYTSNaNnInBSohtaxzQnYq1Y= -github.com/cosmos/iavl v1.0.1 h1:D+mYbcRO2wptYzOM1Hxl9cpmmHU1ZEt9T2Wv5nZTeUw= -github.com/cosmos/iavl v1.0.1/go.mod h1:8xIUkgVvwvVrBu81scdPty+/Dx9GqwHnAvXz4cwF7RY= +github.com/cosmos/gogoproto v1.4.12 h1:vB6Lbe/rtnYGjQuFxkPiPYiCybqFT8QvLipDZP8JpFE= +github.com/cosmos/gogoproto v1.4.12/go.mod h1:LnZob1bXRdUoqMMtwYlcR3wjiElmlC+FkjaZRv1/eLY= +github.com/cosmos/iavl v1.1.2 h1:zL9FK7C4L/P4IF1Dm5fIwz0WXCnn7Bp1M2FxH0ayM7Y= +github.com/cosmos/iavl v1.1.2/go.mod h1:jLeUvm6bGT1YutCaL2fIar/8vGUE8cPZvh/gXEWDaDM= github.com/cosmos/ibc-go/modules/capability v1.0.0 h1:r/l++byFtn7jHYa09zlAdSeevo8ci1mVZNO9+V0xsLE= github.com/cosmos/ibc-go/modules/capability v1.0.0/go.mod h1:D81ZxzjZAe0ZO5ambnvn1qedsFQ8lOwtqicG6liLBco= github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= @@ -661,8 +661,8 @@ github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVH 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-metrics v0.5.1 h1:rfPwUqFU6uZXNvGl4hzjY8LEBsqFVU4si1H9/Hqck/U= -github.com/hashicorp/go-metrics v0.5.1/go.mod h1:KEjodfebIOuBYSAe/bHTm+HChmKSxAOXPBieMLYozDE= +github.com/hashicorp/go-metrics v0.5.3 h1:M5uADWMOGCTUNU1YuC4hfknOeHNaX54LDm4oYSucoNE= +github.com/hashicorp/go-metrics v0.5.3/go.mod h1:KEjodfebIOuBYSAe/bHTm+HChmKSxAOXPBieMLYozDE= 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-plugin v1.5.2 h1:aWv8eimFqWlsEiMrYZdPYl+FdHaBJSN4AWwGWfT1G2Y= @@ -763,8 +763,8 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6 github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/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.8.12 h1:1/pCztQUOa3BX/1gR3jSZDoaKFpeHFvQ1XrqZpSvZVo= -github.com/linxGnu/grocksdb v1.8.12/go.mod h1:xZCIb5Muw+nhbDK4Y5UJuOrin5MceOuiXkVUR7vp4WY= +github.com/linxGnu/grocksdb v1.8.14 h1:HTgyYalNwBSG/1qCQUIott44wU5b2Y9Kr3z7SK5OfGQ= +github.com/linxGnu/grocksdb v1.8.14/go.mod h1:QYiYypR2d4v63Wj1adOOfzglnoII0gLj3PNh4fZkcFA= 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= @@ -872,8 +872,8 @@ github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6 github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= 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-20230904192822-1876fd5063bc h1:8bQZVK1X6BJR/6nYUPxQEP+ReTsceJTKizeuwjWOPUA= -github.com/petermattis/goid v0.0.0-20230904192822-1876fd5063bc/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 h1:jik8PHtAIsPlCRJjJzl4udgEf7hawInF9texMeO2jrU= +github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67/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= @@ -894,32 +894,32 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn 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.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= 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.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= -github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.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.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k= -github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/common v0.52.2 h1:LW8Vk7BccEdONfrJBDffQGRtpSzi5CQaRZGtboOO2ck= +github.com/prometheus/common v0.52.2/go.mod h1:lrWtQx+iDfn2mbH5GUzlH9TSHyfZpHkSiG1W7y3sF2Q= 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.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o= +github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g= 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= @@ -1089,8 +1089,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U 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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= 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= @@ -1102,8 +1102,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 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-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= 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= @@ -1130,8 +1130,8 @@ 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.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1191,8 +1191,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug 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.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= 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= @@ -1218,8 +1218,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri 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.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= -golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= 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= @@ -1234,8 +1234,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ 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.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-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= @@ -1333,13 +1333,13 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= 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= @@ -1421,8 +1421,8 @@ 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.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= -golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= +golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= 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= @@ -1599,12 +1599,12 @@ google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqw 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-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= -google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= -google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 h1:x9PwdEgd11LgK+orcck69WVRo7DezSO4VUMPI4xpc8A= -google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c h1:NUsgEN92SQQqzfA+YtqYNqYmB3DMMYLlIwUZAQFVFbo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= 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= @@ -1646,8 +1646,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu 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.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= -google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= +google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= 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= diff --git a/modules/apps/27-interchain-accounts/controller/client/cli/tx.go b/modules/apps/27-interchain-accounts/controller/client/cli/tx.go index 39f46d22533..d384edd0b95 100644 --- a/modules/apps/27-interchain-accounts/controller/client/cli/tx.go +++ b/modules/apps/27-interchain-accounts/controller/client/cli/tx.go @@ -14,11 +14,15 @@ import ( "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ) const ( // The controller chain channel version - flagVersion = "version" + flagVersion = "version" + // The channel ordering + flagOrdering = "ordering" flagRelativePacketTimeout = "relative-packet-timeout" ) @@ -29,8 +33,8 @@ func newRegisterInterchainAccountCmd() *cobra.Command { Long: strings.TrimSpace(`Register an account on the counterparty chain via the connection id from the source chain. Connection identifier should be for the source chain and the interchain account will be created on the counterparty chain. Callers are expected to -provide the appropriate application version string via {version} flag. Generates a new -port identifier using the provided owner string, binds to the port identifier and claims +provide the appropriate application version string via {version} flag and the desired ordering +via the {ordering} flag. Generates a new port identifier using the provided owner string, binds to the port identifier and claims the associated capability.`), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { @@ -46,13 +50,19 @@ the associated capability.`), return err } - msg := types.NewMsgRegisterInterchainAccount(connectionID, owner, version) + ordering, err := parseOrdering(cmd) + if err != nil { + return err + } + + msg := types.NewMsgRegisterInterchainAccountWithOrdering(connectionID, owner, version, ordering) return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } cmd.Flags().String(flagVersion, "", "Controller chain channel version") + cmd.Flags().String(flagOrdering, channeltypes.UNORDERED.String(), fmt.Sprintf("Channel ordering, can be one of: %s", strings.Join(connectiontypes.SupportedOrderings, ", "))) flags.AddTxFlagsToCmd(cmd) return cmd @@ -107,3 +117,18 @@ appropriate relative timeoutTimestamp must be provided with flag {relative-packe return cmd } + +// parseOrdering gets the channel ordering from the flags. +func parseOrdering(cmd *cobra.Command) (channeltypes.Order, error) { + orderString, err := cmd.Flags().GetString(flagOrdering) + if err != nil { + return channeltypes.NONE, err + } + + order, found := channeltypes.Order_value[strings.ToUpper(orderString)] + if !found { + return channeltypes.NONE, fmt.Errorf("invalid channel ordering: %s", orderString) + } + + return channeltypes.Order(order), nil +} diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index b51592a12d8..fe9ef65a026 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -22,6 +22,7 @@ import ( var ( _ porttypes.Middleware = (*IBCMiddleware)(nil) _ porttypes.PacketDataUnmarshaler = (*IBCMiddleware)(nil) + _ porttypes.UpgradableModule = (*IBCMiddleware)(nil) ) // IBCMiddleware implements the ICS26 callbacks for the fee middleware given the @@ -231,6 +232,83 @@ func (im IBCMiddleware) OnTimeoutPacket( return nil } +// OnChanUpgradeInit implements the IBCModule interface +func (im IBCMiddleware) OnChanUpgradeInit(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) (string, error) { + if !im.keeper.GetParams(ctx).ControllerEnabled { + return "", types.ErrControllerSubModuleDisabled + } + + proposedVersion, err := im.keeper.OnChanUpgradeInit(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion) + if err != nil { + return "", err + } + + connectionID, err := im.keeper.GetConnectionID(ctx, portID, channelID) + if err != nil { + return "", err + } + + if im.app != nil && im.keeper.IsMiddlewareEnabled(ctx, portID, connectionID) { + // Only cast to UpgradableModule if the application is set. + cbs, ok := im.app.(porttypes.UpgradableModule) + if !ok { + return "", errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack") + } + return cbs.OnChanUpgradeInit(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion) + } + + return proposedVersion, nil +} + +// OnChanUpgradeTry implements the IBCModule interface +func (IBCMiddleware) OnChanUpgradeTry(_ sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, counterpartyVersion string) (string, error) { + return "", errorsmod.Wrap(icatypes.ErrInvalidChannelFlow, "channel upgrade handshake must be initiated by controller chain") +} + +// OnChanUpgradeAck implements the IBCModule interface +func (im IBCMiddleware) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { + if !im.keeper.GetParams(ctx).ControllerEnabled { + return types.ErrControllerSubModuleDisabled + } + + if err := im.keeper.OnChanUpgradeAck(ctx, portID, channelID, counterpartyVersion); err != nil { + return err + } + + connectionID, err := im.keeper.GetConnectionID(ctx, portID, channelID) + if err != nil { + return err + } + + if im.app != nil && im.keeper.IsMiddlewareEnabled(ctx, portID, connectionID) { + // Only cast to UpgradableModule if the application is set. + cbs, ok := im.app.(porttypes.UpgradableModule) + if !ok { + return errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack") + } + return cbs.OnChanUpgradeAck(ctx, portID, channelID, counterpartyVersion) + } + + return nil +} + +// OnChanUpgradeOpen implements the IBCModule interface +func (im IBCMiddleware) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) { + connectionID, err := im.keeper.GetConnectionID(ctx, portID, channelID) + if err != nil { + panic(err) + } + + if im.app != nil && im.keeper.IsMiddlewareEnabled(ctx, portID, connectionID) { + // Only cast to UpgradableModule if the application is set. + cbs, ok := im.app.(porttypes.UpgradableModule) + if !ok { + panic(errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack")) + } + cbs.OnChanUpgradeOpen(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion) + } +} + // SendPacket implements the ICS4 Wrapper interface func (IBCMiddleware) SendPacket( ctx sdk.Context, diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index 3394c1af332..a5cff411c5e 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -18,8 +18,11 @@ import ( porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibctesting "github.com/cosmos/ibc-go/v8/testing" + ibcmock "github.com/cosmos/ibc-go/v8/testing/mock" ) +const invalidVersion = "invalid|version" + var ( // TestOwnerAddress defines a reusable bech32 address for testing purposes TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" @@ -79,7 +82,7 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, TestVersion); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccountWithOrdering(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, TestVersion, channeltypes.ORDERED); err != nil { return err } @@ -157,11 +160,6 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { suite.chainA.GetSimApp().ICAControllerKeeper.SetParams(suite.chainA.GetContext(), types.NewParams(false)) }, false, }, - { - "ICA OnChanOpenInit fails - UNORDERED channel", func() { - channel.Ordering = channeltypes.UNORDERED - }, false, - }, { "ICA auth module callback fails", func() { suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, @@ -277,10 +275,10 @@ func (suite *InterchainAccountsTestSuite) TestChanOpenTry() { suite.Require().NoError(err) channelKey := host.ChannelKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - proofInit, proofHeight := path.EndpointB.Chain.QueryProof(channelKey) + initProof, proofHeight := path.EndpointB.Chain.QueryProof(channelKey) // use chainA (controller) for ChanOpenTry - msg := channeltypes.NewMsgChannelOpenTry(path.EndpointA.ChannelConfig.PortID, TestVersion, channeltypes.ORDERED, []string{path.EndpointA.ConnectionID}, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, TestVersion, proofInit, proofHeight, icatypes.ModuleName) + msg := channeltypes.NewMsgChannelOpenTry(path.EndpointA.ChannelConfig.PortID, TestVersion, channeltypes.ORDERED, []string{path.EndpointA.ConnectionID}, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, TestVersion, initProof, proofHeight, icatypes.ModuleName) handler := suite.chainA.GetSimApp().MsgServiceRouter().Handler(msg) _, err = handler(suite.chainA.GetContext(), msg) @@ -327,7 +325,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { }, { "ICA OnChanOpenACK fails - invalid version", func() { - path.EndpointB.ChannelConfig.Version = "invalid|version" + path.EndpointB.ChannelConfig.Version = invalidVersion }, false, }, { @@ -424,10 +422,10 @@ func (suite *InterchainAccountsTestSuite) TestChanOpenConfirm() { // query proof from ChainB channelKey := host.ChannelKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - proofAck, proofHeight := path.EndpointB.Chain.QueryProof(channelKey) + ackProof, proofHeight := path.EndpointB.Chain.QueryProof(channelKey) // use chainA (controller) for ChanOpenConfirm - msg := channeltypes.NewMsgChannelOpenConfirm(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, proofAck, proofHeight, icatypes.ModuleName) + msg := channeltypes.NewMsgChannelOpenConfirm(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, ackProof, proofHeight, icatypes.ModuleName) handler := suite.chainA.GetSimApp().MsgServiceRouter().Handler(msg) _, err = handler(suite.chainA.GetContext(), msg) @@ -762,6 +760,312 @@ func (suite *InterchainAccountsTestSuite) TestOnTimeoutPacket() { } } +func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeInit() { + var ( + path *ibctesting.Path + isNilApp bool + version string + channelOrder channeltypes.Order + ) + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success w/ ORDERED channel", func() {}, nil, + }, + { + "success w/ UNORDERED channel", func() { + channelOrder = channeltypes.UNORDERED + }, nil, + }, + { + "success: nil underlying app", + func() { + isNilApp = true + }, + nil, + }, + { + "controller submodule disabled", func() { + suite.chainA.GetSimApp().ICAControllerKeeper.SetParams(suite.chainA.GetContext(), types.NewParams(false)) + }, types.ErrControllerSubModuleDisabled, + }, + { + "ICA OnChanUpgradeInit fails - invalid version", func() { + version = invalidVersion + }, icatypes.ErrUnknownDataType, + }, + { + "ICA auth module callback fails", func() { + suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanUpgradeInit = func(ctx sdk.Context, portID, channelID string, order channeltypes.Order, connectionHops []string, version string) (string, error) { + return "", ibcmock.MockApplicationCallbackError + } + }, ibcmock.MockApplicationCallbackError, + }, + { + "middleware disabled", func() { + suite.chainA.GetSimApp().ICAControllerKeeper.DeleteMiddlewareEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ConnectionID) + suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanUpgradeInit = func(ctx sdk.Context, portID, channelID string, order channeltypes.Order, connectionHops []string, version string) (string, error) { + return "", ibcmock.MockApplicationCallbackError + } + }, nil, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + isNilApp = false + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) + + metadata := icatypes.NewDefaultMetadata(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) + + tc.malleate() // malleate mutates test data + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + app, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) + + if isNilApp { + cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) + } + + channelOrder = channeltypes.ORDERED + + version, err = cbs.OnChanUpgradeInit( + suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + channelOrder, + []string{path.EndpointA.ConnectionID}, + version, + ) + + if tc.expError == nil { + suite.Require().NoError(err) + } else { + suite.Require().ErrorIs(err, tc.expError) + suite.Require().Empty(version) + } + }) + } +} + +// OnChanUpgradeTry callback returns error on controller chains +func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeTry() { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + // call application callback directly + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + app, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) + + version, err := cbs.OnChanUpgradeTry( + suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, + path.EndpointA.ChannelConfig.Order, []string{path.EndpointA.ConnectionID}, path.EndpointB.ChannelConfig.Version, + ) + suite.Require().Error(err) + suite.Require().ErrorIs(err, icatypes.ErrInvalidChannelFlow) + suite.Require().Equal("", version) +} + +func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeAck() { + var ( + path *ibctesting.Path + isNilApp bool + counterpartyVersion string + ) + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", func() {}, nil, + }, + { + "success: nil underlying app", + func() { + isNilApp = true + }, + nil, + }, + { + "controller submodule disabled", func() { + suite.chainA.GetSimApp().ICAControllerKeeper.SetParams(suite.chainA.GetContext(), types.NewParams(false)) + }, types.ErrControllerSubModuleDisabled, + }, + { + "ICA OnChanUpgradeAck fails - invalid version", func() { + counterpartyVersion = invalidVersion + }, icatypes.ErrUnknownDataType, + }, + { + "ICA auth module callback fails", func() { + suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanUpgradeAck = func(ctx sdk.Context, portID, channelID string, counterpartyVersion string) error { + return ibcmock.MockApplicationCallbackError + } + }, ibcmock.MockApplicationCallbackError, + }, + { + "middleware disabled", func() { + suite.chainA.GetSimApp().ICAControllerKeeper.DeleteMiddlewareEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ConnectionID) + suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanUpgradeAck = func(ctx sdk.Context, portID, channelID string, counterpartyVersion string) error { + return ibcmock.MockApplicationCallbackError + } + }, nil, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + isNilApp = false + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + counterpartyVersion = path.EndpointB.GetChannel().Version + + tc.malleate() // malleate mutates test data + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + app, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) + + if isNilApp { + cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) + } + + err = cbs.OnChanUpgradeAck( + suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + counterpartyVersion, + ) + + if tc.expError == nil { + suite.Require().NoError(err) + } else { + suite.Require().ErrorIs(err, tc.expError) + } + }) + } +} + +func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeOpen() { + var ( + path *ibctesting.Path + isNilApp bool + counterpartyVersion string + channelOrder channeltypes.Order + ) + + testCases := []struct { + name string + malleate func() + }{ + { + "success w/ ORDERED channel", func() {}, + }, + { + "success w/ UNORDERED channel", func() { + channelOrder = channeltypes.UNORDERED + }, + }, + { + "success: nil app", + func() { + isNilApp = true + }, + }, + { + "middleware disabled", func() { + suite.chainA.GetSimApp().ICAControllerKeeper.DeleteMiddlewareEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ConnectionID) + suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanUpgradeAck = func(ctx sdk.Context, portID, channelID string, counterpartyVersion string) error { + return ibcmock.MockApplicationCallbackError + } + }, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + isNilApp = false + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + counterpartyVersion = path.EndpointB.GetChannel().Version + + tc.malleate() // malleate mutates test data + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + app, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) + + if isNilApp { + cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) + } + + channelOrder = channeltypes.ORDERED + + cbs.OnChanUpgradeOpen( + suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + channelOrder, + []string{path.EndpointA.ConnectionID}, + counterpartyVersion, + ) + }) + } +} + func (suite *InterchainAccountsTestSuite) TestSingleHostMultipleControllers() { var ( pathAToB *ibctesting.Path @@ -860,7 +1164,7 @@ func (suite *InterchainAccountsTestSuite) TestInFlightHandshakeRespectsGoAPICall // attempt to start a second handshake via the controller msg server msgServer := controllerkeeper.NewMsgServerImpl(&suite.chainA.GetSimApp().ICAControllerKeeper) - msgRegisterInterchainAccount := types.NewMsgRegisterInterchainAccount(path.EndpointA.ConnectionID, suite.chainA.SenderAccount.GetAddress().String(), TestVersion) + msgRegisterInterchainAccount := types.NewMsgRegisterInterchainAccountWithOrdering(path.EndpointA.ConnectionID, suite.chainA.SenderAccount.GetAddress().String(), TestVersion, channeltypes.ORDERED) res, err := msgServer.RegisterInterchainAccount(suite.chainA.GetContext(), msgRegisterInterchainAccount) suite.Require().Error(err) @@ -873,7 +1177,7 @@ func (suite *InterchainAccountsTestSuite) TestInFlightHandshakeRespectsMsgServer // initiate a channel handshake such that channel.State == INIT msgServer := controllerkeeper.NewMsgServerImpl(&suite.chainA.GetSimApp().ICAControllerKeeper) - msgRegisterInterchainAccount := types.NewMsgRegisterInterchainAccount(path.EndpointA.ConnectionID, suite.chainA.SenderAccount.GetAddress().String(), TestVersion) + msgRegisterInterchainAccount := types.NewMsgRegisterInterchainAccountWithOrdering(path.EndpointA.ConnectionID, suite.chainA.SenderAccount.GetAddress().String(), TestVersion, channeltypes.ORDERED) res, err := msgServer.RegisterInterchainAccount(suite.chainA.GetContext(), msgRegisterInterchainAccount) suite.Require().NotNil(res) @@ -906,7 +1210,7 @@ func (suite *InterchainAccountsTestSuite) TestClosedChannelReopensWithMsgServer( // route a new MsgRegisterInterchainAccount in order to reopen the msgServer := controllerkeeper.NewMsgServerImpl(&suite.chainA.GetSimApp().ICAControllerKeeper) - msgRegisterInterchainAccount := types.NewMsgRegisterInterchainAccount(path.EndpointA.ConnectionID, suite.chainA.SenderAccount.GetAddress().String(), path.EndpointA.ChannelConfig.Version) + msgRegisterInterchainAccount := types.NewMsgRegisterInterchainAccountWithOrdering(path.EndpointA.ConnectionID, suite.chainA.SenderAccount.GetAddress().String(), path.EndpointA.ChannelConfig.Version, channeltypes.ORDERED) res, err := msgServer.RegisterInterchainAccount(suite.chainA.GetContext(), msgRegisterInterchainAccount) suite.Require().NoError(err) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/account.go b/modules/apps/27-interchain-accounts/controller/keeper/account.go index bd0b04513c4..0ccafddcc09 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/account.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/account.go @@ -41,7 +41,48 @@ func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, connectionID, owner, k.SetMiddlewareEnabled(ctx, portID, connectionID) - _, err = k.registerInterchainAccount(ctx, connectionID, portID, version) + _, err = k.registerInterchainAccount(ctx, connectionID, portID, version, channeltypes.UNORDERED) + if err != nil { + return err + } + + return nil +} + +// RegisterInterchainAccountWithOrdering is the entry point to registering an interchain account: +// - It generates a new port identifier using the provided owner string, binds to the port identifier and claims the associated capability. +// - Callers are expected to provide the appropriate application version string. +// - For example, this could be an ICS27 encoded metadata type or an ICS29 encoded metadata type with a nested application version. +// - A new MsgChannelOpenInit is routed through the MsgServiceRouter, executing the OnOpenChanInit callback stack as configured. +// - An error is returned if the port identifier is already in use. Gaining access to interchain accounts whose channels +// have closed cannot be done with this function. A regular MsgChannelOpenInit must be used. +// +// Deprecated: this is a legacy API that is only intended to function correctly in workflows where an underlying authentication application has been set. +// Calling this API will result in all packet callbacks being routed to the underlying application. + +// Please use MsgRegisterInterchainAccount for use cases which do not need to route to an underlying application. + +// Prior to v6.x.x of ibc-go, the controller module was only functional as middleware, with authentication performed +// by the underlying application. For a full summary of the changes in v6.x.x, please see ADR009. +// This API will be removed in later releases. +func (k Keeper) RegisterInterchainAccountWithOrdering(ctx sdk.Context, connectionID, owner, version string, ordering channeltypes.Order) error { + portID, err := icatypes.NewControllerPortID(owner) + if err != nil { + return err + } + + if k.IsMiddlewareDisabled(ctx, portID, connectionID) && !k.IsActiveChannelClosed(ctx, connectionID, portID) { + return errorsmod.Wrap(icatypes.ErrInvalidChannelFlow, "channel is already active or a handshake is in flight") + } + + k.SetMiddlewareEnabled(ctx, portID, connectionID) + + // use ORDER_UNORDERED as default in case ordering is NONE + if ordering == channeltypes.NONE { + ordering = channeltypes.UNORDERED + } + + _, err = k.registerInterchainAccount(ctx, connectionID, portID, version, ordering) if err != nil { return err } @@ -51,7 +92,7 @@ func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, connectionID, owner, // registerInterchainAccount registers an interchain account, returning the channel id of the MsgChannelOpenInitResponse // and an error if one occurred. -func (k Keeper) registerInterchainAccount(ctx sdk.Context, connectionID, portID, version string) (string, error) { +func (k Keeper) registerInterchainAccount(ctx sdk.Context, connectionID, portID, version string, ordering channeltypes.Order) (string, error) { // if there is an active channel for this portID / connectionID return an error activeChannelID, found := k.GetOpenActiveChannel(ctx, connectionID, portID) if found { @@ -69,7 +110,7 @@ func (k Keeper) registerInterchainAccount(ctx sdk.Context, connectionID, portID, } } - msg := channeltypes.NewMsgChannelOpenInit(portID, version, channeltypes.ORDERED, []string{connectionID}, icatypes.HostPortID, authtypes.NewModuleAddress(icatypes.ModuleName).String()) + msg := channeltypes.NewMsgChannelOpenInit(portID, version, ordering, []string{connectionID}, icatypes.HostPortID, authtypes.NewModuleAddress(icatypes.ModuleName).String()) handler := k.msgRouter.Handler(msg) res, err := handler(ctx, msg) if err != nil { diff --git a/modules/apps/27-interchain-accounts/controller/keeper/export_test.go b/modules/apps/27-interchain-accounts/controller/keeper/export_test.go index 382dde7a805..2cd4338dde2 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/export_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/export_test.go @@ -4,9 +4,19 @@ package keeper This file is to allow for unexported functions and fields to be accessible to the testing package. */ -import porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" +) // GetICS4Wrapper is a getter for the keeper's ICS4Wrapper. func (k *Keeper) GetICS4Wrapper() porttypes.ICS4Wrapper { return k.ics4Wrapper } + +// GetAppMetadata is a wrapper around getAppMetadata to allow the function to be directly called in tests. +func (k Keeper) GetAppMetadata(ctx sdk.Context, portID, channelID string) (icatypes.Metadata, error) { + return k.getAppMetadata(ctx, portID, channelID) +} diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go index 0ce3802b48e..a45d09c6604 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go @@ -10,12 +10,12 @@ import ( capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ) // OnChanOpenInit performs basic validation of channel initialization. -// The channel order must be ORDERED, the counterparty port identifier -// must be the host chain representation as defined in the types package, +// The counterparty port identifier must be the host chain representation as defined in the types package, // the channel version must be equal to the version in the types package, // there must not be an active channel for the specfied port identifier, // and the interchain accounts module must be able to claim the channel @@ -30,10 +30,6 @@ func (k Keeper) OnChanOpenInit( counterparty channeltypes.Counterparty, version string, ) (string, error) { - if order != channeltypes.ORDERED { - return "", errorsmod.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s", channeltypes.ORDERED, order) - } - if !strings.HasPrefix(portID, icatypes.ControllerPortPrefix) { return "", errorsmod.Wrapf(icatypes.ErrInvalidControllerPort, "expected %s{owner-account-address}, got %s", icatypes.ControllerPortPrefix, portID) } @@ -42,7 +38,10 @@ func (k Keeper) OnChanOpenInit( return "", errorsmod.Wrapf(icatypes.ErrInvalidHostPort, "expected %s, got %s", icatypes.HostPortID, counterparty.PortId) } - var metadata icatypes.Metadata + var ( + err error + metadata icatypes.Metadata + ) if strings.TrimSpace(version) == "" { connection, err := k.channelKeeper.GetConnection(ctx, connectionHops[0]) if err != nil { @@ -51,8 +50,9 @@ func (k Keeper) OnChanOpenInit( metadata = icatypes.NewDefaultMetadata(connectionHops[0], connection.GetCounterparty().GetConnectionID()) } else { - if err := icatypes.ModuleCdc.UnmarshalJSON([]byte(version), &metadata); err != nil { - return "", errorsmod.Wrapf(icatypes.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain accounts metadata") + metadata, err = icatypes.MetadataFromVersion(version) + if err != nil { + return "", err } } @@ -67,8 +67,12 @@ func (k Keeper) OnChanOpenInit( panic(fmt.Errorf("active channel mapping set for %s but channel does not exist in channel store", activeChannelID)) } - if channel.IsOpen() { - return "", errorsmod.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s is already OPEN", activeChannelID, portID) + if channel.State != channeltypes.CLOSED { + return "", errorsmod.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s must be %s", activeChannelID, portID, channeltypes.CLOSED) + } + + if channel.Ordering != order { + return "", errorsmod.Wrapf(channeltypes.ErrInvalidChannelOrdering, "order cannot change when reopening a channel expected %s, got %s", channel.Ordering, order) } appVersion, found := k.GetAppVersion(ctx, portID, activeChannelID) @@ -100,11 +104,10 @@ func (k Keeper) OnChanOpenAck( return errorsmod.Wrapf(icatypes.ErrInvalidControllerPort, "expected %s{owner-account-address}, got %s", icatypes.ControllerPortPrefix, portID) } - var metadata icatypes.Metadata - if err := icatypes.ModuleCdc.UnmarshalJSON([]byte(counterpartyVersion), &metadata); err != nil { - return errorsmod.Wrapf(icatypes.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain accounts metadata") + metadata, err := icatypes.MetadataFromVersion(counterpartyVersion) + if err != nil { + return err } - if activeChannelID, found := k.GetOpenActiveChannel(ctx, metadata.ControllerConnectionId, portID); found { return errorsmod.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s", activeChannelID, portID) } @@ -136,3 +139,124 @@ func (Keeper) OnChanCloseConfirm( ) error { return nil } + +// OnChanUpgradeInit performs the upgrade init step of the channel upgrade handshake. +// The upgrade init callback must verify the proposed changes to the order, connectionHops, and version. +// Within the version we have the tx type, encoding, interchain account address, host/controller connectionID's +// and the ICS27 protocol version. +// +// The following may be changed: +// - tx type (must be supported) +// - encoding (must be supported) +// - order +// +// The following may not be changed: +// - connectionHops (and subsequently host/controller connectionIDs) +// - interchain account address +// - ICS27 protocol version +func (k Keeper) OnChanUpgradeInit(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedversion string) (string, error) { + // verify connection hops has not changed + connectionID, err := k.GetConnectionID(ctx, portID, channelID) + if err != nil { + return "", err + } + + if len(proposedConnectionHops) != 1 || proposedConnectionHops[0] != connectionID { + return "", errorsmod.Wrapf(channeltypes.ErrInvalidUpgrade, "expected connection hops %s, got %s", []string{connectionID}, proposedConnectionHops) + } + + // verify proposed version only modifies tx type or encoding + if strings.TrimSpace(proposedversion) == "" { + return "", errorsmod.Wrap(icatypes.ErrInvalidVersion, "version cannot be empty") + } + + proposedMetadata, err := icatypes.MetadataFromVersion(proposedversion) + if err != nil { + return "", err + } + + currentMetadata, err := k.getAppMetadata(ctx, portID, channelID) + if err != nil { + return "", err + } + + // ValidateControllerMetadata will ensure the ICS27 protocol version has not changed and that the + // tx type and encoding are supported + if err := icatypes.ValidateControllerMetadata(ctx, k.channelKeeper, proposedConnectionHops, proposedMetadata); err != nil { + return "", errorsmod.Wrap(err, "invalid upgrade metadata") + } + + // the interchain account address on the host chain + // must remain the same after the upgrade. + if currentMetadata.Address != proposedMetadata.Address { + return "", errorsmod.Wrap(icatypes.ErrInvalidAccountAddress, "interchain account address cannot be changed") + } + + if currentMetadata.ControllerConnectionId != proposedMetadata.ControllerConnectionId { + return "", errorsmod.Wrap(connectiontypes.ErrInvalidConnection, "proposed controller connection ID must not change") + } + + if currentMetadata.HostConnectionId != proposedMetadata.HostConnectionId { + return "", errorsmod.Wrap(connectiontypes.ErrInvalidConnection, "proposed host connection ID must not change") + } + + return proposedversion, nil +} + +// OnChanUpgradeAck implements the ack setup of the channel upgrade handshake. +// The upgrade ack callback must verify the proposed changes to the channel version. +// Within the channel version we have the tx type, encoding, interchain account address, host/controller connectionID's +// and the ICS27 protocol version. +// +// The following may be changed: +// - tx type (must be supported) +// - encoding (must be supported) +// +// The following may not be changed: +// - controller connectionID +// - host connectionID +// - interchain account address +// - ICS27 protocol version +func (k Keeper) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { + if strings.TrimSpace(counterpartyVersion) == "" { + return errorsmod.Wrap(channeltypes.ErrInvalidChannelVersion, "counterparty version cannot be empty") + } + + proposedMetadata, err := icatypes.MetadataFromVersion(counterpartyVersion) + if err != nil { + return err + } + + currentMetadata, err := k.getAppMetadata(ctx, portID, channelID) + if err != nil { + return err + } + + channel, found := k.channelKeeper.GetChannel(ctx, portID, channelID) + if !found { + return errorsmod.Wrapf(channeltypes.ErrChannelNotFound, "failed to retrieve channel %s on port %s", channelID, portID) + } + + // ValidateControllerMetadata will ensure the ICS27 protocol version has not changed and that the + // tx type and encoding are supported. Note, we pass in the current channel connection hops. The upgrade init + // step will verify that the proposed connection hops will not change. + if err := icatypes.ValidateControllerMetadata(ctx, k.channelKeeper, channel.ConnectionHops, proposedMetadata); err != nil { + return errorsmod.Wrap(err, "invalid upgrade metadata") + } + + // the interchain account address on the host chain + // must remain the same after the upgrade. + if currentMetadata.Address != proposedMetadata.Address { + return errorsmod.Wrap(icatypes.ErrInvalidAccountAddress, "address cannot be changed") + } + + if currentMetadata.ControllerConnectionId != proposedMetadata.ControllerConnectionId { + return errorsmod.Wrap(connectiontypes.ErrInvalidConnection, "proposed controller connection ID must not change") + } + + if currentMetadata.HostConnectionId != proposedMetadata.HostConnectionId { + return errorsmod.Wrap(connectiontypes.ErrInvalidConnection, "proposed host connection ID must not change") + } + + return nil +} diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go index 29ebf75dec1..341df9b6295 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go @@ -3,11 +3,17 @@ package keeper_test import ( capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) +const ( + differentConnectionID = "connection-100" +) + func (suite *KeeperTestSuite) TestOnChanOpenInit() { var ( channel *channeltypes.Channel @@ -19,12 +25,12 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { testCases := []struct { name string malleate func() - expPass bool + expError error }{ { "success", func() {}, - true, + nil, }, { "success: previous active channel closed", @@ -42,14 +48,14 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { path.EndpointA.SetChannel(channel) }, - true, + nil, }, { "success: empty channel version returns default metadata JSON string", func() { channel.Version = "" }, - true, + nil, }, { "success: channel reopening", @@ -66,7 +72,25 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { path.EndpointA.ChannelID = "" path.EndpointB.ChannelID = "" }, - true, + nil, + }, + { + "failure: different ordering from previous channel", + func() { + suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + + counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + channel := channeltypes.Channel{ + State: channeltypes.CLOSED, + Ordering: channeltypes.UNORDERED, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointA.ConnectionID}, + Version: TestVersion, + } + + path.EndpointA.SetChannel(channel) + }, + channeltypes.ErrInvalidChannelOrdering, }, { "invalid metadata - previous metadata is different", @@ -90,21 +114,14 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { } path.EndpointA.SetChannel(closedChannel) }, - false, - }, - { - "invalid order - UNORDERED", - func() { - channel.Ordering = channeltypes.UNORDERED - }, - false, + icatypes.ErrInvalidVersion, }, { "invalid port ID", func() { path.EndpointA.ChannelConfig.PortID = "invalid-port-id" //nolint:goconst }, - false, + icatypes.ErrInvalidControllerPort, }, { "invalid counterparty port ID", @@ -112,7 +129,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { path.EndpointA.SetChannel(*channel) channel.Counterparty.PortId = "invalid-port-id" }, - false, + icatypes.ErrInvalidHostPort, }, { "invalid metadata bytestring", @@ -120,7 +137,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { path.EndpointA.SetChannel(*channel) channel.Version = "invalid-metadata-bytestring" }, - false, + icatypes.ErrUnknownDataType, }, { "unsupported encoding format", @@ -133,7 +150,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { channel.Version = string(versionBytes) path.EndpointA.SetChannel(*channel) }, - false, + icatypes.ErrInvalidCodec, }, { "unsupported transaction type", @@ -146,7 +163,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { channel.Version = string(versionBytes) path.EndpointA.SetChannel(*channel) }, - false, + icatypes.ErrUnknownDataType, }, { "connection not found", @@ -154,7 +171,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { channel.ConnectionHops = []string{"invalid-connnection-id"} path.EndpointA.SetChannel(*channel) }, - false, + connectiontypes.ErrConnectionNotFound, }, { "connection not found with default empty channel version", @@ -162,7 +179,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { channel.ConnectionHops = []string{"connection-10"} channel.Version = "" }, - false, + connectiontypes.ErrConnectionNotFound, }, { "invalid controller connection ID", @@ -175,7 +192,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { channel.Version = string(versionBytes) path.EndpointA.SetChannel(*channel) }, - false, + connectiontypes.ErrInvalidConnection, }, { "invalid host connection ID", @@ -188,7 +205,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { channel.Version = string(versionBytes) path.EndpointA.SetChannel(*channel) }, - false, + connectiontypes.ErrInvalidConnection, }, { "invalid version", @@ -201,10 +218,10 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { channel.Version = string(versionBytes) path.EndpointA.SetChannel(*channel) }, - false, + icatypes.ErrInvalidVersion, }, { - "channel is already active", + "channel is already active (OPEN state)", func() { suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) @@ -218,7 +235,24 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { } suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channel) }, - false, + icatypes.ErrActiveChannelAlreadySet, + }, + { + "channel is already active (FLUSHING state)", + func() { + suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + + counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + channel := channeltypes.Channel{ + State: channeltypes.FLUSHING, + Ordering: channeltypes.ORDERED, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointA.ConnectionID}, + Version: TestVersion, + } + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channel) + }, + icatypes.ErrActiveChannelAlreadySet, }, } @@ -262,11 +296,13 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.Version, ) - if tc.expPass { + expPass := tc.expError == nil + if expPass { suite.Require().NoError(err) suite.Require().Equal(string(versionBytes), version) } else { suite.Require().Error(err) + suite.Require().ErrorIs(err, tc.expError) } }) } @@ -471,3 +507,357 @@ func (suite *KeeperTestSuite) TestOnChanCloseConfirm() { }) } } + +func (suite *KeeperTestSuite) TestOnChanUpgradeInit() { + const ( + invalidVersion = "invalid-version" + ) + + var ( + path *ibctesting.Path + metadata icatypes.Metadata + version string + order channeltypes.Order + ) + + // updateMetadata is a helper function which modifies the metadata stored in the channel version + // and marshals it into a string to pass to OnChanUpgradeInit as the version string. + updateMetadata := func(modificationFn func(*icatypes.Metadata)) { + metadata, err := icatypes.MetadataFromVersion(path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version) + suite.Require().NoError(err) + modificationFn(&metadata) + version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) + } + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + name: "success: change order", + malleate: func() { + order = channeltypes.UNORDERED + }, + expError: nil, + }, + { + name: "failure: connectionID not found", + malleate: func() { + // channelID is provided via the endpoint channelID + path.EndpointA.ChannelID = "invalid channel" + }, + expError: channeltypes.ErrChannelNotFound, + }, + { + name: "failure: invalid proposed connectionHops", + malleate: func() { + // connection hops is provided via endpoint connectionID + path.EndpointA.ConnectionID = differentConnectionID + }, + expError: channeltypes.ErrInvalidUpgrade, + }, + { + name: "failure: empty version", + malleate: func() { + version = "" + }, + expError: icatypes.ErrInvalidVersion, + }, + { + name: "failure: cannot decode version string", + malleate: func() { + version = invalidVersion + }, + expError: icatypes.ErrUnknownDataType, + }, + { + name: "failure: cannot decode self version string", + malleate: func() { + ch := path.EndpointA.GetChannel() + ch.Version = invalidVersion + path.EndpointA.SetChannel(ch) + }, + expError: icatypes.ErrUnknownDataType, + }, + { + name: "failure: failed controller metadata validation, invalid encoding", + malleate: func() { + updateMetadata(func(metadata *icatypes.Metadata) { + metadata.Encoding = "invalid-encoding" + }) + }, + expError: icatypes.ErrInvalidCodec, + }, + { + name: "failure: failed controller metadata validation, invalid tx type", + malleate: func() { + updateMetadata(func(metadata *icatypes.Metadata) { + metadata.TxType = "invalid-tx-type" + }) + }, + expError: icatypes.ErrUnknownDataType, + }, + { + name: "failure: failed controller metadata validation, invalid interchain account version", + malleate: func() { + updateMetadata(func(metadata *icatypes.Metadata) { + metadata.Version = "invalid-interchain-account-version" + }) + }, + expError: icatypes.ErrInvalidVersion, + }, + { + name: "failure: interchain account address changed", + malleate: func() { + updateMetadata(func(metadata *icatypes.Metadata) { + metadata.Address = TestOwnerAddress // use valid address + }) + }, + expError: icatypes.ErrInvalidAccountAddress, + }, + { + name: "failure: controller connection ID has changed", + malleate: func() { + updateMetadata(func(metadata *icatypes.Metadata) { + metadata.ControllerConnectionId = differentConnectionID + }) + }, + expError: connectiontypes.ErrInvalidConnection, // the explicit checks on the controller connection identifier are unreachable + }, + { + name: "failure: host connection ID has changed", + malleate: func() { + updateMetadata(func(metadata *icatypes.Metadata) { + metadata.HostConnectionId = differentConnectionID + }) + }, + expError: connectiontypes.ErrInvalidConnection, // the explicit checks on the host connection identifier are unreachable + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + currentMetadata, err := suite.chainA.GetSimApp().ICAControllerKeeper.GetAppMetadata(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().NoError(err) + + order = channeltypes.ORDERED + metadata = icatypes.NewDefaultMetadata(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + // use the same address as the previous metadata. + metadata.Address = currentMetadata.Address + + // this is the actual change to the version. + metadata.Encoding = icatypes.EncodingProto3JSON + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) + + version = path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version + + tc.malleate() // malleate mutates test data + + upgradeVersion, err := path.EndpointA.Chain.GetSimApp().ICAControllerKeeper.OnChanUpgradeInit( + path.EndpointA.Chain.GetContext(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + order, + []string{path.EndpointA.ConnectionID}, + version, + ) + + expPass := tc.expError == nil + + if expPass { + suite.Require().NoError(err) + suite.Require().Equal(upgradeVersion, version) + } else { + suite.Require().ErrorIs(err, tc.expError) + } + }) + } +} + +func (suite *KeeperTestSuite) TestOnChanUpgradeAck() { + const ( + invalidVersion = "invalid-version" + ) + + var ( + path *ibctesting.Path + metadata icatypes.Metadata + counterpartyVersion string + ) + + // updateMetadata is a helper function which modifies the metadata stored in the channel version + // and marshals it into a string to pass to OnChanUpgradeAck as the counterpartyVersion string. + updateMetadata := func(modificationFn func(*icatypes.Metadata)) { + metadata, err := icatypes.MetadataFromVersion(path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version) + suite.Require().NoError(err) + modificationFn(&metadata) + counterpartyVersion = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) + } + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + name: "failure: empty counterparty version", + malleate: func() { + counterpartyVersion = "" + }, + expError: channeltypes.ErrInvalidChannelVersion, + }, + { + name: "failure: invalid counterparty version", + malleate: func() { + counterpartyVersion = invalidVersion + }, + expError: icatypes.ErrUnknownDataType, + }, + { + name: "failure: cannot decode self version string", + malleate: func() { + channel := path.EndpointA.GetChannel() + channel.Version = invalidVersion + path.EndpointA.SetChannel(channel) + }, + expError: icatypes.ErrUnknownDataType, + }, + { + name: "failure: channel not found", + malleate: func() { + // channelID is provided via the endpoint channelID + path.EndpointA.ChannelID = "invalid channel" + }, + expError: ibcerrors.ErrNotFound, // GetChannel error is unreachable + }, + { + name: "failure: failed controller metadata validation, invalid encoding", + malleate: func() { + updateMetadata(func(metadata *icatypes.Metadata) { + metadata.Encoding = "invalid-encoding" + }) + }, + expError: icatypes.ErrInvalidCodec, + }, + { + name: "failure: failed controller metadata validation, invalid tx type", + malleate: func() { + updateMetadata(func(metadata *icatypes.Metadata) { + metadata.TxType = "invalid-tx-type" + }) + }, + expError: icatypes.ErrUnknownDataType, + }, + { + name: "failure: failed controller metadata validation, invalid interchain account version", + malleate: func() { + updateMetadata(func(metadata *icatypes.Metadata) { + metadata.Version = "invalid-interchain-account-version" + }) + }, + expError: icatypes.ErrInvalidVersion, + }, + { + name: "failure: interchain account address changed", + malleate: func() { + updateMetadata(func(metadata *icatypes.Metadata) { + metadata.Address = TestOwnerAddress // use valid address + }) + }, + expError: icatypes.ErrInvalidAccountAddress, + }, + { + name: "failure: controller connection ID has changed", + malleate: func() { + updateMetadata(func(metadata *icatypes.Metadata) { + metadata.ControllerConnectionId = differentConnectionID + }) + }, + expError: connectiontypes.ErrInvalidConnection, // the explicit checks on the controller identifier are unreachable + }, + { + name: "failure: host connection ID has changed", + malleate: func() { + updateMetadata(func(metadata *icatypes.Metadata) { + metadata.HostConnectionId = differentConnectionID + }) + }, + expError: connectiontypes.ErrInvalidConnection, // the explicit checks on the host identifier are unreachable + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + currentMetadata, err := suite.chainA.GetSimApp().ICAControllerKeeper.GetAppMetadata(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().NoError(err) + + metadata = icatypes.NewDefaultMetadata(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + // use the same address as the previous metadata. + metadata.Address = currentMetadata.Address + + // this is the actual change to the version. + metadata.Encoding = icatypes.EncodingProto3JSON + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) + + err = path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + counterpartyVersion = path.EndpointB.GetChannel().Version + + tc.malleate() // malleate mutates test data + + err = suite.chainA.GetSimApp().ICAControllerKeeper.OnChanUpgradeAck( + suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + counterpartyVersion, + ) + + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err) + suite.Require().Equal(path.EndpointA.GetChannel().Version, counterpartyVersion) + } else { + suite.Require().ErrorIs(err, tc.expError) + } + }) + } +} diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go index 63e606c395e..d378863a0e5 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go @@ -20,6 +20,7 @@ import ( channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" "github.com/cosmos/ibc-go/v8/modules/core/exported" ) @@ -149,7 +150,7 @@ func (k Keeper) GetOpenActiveChannel(ctx sdk.Context, connectionID, portID strin channel, found := k.channelKeeper.GetChannel(ctx, portID, channelID) - if found && channel.IsOpen() { + if found && channel.State == channeltypes.OPEN { return channelID, true } @@ -164,7 +165,7 @@ func (k Keeper) IsActiveChannelClosed(ctx sdk.Context, connectionID, portID stri } channel, found := k.channelKeeper.GetChannel(ctx, portID, channelID) - return found && channel.IsClosed() + return found && channel.State == channeltypes.CLOSED } // GetAllActiveChannels returns a list of all active interchain accounts controller channels and their associated connection and port identifiers @@ -280,6 +281,16 @@ func (k Keeper) GetAuthority() string { return k.authority } +// getAppMetadata retrieves the interchain accounts channel metadata from the store associated with the provided portID and channelID +func (k Keeper) getAppMetadata(ctx sdk.Context, portID, channelID string) (icatypes.Metadata, error) { + appVersion, found := k.GetAppVersion(ctx, portID, channelID) + if !found { + return icatypes.Metadata{}, errorsmod.Wrapf(ibcerrors.ErrNotFound, "app version not found for port %s and channel %s", portID, channelID) + } + + return icatypes.MetadataFromVersion(appVersion) +} + // GetParams returns the current ica/controller submodule parameters. func (k Keeper) GetParams(ctx sdk.Context) types.Params { store := ctx.KVStore(k.storeKey) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go index 2f06fa019f5..0e5f455e2ce 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go @@ -90,7 +90,7 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, TestVersion); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccountWithOrdering(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, TestVersion, channeltypes.ORDERED); err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/migrations.go b/modules/apps/27-interchain-accounts/controller/keeper/migrations.go index 705d93cb4b4..77f62a73c5d 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/migrations.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/migrations.go @@ -55,9 +55,10 @@ func (m Migrator) AssertChannelCapabilityMigrations(ctx sdk.Context) error { // MigrateParams migrates the controller submodule's parameters from the x/params to self store. func (m Migrator) MigrateParams(ctx sdk.Context) error { if m.keeper != nil { - var params controllertypes.Params - m.keeper.legacySubspace.GetParamSet(ctx, ¶ms) - + params := controllertypes.DefaultParams() + if m.keeper.legacySubspace != nil { + m.keeper.legacySubspace.GetParamSetIfExists(ctx, ¶ms) + } m.keeper.SetParams(ctx, params) m.keeper.Logger(ctx).Info("successfully migrated ica/controller submodule to self-manage params") } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/migrations_test.go b/modules/apps/27-interchain-accounts/controller/keeper/migrations_test.go index dbb7dc746a5..831a950daf0 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/migrations_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/migrations_test.go @@ -92,6 +92,23 @@ func (suite *KeeperTestSuite) TestMigratorMigrateParams() { }, icacontrollertypes.DefaultParams(), }, + { + "success: no legacy params pre-migration", + func() { + suite.chainA.GetSimApp().ICAControllerKeeper = icacontrollerkeeper.NewKeeper( + suite.chainA.Codec, + suite.chainA.GetSimApp().GetKey(icacontrollertypes.StoreKey), + nil, // assign a nil legacy param subspace + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper, + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper, + suite.chainA.GetSimApp().IBCKeeper.PortKeeper, + suite.chainA.GetSimApp().ScopedICAControllerKeeper, + suite.chainA.GetSimApp().MsgServiceRouter(), + suite.chainA.GetSimApp().ICAControllerKeeper.GetAuthority(), + ) + }, + icacontrollertypes.DefaultParams(), + }, } for _, tc := range testCases { diff --git a/modules/apps/27-interchain-accounts/controller/keeper/msg_server.go b/modules/apps/27-interchain-accounts/controller/keeper/msg_server.go index 86355cac4f9..27434730132 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/msg_server.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/msg_server.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ) @@ -39,7 +40,15 @@ func (s msgServer) RegisterInterchainAccount(goCtx context.Context, msg *types.M s.SetMiddlewareDisabled(ctx, portID, msg.ConnectionId) - channelID, err := s.registerInterchainAccount(ctx, msg.ConnectionId, portID, msg.Version) + // use ORDER_UNORDERED as default in case msg's ordering is NONE + var order channeltypes.Order + if msg.Ordering == channeltypes.NONE { + order = channeltypes.UNORDERED + } else { + order = msg.Ordering + } + + channelID, err := s.registerInterchainAccount(ctx, msg.ConnectionId, portID, msg.Version, order) if err != nil { s.Logger(ctx).Error("error registering interchain account", "error", err.Error()) return nil, err diff --git a/modules/apps/27-interchain-accounts/controller/keeper/msg_server_test.go b/modules/apps/27-interchain-accounts/controller/keeper/msg_server_test.go index 4518a4c3825..9daed01fb08 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/msg_server_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/msg_server_test.go @@ -21,6 +21,7 @@ import ( func (suite *KeeperTestSuite) TestRegisterInterchainAccount_MsgServer() { var ( msg *types.MsgRegisterInterchainAccount + expectedOrderding channeltypes.Order expectedChannelID = "channel-0" ) @@ -35,10 +36,11 @@ func (suite *KeeperTestSuite) TestRegisterInterchainAccount_MsgServer() { func() {}, }, { - "invalid connection id", - false, + "success: ordering falls back to UNORDERED if not specified", + true, func() { - msg.ConnectionId = "connection-100" + msg.Ordering = channeltypes.NONE + expectedOrderding = channeltypes.UNORDERED }, }, { @@ -48,6 +50,13 @@ func (suite *KeeperTestSuite) TestRegisterInterchainAccount_MsgServer() { msg.Owner = "" }, }, + { + "invalid connection id", + false, + func() { + msg.ConnectionId = "connection-100" + }, + }, { "empty address invalid", false, @@ -70,12 +79,14 @@ func (suite *KeeperTestSuite) TestRegisterInterchainAccount_MsgServer() { tc := tc suite.Run(tc.name, func() { + expectedOrderding = channeltypes.ORDERED + suite.SetupTest() path := NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) - msg = types.NewMsgRegisterInterchainAccount(ibctesting.FirstConnectionID, ibctesting.TestAccAddress, "") + msg = types.NewMsgRegisterInterchainAccountWithOrdering(ibctesting.FirstConnectionID, ibctesting.TestAccAddress, "", channeltypes.ORDERED) tc.malleate() @@ -92,6 +103,11 @@ func (suite *KeeperTestSuite) TestRegisterInterchainAccount_MsgServer() { suite.Require().Len(events, 2) suite.Require().Equal(events[0].Type, channeltypes.EventTypeChannelOpenInit) suite.Require().Equal(events[1].Type, sdk.EventTypeMessage) + + path.EndpointA.ChannelConfig.PortID = res.PortId + path.EndpointA.ChannelID = res.ChannelId + channel := path.EndpointA.GetChannel() + suite.Require().Equal(expectedOrderding, channel.Ordering) } else { suite.Require().Error(err) suite.Require().Nil(res) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/relay.go b/modules/apps/27-interchain-accounts/controller/keeper/relay.go index 54fce59e4fe..f728455e646 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/relay.go @@ -6,6 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" + "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -27,6 +28,10 @@ func (k Keeper) SendTx(ctx sdk.Context, _ *capabilitytypes.Capability, connectio } func (k Keeper) sendTx(ctx sdk.Context, connectionID, portID string, icaPacketData icatypes.InterchainAccountPacketData, timeoutTimestamp uint64) (uint64, error) { + if !k.GetParams(ctx).ControllerEnabled { + return 0, types.ErrControllerSubModuleDisabled + } + activeChannelID, found := k.GetOpenActiveChannel(ctx, connectionID, portID) if !found { return 0, errorsmod.Wrapf(icatypes.ErrActiveChannelNotFound, "failed to retrieve active channel on connection %s for port %s", connectionID, portID) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go b/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go index 872c041b4c4..f1fe089bb57 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go @@ -8,6 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -113,6 +114,13 @@ func (suite *KeeperTestSuite) TestSendTx() { }, false, }, + { + "controller submodule disabled", + func() { + suite.chainA.GetSimApp().ICAControllerKeeper.SetParams(suite.chainA.GetContext(), types.NewParams(false)) + }, + false, + }, { "timeout timestamp is not in the future", func() { diff --git a/modules/apps/27-interchain-accounts/controller/migrations/v6/migrations_test.go b/modules/apps/27-interchain-accounts/controller/migrations/v6/migrations_test.go index cb63db4ecd4..b8936afc7ca 100644 --- a/modules/apps/27-interchain-accounts/controller/migrations/v6/migrations_test.go +++ b/modules/apps/27-interchain-accounts/controller/migrations/v6/migrations_test.go @@ -66,7 +66,7 @@ func (*MigrationsTestSuite) RegisterInterchainAccount(endpoint *ibctesting.Endpo channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, endpoint.ChannelConfig.Version); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccountWithOrdering(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, endpoint.ChannelConfig.Version, channeltypes.ORDERED); err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/controller/types/msgs.go b/modules/apps/27-interchain-accounts/controller/types/msgs.go index 213fcbfbc04..ccd0c700a51 100644 --- a/modules/apps/27-interchain-accounts/controller/types/msgs.go +++ b/modules/apps/27-interchain-accounts/controller/types/msgs.go @@ -8,6 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ) @@ -24,12 +25,25 @@ var ( _ sdk.HasValidateBasic = (*MsgUpdateParams)(nil) ) -// NewMsgRegisterInterchainAccount creates a new instance of MsgRegisterInterchainAccount +// NewMsgRegisterInterchainAccountWithOrdering creates a new instance of MsgRegisterInterchainAccount. +func NewMsgRegisterInterchainAccountWithOrdering(connectionID, owner, version string, ordering channeltypes.Order) *MsgRegisterInterchainAccount { + return &MsgRegisterInterchainAccount{ + ConnectionId: connectionID, + Owner: owner, + Version: version, + Ordering: ordering, + } +} + +// NewMsgRegisterInterchainAccount creates a new instance of MsgRegisterInterchainAccount. +// It uses channeltypes.UNORDERED as the default ordering. Breakage in v9.0.0 will allow the ordering to be provided +// directly. Use NewMsgRegisterInterchainAccountWithOrdering to provide the ordering in previous versions. func NewMsgRegisterInterchainAccount(connectionID, owner, version string) *MsgRegisterInterchainAccount { return &MsgRegisterInterchainAccount{ ConnectionId: connectionID, Owner: owner, Version: version, + Ordering: channeltypes.UNORDERED, } } diff --git a/modules/apps/27-interchain-accounts/controller/types/tx.pb.go b/modules/apps/27-interchain-accounts/controller/types/tx.pb.go index 4bb498300a7..a61a35f4ba4 100644 --- a/modules/apps/27-interchain-accounts/controller/types/tx.pb.go +++ b/modules/apps/27-interchain-accounts/controller/types/tx.pb.go @@ -10,7 +10,8 @@ import ( _ "github.com/cosmos/gogoproto/gogoproto" grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" - types "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + types1 "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + types "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" @@ -32,9 +33,10 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // MsgRegisterInterchainAccount defines the payload for Msg/RegisterAccount type MsgRegisterInterchainAccount struct { - Owner string `protobuf:"bytes,1,opt,name=owner,proto3" json:"owner,omitempty"` - ConnectionId string `protobuf:"bytes,2,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"` - Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` + Owner string `protobuf:"bytes,1,opt,name=owner,proto3" json:"owner,omitempty"` + ConnectionId string `protobuf:"bytes,2,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` + Ordering types.Order `protobuf:"varint,4,opt,name=ordering,proto3,enum=ibc.core.channel.v1.Order" json:"ordering,omitempty"` } func (m *MsgRegisterInterchainAccount) Reset() { *m = MsgRegisterInterchainAccount{} } @@ -111,9 +113,9 @@ var xxx_messageInfo_MsgRegisterInterchainAccountResponse proto.InternalMessageIn // MsgSendTx defines the payload for Msg/SendTx type MsgSendTx struct { - Owner string `protobuf:"bytes,1,opt,name=owner,proto3" json:"owner,omitempty"` - ConnectionId string `protobuf:"bytes,2,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"` - PacketData types.InterchainAccountPacketData `protobuf:"bytes,3,opt,name=packet_data,json=packetData,proto3" json:"packet_data"` + Owner string `protobuf:"bytes,1,opt,name=owner,proto3" json:"owner,omitempty"` + ConnectionId string `protobuf:"bytes,2,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"` + PacketData types1.InterchainAccountPacketData `protobuf:"bytes,3,opt,name=packet_data,json=packetData,proto3" json:"packet_data"` // Relative timeout timestamp provided will be added to the current block time during transaction execution. // The timeout timestamp must be non-zero. RelativeTimeout uint64 `protobuf:"varint,4,opt,name=relative_timeout,json=relativeTimeout,proto3" json:"relative_timeout,omitempty"` @@ -284,47 +286,49 @@ func init() { } var fileDescriptor_7def041328c84a30 = []byte{ - // 626 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0x4f, 0x4f, 0x13, 0x4f, - 0x18, 0xee, 0xfc, 0x58, 0xca, 0x8f, 0x01, 0x45, 0x37, 0x44, 0xca, 0x46, 0x17, 0x52, 0x3d, 0x20, - 0x09, 0x3b, 0x69, 0xd5, 0x68, 0x6a, 0x3c, 0x08, 0x78, 0x68, 0x4c, 0x93, 0x66, 0xc5, 0x84, 0x78, - 0x69, 0xa6, 0xb3, 0x93, 0x61, 0x64, 0x77, 0x66, 0xdd, 0x99, 0xae, 0x78, 0x33, 0x7a, 0x31, 0x1e, - 0x8c, 0x07, 0x3f, 0x00, 0x1f, 0x81, 0x6f, 0x21, 0x47, 0x8e, 0x9e, 0x8c, 0x81, 0x03, 0x37, 0x3f, - 0x83, 0xd9, 0x3f, 0xdd, 0xa2, 0x20, 0xc1, 0xc2, 0xad, 0xef, 0xfb, 0xf6, 0x79, 0xde, 0xe7, 0x79, - 0xe7, 0xdd, 0x17, 0x3e, 0xe4, 0x5d, 0x82, 0x70, 0x18, 0xfa, 0x9c, 0x60, 0xcd, 0xa5, 0x50, 0x88, - 0x0b, 0x4d, 0x23, 0xb2, 0x81, 0xb9, 0xe8, 0x60, 0x42, 0x64, 0x4f, 0x68, 0x85, 0x88, 0x14, 0x3a, - 0x92, 0xbe, 0x4f, 0x23, 0x14, 0xd7, 0x90, 0xde, 0x72, 0xc2, 0x48, 0x6a, 0x69, 0xd6, 0x79, 0x97, - 0x38, 0x47, 0xc1, 0xce, 0x09, 0x60, 0x67, 0x00, 0x76, 0xe2, 0x9a, 0x35, 0xcd, 0x24, 0x93, 0x29, - 0x1c, 0x25, 0xbf, 0x32, 0x26, 0xeb, 0xee, 0x99, 0x64, 0xc4, 0x35, 0x14, 0x62, 0xb2, 0x49, 0x75, - 0x8e, 0x5a, 0x19, 0x42, 0xfc, 0x11, 0x35, 0x19, 0xc9, 0x0c, 0x91, 0x2a, 0x90, 0x0a, 0x05, 0x8a, - 0x25, 0xf5, 0x40, 0xb1, 0xac, 0x50, 0x7d, 0x0f, 0xe0, 0xf5, 0x96, 0x62, 0x2e, 0x65, 0x5c, 0x69, - 0x1a, 0x35, 0x0b, 0xea, 0xc7, 0x19, 0xb3, 0x39, 0x0d, 0x47, 0xe5, 0x6b, 0x41, 0xa3, 0x0a, 0x98, - 0x07, 0x0b, 0xe3, 0x6e, 0x16, 0x98, 0x37, 0xe1, 0x25, 0x22, 0x85, 0xa0, 0x24, 0x51, 0xd4, 0xe1, - 0x5e, 0xe5, 0xbf, 0xb4, 0x3a, 0x39, 0x48, 0x36, 0x3d, 0xb3, 0x02, 0xc7, 0x62, 0x1a, 0x29, 0x2e, - 0x45, 0x65, 0x24, 0x2d, 0xf7, 0xc3, 0xc6, 0xe5, 0x0f, 0xdb, 0x73, 0xa5, 0x77, 0x87, 0x3b, 0x8b, - 0x19, 0x5d, 0xd5, 0x83, 0xb7, 0x4e, 0x13, 0xe1, 0x52, 0x15, 0x4a, 0xa1, 0xa8, 0x79, 0x03, 0x42, - 0xb2, 0x81, 0x85, 0xa0, 0x7e, 0xd2, 0x33, 0x53, 0x34, 0x9e, 0x67, 0x9a, 0x9e, 0x39, 0x03, 0xc7, - 0x42, 0x19, 0xe9, 0x81, 0x9e, 0x72, 0x12, 0x36, 0xbd, 0x86, 0x91, 0xf4, 0xab, 0xfe, 0x04, 0x70, - 0xbc, 0xa5, 0xd8, 0x33, 0x2a, 0xbc, 0xb5, 0xad, 0xf3, 0x18, 0xdb, 0x84, 0x13, 0xd9, 0x13, 0x75, - 0x3c, 0xac, 0x71, 0x6a, 0x6e, 0xa2, 0xbe, 0xea, 0x9c, 0x69, 0x51, 0xe2, 0x9a, 0x73, 0xcc, 0x5f, - 0x3b, 0x25, 0x5b, 0xc5, 0x1a, 0x2f, 0x1b, 0xbb, 0xdf, 0xe7, 0x4a, 0x2e, 0x0c, 0x8b, 0x8c, 0x79, - 0x1b, 0x5e, 0x89, 0xa8, 0x8f, 0x35, 0x8f, 0x69, 0x47, 0xf3, 0x80, 0xca, 0x9e, 0xae, 0x18, 0xf3, - 0x60, 0xc1, 0x70, 0xa7, 0xfa, 0xf9, 0xb5, 0x2c, 0x7d, 0x6c, 0xac, 0xf7, 0xe0, 0xd5, 0xc2, 0x6f, - 0x31, 0x43, 0x0b, 0xfe, 0xaf, 0xe8, 0xab, 0x1e, 0x15, 0x84, 0xa6, 0xd6, 0x0d, 0xb7, 0x88, 0xf3, - 0x39, 0x7d, 0x01, 0x70, 0xaa, 0xa5, 0xd8, 0xf3, 0xd0, 0xc3, 0x9a, 0xb6, 0x71, 0x84, 0x03, 0x65, - 0x5e, 0x83, 0x65, 0xc5, 0xd9, 0x60, 0x5c, 0x79, 0x64, 0xae, 0xc3, 0x72, 0x98, 0xfe, 0x23, 0x1d, - 0xd4, 0x44, 0xbd, 0xe1, 0xfc, 0xfb, 0xe7, 0xe2, 0x64, 0x3d, 0x72, 0xef, 0x39, 0x5f, 0x63, 0xaa, - 0x6f, 0x26, 0x6f, 0x55, 0x9d, 0x85, 0x33, 0x7f, 0xa8, 0xea, 0x7b, 0xaa, 0x7f, 0x34, 0xe0, 0x48, - 0x4b, 0x31, 0xf3, 0x2b, 0x80, 0xb3, 0x7f, 0x5f, 0xe5, 0xf6, 0x30, 0xda, 0x4e, 0xdb, 0x4b, 0x6b, - 0xfd, 0xa2, 0x19, 0x8b, 0x57, 0xfa, 0x04, 0x60, 0x39, 0x5f, 0xd4, 0x47, 0x43, 0x36, 0xc9, 0xe0, - 0xd6, 0x93, 0x73, 0xc1, 0x0b, 0x41, 0xdb, 0x00, 0x4e, 0xfe, 0xb6, 0x11, 0x2b, 0x43, 0xf2, 0x1e, - 0x25, 0xb1, 0x9e, 0x5e, 0x00, 0x49, 0x5f, 0xa2, 0x35, 0xfa, 0xf6, 0x70, 0x67, 0x11, 0x2c, 0xbf, - 0xdc, 0xdd, 0xb7, 0xc1, 0xde, 0xbe, 0x0d, 0x7e, 0xec, 0xdb, 0xe0, 0xf3, 0x81, 0x5d, 0xda, 0x3b, - 0xb0, 0x4b, 0xdf, 0x0e, 0xec, 0xd2, 0x8b, 0x36, 0xe3, 0x7a, 0xa3, 0xd7, 0x75, 0x88, 0x0c, 0x50, - 0x7e, 0x10, 0x79, 0x97, 0x2c, 0x31, 0x89, 0xe2, 0x07, 0x28, 0x90, 0x5e, 0xcf, 0xa7, 0x2a, 0x39, - 0xb5, 0x0a, 0xd5, 0xef, 0x2f, 0x0d, 0x74, 0x2c, 0x9d, 0x74, 0x65, 0xf5, 0x9b, 0x90, 0xaa, 0x6e, - 0x39, 0xbd, 0xa2, 0x77, 0x7e, 0x05, 0x00, 0x00, 0xff, 0xff, 0xa1, 0x90, 0xb0, 0xb9, 0x62, 0x06, - 0x00, 0x00, + // 671 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0x4f, 0x4f, 0x13, 0x4d, + 0x1c, 0xee, 0xbe, 0x94, 0x02, 0x03, 0x2f, 0xbc, 0xef, 0x86, 0x48, 0xd9, 0x68, 0xc1, 0xea, 0x01, + 0x49, 0x98, 0x49, 0xeb, 0xdf, 0xd4, 0x78, 0x10, 0xf0, 0xd0, 0x98, 0xc6, 0x66, 0xc5, 0x84, 0x78, + 0x69, 0xa6, 0xb3, 0x93, 0x61, 0xa4, 0x3b, 0xb3, 0xce, 0x4c, 0x57, 0xbc, 0x19, 0x4f, 0xc6, 0x83, + 0xf1, 0xe0, 0x07, 0xe0, 0x23, 0x70, 0xf7, 0x03, 0xc8, 0x91, 0xa3, 0x27, 0x63, 0xe0, 0xc0, 0xcd, + 0xcf, 0x60, 0xf6, 0x4f, 0xb7, 0x28, 0x48, 0xb0, 0x70, 0xdb, 0xdf, 0x6f, 0xe6, 0x79, 0x7e, 0xcf, + 0xf3, 0xcc, 0xec, 0x80, 0xfb, 0xbc, 0x4d, 0x10, 0x0e, 0x82, 0x0e, 0x27, 0xd8, 0x70, 0x29, 0x34, + 0xe2, 0xc2, 0x50, 0x45, 0x36, 0x30, 0x17, 0x2d, 0x4c, 0x88, 0xec, 0x0a, 0xa3, 0x11, 0x91, 0xc2, + 0x28, 0xd9, 0xe9, 0x50, 0x85, 0xc2, 0x0a, 0x32, 0x5b, 0x30, 0x50, 0xd2, 0x48, 0xbb, 0xca, 0xdb, + 0x04, 0x1e, 0x05, 0xc3, 0x13, 0xc0, 0xb0, 0x0f, 0x86, 0x61, 0xc5, 0x99, 0x66, 0x92, 0xc9, 0x18, + 0x8e, 0xa2, 0xaf, 0x84, 0xc9, 0xb9, 0x75, 0x26, 0x19, 0x61, 0x05, 0x05, 0x98, 0x6c, 0x52, 0x93, + 0xa2, 0x56, 0x06, 0x10, 0x7f, 0x44, 0x4d, 0x42, 0x32, 0x43, 0xa4, 0xf6, 0xa5, 0x46, 0xbe, 0x66, + 0xd1, 0xba, 0xaf, 0x59, 0xba, 0x70, 0x35, 0x62, 0x27, 0x52, 0x51, 0x44, 0x36, 0xb0, 0x10, 0xb4, + 0x13, 0xc3, 0x93, 0xcf, 0x64, 0x4b, 0xf9, 0xb3, 0x05, 0x2e, 0x37, 0x34, 0x73, 0x29, 0xe3, 0xda, + 0x50, 0x55, 0xcf, 0xa6, 0x3f, 0x4c, 0x86, 0xdb, 0xd3, 0x60, 0x58, 0xbe, 0x12, 0x54, 0x15, 0xad, + 0x79, 0x6b, 0x61, 0xcc, 0x4d, 0x0a, 0xfb, 0x1a, 0xf8, 0x97, 0x48, 0x21, 0x28, 0x89, 0x44, 0xb7, + 0xb8, 0x57, 0xfc, 0x27, 0x5e, 0x9d, 0xe8, 0x37, 0xeb, 0x9e, 0x5d, 0x04, 0x23, 0x21, 0x55, 0x9a, + 0x4b, 0x51, 0x1c, 0x8a, 0x97, 0x7b, 0xa5, 0x7d, 0x07, 0x8c, 0x4a, 0xe5, 0x51, 0xc5, 0x05, 0x2b, + 0xe6, 0xe7, 0xad, 0x85, 0xc9, 0xaa, 0x03, 0xa3, 0x93, 0x88, 0xb4, 0xc2, 0x9e, 0xc0, 0xb0, 0x02, + 0x9f, 0x44, 0x9b, 0xdc, 0x6c, 0x6f, 0x6d, 0xf2, 0xdd, 0xf6, 0x5c, 0xee, 0xed, 0xe1, 0xce, 0x62, + 0x22, 0xa3, 0xec, 0x81, 0xeb, 0xa7, 0x89, 0x77, 0xa9, 0x0e, 0xa4, 0xd0, 0xd4, 0xbe, 0x02, 0x40, + 0xca, 0x1a, 0x69, 0x4d, 0x9c, 0x8c, 0xa5, 0x9d, 0xba, 0x67, 0xcf, 0x80, 0x91, 0x40, 0x2a, 0xd3, + 0xf7, 0x51, 0x88, 0xca, 0xba, 0x57, 0xcb, 0x47, 0xf3, 0xca, 0x3f, 0x2c, 0x30, 0xd6, 0xd0, 0xec, + 0x29, 0x15, 0xde, 0xda, 0xd6, 0x79, 0x02, 0xd9, 0x04, 0xe3, 0xc9, 0xe9, 0xb7, 0x3c, 0x6c, 0x70, + 0x1c, 0xca, 0x78, 0x75, 0x15, 0x9e, 0xe9, 0x0e, 0x86, 0x15, 0x78, 0xcc, 0x5f, 0x33, 0x26, 0x5b, + 0xc5, 0x06, 0x2f, 0xe7, 0x77, 0xbf, 0xcd, 0xe5, 0x5c, 0x10, 0x64, 0x1d, 0xfb, 0x06, 0xf8, 0x4f, + 0xd1, 0x0e, 0x36, 0x3c, 0xa4, 0x2d, 0xc3, 0x7d, 0x2a, 0xbb, 0x26, 0xce, 0x3a, 0xef, 0x4e, 0xf5, + 0xfa, 0x6b, 0x49, 0xfb, 0x58, 0xac, 0xb7, 0xc1, 0xff, 0x99, 0xdf, 0x2c, 0x43, 0x07, 0x8c, 0x6a, + 0xfa, 0xb2, 0x4b, 0x05, 0xa1, 0xb1, 0xf5, 0xbc, 0x9b, 0xd5, 0x69, 0x4e, 0x9f, 0x2c, 0x30, 0xd5, + 0xd0, 0xec, 0x59, 0xe0, 0x61, 0x43, 0x9b, 0x58, 0x61, 0x5f, 0xdb, 0x97, 0x40, 0x41, 0x73, 0xd6, + 0x8f, 0x2b, 0xad, 0xec, 0x75, 0x50, 0x08, 0xe2, 0x1d, 0x71, 0x50, 0xe3, 0xd5, 0x1a, 0xfc, 0xfb, + 0x3f, 0x11, 0x26, 0x33, 0x52, 0xef, 0x29, 0x5f, 0x6d, 0xaa, 0x67, 0x26, 0x1d, 0x55, 0x9e, 0x05, + 0x33, 0xbf, 0xa9, 0xea, 0x79, 0xaa, 0xbe, 0xcf, 0x83, 0xa1, 0x86, 0x66, 0xf6, 0x17, 0x0b, 0xcc, + 0xfe, 0xf9, 0x17, 0x68, 0x0e, 0xa2, 0xed, 0xb4, 0x7b, 0xe9, 0xac, 0x5f, 0x34, 0x63, 0x76, 0x4a, + 0x1f, 0x2c, 0x50, 0x48, 0x2f, 0xea, 0x83, 0x01, 0x87, 0x24, 0x70, 0xe7, 0xd1, 0xb9, 0xe0, 0x99, + 0xa0, 0x6d, 0x0b, 0x4c, 0xfc, 0x72, 0x23, 0x56, 0x06, 0xe4, 0x3d, 0x4a, 0xe2, 0x3c, 0xbe, 0x00, + 0x92, 0x9e, 0x44, 0x67, 0xf8, 0xcd, 0xe1, 0xce, 0xa2, 0xb5, 0xfc, 0x62, 0x77, 0xbf, 0x64, 0xed, + 0xed, 0x97, 0xac, 0xef, 0xfb, 0x25, 0xeb, 0xe3, 0x41, 0x29, 0xb7, 0x77, 0x50, 0xca, 0x7d, 0x3d, + 0x28, 0xe5, 0x9e, 0x37, 0x19, 0x37, 0x1b, 0xdd, 0x36, 0x24, 0xd2, 0x47, 0xe9, 0x5b, 0xcb, 0xdb, + 0x64, 0x89, 0x49, 0x14, 0xde, 0x43, 0xbe, 0xf4, 0xba, 0x1d, 0xaa, 0xa3, 0x57, 0x5c, 0xa3, 0xea, + 0xdd, 0xa5, 0xbe, 0x8e, 0xa5, 0x93, 0x1e, 0x70, 0xf3, 0x3a, 0xa0, 0xba, 0x5d, 0x88, 0x5f, 0xdf, + 0x9b, 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xee, 0x6a, 0x51, 0xfa, 0xbd, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -505,6 +509,11 @@ func (m *MsgRegisterInterchainAccount) MarshalToSizedBuffer(dAtA []byte) (int, e _ = i var l int _ = l + if m.Ordering != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Ordering)) + i-- + dAtA[i] = 0x20 + } if len(m.Version) > 0 { i -= len(m.Version) copy(dAtA[i:], m.Version) @@ -738,6 +747,9 @@ func (m *MsgRegisterInterchainAccount) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } + if m.Ordering != 0 { + n += 1 + sovTx(uint64(m.Ordering)) + } return n } @@ -947,6 +959,25 @@ func (m *MsgRegisterInterchainAccount) Unmarshal(dAtA []byte) error { } m.Version = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Ordering", wireType) + } + m.Ordering = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Ordering |= types.Order(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index 50efd5c9dd2..81dbb148679 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -20,6 +20,7 @@ import ( var ( _ porttypes.IBCModule = (*IBCModule)(nil) _ porttypes.PacketDataUnmarshaler = (*IBCModule)(nil) + _ porttypes.UpgradableModule = (*IBCModule)(nil) ) // IBCModule implements the ICS26 interface for interchain accounts host chains @@ -118,6 +119,7 @@ func (im IBCModule) OnRecvPacket( logger := im.keeper.Logger(ctx) if !im.keeper.GetParams(ctx).HostEnabled { logger.Info("host submodule is disabled") + keeper.EmitHostDisabledEvent(ctx, packet) return channeltypes.NewErrorAcknowledgement(types.ErrHostSubModuleDisabled) } @@ -127,7 +129,7 @@ func (im IBCModule) OnRecvPacket( ack = channeltypes.NewErrorAcknowledgement(err) logger.Error(fmt.Sprintf("%s sequence %d", err.Error(), packet.Sequence)) } else { - logger.Info("successfully handled packet sequence: %d", packet.Sequence) + logger.Info("successfully handled packet", "sequence", packet.Sequence) } // Emit an event indicating a successful or failed acknowledgement. @@ -156,6 +158,29 @@ func (IBCModule) OnTimeoutPacket( return errorsmod.Wrap(icatypes.ErrInvalidChannelFlow, "cannot cause a packet timeout on a host channel end, a host chain does not send a packet over the channel") } +// OnChanUpgradeInit implements the IBCModule interface +func (IBCModule) OnChanUpgradeInit(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) (string, error) { + return "", errorsmod.Wrap(icatypes.ErrInvalidChannelFlow, "channel upgrade handshake must be initiated by controller chain") +} + +// OnChanUpgradeTry implements the IBCModule interface +func (im IBCModule) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, counterpartyVersion string) (string, error) { + if !im.keeper.GetParams(ctx).HostEnabled { + return "", types.ErrHostSubModuleDisabled + } + + return im.keeper.OnChanUpgradeTry(ctx, portID, channelID, proposedOrder, proposedConnectionHops, counterpartyVersion) +} + +// OnChanUpgradeAck implements the IBCModule interface +func (IBCModule) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { + return errorsmod.Wrap(icatypes.ErrInvalidChannelFlow, "channel upgrade handshake must be initiated by controller chain") +} + +// OnChanUpgradeOpen implements the IBCModule interface +func (IBCModule) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) { +} + // UnmarshalPacketData attempts to unmarshal the provided packet data bytes // into an InterchainAccountPacketData. This function implements the optional // PacketDataUnmarshaler interface required for ADR 008 support. diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index a5bb9381e66..c4922806074 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -20,6 +20,7 @@ import ( feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v8/testing" @@ -82,7 +83,7 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, endpoint.ChannelConfig.Version); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccountWithOrdering(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, endpoint.ChannelConfig.Version, channeltypes.ORDERED); err != nil { return err } @@ -140,7 +141,12 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { expPass bool }{ { - "success", func() {}, true, + "success w/ ORDERED channel", func() {}, true, + }, + { + "success w/ UNORDERED channel", func() { + channel.Ordering = channeltypes.UNORDERED + }, true, }, { "account address generation is block dependent", func() { @@ -169,11 +175,6 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { } }, true, }, - { - "ICA callback fails - invalid channel order", func() { - channel.Ordering = channeltypes.UNORDERED - }, false, - }, } for _, tc := range testCases { @@ -256,10 +257,10 @@ func (suite *InterchainAccountsTestSuite) TestChanOpenAck() { // query proof from ChainA channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - proofTry, proofHeight := path.EndpointA.Chain.QueryProof(channelKey) + tryProof, proofHeight := path.EndpointA.Chain.QueryProof(channelKey) // use chainB (host) for ChanOpenAck - msg := channeltypes.NewMsgChannelOpenAck(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelID, TestVersion, proofTry, proofHeight, icatypes.ModuleName) + msg := channeltypes.NewMsgChannelOpenAck(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelID, TestVersion, tryProof, proofHeight, icatypes.ModuleName) handler := suite.chainB.GetSimApp().MsgServiceRouter().Handler(msg) _, err = handler(suite.chainB.GetContext(), msg) @@ -603,6 +604,126 @@ func (suite *InterchainAccountsTestSuite) TestOnTimeoutPacket() { } } +// OnChanUpgradeInit callback returns error on host chains +func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeInit() { + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + // call application callback directly + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) + + app, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) + + version, err := cbs.OnChanUpgradeInit( + suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, + path.EndpointB.ChannelConfig.Order, []string{path.EndpointB.ConnectionID}, path.EndpointB.ChannelConfig.Version, + ) + + suite.Require().Error(err) + suite.Require().ErrorIs(err, icatypes.ErrInvalidChannelFlow) + suite.Require().Equal("", version) +} + +func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeTry() { + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", func() {}, nil, + }, + { + "host submodule disabled", func() { + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), types.NewParams(false, []string{})) + }, types.ErrHostSubModuleDisabled, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + metadata := icatypes.NewDefaultMetadata(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + metadata.Address = interchainAccountAddr + metadata.Encoding = icatypes.EncodingProto3JSON // this is the actual change to the version + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) + + err = path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + tc.malleate() // malleate mutates test data + + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) + + app, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) + + version, err := cbs.OnChanUpgradeTry( + suite.chainB.GetContext(), + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + channeltypes.ORDERED, + []string{path.EndpointB.ConnectionID}, + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version, + ) + + if tc.expError == nil { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + suite.Require().Empty(version) + } + }) + } +} + +// OnChanUpgradeAck callback returns error on host chains +func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeAck() { + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + // call application callback directly + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) + + app, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) + + err = cbs.OnChanUpgradeAck( + suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelConfig.Version, + ) + + suite.Require().Error(err) + suite.Require().ErrorIs(err, icatypes.ErrInvalidChannelFlow) +} + func (suite *InterchainAccountsTestSuite) fundICAWallet(ctx sdk.Context, portID string, amount sdk.Coins) { interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(ctx, ibctesting.FirstConnectionID, portID) suite.Require().True(found) diff --git a/modules/apps/27-interchain-accounts/host/keeper/events.go b/modules/apps/27-interchain-accounts/host/keeper/events.go index 3bfe7759670..77b5cf5a75b 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/events.go +++ b/modules/apps/27-interchain-accounts/host/keeper/events.go @@ -5,7 +5,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" "github.com/cosmos/ibc-go/v8/modules/core/exported" ) @@ -29,3 +31,16 @@ func EmitAcknowledgementEvent(ctx sdk.Context, packet exported.PacketI, ack expo ), ) } + +// EmitHostDisabledEvent emits an event signalling that the host submodule is disabled. +func EmitHostDisabledEvent(ctx sdk.Context, packet channeltypes.Packet) { + ctx.EventManager().EmitEvent( + sdk.NewEvent( + icatypes.EventTypePacket, + sdk.NewAttribute(sdk.AttributeKeyModule, icatypes.ModuleName), + sdk.NewAttribute(icatypes.AttributeKeyHostChannelID, packet.GetDestChannel()), + sdk.NewAttribute(icatypes.AttributeKeyAckError, types.ErrHostSubModuleDisabled.Error()), + sdk.NewAttribute(icatypes.AttributeKeyAckSuccess, "false"), + ), + ) +} diff --git a/modules/apps/27-interchain-accounts/host/keeper/export_test.go b/modules/apps/27-interchain-accounts/host/keeper/export_test.go index 2cd4338dde2..cbd7a14ef34 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/export_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/export_test.go @@ -20,3 +20,8 @@ func (k *Keeper) GetICS4Wrapper() porttypes.ICS4Wrapper { func (k Keeper) GetAppMetadata(ctx sdk.Context, portID, channelID string) (icatypes.Metadata, error) { return k.getAppMetadata(ctx, portID, channelID) } + +// NewModuleQuerySafeAllowList is a wrapper around newModuleQuerySafeAllowList to allow the function to be directly called in tests. +func NewModuleQuerySafeAllowList() []string { + return newModuleQuerySafeAllowList() +} diff --git a/modules/apps/27-interchain-accounts/host/keeper/handshake.go b/modules/apps/27-interchain-accounts/host/keeper/handshake.go index f3a202a3bae..9539db1b075 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/host/keeper/handshake.go @@ -2,6 +2,7 @@ package keeper import ( "fmt" + "strings" errorsmod "cosmossdk.io/errors" @@ -9,7 +10,9 @@ import ( capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ) @@ -27,20 +30,23 @@ func (k Keeper) OnChanOpenTry( counterparty channeltypes.Counterparty, counterpartyVersion string, ) (string, error) { - if order != channeltypes.ORDERED { - return "", errorsmod.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s", channeltypes.ORDERED, order) - } - if portID != icatypes.HostPortID { return "", errorsmod.Wrapf(icatypes.ErrInvalidHostPort, "expected %s, got %s", icatypes.HostPortID, portID) } - var metadata icatypes.Metadata - if err := icatypes.ModuleCdc.UnmarshalJSON([]byte(counterpartyVersion), &metadata); err != nil { - return "", errorsmod.Wrapf(icatypes.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain accounts metadata") + metadata, err := icatypes.MetadataFromVersion(counterpartyVersion) + if err != nil { + // Propose the default metadata if the counterparty version is invalid + connection, err := k.channelKeeper.GetConnection(ctx, connectionHops[0]) + if err != nil { + return "", errorsmod.Wrapf(err, "failed to retrieve connection %s", connectionHops[0]) + } + + k.Logger(ctx).Debug("counterparty version is invalid, proposing default metadata") + metadata = icatypes.NewDefaultMetadata(connection.GetCounterparty().GetConnectionID(), connectionHops[0]) } - if err := icatypes.ValidateHostMetadata(ctx, k.channelKeeper, connectionHops, metadata); err != nil { + if err = icatypes.ValidateHostMetadata(ctx, k.channelKeeper, connectionHops, metadata); err != nil { return "", err } @@ -51,30 +57,22 @@ func (k Keeper) OnChanOpenTry( panic(fmt.Errorf("active channel mapping set for %s but channel does not exist in channel store", activeChannelID)) } - if channel.IsOpen() { - return "", errorsmod.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s is already OPEN", activeChannelID, portID) + if channel.State != channeltypes.CLOSED { + return "", errorsmod.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s must be %s", activeChannelID, portID, channeltypes.CLOSED) } - appVersion, found := k.GetAppVersion(ctx, portID, activeChannelID) - if !found { - panic(fmt.Errorf("active channel mapping set for %s, but channel does not exist in channel store", activeChannelID)) - } - - if !icatypes.IsPreviousMetadataEqual(appVersion, metadata) { - return "", errorsmod.Wrap(icatypes.ErrInvalidVersion, "previous active channel metadata does not match provided version") - } + // if a channel is being reopened, we allow the controller to propose new fields + // which are not exactly the same as the previous. The provided address will + // be overwritten with the correct one before the metadata is returned. } // On the host chain the capability may only be claimed during the OnChanOpenTry // The capability being claimed in OpenInit is for a controller chain (the port is different) - if err := k.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + if err = k.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { return "", errorsmod.Wrapf(err, "failed to claim capability for channel %s on port %s", channelID, portID) } - var ( - accAddress sdk.AccAddress - err error - ) + var accAddress sdk.AccAddress interchainAccAddr, found := k.GetInterchainAccountAddress(ctx, metadata.HostConnectionId, counterparty.PortId) if found { @@ -130,3 +128,71 @@ func (Keeper) OnChanCloseConfirm( ) error { return nil } + +// OnChanUpgradeTry performs the upgrade try step of the channel upgrade handshake. +// The upgrade try callback must verify the proposed changes to the order, connectionHops, and version. +// Within the version we have the tx type, encoding, interchain account address, host/controller connectionID's +// and the ICS27 protocol version. +// +// The following may be changed: +// - tx type (must be supported) +// - encoding (must be supported) +// - order +// +// The following may not be changed: +// - connectionHops (and subsequently host/controller connectionIDs) +// - interchain account address +// - ICS27 protocol version +func (k Keeper) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, counterpartyVersion string) (string, error) { + if portID != icatypes.HostPortID { + return "", errorsmod.Wrapf(porttypes.ErrInvalidPort, "expected %s, got %s", icatypes.HostPortID, portID) + } + + // verify connection hops has not changed + connectionID, err := k.getConnectionID(ctx, portID, channelID) + if err != nil { + return "", err + } + + if len(proposedConnectionHops) != 1 || proposedConnectionHops[0] != connectionID { + return "", errorsmod.Wrapf(channeltypes.ErrInvalidUpgrade, "expected connection hops %s, got %s", []string{connectionID}, proposedConnectionHops) + } + + if strings.TrimSpace(counterpartyVersion) == "" { + return "", errorsmod.Wrap(channeltypes.ErrInvalidChannelVersion, "counterparty version cannot be empty") + } + + proposedCounterpartyMetadata, err := icatypes.MetadataFromVersion(counterpartyVersion) + if err != nil { + return "", err + } + + currentMetadata, err := k.getAppMetadata(ctx, portID, channelID) + if err != nil { + return "", err + } + + // ValidateHostMetadata will ensure the ICS27 protocol version has not changed and that the + // tx type and encoding are supported. It also validates the connection params against the counterparty metadata. + if err := icatypes.ValidateHostMetadata(ctx, k.channelKeeper, proposedConnectionHops, proposedCounterpartyMetadata); err != nil { + return "", errorsmod.Wrap(err, "invalid metadata") + } + + // the interchain account address on the host chain + // must remain the same after the upgrade. + if currentMetadata.Address != proposedCounterpartyMetadata.Address { + return "", errorsmod.Wrap(icatypes.ErrInvalidAccountAddress, "interchain account address cannot be changed") + } + + // these explicit checks on the controller connection identifier should be unreachable + if currentMetadata.ControllerConnectionId != proposedCounterpartyMetadata.ControllerConnectionId { + return "", errorsmod.Wrap(connectiontypes.ErrInvalidConnection, "proposed controller connection ID must not change") + } + + // these explicit checks on the host connection identifier should be unreachable + if currentMetadata.HostConnectionId != proposedConnectionHops[0] { + return "", errorsmod.Wrap(connectiontypes.ErrInvalidConnectionIdentifier, "proposed connection hop must not change") + } + + return counterpartyVersion, nil +} diff --git a/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go index 3074faf9b8e..97eecfd21a9 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go @@ -8,11 +8,17 @@ import ( capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" hosttypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) +const ( + differentConnectionID = "connection-100" +) + // open and close channel is a helper function for TestOnChanOpenTry for reopening accounts func (suite *KeeperTestSuite) openAndCloseChannel(path *ibctesting.Path) { err := path.EndpointB.ChanOpenTry() @@ -89,6 +95,25 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { suite.Require().False(found) }, true, }, + { + "success - previous metadata is different", + func() { + // set the active channelID in state + suite.chainB.GetSimApp().ICAHostKeeper.SetActiveChannelID(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointB.ChannelID) + + // set the previous encoding to be proto3json. + // the new encoding is set to be protobuf in the test below. + metadata.Encoding = icatypes.EncodingProto3JSON + + versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) + suite.Require().NoError(err) + + channel.State = channeltypes.CLOSED + channel.Version = string(versionBytes) + + path.EndpointB.SetChannel(*channel) + }, true, + }, { "reopening account fails - no existing account", func() { @@ -142,34 +167,6 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { }, false, }, - { - "invalid metadata - previous metadata is different", - func() { - // create a new channel and set it in state - ch := channeltypes.NewChannel(channeltypes.CLOSED, channeltypes.ORDERED, channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID), []string{path.EndpointA.ConnectionID}, TestVersion) - suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, ch) - - // set the active channelID in state - suite.chainB.GetSimApp().ICAHostKeeper.SetActiveChannelID(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointB.ChannelID) - - // attempt to downgrade version by reinitializing channel with version 1, but setting channel to version 2 - metadata.Version = "ics27-2" - - versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) - suite.Require().NoError(err) - - channel.Version = string(versionBytes) - - path.EndpointB.SetChannel(*channel) - }, false, - }, - { - "invalid order - UNORDERED", - func() { - channel.Ordering = channeltypes.UNORDERED - }, - false, - }, { "invalid port ID", func() { @@ -188,9 +185,10 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { { "invalid metadata bytestring", func() { + // the try step will propose a new valid version path.EndpointA.ChannelConfig.Version = "invalid-metadata-bytestring" }, - false, + true, }, { "unsupported encoding format", @@ -262,7 +260,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { false, }, { - "active channel already set", + "active channel already set (OPEN state)", func() { // create a new channel and set it in state ch := channeltypes.NewChannel(channeltypes.OPEN, channeltypes.ORDERED, channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID), []string{path.EndpointA.ConnectionID}, ibctesting.DefaultChannelVersion) @@ -272,6 +270,23 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { suite.chainB.GetSimApp().ICAHostKeeper.SetActiveChannelID(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointB.ChannelID) }, false, }, + { + "channel is already active (FLUSHING state)", + func() { + suite.chainB.GetSimApp().ICAHostKeeper.SetActiveChannelID(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointB.ChannelID) + + counterparty := channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channel := channeltypes.Channel{ + State: channeltypes.FLUSHING, + Ordering: channeltypes.ORDERED, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointB.ConnectionID}, + Version: TestVersion, + } + suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, channel) + }, + false, + }, } for _, tc := range testCases { @@ -422,3 +437,182 @@ func (suite *KeeperTestSuite) TestOnChanCloseConfirm() { }) } } + +func (suite *KeeperTestSuite) TestOnChanUpgradeTry() { + var ( + path *ibctesting.Path + metadata icatypes.Metadata + order channeltypes.Order + counterpartyVersion string + ) + + // updateMetadata is a helper function which modifies the metadata stored in the channel version + // and marshals it into a string to pass to OnChanUpgradeTry as the counterpartyVersion string. + updateMetadata := func(modificationFn func(*icatypes.Metadata)) { + metadata, err := icatypes.MetadataFromVersion(path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version) + suite.Require().NoError(err) + modificationFn(&metadata) + counterpartyVersion = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) + } + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + name: "success: change order", + malleate: func() { + order = channeltypes.UNORDERED + }, + expError: nil, + }, + { + name: "failure: invalid port ID", + malleate: func() { + path.EndpointB.ChannelConfig.PortID = "invalid-port-id" + }, + expError: porttypes.ErrInvalidPort, + }, + { + name: "failure: invalid proposed connectionHops", + malleate: func() { + // connection hops is provided via endpoint connectionID + path.EndpointB.ConnectionID = differentConnectionID + }, + expError: channeltypes.ErrInvalidUpgrade, + }, + { + name: "failure: empty counterparty version", + malleate: func() { + counterpartyVersion = "" + }, + expError: channeltypes.ErrInvalidChannelVersion, + }, + { + name: "failure: cannot parse metadata from counterparty version string", + malleate: func() { + counterpartyVersion = "invalid-version" + }, + expError: icatypes.ErrUnknownDataType, + }, + { + name: "failure: cannot decode version string from channel", + malleate: func() { + channel := path.EndpointB.GetChannel() + channel.Version = "invalid-metadata-string" + path.EndpointB.SetChannel(channel) + }, + expError: icatypes.ErrUnknownDataType, + }, + { + name: "failure: metadata encoding not supported", + malleate: func() { + updateMetadata(func(metadata *icatypes.Metadata) { + metadata.Encoding = "invalid-encoding-format" + }) + }, + expError: icatypes.ErrInvalidCodec, + }, + { + name: "failure: metadata tx type not supported", + malleate: func() { + updateMetadata(func(metadata *icatypes.Metadata) { + metadata.TxType = "invalid-tx-type" + }) + }, + expError: icatypes.ErrUnknownDataType, + }, + { + name: "failure: interchain account address has changed", + malleate: func() { + updateMetadata(func(metadata *icatypes.Metadata) { + metadata.Address = TestOwnerAddress // use valid address + }) + }, + expError: icatypes.ErrInvalidAccountAddress, + }, + { + name: "failure: controller connection ID has changed", + malleate: func() { + updateMetadata(func(metadata *icatypes.Metadata) { + metadata.ControllerConnectionId = differentConnectionID + }) + }, + expError: connectiontypes.ErrInvalidConnection, // the explicit checks on the controller connection identifier are unreachable + }, + { + name: "failure: host connection ID has changed", + malleate: func() { + updateMetadata(func(metadata *icatypes.Metadata) { + metadata.HostConnectionId = differentConnectionID + }) + }, + expError: connectiontypes.ErrInvalidConnection, // the explicit checks on the host connection identifier are unreachable + }, + { + name: "failure: channel not found", + malleate: func() { + path.EndpointB.ChannelID = "invalid-channel-id" + }, + expError: channeltypes.ErrChannelNotFound, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + currentMetadata, err := suite.chainB.GetSimApp().ICAHostKeeper.GetAppMetadata(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().NoError(err) + + order = channeltypes.ORDERED + metadata = icatypes.NewDefaultMetadata(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + // use the same address as the previous metadata. + metadata.Address = currentMetadata.Address + + // this is the actual change to the version. + metadata.Encoding = icatypes.EncodingProto3JSON + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) + + err = path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + counterpartyVersion = path.EndpointA.GetChannel().Version + + tc.malleate() // malleate mutates test data + + version, err := suite.chainB.GetSimApp().ICAHostKeeper.OnChanUpgradeTry( + suite.chainB.GetContext(), + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + order, + []string{path.EndpointB.ConnectionID}, + counterpartyVersion, + ) + + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err) + suite.Require().Equal(path.EndpointB.GetChannel().Version, version) + } else { + suite.Require().ErrorIs(err, tc.expError) + } + }) + } +} diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper.go b/modules/apps/27-interchain-accounts/host/keeper/keeper.go index c426c4cc0cb..170fa6e1f33 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper.go @@ -5,6 +5,12 @@ import ( "fmt" "strings" + gogoproto "github.com/cosmos/gogoproto/proto" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + + msgv1 "cosmossdk.io/api/cosmos/msg/v1" + queryv1 "cosmossdk.io/api/cosmos/query/v1" errorsmod "cosmossdk.io/errors" "cosmossdk.io/log" storetypes "cosmossdk.io/store/types" @@ -16,6 +22,7 @@ import ( genesistypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/genesis/types" "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" @@ -35,7 +42,11 @@ type Keeper struct { scopedKeeper exported.ScopedKeeper - msgRouter icatypes.MessageRouter + msgRouter icatypes.MessageRouter + queryRouter icatypes.QueryRouter + + // mqsAllowList is a list of all module safe query paths + mqsAllowList []string // the address capable of executing a MsgUpdateParams message. Typically, this // should be the x/gov module account. @@ -68,22 +79,44 @@ func NewKeeper( accountKeeper: accountKeeper, scopedKeeper: scopedKeeper, msgRouter: msgRouter, + mqsAllowList: newModuleQuerySafeAllowList(), authority: authority, } } // WithICS4Wrapper sets the ICS4Wrapper. This function may be used after -// the keepers creation to set the middleware which is above this module +// the keeper's creation to set the middleware which is above this module // in the IBC application stack. func (k *Keeper) WithICS4Wrapper(wrapper porttypes.ICS4Wrapper) { k.ics4Wrapper = wrapper } +// WithQueryRouter sets the QueryRouter. This function may be used after +// the keeper's creation to set the query router to which queries in the +// ICA packet data will be routed to if they are module_safe_query. +// Panics if the queryRouter is nil. +func (k *Keeper) WithQueryRouter(queryRouter icatypes.QueryRouter) { + if queryRouter == nil { + panic(errors.New("cannot set a nil query router")) + } + + k.queryRouter = queryRouter +} + // Logger returns the application logger, scoped to the associated module func (Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", exported.ModuleName, icatypes.ModuleName)) } +// getConnectionID returns the connection id for the given port and channelIDs. +func (k Keeper) getConnectionID(ctx sdk.Context, portID, channelID string) (string, error) { + channel, found := k.channelKeeper.GetChannel(ctx, portID, channelID) + if !found { + return "", errorsmod.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + return channel.ConnectionHops[0], nil +} + // setPort sets the provided portID in state. func (k Keeper) setPort(ctx sdk.Context, portID string) { store := ctx.KVStore(k.storeKey) @@ -111,20 +144,14 @@ func (k Keeper) GetAppVersion(ctx sdk.Context, portID, channelID string) (string return k.ics4Wrapper.GetAppVersion(ctx, portID, channelID) } -// GetAppMetadata retrieves the interchain accounts channel metadata from the store associated with the provided portID and channelID +// getAppMetadata retrieves the interchain accounts channel metadata from the store associated with the provided portID and channelID func (k Keeper) getAppMetadata(ctx sdk.Context, portID, channelID string) (icatypes.Metadata, error) { appVersion, found := k.GetAppVersion(ctx, portID, channelID) if !found { return icatypes.Metadata{}, errorsmod.Wrapf(ibcerrors.ErrNotFound, "app version not found for port %s and channel %s", portID, channelID) } - var metadata icatypes.Metadata - if err := icatypes.ModuleCdc.UnmarshalJSON([]byte(appVersion), &metadata); err != nil { - // UnmarshalJSON errors are indeterminate and therefore are not wrapped and included in failed acks - return icatypes.Metadata{}, errorsmod.Wrapf(icatypes.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain accounts metadata") - } - - return metadata, nil + return icatypes.MetadataFromVersion(appVersion) } // GetActiveChannelID retrieves the active channelID from the store keyed by the provided connectionID and portID @@ -148,7 +175,7 @@ func (k Keeper) GetOpenActiveChannel(ctx sdk.Context, connectionID, portID strin channel, found := k.channelKeeper.GetChannel(ctx, portID, channelID) - if found && channel.IsOpen() { + if found && channel.State == channeltypes.OPEN { return channelID, true } @@ -252,3 +279,40 @@ func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { bz := k.cdc.MustMarshal(¶ms) store.Set([]byte(types.ParamsKey), bz) } + +// newModuleQuerySafeAllowList returns a list of all query paths labeled with module_query_safe in the proto files. +func newModuleQuerySafeAllowList() []string { + protoFiles, err := gogoproto.MergedRegistry() + if err != nil { + panic(err) + } + + allowList := []string{} + protoFiles.RangeFiles(func(fd protoreflect.FileDescriptor) bool { + for i := 0; i < fd.Services().Len(); i++ { + // Get the service descriptor + sd := fd.Services().Get(i) + + // Skip services that are annotated with the "cosmos.msg.v1.service" option. + if ext := proto.GetExtension(sd.Options(), msgv1.E_Service); ext != nil && ext.(bool) { + continue + } + + for j := 0; j < sd.Methods().Len(); j++ { + // Get the method descriptor + md := sd.Methods().Get(j) + + // Skip methods that are not annotated with the "cosmos.query.v1.module_query_safe" option. + if ext := proto.GetExtension(md.Options(), queryv1.E_ModuleQuerySafe); ext == nil || !ext.(bool) { + continue + } + + // Add the method to the whitelist + allowList = append(allowList, fmt.Sprintf("/%s/%s", sd.FullName(), md.Name())) + } + } + return true + }) + + return allowList +} diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go index a300832818d..a229f36a476 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go @@ -112,7 +112,7 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, endpoint.ChannelConfig.Version); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccountWithOrdering(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, endpoint.ChannelConfig.Version, channeltypes.ORDERED); err != nil { return err } @@ -198,6 +198,31 @@ func (suite *KeeperTestSuite) TestNewKeeper() { } } +func (suite *KeeperTestSuite) TestNewModuleQuerySafeAllowList() { + // Currently, all queries in bank, staking, auth, and circuit are marked safe + // Notably, the gov and distribution modules are not marked safe + + var allowList []string + suite.Require().NotPanics(func() { + allowList = keeper.NewModuleQuerySafeAllowList() + }) + + suite.Require().NotEmpty(allowList) + suite.Require().Contains(allowList, "/cosmos.bank.v1beta1.Query/Balance") + suite.Require().Contains(allowList, "/cosmos.bank.v1beta1.Query/AllBalances") + suite.Require().Contains(allowList, "/cosmos.staking.v1beta1.Query/Validator") + suite.Require().Contains(allowList, "/cosmos.staking.v1beta1.Query/Validators") + suite.Require().Contains(allowList, "/cosmos.circuit.v1.Query/Account") + suite.Require().Contains(allowList, "/cosmos.circuit.v1.Query/DisabledList") + suite.Require().Contains(allowList, "/cosmos.auth.v1beta1.Query/Accounts") + suite.Require().Contains(allowList, "/cosmos.auth.v1beta1.Query/ModuleAccountByName") + suite.Require().Contains(allowList, "/ibc.core.client.v1.Query/VerifyMembership") + suite.Require().NotContains(allowList, "/cosmos.gov.v1beta1.Query/Proposals") + suite.Require().NotContains(allowList, "/cosmos.gov.v1.Query/Proposals") + suite.Require().NotContains(allowList, "/cosmos.distribution.v1beta1.Query/Params") + suite.Require().NotContains(allowList, "/cosmos.distribution.v1beta1.Query/DelegationRewards") +} + func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() { suite.SetupTest() diff --git a/modules/apps/27-interchain-accounts/host/keeper/migrations.go b/modules/apps/27-interchain-accounts/host/keeper/migrations.go index 894018606c7..992027d92f1 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/migrations.go +++ b/modules/apps/27-interchain-accounts/host/keeper/migrations.go @@ -21,9 +21,10 @@ func NewMigrator(k *Keeper) Migrator { // MigrateParams migrates the host submodule's parameters from the x/params to self store. func (m Migrator) MigrateParams(ctx sdk.Context) error { if m.keeper != nil { - var params types.Params - m.keeper.legacySubspace.GetParamSet(ctx, ¶ms) - + params := types.DefaultParams() + if m.keeper.legacySubspace != nil { + m.keeper.legacySubspace.GetParamSetIfExists(ctx, ¶ms) + } if err := params.Validate(); err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/host/keeper/migrations_test.go b/modules/apps/27-interchain-accounts/host/keeper/migrations_test.go index e47e40f100f..f4af49400e9 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/migrations_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/migrations_test.go @@ -3,6 +3,9 @@ package keeper_test import ( "fmt" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + icahostkeeper "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/keeper" icahosttypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" ) @@ -22,6 +25,24 @@ func (suite *KeeperTestSuite) TestMigratorMigrateParams() { }, icahosttypes.DefaultParams(), }, + { + "success: no legacy params pre-migration", + func() { + suite.chainA.GetSimApp().ICAHostKeeper = icahostkeeper.NewKeeper( + suite.chainA.Codec, + suite.chainA.GetSimApp().GetKey(icahosttypes.StoreKey), + nil, // assign a nil legacy param subspace + suite.chainA.GetSimApp().IBCFeeKeeper, + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper, + suite.chainA.GetSimApp().IBCKeeper.PortKeeper, + suite.chainA.GetSimApp().AccountKeeper, + suite.chainA.GetSimApp().ScopedICAHostKeeper, + suite.chainA.GetSimApp().MsgServiceRouter(), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + ) + }, + icahosttypes.DefaultParams(), + }, } for _, tc := range testCases { diff --git a/modules/apps/27-interchain-accounts/host/keeper/msg_server.go b/modules/apps/27-interchain-accounts/host/keeper/msg_server.go index c71dba65576..711052f64bb 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/msg_server.go +++ b/modules/apps/27-interchain-accounts/host/keeper/msg_server.go @@ -2,11 +2,15 @@ package keeper import ( "context" + "errors" + "slices" errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ) @@ -20,9 +24,51 @@ type msgServer struct { // NewMsgServerImpl returns an implementation of the ICS27 host MsgServer interface // for the provided Keeper. func NewMsgServerImpl(keeper *Keeper) types.MsgServer { + if keeper.queryRouter == nil { + panic("query router must not be nil") + } return &msgServer{Keeper: keeper} } +// ModuleQuerySafe routes the queries to the keeper's query router if they are module_query_safe. +// This handler doesn't use the signer. +func (m msgServer) ModuleQuerySafe(goCtx context.Context, msg *types.MsgModuleQuerySafe) (*types.MsgModuleQuerySafeResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + responses := make([][]byte, len(msg.Requests)) + for i, query := range msg.Requests { + isModuleQuerySafe := slices.Contains(m.mqsAllowList, query.Path) + if !isModuleQuerySafe { + return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "not module query safe: %s", query.Path) + } + + if m.queryRouter == nil { + return nil, errors.New("query router must not be nil") + } + + route := m.queryRouter.Route(query.Path) + if route == nil { + return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "no route to query: %s", query.Path) + } + + res, err := route(ctx, &abci.RequestQuery{ + Path: query.Path, + Data: query.Data, + }) + if err != nil { + m.Logger(ctx).Debug("query failed", "path", query.Path, "error", err) + return nil, err + } + if res == nil || res.Value == nil { + return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "no response for query: %s", query.Path) + } + + responses[i] = res.Value + } + + return &types.MsgModuleQuerySafeResponse{Responses: responses, Height: uint64(ctx.BlockHeight())}, nil +} + // UpdateParams updates the host submodule's params. func (m msgServer) UpdateParams(goCtx context.Context, msg *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { if m.GetAuthority() != msg.Signer { diff --git a/modules/apps/27-interchain-accounts/host/keeper/msg_server_test.go b/modules/apps/27-interchain-accounts/host/keeper/msg_server_test.go index 4cc47f781d2..d358303fc12 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/msg_server_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/msg_server_test.go @@ -1,10 +1,157 @@ package keeper_test import ( + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" + transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ) +func (suite *KeeperTestSuite) TestModuleQuerySafe() { + var ( + msg *types.MsgModuleQuerySafe + expResponses [][]byte + ) + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success", + func() { + balanceQueryBz, err := banktypes.NewQueryBalanceRequest(suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom).Marshal() + suite.Require().NoError(err) + + queryReq := types.QueryRequest{ + Path: "/cosmos.bank.v1beta1.Query/Balance", + Data: balanceQueryBz, + } + + msg = types.NewMsgModuleQuerySafe(suite.chainA.GetSimApp().ICAHostKeeper.GetAuthority(), []*types.QueryRequest{&queryReq}) + + balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) + + expResp := banktypes.QueryBalanceResponse{Balance: &balance} + expRespBz, err := expResp.Marshal() + suite.Require().NoError(err) + + expResponses = [][]byte{expRespBz} + }, + nil, + }, + { + "success: multiple queries", + func() { + balanceQueryBz, err := banktypes.NewQueryBalanceRequest(suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom).Marshal() + suite.Require().NoError(err) + + queryReq := types.QueryRequest{ + Path: "/cosmos.bank.v1beta1.Query/Balance", + Data: balanceQueryBz, + } + + paramsQuery := stakingtypes.QueryParamsRequest{} + paramsQueryBz, err := paramsQuery.Marshal() + suite.Require().NoError(err) + + paramsQueryReq := types.QueryRequest{ + Path: "/cosmos.staking.v1beta1.Query/Params", + Data: paramsQueryBz, + } + + msg = types.NewMsgModuleQuerySafe(suite.chainA.GetSimApp().ICAHostKeeper.GetAuthority(), []*types.QueryRequest{&queryReq, ¶msQueryReq}) + + balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) + + expResp := banktypes.QueryBalanceResponse{Balance: &balance} + expRespBz, err := expResp.Marshal() + suite.Require().NoError(err) + + params, err := suite.chainA.GetSimApp().StakingKeeper.GetParams(suite.chainA.GetContext()) + suite.Require().NoError(err) + expParamsResp := stakingtypes.QueryParamsResponse{Params: params} + expParamsRespBz, err := expParamsResp.Marshal() + suite.Require().NoError(err) + + expResponses = [][]byte{expRespBz, expParamsRespBz} + }, + nil, + }, + { + "failure: not module query safe", + func() { + balanceQueryBz, err := banktypes.NewQueryBalanceRequest(suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom).Marshal() + suite.Require().NoError(err) + + queryReq := types.QueryRequest{ + Path: "/cosmos.bank.v1beta1.Query/Balance", + Data: balanceQueryBz, + } + + paramsQuery := transfertypes.QueryParamsRequest{} + paramsQueryBz, err := paramsQuery.Marshal() + suite.Require().NoError(err) + + paramsQueryReq := types.QueryRequest{ + Path: "/ibc.applications.transfer.v1.Query/Params", + Data: paramsQueryBz, + } + + msg = types.NewMsgModuleQuerySafe(suite.chainA.GetSimApp().ICAHostKeeper.GetAuthority(), []*types.QueryRequest{&queryReq, ¶msQueryReq}) + }, + ibcerrors.ErrInvalidRequest, + }, + { + "failure: invalid query path", + func() { + balanceQueryBz, err := banktypes.NewQueryBalanceRequest(suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom).Marshal() + suite.Require().NoError(err) + + queryReq := types.QueryRequest{ + Path: "/cosmos.invalid.Query/Invalid", + Data: balanceQueryBz, + } + + msg = types.NewMsgModuleQuerySafe(suite.chainA.GetSimApp().ICAHostKeeper.GetAuthority(), []*types.QueryRequest{&queryReq}) + }, + ibcerrors.ErrInvalidRequest, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() + + // reset + msg = nil + expResponses = nil + + tc.malleate() + + ctx := suite.chainA.GetContext() + msgServer := keeper.NewMsgServerImpl(&suite.chainA.GetSimApp().ICAHostKeeper) + res, err := msgServer.ModuleQuerySafe(ctx, msg) + + if tc.expErr == nil { + suite.Require().NoError(err) + suite.Require().NotNil(res) + + suite.Require().ElementsMatch(expResponses, res.Responses) + } else { + suite.Require().ErrorIs(err, tc.expErr) + suite.Require().Nil(res) + } + }) + } +} + func (suite *KeeperTestSuite) TestUpdateParams() { testCases := []struct { name string diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go index a83626aa117..26dc5f79a41 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go @@ -273,6 +273,38 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { }, true, }, + { + "interchain account successfully executes icahosttypes.MsgModuleQuerySafe", + func(encoding string) { + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + balanceQuery := banktypes.NewQueryBalanceRequest(suite.chainB.SenderAccount.GetAddress(), sdk.DefaultBondDenom) + queryBz, err := balanceQuery.Marshal() + suite.Require().NoError(err) + + msg := types.NewMsgModuleQuerySafe(interchainAccountAddr, []*types.QueryRequest{ + { + Path: "/cosmos.bank.v1beta1.Query/Balance", + Data: queryBz, + }, + }) + + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msg}, encoding) + suite.Require().NoError(err) + + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: data, + } + + packetData = icaPacketData.GetBytes() + + params := types.NewParams(true, []string{sdk.MsgTypeURL(msg)}) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) + }, + true, + }, { "interchain account successfully executes disttypes.MsgSetWithdrawAddress", func(encoding string) { diff --git a/modules/apps/27-interchain-accounts/host/types/codec.go b/modules/apps/27-interchain-accounts/host/types/codec.go index 8752640e767..710d732573b 100644 --- a/modules/apps/27-interchain-accounts/host/types/codec.go +++ b/modules/apps/27-interchain-accounts/host/types/codec.go @@ -11,6 +11,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations( (*sdk.Msg)(nil), &MsgUpdateParams{}, + &MsgModuleQuerySafe{}, ) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) diff --git a/modules/apps/27-interchain-accounts/host/types/codec_test.go b/modules/apps/27-interchain-accounts/host/types/codec_test.go index 6fb2591cf47..581a9401e2b 100644 --- a/modules/apps/27-interchain-accounts/host/types/codec_test.go +++ b/modules/apps/27-interchain-accounts/host/types/codec_test.go @@ -23,6 +23,11 @@ func TestCodecTypeRegistration(t *testing.T) { sdk.MsgTypeURL(&types.MsgUpdateParams{}), true, }, + { + "success: MsgModuleQuerySafe", + sdk.MsgTypeURL(&types.MsgModuleQuerySafe{}), + true, + }, { "type not registered on codec", "ibc.invalid.MsgTypeURL", diff --git a/modules/apps/27-interchain-accounts/host/types/host.pb.go b/modules/apps/27-interchain-accounts/host/types/host.pb.go index 77db265b6b5..54df248f119 100644 --- a/modules/apps/27-interchain-accounts/host/types/host.pb.go +++ b/modules/apps/27-interchain-accounts/host/types/host.pb.go @@ -78,8 +78,67 @@ func (m *Params) GetAllowMessages() []string { return nil } +// QueryRequest defines the parameters for a particular query request +// by an interchain account. +type QueryRequest struct { + // path defines the path of the query request as defined by ADR-021. + // https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-021-protobuf-query-encoding.md#custom-query-registration-and-routing + Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` + // data defines the payload of the query request as defined by ADR-021. + // https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-021-protobuf-query-encoding.md#custom-query-registration-and-routing + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *QueryRequest) Reset() { *m = QueryRequest{} } +func (m *QueryRequest) String() string { return proto.CompactTextString(m) } +func (*QueryRequest) ProtoMessage() {} +func (*QueryRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_48e202774f13d08e, []int{1} +} +func (m *QueryRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryRequest.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 *QueryRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryRequest.Merge(m, src) +} +func (m *QueryRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryRequest proto.InternalMessageInfo + +func (m *QueryRequest) GetPath() string { + if m != nil { + return m.Path + } + return "" +} + +func (m *QueryRequest) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + func init() { proto.RegisterType((*Params)(nil), "ibc.applications.interchain_accounts.host.v1.Params") + proto.RegisterType((*QueryRequest)(nil), "ibc.applications.interchain_accounts.host.v1.QueryRequest") } func init() { @@ -87,23 +146,25 @@ func init() { } var fileDescriptor_48e202774f13d08e = []byte{ - // 246 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0xcf, 0xbf, 0x4a, 0xc4, 0x40, - 0x10, 0xc7, 0xf1, 0x44, 0xe1, 0xd0, 0xf8, 0xa7, 0x48, 0x75, 0xd5, 0x72, 0x0a, 0xc2, 0x15, 0x66, - 0x97, 0xd3, 0xe2, 0xac, 0x05, 0x1b, 0x41, 0x90, 0x94, 0x36, 0x61, 0x77, 0xb2, 0x24, 0x0b, 0xbb, - 0x3b, 0x21, 0xb3, 0x89, 0xf8, 0x16, 0x3e, 0x96, 0xe5, 0x95, 0x96, 0x92, 0xbc, 0x88, 0x24, 0x0a, - 0x2a, 0x58, 0x0d, 0x7c, 0xe0, 0x07, 0xf3, 0x4d, 0xb6, 0x46, 0x81, 0x90, 0x4d, 0x63, 0x0d, 0xc8, - 0x60, 0xd0, 0x93, 0x30, 0x3e, 0xe8, 0x16, 0x6a, 0x69, 0x7c, 0x21, 0x01, 0xb0, 0xf3, 0x81, 0x44, - 0x8d, 0x14, 0x44, 0xbf, 0x99, 0x2f, 0x6f, 0x5a, 0x0c, 0x98, 0x5e, 0x1a, 0x05, 0xfc, 0xf7, 0x90, - 0xff, 0x33, 0xe4, 0xf3, 0xa0, 0xdf, 0x9c, 0xe7, 0xc9, 0xe2, 0x51, 0xb6, 0xd2, 0x51, 0x7a, 0x96, - 0x1c, 0x4f, 0x58, 0x68, 0x2f, 0x95, 0xd5, 0xe5, 0x32, 0x5e, 0xc5, 0xeb, 0x83, 0xfc, 0x68, 0xb2, - 0xbb, 0x2f, 0x4a, 0x2f, 0x92, 0x53, 0x69, 0x2d, 0x3e, 0x17, 0x4e, 0x13, 0xc9, 0x4a, 0xd3, 0x72, - 0x6f, 0xb5, 0xbf, 0x3e, 0xcc, 0x4f, 0x66, 0x7d, 0xf8, 0xc6, 0xdb, 0xf2, 0x6d, 0x60, 0xf1, 0x6e, - 0x60, 0xf1, 0xc7, 0xc0, 0xe2, 0xd7, 0x91, 0x45, 0xbb, 0x91, 0x45, 0xef, 0x23, 0x8b, 0x9e, 0xee, - 0x2b, 0x13, 0xea, 0x4e, 0x71, 0x40, 0x27, 0x00, 0xc9, 0x21, 0x09, 0xa3, 0x20, 0xab, 0x50, 0xf4, - 0x37, 0xc2, 0x61, 0xd9, 0x59, 0x4d, 0x53, 0x34, 0x89, 0xab, 0x6d, 0xf6, 0xf3, 0x76, 0xf6, 0xb7, - 0x37, 0xbc, 0x34, 0x9a, 0xd4, 0x62, 0xce, 0xbd, 0xfe, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x51, 0x50, - 0x78, 0xd7, 0x29, 0x01, 0x00, 0x00, + // 284 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0xd0, 0x31, 0x4b, 0xfc, 0x30, + 0x18, 0x06, 0xf0, 0xcb, 0xfd, 0xff, 0x1c, 0x5e, 0x3c, 0x1d, 0x3a, 0xdd, 0x14, 0xce, 0x03, 0xa1, + 0x83, 0x6d, 0x38, 0x05, 0xcf, 0x59, 0x70, 0x11, 0x04, 0xcd, 0xe8, 0x52, 0xde, 0xa4, 0xa1, 0x0d, + 0xb4, 0x4d, 0xed, 0x9b, 0x56, 0xee, 0x5b, 0xf8, 0xb1, 0x1c, 0x6f, 0x74, 0x94, 0xf6, 0x8b, 0x48, + 0xa3, 0xa0, 0x82, 0x53, 0x1e, 0x7e, 0xf0, 0x04, 0xde, 0x87, 0x6e, 0x8d, 0x54, 0x1c, 0xea, 0xba, + 0x30, 0x0a, 0x9c, 0xb1, 0x15, 0x72, 0x53, 0x39, 0xdd, 0xa8, 0x1c, 0x4c, 0x95, 0x80, 0x52, 0xb6, + 0xad, 0x1c, 0xf2, 0xdc, 0xa2, 0xe3, 0xdd, 0xc6, 0xbf, 0x71, 0xdd, 0x58, 0x67, 0x83, 0x33, 0x23, + 0x55, 0xfc, 0xb3, 0x18, 0xff, 0x51, 0x8c, 0x7d, 0xa1, 0xdb, 0xac, 0x05, 0x9d, 0xdd, 0x43, 0x03, + 0x25, 0x06, 0x27, 0x74, 0x31, 0x62, 0xa2, 0x2b, 0x90, 0x85, 0x4e, 0x97, 0x64, 0x45, 0xc2, 0x03, + 0x71, 0x38, 0xda, 0xcd, 0x27, 0x05, 0xa7, 0xf4, 0x18, 0x8a, 0xc2, 0x3e, 0x27, 0xa5, 0x46, 0x84, + 0x4c, 0xe3, 0x72, 0xba, 0xfa, 0x17, 0xce, 0xc5, 0x91, 0xd7, 0xbb, 0x2f, 0x5c, 0x5f, 0xd2, 0xc5, + 0x43, 0xab, 0x9b, 0x9d, 0xd0, 0x4f, 0xad, 0x46, 0x17, 0x04, 0xf4, 0x7f, 0x0d, 0x2e, 0xf7, 0x3f, + 0xce, 0x85, 0xcf, 0xa3, 0xa5, 0xe0, 0x60, 0x39, 0x5d, 0x91, 0x70, 0x21, 0x7c, 0xbe, 0x4e, 0x5f, + 0x7b, 0x46, 0xf6, 0x3d, 0x23, 0xef, 0x3d, 0x23, 0x2f, 0x03, 0x9b, 0xec, 0x07, 0x36, 0x79, 0x1b, + 0xd8, 0xe4, 0xf1, 0x36, 0x33, 0x2e, 0x6f, 0x65, 0xac, 0x6c, 0xc9, 0x95, 0xc5, 0xd2, 0x22, 0x37, + 0x52, 0x45, 0x99, 0xe5, 0xdd, 0x15, 0x2f, 0x6d, 0xda, 0x16, 0x1a, 0xc7, 0xb1, 0x90, 0x9f, 0x6f, + 0xa3, 0xef, 0x73, 0xa3, 0xdf, 0x3b, 0xb9, 0x5d, 0xad, 0x51, 0xce, 0xfc, 0x4c, 0x17, 0x1f, 0x01, + 0x00, 0x00, 0xff, 0xff, 0x56, 0xc6, 0xd2, 0x5a, 0x61, 0x01, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -148,6 +209,43 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *QueryRequest) 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 *QueryRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintHost(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x12 + } + if len(m.Path) > 0 { + i -= len(m.Path) + copy(dAtA[i:], m.Path) + i = encodeVarintHost(dAtA, i, uint64(len(m.Path))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintHost(dAtA []byte, offset int, v uint64) int { offset -= sovHost(v) base := offset @@ -177,6 +275,23 @@ func (m *Params) Size() (n int) { return n } +func (m *QueryRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Path) + if l > 0 { + n += 1 + l + sovHost(uint64(l)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovHost(uint64(l)) + } + return n +} + func sovHost(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -285,6 +400,122 @@ func (m *Params) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryRequest) 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 ErrIntOverflowHost + } + 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: QueryRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryRequest: 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 stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHost + } + 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 ErrInvalidLengthHost + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthHost + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Path = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHost + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthHost + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthHost + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipHost(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthHost + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipHost(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/modules/apps/27-interchain-accounts/host/types/msgs.go b/modules/apps/27-interchain-accounts/host/types/msgs.go index 845139a4a34..06641c0b7e6 100644 --- a/modules/apps/27-interchain-accounts/host/types/msgs.go +++ b/modules/apps/27-interchain-accounts/host/types/msgs.go @@ -11,6 +11,9 @@ import ( var ( _ sdk.Msg = (*MsgUpdateParams)(nil) _ sdk.HasValidateBasic = (*MsgUpdateParams)(nil) + + _ sdk.Msg = (*MsgModuleQuerySafe)(nil) + _ sdk.HasValidateBasic = (*MsgModuleQuerySafe)(nil) ) // NewMsgUpdateParams creates a new MsgUpdateParams instance @@ -21,7 +24,7 @@ func NewMsgUpdateParams(signer string, params Params) *MsgUpdateParams { } } -// ValidateBasic implements sdk.Msg +// ValidateBasic implements sdk.HasValidateBasic func (msg MsgUpdateParams) ValidateBasic() error { _, err := sdk.AccAddressFromBech32(msg.Signer) if err != nil { @@ -40,3 +43,35 @@ func (msg MsgUpdateParams) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{accAddr} } + +// NewMsgModuleQuerySafe creates a new MsgModuleQuerySafe instance +func NewMsgModuleQuerySafe(signer string, requests []*QueryRequest) *MsgModuleQuerySafe { + return &MsgModuleQuerySafe{ + Signer: signer, + Requests: requests, + } +} + +// ValidateBasic implements sdk.HasValidateBasic +func (msg MsgModuleQuerySafe) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err) + } + + if len(msg.Requests) == 0 { + return errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "no queries provided") + } + + return nil +} + +// GetSigners implements sdk.Msg +func (msg MsgModuleQuerySafe) GetSigners() []sdk.AccAddress { + accAddr, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + panic(err) + } + + return []sdk.AccAddress{accAddr} +} diff --git a/modules/apps/27-interchain-accounts/host/types/msgs_test.go b/modules/apps/27-interchain-accounts/host/types/msgs_test.go index 1170f82b895..8b95e5d7e05 100644 --- a/modules/apps/27-interchain-accounts/host/types/msgs_test.go +++ b/modules/apps/27-interchain-accounts/host/types/msgs_test.go @@ -8,6 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -71,3 +72,70 @@ func TestMsgUpdateParamsGetSigners(t *testing.T) { } } } + +func TestMsgModuleQuerySafeValidateBasic(t *testing.T) { + queryRequest := &types.QueryRequest{ + Path: "/cosmos.bank.v1beta1.Query/Balance", + Data: []byte{}, + } + + testCases := []struct { + name string + msg *types.MsgModuleQuerySafe + expErr error + }{ + { + "success: valid signer address", + types.NewMsgModuleQuerySafe(sdk.AccAddress(ibctesting.TestAccAddress).String(), []*types.QueryRequest{queryRequest}), + nil, + }, + { + "failure: invalid signer address", + types.NewMsgModuleQuerySafe("signer", []*types.QueryRequest{queryRequest}), + ibcerrors.ErrInvalidAddress, + }, + { + "failure: empty query requests", + types.NewMsgModuleQuerySafe(sdk.AccAddress(ibctesting.TestAccAddress).String(), []*types.QueryRequest{}), + ibcerrors.ErrInvalidRequest, + }, + } + + for _, tc := range testCases { + tc := tc + + err := tc.msg.ValidateBasic() + + expPass := tc.expErr == nil + if expPass { + require.NoError(t, err) + } else { + require.Error(t, err) + require.ErrorIs(t, err, tc.expErr) + } + } +} + +func TestMsgModuleQuerySafeGetSigners(t *testing.T) { + testCases := []struct { + name string + address sdk.AccAddress + expPass bool + }{ + {"success: valid address", sdk.AccAddress(ibctesting.TestAccAddress), true}, + {"failure: nil address", nil, false}, + } + + for _, tc := range testCases { + tc := tc + + msg := types.NewMsgModuleQuerySafe(tc.address.String(), []*types.QueryRequest{}) + if tc.expPass { + require.Equal(t, []sdk.AccAddress{tc.address}, msg.GetSigners()) + } else { + require.Panics(t, func() { + msg.GetSigners() + }) + } + } +} diff --git a/modules/apps/27-interchain-accounts/host/types/tx.pb.go b/modules/apps/27-interchain-accounts/host/types/tx.pb.go index ebcc8995cb5..8663234557f 100644 --- a/modules/apps/27-interchain-accounts/host/types/tx.pb.go +++ b/modules/apps/27-interchain-accounts/host/types/tx.pb.go @@ -109,9 +109,107 @@ func (m *MsgUpdateParamsResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo +// MsgModuleQuerySafe defines the payload for Msg/ModuleQuerySafe +type MsgModuleQuerySafe struct { + // signer address + Signer string `protobuf:"bytes,1,opt,name=signer,proto3" json:"signer,omitempty"` + // requests defines the module safe queries to execute. + Requests []*QueryRequest `protobuf:"bytes,2,rep,name=requests,proto3" json:"requests,omitempty"` +} + +func (m *MsgModuleQuerySafe) Reset() { *m = MsgModuleQuerySafe{} } +func (m *MsgModuleQuerySafe) String() string { return proto.CompactTextString(m) } +func (*MsgModuleQuerySafe) ProtoMessage() {} +func (*MsgModuleQuerySafe) Descriptor() ([]byte, []int) { + return fileDescriptor_fa437afde7f1e7ae, []int{2} +} +func (m *MsgModuleQuerySafe) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgModuleQuerySafe) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgModuleQuerySafe.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 *MsgModuleQuerySafe) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgModuleQuerySafe.Merge(m, src) +} +func (m *MsgModuleQuerySafe) XXX_Size() int { + return m.Size() +} +func (m *MsgModuleQuerySafe) XXX_DiscardUnknown() { + xxx_messageInfo_MsgModuleQuerySafe.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgModuleQuerySafe proto.InternalMessageInfo + +// MsgModuleQuerySafeResponse defines the response for Msg/ModuleQuerySafe +type MsgModuleQuerySafeResponse struct { + // height at which the responses were queried + Height uint64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` + // protobuf encoded responses for each query + Responses [][]byte `protobuf:"bytes,2,rep,name=responses,proto3" json:"responses,omitempty"` +} + +func (m *MsgModuleQuerySafeResponse) Reset() { *m = MsgModuleQuerySafeResponse{} } +func (m *MsgModuleQuerySafeResponse) String() string { return proto.CompactTextString(m) } +func (*MsgModuleQuerySafeResponse) ProtoMessage() {} +func (*MsgModuleQuerySafeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_fa437afde7f1e7ae, []int{3} +} +func (m *MsgModuleQuerySafeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgModuleQuerySafeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgModuleQuerySafeResponse.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 *MsgModuleQuerySafeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgModuleQuerySafeResponse.Merge(m, src) +} +func (m *MsgModuleQuerySafeResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgModuleQuerySafeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgModuleQuerySafeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgModuleQuerySafeResponse proto.InternalMessageInfo + +func (m *MsgModuleQuerySafeResponse) GetHeight() uint64 { + if m != nil { + return m.Height + } + return 0 +} + +func (m *MsgModuleQuerySafeResponse) GetResponses() [][]byte { + if m != nil { + return m.Responses + } + return nil +} + func init() { proto.RegisterType((*MsgUpdateParams)(nil), "ibc.applications.interchain_accounts.host.v1.MsgUpdateParams") proto.RegisterType((*MsgUpdateParamsResponse)(nil), "ibc.applications.interchain_accounts.host.v1.MsgUpdateParamsResponse") + proto.RegisterType((*MsgModuleQuerySafe)(nil), "ibc.applications.interchain_accounts.host.v1.MsgModuleQuerySafe") + proto.RegisterType((*MsgModuleQuerySafeResponse)(nil), "ibc.applications.interchain_accounts.host.v1.MsgModuleQuerySafeResponse") } func init() { @@ -119,29 +217,36 @@ func init() { } var fileDescriptor_fa437afde7f1e7ae = []byte{ - // 352 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0xcd, 0x4c, 0x4a, 0xd6, - 0x4f, 0x2c, 0x28, 0xc8, 0xc9, 0x4c, 0x4e, 0x2c, 0xc9, 0xcc, 0xcf, 0x2b, 0xd6, 0xcf, 0xcc, 0x2b, - 0x49, 0x2d, 0x4a, 0xce, 0x48, 0xcc, 0xcc, 0x8b, 0x4f, 0x4c, 0x4e, 0xce, 0x2f, 0xcd, 0x2b, 0x29, - 0xd6, 0xcf, 0xc8, 0x2f, 0x2e, 0xd1, 0x2f, 0x33, 0xd4, 0x2f, 0xa9, 0xd0, 0x2b, 0x28, 0xca, 0x2f, - 0xc9, 0x17, 0xd2, 0xc9, 0x4c, 0x4a, 0xd6, 0x43, 0xd6, 0xa6, 0x87, 0x45, 0x9b, 0x1e, 0x48, 0x9b, - 0x5e, 0x99, 0xa1, 0x94, 0x48, 0x7a, 0x7e, 0x7a, 0x3e, 0x58, 0xa3, 0x3e, 0x88, 0x05, 0x31, 0x43, - 0x4a, 0x3c, 0x39, 0xbf, 0x38, 0x37, 0xbf, 0x58, 0x3f, 0xb7, 0x38, 0x1d, 0x64, 0x76, 0x6e, 0x71, - 0x3a, 0x54, 0xc2, 0x9c, 0x24, 0x37, 0x81, 0x2d, 0x01, 0x6b, 0x54, 0xea, 0x63, 0xe4, 0xe2, 0xf7, - 0x2d, 0x4e, 0x0f, 0x2d, 0x48, 0x49, 0x2c, 0x49, 0x0d, 0x48, 0x2c, 0x4a, 0xcc, 0x2d, 0x16, 0x12, - 0xe3, 0x62, 0x2b, 0xce, 0x4c, 0xcf, 0x4b, 0x2d, 0x92, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0x82, - 0xf2, 0x84, 0x82, 0xb8, 0xd8, 0x0a, 0xc0, 0x2a, 0x24, 0x98, 0x14, 0x18, 0x35, 0xb8, 0x8d, 0x4c, - 0xf4, 0x48, 0xf1, 0x92, 0x1e, 0xc4, 0x74, 0x27, 0x96, 0x13, 0xf7, 0xe4, 0x19, 0x82, 0xa0, 0x26, - 0x59, 0xf1, 0x77, 0x2c, 0x90, 0x67, 0x68, 0x7a, 0xbe, 0x41, 0x0b, 0x6a, 0x89, 0x92, 0x24, 0x97, - 0x38, 0x9a, 0x7b, 0x82, 0x52, 0x8b, 0x0b, 0xf2, 0xf3, 0x8a, 0x53, 0x8d, 0x16, 0x33, 0x72, 0x31, - 0xfb, 0x16, 0xa7, 0x0b, 0x4d, 0x61, 0xe4, 0xe2, 0x41, 0x71, 0xb0, 0x2d, 0x69, 0x0e, 0x41, 0x33, - 0x5f, 0xca, 0x95, 0x22, 0xed, 0x30, 0xe7, 0x49, 0xb1, 0x36, 0x3c, 0xdf, 0xa0, 0xc5, 0xe8, 0x94, - 0x72, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, - 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x5e, 0xe9, 0x99, 0x25, 0x19, - 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0xd0, 0x88, 0xcc, 0x4c, 0x4a, 0xd6, 0x4d, 0xcf, 0xd7, - 0x2f, 0xb3, 0xd0, 0xcf, 0xcd, 0x4f, 0x29, 0xcd, 0x49, 0x2d, 0x06, 0x45, 0x62, 0xb1, 0xbe, 0x91, - 0xb9, 0x2e, 0xc2, 0x05, 0xba, 0xa8, 0xf1, 0x57, 0x52, 0x59, 0x90, 0x5a, 0x9c, 0xc4, 0x06, 0x8e, - 0x3e, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x76, 0xa2, 0x96, 0x3e, 0x8d, 0x02, 0x00, 0x00, + // 456 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x93, 0x41, 0x6b, 0xd4, 0x40, + 0x14, 0xc7, 0x33, 0x6d, 0x5d, 0xec, 0xb4, 0x50, 0x08, 0x62, 0x6b, 0x90, 0xb4, 0xec, 0x69, 0x29, + 0xee, 0x0c, 0x5d, 0x95, 0x4a, 0x41, 0x90, 0x82, 0x20, 0x42, 0x40, 0x47, 0xf4, 0xe0, 0x45, 0x26, + 0xb3, 0xe3, 0x64, 0xa0, 0xc9, 0xc4, 0xbc, 0xc9, 0x62, 0x6f, 0xe2, 0xc9, 0x93, 0x78, 0xd0, 0xa3, + 0xe0, 0x47, 0xe8, 0x77, 0xf0, 0xd2, 0x63, 0x8f, 0x9e, 0x44, 0x76, 0x0f, 0xfd, 0x1a, 0x92, 0x49, + 0xda, 0xda, 0xd4, 0x1e, 0x42, 0x6f, 0x99, 0x64, 0xfe, 0xbf, 0xf7, 0x7b, 0x99, 0x79, 0xf8, 0xbe, + 0x8e, 0x05, 0xe5, 0x79, 0xbe, 0xa7, 0x05, 0xb7, 0xda, 0x64, 0x40, 0x75, 0x66, 0x65, 0x21, 0x12, + 0xae, 0xb3, 0x37, 0x5c, 0x08, 0x53, 0x66, 0x16, 0x68, 0x62, 0xc0, 0xd2, 0xc9, 0x16, 0xb5, 0xef, + 0x49, 0x5e, 0x18, 0x6b, 0xfc, 0x3b, 0x3a, 0x16, 0xe4, 0xdf, 0x18, 0xf9, 0x4f, 0x8c, 0x54, 0x31, + 0x32, 0xd9, 0x0a, 0x6e, 0x28, 0xa3, 0x8c, 0x0b, 0xd2, 0xea, 0xa9, 0x66, 0x04, 0xab, 0xc2, 0x40, + 0x6a, 0x80, 0xa6, 0xa0, 0x2a, 0x76, 0x0a, 0xaa, 0xf9, 0xb0, 0xdd, 0xc9, 0xc9, 0x15, 0x71, 0xc1, + 0xfe, 0x67, 0x84, 0x57, 0x22, 0x50, 0x2f, 0xf3, 0x31, 0xb7, 0xf2, 0x19, 0x2f, 0x78, 0x0a, 0xfe, + 0x4d, 0xdc, 0x03, 0xad, 0x32, 0x59, 0xac, 0xa1, 0x0d, 0x34, 0x58, 0x64, 0xcd, 0xca, 0x67, 0xb8, + 0x97, 0xbb, 0x1d, 0x6b, 0x73, 0x1b, 0x68, 0xb0, 0x34, 0xba, 0x47, 0xba, 0xb4, 0x44, 0x6a, 0xfa, + 0xee, 0xc2, 0xe1, 0xef, 0x75, 0x8f, 0x35, 0xa4, 0x9d, 0x95, 0x4f, 0x3f, 0xd6, 0xbd, 0x8f, 0xc7, + 0x07, 0x9b, 0x4d, 0x91, 0xfe, 0x2d, 0xbc, 0xda, 0xf2, 0x61, 0x12, 0x72, 0x93, 0x81, 0xec, 0x7f, + 0x43, 0xd8, 0x8f, 0x40, 0x45, 0x66, 0x5c, 0xee, 0xc9, 0xe7, 0xa5, 0x2c, 0xf6, 0x5f, 0xf0, 0xb7, + 0xf2, 0x52, 0xdd, 0x57, 0xf8, 0x7a, 0x21, 0xdf, 0x95, 0x12, 0x6c, 0x25, 0x3c, 0x3f, 0x58, 0x1a, + 0xed, 0x74, 0x13, 0x76, 0x25, 0x58, 0x8d, 0x60, 0xa7, 0xac, 0x8b, 0xca, 0x0c, 0x07, 0x17, 0xb5, + 0x4e, 0xac, 0x2b, 0xbd, 0x44, 0x6a, 0x95, 0x58, 0xa7, 0xb7, 0xc0, 0x9a, 0x95, 0x7f, 0x1b, 0x2f, + 0x16, 0xcd, 0x9e, 0xda, 0x6f, 0x99, 0x9d, 0xbd, 0x18, 0xfd, 0x9c, 0xc3, 0xf3, 0x11, 0x28, 0xff, + 0x2b, 0xc2, 0xcb, 0xe7, 0x0e, 0xe7, 0x61, 0xb7, 0x1e, 0x5a, 0xff, 0x32, 0x78, 0x7c, 0xa5, 0xf8, + 0x69, 0x53, 0xdf, 0xab, 0x6b, 0xd3, 0x3a, 0x87, 0x47, 0x9d, 0xd1, 0x2d, 0x42, 0xf0, 0xe4, 0xaa, + 0x84, 0x13, 0xbf, 0xe0, 0xda, 0x87, 0xe3, 0x83, 0x4d, 0xb4, 0x3b, 0x3e, 0x9c, 0x86, 0xe8, 0x68, + 0x1a, 0xa2, 0x3f, 0xd3, 0x10, 0x7d, 0x99, 0x85, 0xde, 0xd1, 0x2c, 0xf4, 0x7e, 0xcd, 0x42, 0xef, + 0xf5, 0x53, 0xa5, 0x6d, 0x52, 0xc6, 0x44, 0x98, 0x94, 0x36, 0x43, 0xa5, 0x63, 0x31, 0x54, 0x86, + 0x4e, 0x1e, 0xd0, 0xd4, 0x51, 0xa1, 0x1a, 0x28, 0xa0, 0xa3, 0xed, 0xe1, 0x99, 0xc4, 0xf0, 0xfc, + 0x2c, 0xd9, 0xfd, 0x5c, 0x42, 0xdc, 0x73, 0xa3, 0x74, 0xf7, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x49, 0x5c, 0x48, 0xd7, 0x19, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -158,6 +263,8 @@ const _ = grpc.SupportPackageIsVersion4 type MsgClient interface { // UpdateParams defines a rpc handler for MsgUpdateParams. UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) + // ModuleQuerySafe defines a rpc handler for MsgModuleQuerySafe. + ModuleQuerySafe(ctx context.Context, in *MsgModuleQuerySafe, opts ...grpc.CallOption) (*MsgModuleQuerySafeResponse, error) } type msgClient struct { @@ -177,10 +284,21 @@ func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts return out, nil } +func (c *msgClient) ModuleQuerySafe(ctx context.Context, in *MsgModuleQuerySafe, opts ...grpc.CallOption) (*MsgModuleQuerySafeResponse, error) { + out := new(MsgModuleQuerySafeResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.interchain_accounts.host.v1.Msg/ModuleQuerySafe", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // MsgServer is the server API for Msg service. type MsgServer interface { // UpdateParams defines a rpc handler for MsgUpdateParams. UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) + // ModuleQuerySafe defines a rpc handler for MsgModuleQuerySafe. + ModuleQuerySafe(context.Context, *MsgModuleQuerySafe) (*MsgModuleQuerySafeResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -190,6 +308,9 @@ type UnimplementedMsgServer struct { func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") } +func (*UnimplementedMsgServer) ModuleQuerySafe(ctx context.Context, req *MsgModuleQuerySafe) (*MsgModuleQuerySafeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ModuleQuerySafe not implemented") +} func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) @@ -213,6 +334,24 @@ func _Msg_UpdateParams_Handler(srv interface{}, ctx context.Context, dec func(in return interceptor(ctx, in, info, handler) } +func _Msg_ModuleQuerySafe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgModuleQuerySafe) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ModuleQuerySafe(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.applications.interchain_accounts.host.v1.Msg/ModuleQuerySafe", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ModuleQuerySafe(ctx, req.(*MsgModuleQuerySafe)) + } + return interceptor(ctx, in, info, handler) +} + var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "ibc.applications.interchain_accounts.host.v1.Msg", HandlerType: (*MsgServer)(nil), @@ -221,6 +360,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "UpdateParams", Handler: _Msg_UpdateParams_Handler, }, + { + MethodName: "ModuleQuerySafe", + Handler: _Msg_ModuleQuerySafe_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "ibc/applications/interchain_accounts/host/v1/tx.proto", @@ -289,6 +432,87 @@ func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *MsgModuleQuerySafe) 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 *MsgModuleQuerySafe) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgModuleQuerySafe) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Requests) > 0 { + for iNdEx := len(m.Requests) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Requests[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgModuleQuerySafeResponse) 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 *MsgModuleQuerySafeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgModuleQuerySafeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Responses) > 0 { + for iNdEx := len(m.Responses) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Responses[iNdEx]) + copy(dAtA[i:], m.Responses[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.Responses[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if m.Height != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func encodeVarintTx(dAtA []byte, offset int, v uint64) int { offset -= sovTx(v) base := offset @@ -324,6 +548,43 @@ func (m *MsgUpdateParamsResponse) Size() (n int) { return n } +func (m *MsgModuleQuerySafe) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Requests) > 0 { + for _, e := range m.Requests { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgModuleQuerySafeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Height != 0 { + n += 1 + sovTx(uint64(m.Height)) + } + if len(m.Responses) > 0 { + for _, b := range m.Responses { + l = len(b) + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + func sovTx(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -495,6 +756,223 @@ func (m *MsgUpdateParamsResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgModuleQuerySafe) 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: MsgModuleQuerySafe: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgModuleQuerySafe: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", 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.Signer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Requests", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Requests = append(m.Requests, &QueryRequest{}) + if err := m.Requests[len(m.Requests)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + 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 *MsgModuleQuerySafeResponse) 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: MsgModuleQuerySafeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgModuleQuerySafeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Responses", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Responses = append(m.Responses, make([]byte, postIndex-iNdEx)) + copy(m.Responses[len(m.Responses)-1], 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 skipTx(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/modules/apps/27-interchain-accounts/types/expected_keepers.go b/modules/apps/27-interchain-accounts/types/expected_keepers.go index 09cf6c22024..bf318a2221d 100644 --- a/modules/apps/27-interchain-accounts/types/expected_keepers.go +++ b/modules/apps/27-interchain-accounts/types/expected_keepers.go @@ -37,4 +37,5 @@ type PortKeeper interface { // ParamSubspace defines the expected Subspace interface for module parameters. type ParamSubspace interface { GetParamSet(ctx sdk.Context, ps paramtypes.ParamSet) + GetParamSetIfExists(ctx sdk.Context, ps paramtypes.ParamSet) } diff --git a/modules/apps/27-interchain-accounts/types/metadata.go b/modules/apps/27-interchain-accounts/types/metadata.go index 29d1da45d42..a63e4a93083 100644 --- a/modules/apps/27-interchain-accounts/types/metadata.go +++ b/modules/apps/27-interchain-accounts/types/metadata.go @@ -54,11 +54,20 @@ func NewDefaultMetadataString(controllerConnectionID, hostConnectionID string) s return string(ModuleCdc.MustMarshalJSON(&metadata)) } +// MetadataFromVersion parses Metadata from a json encoded version string. +func MetadataFromVersion(versionString string) (Metadata, error) { + var metadata Metadata + if err := ModuleCdc.UnmarshalJSON([]byte(versionString), &metadata); err != nil { + return Metadata{}, errorsmod.Wrapf(ErrUnknownDataType, "cannot unmarshal ICS-27 interchain accounts metadata") + } + return metadata, nil +} + // IsPreviousMetadataEqual compares a metadata to a previous version string set in a channel struct. // It ensures all fields are equal except the Address string func IsPreviousMetadataEqual(previousVersion string, metadata Metadata) bool { - var previousMetadata Metadata - if err := ModuleCdc.UnmarshalJSON([]byte(previousVersion), &previousMetadata); err != nil { + previousMetadata, err := MetadataFromVersion(previousVersion) + if err != nil { return false } @@ -69,7 +78,8 @@ func IsPreviousMetadataEqual(previousVersion string, metadata Metadata) bool { previousMetadata.TxType == metadata.TxType) } -// ValidateControllerMetadata performs validation of the provided ICS27 controller metadata parameters +// ValidateControllerMetadata performs validation of the provided ICS27 controller metadata parameters as well +// as the connection params against the provided metadata func ValidateControllerMetadata(ctx sdk.Context, channelKeeper ChannelKeeper, connectionHops []string, metadata Metadata) error { if !isSupportedEncoding(metadata.Encoding) { return errorsmod.Wrapf(ErrInvalidCodec, "unsupported encoding format %s", metadata.Encoding) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 524e2ebc44a..fea649dfac1 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -19,7 +19,7 @@ var ( ) // MaxMemoCharLength defines the maximum length for the InterchainAccountPacketData memo field -const MaxMemoCharLength = 256 +const MaxMemoCharLength = 32768 var ( // DefaultRelativePacketTimeoutHeight is the default packet timeout height (in blocks) relative diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index c8bbec6ced8..889d575d919 100644 --- a/modules/apps/27-interchain-accounts/types/packet_test.go +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -7,8 +7,6 @@ import ( ibctesting "github.com/cosmos/ibc-go/v8/testing" ) -var largeMemo = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum" - func (suite *TypesTestSuite) TestValidateBasic() { testCases := []struct { name string @@ -64,7 +62,7 @@ func (suite *TypesTestSuite) TestValidateBasic() { types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: largeMemo, + Memo: ibctesting.GenerateString(types.MaxMemoCharLength + 1), }, false, }, diff --git a/modules/apps/27-interchain-accounts/types/router.go b/modules/apps/27-interchain-accounts/types/router.go index 007091b9d0d..32a334f5f46 100644 --- a/modules/apps/27-interchain-accounts/types/router.go +++ b/modules/apps/27-interchain-accounts/types/router.go @@ -10,3 +10,11 @@ import ( type MessageRouter interface { Handler(msg sdk.Msg) baseapp.MsgServiceHandler } + +// QueryRouter ADR 021 query type routing +// https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-021-protobuf-query-encoding.md +type QueryRouter interface { + // Route returns the GRPCQueryHandler for a given query route path or nil + // if not found + Route(path string) baseapp.GRPCQueryHandler +} diff --git a/modules/apps/29-fee/fee_test.go b/modules/apps/29-fee/fee_test.go index cc52cb6f2b2..047463c683e 100644 --- a/modules/apps/29-fee/fee_test.go +++ b/modules/apps/29-fee/fee_test.go @@ -5,9 +5,16 @@ import ( testifysuite "github.com/stretchr/testify/suite" + icacontroller "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller" + icacontrollertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" + icahost "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host" + icahosttypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" + "github.com/cosmos/ibc-go/v8/modules/apps/transfer" + transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" ibctesting "github.com/cosmos/ibc-go/v8/testing" ibcmock "github.com/cosmos/ibc-go/v8/testing/mock" ) @@ -64,6 +71,40 @@ func (suite *FeeTestSuite) CreateMockPacket() channeltypes.Packet { ) } +// RemoveFeeMiddleware removes: +// - Fee middleware from transfer module +// - Fee middleware from icahost submodule +// - Fee middleware from icacontroller submodule +// - The entire mock-fee module +// +// It does this by overriding the IBC router with a new router. +func RemoveFeeMiddleware(chain *ibctesting.TestChain) { + channelKeeper := chain.GetSimApp().IBCKeeper.ChannelKeeper + + // Unseal the IBC router by force + chain.GetSimApp().IBCKeeper.Router = nil + chain.GetSimApp().IBCKeeper.PortKeeper.Router = nil + + newRouter := porttypes.NewRouter() // Create a new router + // Remove Fee middleware from transfer module + chain.GetSimApp().TransferKeeper.WithICS4Wrapper(channelKeeper) + transferStack := transfer.NewIBCModule(chain.GetSimApp().TransferKeeper) + newRouter.AddRoute(transfertypes.ModuleName, transferStack) + + // Remove Fee middleware from icahost submodule + chain.GetSimApp().ICAHostKeeper.WithICS4Wrapper(channelKeeper) + icaHostStack := icahost.NewIBCModule(chain.GetSimApp().ICAHostKeeper) + newRouter.AddRoute(icahosttypes.SubModuleName, icaHostStack) + + // Remove Fee middleware from icacontroller submodule + chain.GetSimApp().ICAControllerKeeper.WithICS4Wrapper(channelKeeper) + icaControllerStack := icacontroller.NewIBCMiddleware(nil, chain.GetSimApp().ICAControllerKeeper) + newRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) + + // Override and seal the router + chain.GetSimApp().IBCKeeper.SetRouter(newRouter) +} + // helper function func lockFeeModule(chain *ibctesting.TestChain) { ctx := chain.GetContext() diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index fa97ae7423f..16b1af474e6 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -19,6 +19,7 @@ import ( var ( _ porttypes.Middleware = (*IBCMiddleware)(nil) _ porttypes.PacketDataUnmarshaler = (*IBCMiddleware)(nil) + _ porttypes.UpgradableModule = (*IBCMiddleware)(nil) ) // IBCMiddleware implements the ICS26 callbacks for the fee middleware given the @@ -138,12 +139,13 @@ func (im IBCMiddleware) OnChanOpenAck( counterpartyChannelID string, counterpartyVersion string, ) error { - // If handshake was initialized with fee enabled it must complete with fee enabled. - // If handshake was initialized with fee disabled it must complete with fee disabled. if im.keeper.IsFeeEnabled(ctx, portID, channelID) { versionMetadata, err := types.MetadataFromVersion(counterpartyVersion) if err != nil { - return errorsmod.Wrapf(err, "failed to unmarshal ICS29 counterparty version metadata: %s", counterpartyVersion) + // we pass the entire version string onto the underlying application. + // and disable fees for this channel + im.keeper.DeleteFeeEnabled(ctx, portID, channelID) + return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) } if versionMetadata.FeeVersion != types.Version { @@ -326,6 +328,119 @@ func (im IBCMiddleware) OnTimeoutPacket( return im.app.OnTimeoutPacket(ctx, packet, relayer) } +// OnChanUpgradeInit implements the IBCModule interface +func (im IBCMiddleware) OnChanUpgradeInit( + ctx sdk.Context, + portID string, + channelID string, + proposedOrder channeltypes.Order, + proposedConnectionHops []string, + proposedVersion string, +) (string, error) { + cbs, ok := im.app.(porttypes.UpgradableModule) + if !ok { + return "", errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack") + } + + versionMetadata, err := types.MetadataFromVersion(proposedVersion) + if err != nil { + // since it is valid for fee version to not be specified, the upgrade version may be for a middleware + // or application further down in the stack. Thus, passthrough to next middleware or application in callstack. + return cbs.OnChanUpgradeInit(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion) + } + + if versionMetadata.FeeVersion != types.Version { + return "", errorsmod.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, versionMetadata.FeeVersion) + } + + appVersion, err := cbs.OnChanUpgradeInit(ctx, portID, channelID, proposedOrder, proposedConnectionHops, versionMetadata.AppVersion) + if err != nil { + return "", err + } + + versionMetadata.AppVersion = appVersion + versionBz, err := types.ModuleCdc.MarshalJSON(&versionMetadata) + if err != nil { + return "", err + } + + return string(versionBz), nil +} + +// OnChanUpgradeTry implement s the IBCModule interface +func (im IBCMiddleware) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, counterpartyVersion string) (string, error) { + cbs, ok := im.app.(porttypes.UpgradableModule) + if !ok { + return "", errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack") + } + + versionMetadata, err := types.MetadataFromVersion(counterpartyVersion) + if err != nil { + // since it is valid for fee version to not be specified, the counterparty upgrade version may be for a middleware + // or application further down in the stack. Thus, passthrough to next middleware or application in callstack. + return cbs.OnChanUpgradeTry(ctx, portID, channelID, proposedOrder, proposedConnectionHops, counterpartyVersion) + } + + if versionMetadata.FeeVersion != types.Version { + return "", errorsmod.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, versionMetadata.FeeVersion) + } + + appVersion, err := cbs.OnChanUpgradeTry(ctx, portID, channelID, proposedOrder, proposedConnectionHops, versionMetadata.AppVersion) + if err != nil { + return "", err + } + + versionMetadata.AppVersion = appVersion + versionBz, err := types.ModuleCdc.MarshalJSON(&versionMetadata) + if err != nil { + return "", err + } + + return string(versionBz), nil +} + +// OnChanUpgradeAck implements the IBCModule interface +func (im IBCMiddleware) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { + cbs, ok := im.app.(porttypes.UpgradableModule) + if !ok { + return errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack") + } + + versionMetadata, err := types.MetadataFromVersion(counterpartyVersion) + if err != nil { + // since it is valid for fee version to not be specified, the counterparty upgrade version may be for a middleware + // or application further down in the stack. Thus, passthrough to next middleware or application in callstack. + return cbs.OnChanUpgradeAck(ctx, portID, channelID, counterpartyVersion) + } + + if versionMetadata.FeeVersion != types.Version { + return errorsmod.Wrapf(types.ErrInvalidVersion, "expected counterparty fee version: %s, got: %s", types.Version, versionMetadata.FeeVersion) + } + + // call underlying app's OnChanUpgradeAck callback with the counterparty app version. + return cbs.OnChanUpgradeAck(ctx, portID, channelID, versionMetadata.AppVersion) +} + +// OnChanUpgradeOpen implements the IBCModule interface +func (im IBCMiddleware) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) { + cbs, ok := im.app.(porttypes.UpgradableModule) + if !ok { + panic(errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack")) + } + + versionMetadata, err := types.MetadataFromVersion(proposedVersion) + if err != nil { + // set fee disabled and passthrough to the next middleware or application in callstack. + im.keeper.DeleteFeeEnabled(ctx, portID, channelID) + cbs.OnChanUpgradeOpen(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion) + return + } + + // set fee enabled and passthrough to the next middleware of application in callstack. + im.keeper.SetFeeEnabled(ctx, portID, channelID) + cbs.OnChanUpgradeOpen(ctx, portID, channelID, proposedOrder, proposedConnectionHops, versionMetadata.AppVersion) +} + // SendPacket implements the ICS4 Wrapper interface func (im IBCMiddleware) SendPacket( ctx sdk.Context, diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 941bce02dd4..1515b1e3327 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -25,7 +25,6 @@ var ( defaultRecvFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdkmath.NewInt(100)}} defaultAckFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdkmath.NewInt(200)}} defaultTimeoutFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdkmath.NewInt(300)}} - smallAmount = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdkmath.NewInt(50)}} ) // Tests OnChanOpenInit on ChainA @@ -256,7 +255,7 @@ func (suite *FeeTestSuite) TestOnChanOpenAck() { }, { "invalid version fails to unmarshal metadata", - "invalid-version", + ibctesting.InvalidID, func(suite *FeeTestSuite) {}, false, }, @@ -605,6 +604,8 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { packetFee types.PacketFee refundAddr sdk.AccAddress relayerAddr sdk.AccAddress + escrowAmount sdk.Coins + initialRefundAccBal sdk.Coins expRefundAccBalance sdk.Coins expPayeeAccBalance sdk.Coins ) @@ -621,10 +622,31 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { // retrieve the relayer acc balance and add the expected recv and ack fees relayerAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, sdk.DefaultBondDenom)) expPayeeAccBalance = relayerAccBalance.Add(packetFee.Fee.RecvFee...).Add(packetFee.Fee.AckFee...) + }, + true, + func() { + // assert that the packet fees have been distributed + found := suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().False(found) - // retrieve the refund acc balance and add the expected timeout fees - refundAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom)) - expRefundAccBalance = refundAccBalance.Add(packetFee.Fee.TimeoutFee...) + relayerAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, sdk.DefaultBondDenom) + suite.Require().Equal(expPayeeAccBalance, sdk.NewCoins(relayerAccBalance)) + + refundAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom) + suite.Require().Equal(initialRefundAccBal, sdk.NewCoins(refundAccBalance)) + }, + }, + { + "success: some refunds", + func() { + // set timeout_fee > recv_fee + ack_fee + packetFee.Fee.TimeoutFee = packetFee.Fee.Total().Add(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)))...) + + escrowAmount = packetFee.Fee.Total() + + // retrieve the relayer acc balance and add the expected recv and ack fees + relayerAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, sdk.DefaultBondDenom)) + expPayeeAccBalance = relayerAccBalance.Add(packetFee.Fee.RecvFee...).Add(packetFee.Fee.AckFee...) }, true, func() { @@ -635,6 +657,9 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { relayerAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, sdk.DefaultBondDenom) suite.Require().Equal(expPayeeAccBalance, sdk.NewCoins(relayerAccBalance)) + // expect the correct refunds + refundCoins := packetFee.Fee.Total().Sub(packetFee.Fee.RecvFee...).Sub(packetFee.Fee.AckFee...) + expRefundAccBalance = initialRefundAccBal.Add(refundCoins...) refundAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom) suite.Require().Equal(expRefundAccBalance, sdk.NewCoins(refundAccBalance)) }, @@ -656,10 +681,6 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { // retrieve the payee acc balance and add the expected recv and ack fees payeeAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), payeeAddr, sdk.DefaultBondDenom)) expPayeeAccBalance = payeeAccBalance.Add(packetFee.Fee.RecvFee...).Add(packetFee.Fee.AckFee...) - - // retrieve the refund acc balance and add the expected timeout fees - refundAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom)) - expRefundAccBalance = refundAccBalance.Add(packetFee.Fee.TimeoutFee...) }, true, func() { @@ -671,8 +692,9 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { payeeAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), payeeAddr, sdk.DefaultBondDenom) suite.Require().Equal(expPayeeAccBalance, sdk.NewCoins(payeeAccBalance)) + // expect zero refunds refundAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom) - suite.Require().Equal(expRefundAccBalance, sdk.NewCoins(refundAccBalance)) + suite.Require().Equal(initialRefundAccBal, sdk.NewCoins(refundAccBalance)) }, }, { @@ -721,10 +743,6 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { // retrieve the relayer acc balance and add the expected ack fees relayerAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, sdk.DefaultBondDenom)) expPayeeAccBalance = relayerAccBalance.Add(packetFee.Fee.AckFee...) - - // retrieve the refund acc balance and add the expected recv fees and timeout fees - refundAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom)) - expRefundAccBalance = refundAccBalance.Add(packetFee.Fee.RecvFee...).Add(packetFee.Fee.TimeoutFee...) }, true, func() { @@ -735,6 +753,8 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { relayerAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, sdk.DefaultBondDenom) suite.Require().Equal(expPayeeAccBalance, sdk.NewCoins(relayerAccBalance)) + // expect only recv fee to be refunded + expRefundAccBalance = initialRefundAccBal.Add(packetFee.Fee.RecvFee...) refundAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom) suite.Require().Equal(expRefundAccBalance, sdk.NewCoins(refundAccBalance)) }, @@ -742,8 +762,7 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { { "fail: fee distribution fails and fee module is locked when escrow account does not have sufficient funds", func() { - err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainA.GetContext(), types.ModuleName, suite.chainA.SenderAccount.GetAddress(), smallAmount) - suite.Require().NoError(err) + escrowAmount = sdk.NewCoins() }, true, func() { @@ -796,15 +815,18 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { packet := suite.CreateMockPacket() packetID = channeltypes.NewPacketID(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) packetFee = types.NewPacketFee(types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee), refundAddr.String(), nil) + escrowAmount = packetFee.Fee.Total() + + ack = types.NewIncentivizedAcknowledgement(relayerAddr.String(), ibcmock.MockAcknowledgement.Acknowledgement(), true).Acknowledgement() + + tc.malleate() // malleate mutates test data suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees([]types.PacketFee{packetFee})) - err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAddr, types.ModuleName, packetFee.Fee.Total()) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAddr, types.ModuleName, escrowAmount) suite.Require().NoError(err) - ack = types.NewIncentivizedAcknowledgement(relayerAddr.String(), ibcmock.MockAcknowledgement.Acknowledgement(), true).Acknowledgement() - - tc.malleate() // malleate mutates test data + initialRefundAccBal = sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom)) // retrieve module callbacks module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) @@ -828,12 +850,14 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { func (suite *FeeTestSuite) TestOnTimeoutPacket() { var ( - packetID channeltypes.PacketId - packetFee types.PacketFee - refundAddr sdk.AccAddress - relayerAddr sdk.AccAddress - expRefundAccBalance sdk.Coins - expPayeeAccBalance sdk.Coins + packetID channeltypes.PacketId + packetFee types.PacketFee + refundAddr sdk.AccAddress + relayerAddr sdk.AccAddress + escrowAmount sdk.Coins + initialRelayerAccBal sdk.Coins + expRefundAccBalance sdk.Coins + expPayeeAccBalance sdk.Coins ) testCases := []struct { @@ -843,15 +867,38 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { expResult func() }{ { - "success", + "success: no refund", func() { - // retrieve the relayer acc balance and add the expected timeout fees - relayerAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, sdk.DefaultBondDenom)) - expPayeeAccBalance = relayerAccBalance.Add(packetFee.Fee.TimeoutFee...) + // expect zero refunds + refundAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom)) + expRefundAccBalance = refundAccBalance + }, + true, + func() { + // assert that the packet fees have been distributed + found := suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().False(found) + + expPayeeAccBalance = initialRelayerAccBal.Add(packetFee.Fee.TimeoutFee...) + relayerAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, sdk.DefaultBondDenom) + suite.Require().Equal(expPayeeAccBalance, sdk.NewCoins(relayerAccBalance)) + + refundAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom) + suite.Require().Equal(expRefundAccBalance, sdk.NewCoins(refundAccBalance)) + }, + }, + { + "success: refund (recv_fee + ack_fee) - timeout_fee", + func() { + // set recv_fee + ack_fee > timeout_fee + packetFee.Fee.RecvFee = packetFee.Fee.Total().Add(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)))...) + + escrowAmount = packetFee.Fee.Total() // retrieve the refund acc balance and add the expected recv and ack fees + refundCoins := packetFee.Fee.Total().Sub(packetFee.Fee.TimeoutFee...) refundAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom)) - expRefundAccBalance = refundAccBalance.Add(packetFee.Fee.RecvFee...).Add(packetFee.Fee.AckFee...) + expRefundAccBalance = refundAccBalance.Add(refundCoins...) }, true, func() { @@ -859,6 +906,7 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { found := suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID) suite.Require().False(found) + expPayeeAccBalance = initialRelayerAccBal.Add(packetFee.Fee.TimeoutFee...) relayerAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, sdk.DefaultBondDenom) suite.Require().Equal(expPayeeAccBalance, sdk.NewCoins(relayerAccBalance)) @@ -881,9 +929,9 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { payeeAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), payeeAddr, sdk.DefaultBondDenom)) expPayeeAccBalance = payeeAccBalance.Add(packetFee.Fee.TimeoutFee...) - // retrieve the refund acc balance and add the expected recv and ack fees + // expect zero refunds refundAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom)) - expRefundAccBalance = refundAccBalance.Add(packetFee.Fee.RecvFee...).Add(packetFee.Fee.AckFee...) + expRefundAccBalance = refundAccBalance }, true, func() { @@ -936,8 +984,7 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { { "fee distribution fails and fee module is locked when escrow account does not have sufficient funds", func() { - err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainA.GetContext(), types.ModuleName, suite.chainA.SenderAccount.GetAddress(), smallAmount) - suite.Require().NoError(err) + escrowAmount = sdk.NewCoins() }, true, func() { @@ -982,12 +1029,15 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { packet := suite.CreateMockPacket() packetID = channeltypes.NewPacketID(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) packetFee = types.NewPacketFee(types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee), refundAddr.String(), nil) + escrowAmount = packetFee.Fee.Total() + + tc.malleate() // malleate mutates test data suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees([]types.PacketFee{packetFee})) - err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), types.ModuleName, packetFee.Fee.Total()) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), types.ModuleName, escrowAmount) suite.Require().NoError(err) - tc.malleate() // malleate mutates test data + initialRelayerAccBal = sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, sdk.DefaultBondDenom)) // retrieve module callbacks module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) @@ -1009,6 +1059,441 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { } } +func (suite *FeeTestSuite) TestOnChanUpgradeInit() { + var path *ibctesting.Path + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + "success with downgraded version", + func() { + // create a new path using a fee enabled channel and downgrade it to disable fees + path = ibctesting.NewPath(suite.chainA, suite.chainB) + + mockFeeVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})) + path.EndpointA.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointB.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointA.ChannelConfig.Version = mockFeeVersion + path.EndpointB.ChannelConfig.Version = mockFeeVersion + + upgradeVersion := ibcmock.Version + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion + + suite.coordinator.Setup(path) + }, + nil, + }, + { + "invalid upgrade version", + func() { + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = ibctesting.InvalidID + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = ibctesting.InvalidID + + suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanUpgradeInit = func(_ sdk.Context, _, _ string, _ channeltypes.Order, _ []string, _ string) (string, error) { + // intentionally force the error here so we can assert that a passthrough occurs when fees should not be enabled for this channel + return "", ibcmock.MockApplicationCallbackError + } + }, + ibcmock.MockApplicationCallbackError, + }, + { + "invalid fee version", + func() { + upgradeVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: ibctesting.InvalidID, AppVersion: ibcmock.Version})) + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion + }, + types.ErrInvalidVersion, + }, + { + "underlying app callback returns error", + func() { + suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanUpgradeInit = func(_ sdk.Context, _, _ string, _ channeltypes.Order, _ []string, _ string) (string, error) { + return "", ibcmock.MockApplicationCallbackError + } + }, + ibcmock.MockApplicationCallbackError, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + + // configure the initial path to create an unincentivized mock channel + path.EndpointA.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointB.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointA.ChannelConfig.Version = ibcmock.Version + path.EndpointB.ChannelConfig.Version = ibcmock.Version + + suite.coordinator.Setup(path) + + // configure the channel upgrade version to enabled ics29 fee middleware + upgradeVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})) + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion + + tc.malleate() + + err := path.EndpointA.ChanUpgradeInit() + + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + suite.Require().Contains(err.Error(), tc.expError.Error()) + } + }) + } +} + +func (suite *FeeTestSuite) TestOnChanUpgradeTry() { + var path *ibctesting.Path + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + "success disable fees", + func() { + // create a new path using a fee enabled channel and downgrade it to disable fees + path = ibctesting.NewPath(suite.chainA, suite.chainB) + + mockFeeVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})) + path.EndpointA.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointB.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointA.ChannelConfig.Version = mockFeeVersion + path.EndpointB.ChannelConfig.Version = mockFeeVersion + + upgradeVersion := ibcmock.Version + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion + + suite.coordinator.Setup(path) + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + }, + nil, + }, + { + "invalid upgrade version", + func() { + counterpartyUpgrade := path.EndpointA.GetChannelUpgrade() + counterpartyUpgrade.Fields.Version = ibctesting.InvalidID + path.EndpointA.SetChannelUpgrade(counterpartyUpgrade) + + suite.coordinator.CommitBlock(suite.chainA) + + // intentionally force the error here so we can assert that a passthrough occurs when fees should not be enabled for this channel + suite.chainB.GetSimApp().FeeMockModule.IBCApp.OnChanUpgradeTry = func(_ sdk.Context, _, _ string, _ channeltypes.Order, _ []string, _ string) (string, error) { + return "", ibcmock.MockApplicationCallbackError + } + }, + ibcmock.MockApplicationCallbackError, + }, + { + "invalid fee version", + func() { + upgradeVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: ibctesting.InvalidID, AppVersion: ibcmock.Version})) + + counterpartyUpgrade := path.EndpointA.GetChannelUpgrade() + counterpartyUpgrade.Fields.Version = upgradeVersion + path.EndpointA.SetChannelUpgrade(counterpartyUpgrade) + + suite.coordinator.CommitBlock(suite.chainA) + }, + types.ErrInvalidVersion, + }, + { + "underlying app callback returns error", + func() { + suite.chainB.GetSimApp().FeeMockModule.IBCApp.OnChanUpgradeTry = func(_ sdk.Context, _, _ string, _ channeltypes.Order, _ []string, _ string) (string, error) { + return "", ibcmock.MockApplicationCallbackError + } + }, + ibcmock.MockApplicationCallbackError, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + + // configure the initial path to create an unincentivized mock channel + path.EndpointA.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointB.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointA.ChannelConfig.Version = ibcmock.Version + path.EndpointB.ChannelConfig.Version = ibcmock.Version + + suite.coordinator.Setup(path) + + // configure the channel upgrade version to enabled ics29 fee middleware + upgradeVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})) + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + tc.malleate() + + err = path.EndpointB.ChanUpgradeTry() + + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + suite.Require().Contains(err.Error(), tc.expError.Error()) + } + }) + } +} + +func (suite *FeeTestSuite) TestOnChanUpgradeAck() { + var path *ibctesting.Path + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + "success with fee middleware disabled", + func() { + suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeeEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + }, + nil, + }, + { + "invalid upgrade version", + func() { + counterpartyUpgrade := path.EndpointB.GetChannelUpgrade() + counterpartyUpgrade.Fields.Version = ibctesting.InvalidID + path.EndpointB.SetChannelUpgrade(counterpartyUpgrade) + + suite.coordinator.CommitBlock(suite.chainB) + + suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanUpgradeAck = func(_ sdk.Context, _, _, _ string) error { + return types.ErrInvalidVersion + } + }, + types.ErrInvalidVersion, + }, + { + "invalid fee version", + func() { + upgradeVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: ibctesting.InvalidID, AppVersion: ibcmock.Version})) + + counterpartyUpgrade := path.EndpointB.GetChannelUpgrade() + counterpartyUpgrade.Fields.Version = upgradeVersion + path.EndpointB.SetChannelUpgrade(counterpartyUpgrade) + + suite.coordinator.CommitBlock(suite.chainB) + }, + types.ErrInvalidVersion, + }, + { + "underlying app callback returns error", + func() { + suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanUpgradeAck = func(_ sdk.Context, _, _, _ string) error { + return ibcmock.MockApplicationCallbackError + } + }, + ibcmock.MockApplicationCallbackError, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + + // configure the initial path to create an unincentivized mock channel + path.EndpointA.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointB.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointA.ChannelConfig.Version = ibcmock.Version + path.EndpointB.ChannelConfig.Version = ibcmock.Version + + suite.coordinator.Setup(path) + + // configure the channel upgrade version to enabled ics29 fee middleware + upgradeVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})) + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + tc.malleate() + + counterpartyUpgrade := path.EndpointB.GetChannelUpgrade() + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) + suite.Require().NoError(err) + + app, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) + + err = cbs.OnChanUpgradeAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, counterpartyUpgrade.Fields.Version) + + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + suite.Require().ErrorIs(err, tc.expError) + } + }) + } +} + +func (suite *FeeTestSuite) TestOnChanUpgradeOpen() { + var path *ibctesting.Path + + testCases := []struct { + name string + malleate func() + expFeeEnabled bool + }{ + { + "success: enable fees", + func() { + // Assert in callback that correct upgrade information is passed + suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanUpgradeOpen = func(_ sdk.Context, portID, channelID string, order channeltypes.Order, connectionHops []string, version string) { + suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, portID) + suite.Require().Equal(path.EndpointA.ChannelID, channelID) + suite.Require().Equal(channeltypes.UNORDERED, order) + suite.Require().Equal([]string{path.EndpointA.ConnectionID}, connectionHops) + suite.Require().Equal(ibcmock.Version, version) + } + }, + true, + }, + { + "success: disable fees", + func() { + // create a new path using a fee enabled channel and downgrade it to disable fees + path = ibctesting.NewPath(suite.chainA, suite.chainB) + + mockFeeVersion := &types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version} + mockFeeVersionBz := string(types.ModuleCdc.MustMarshalJSON(mockFeeVersion)) + path.EndpointA.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointB.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointA.ChannelConfig.Version = mockFeeVersionBz + path.EndpointB.ChannelConfig.Version = mockFeeVersionBz + + upgradeVersion := ibcmock.Version + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion + + suite.coordinator.Setup(path) + + // Assert in callback that correct version is passed + suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanUpgradeOpen = func(_ sdk.Context, portID, channelID string, order channeltypes.Order, connectionHops []string, version string) { + suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, portID) + suite.Require().Equal(path.EndpointA.ChannelID, channelID) + suite.Require().Equal(channeltypes.UNORDERED, order) + suite.Require().Equal([]string{path.EndpointA.ConnectionID}, connectionHops) + suite.Require().Equal(mockFeeVersion.AppVersion, version) + } + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + + // configure the initial path to create an unincentivized mock channel + path.EndpointA.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointB.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointA.ChannelConfig.Version = ibcmock.Version + path.EndpointB.ChannelConfig.Version = ibcmock.Version + + suite.coordinator.Setup(path) + + // configure the channel upgrade version to enabled ics29 fee middleware + upgradeVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})) + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion + + tc.malleate() + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeAck() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeConfirm() + suite.Require().NoError(err) + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) + suite.Require().NoError(err) + + app, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) + + upgrade := path.EndpointA.GetChannelUpgrade() + cbs.OnChanUpgradeOpen(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, upgrade.Fields.Ordering, upgrade.Fields.ConnectionHops, upgrade.Fields.Version) + + isFeeEnabled := suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + if tc.expFeeEnabled { + suite.Require().True(isFeeEnabled) + } else { + suite.Require().False(isFeeEnabled) + } + }) + } +} + func (suite *FeeTestSuite) TestGetAppVersion() { var ( portID string diff --git a/modules/apps/29-fee/ica_test.go b/modules/apps/29-fee/ica_test.go index 530ffa2f631..b879ba2be16 100644 --- a/modules/apps/29-fee/ica_test.go +++ b/modules/apps/29-fee/ica_test.go @@ -75,7 +75,7 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, endpoint.ChannelConfig.Version); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccountWithOrdering(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, endpoint.ChannelConfig.Version, channeltypes.ORDERED); err != nil { return err } @@ -181,6 +181,31 @@ func (suite *FeeTestSuite) TestFeeInterchainAccounts() { suite.Require().Equal(preEscrowBalance.SubAmount(defaultRecvFee.AmountOf(sdk.DefaultBondDenom)), postDistBalance) } +func (suite *FeeTestSuite) TestOnesidedFeeMiddlewareICAHandshake() { + RemoveFeeMiddleware(suite.chainB) // remove fee middleware from chainB + + path := NewIncentivizedICAPath(suite.chainA, suite.chainB) + + suite.coordinator.SetupConnections(path) + + err := SetupPath(path, defaultOwnerAddress) + suite.Require().NoError(err) + + // assert the newly established channel is not fee enabled on chainB + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + expVersionMetadata, err := icatypes.MetadataFromVersion(defaultICAVersion) + suite.Require().NoError(err) + + expVersionMetadata.Address = interchainAccountAddr + + expVersion := string(icatypes.ModuleCdc.MustMarshalJSON(&expVersionMetadata)) + + suite.Require().Equal(path.EndpointA.ChannelConfig.Version, expVersion) + suite.Require().Equal(path.EndpointB.ChannelConfig.Version, expVersion) +} + func buildInterchainAccountsPacket(path *ibctesting.Path, data []byte, seq uint64) channeltypes.Packet { packet := channeltypes.NewPacket( data, diff --git a/modules/apps/29-fee/keeper/escrow.go b/modules/apps/29-fee/keeper/escrow.go index e21dc85fb99..a6e8d5eb13b 100644 --- a/modules/apps/29-fee/keeper/escrow.go +++ b/modules/apps/29-fee/keeper/escrow.go @@ -97,8 +97,9 @@ func (k Keeper) distributePacketFeeOnAcknowledgement(ctx sdk.Context, refundAddr // distribute fee for reverse relaying k.distributeFee(ctx, reverseRelayer, refundAddr, packetFee.Fee.AckFee) - // refund timeout fee for unused timeout - k.distributeFee(ctx, refundAddr, refundAddr, packetFee.Fee.TimeoutFee) + // refund unused amount from the escrowed fee + refundCoins := packetFee.Fee.Total().Sub(packetFee.Fee.RecvFee...).Sub(packetFee.Fee.AckFee...) + k.distributeFee(ctx, refundAddr, refundAddr, refundCoins) } // DistributePacketsFeesOnTimeout pays all the timeout fees for a given packetID while refunding the acknowledgement & receive fees to the refund account. @@ -137,14 +138,12 @@ func (k Keeper) DistributePacketFeesOnTimeout(ctx sdk.Context, timeoutRelayer sd // distributePacketFeeOnTimeout pays the timeout fee to the timeout relayer and refunds the acknowledgement & receive fee. func (k Keeper) distributePacketFeeOnTimeout(ctx sdk.Context, refundAddr, timeoutRelayer sdk.AccAddress, packetFee types.PacketFee) { - // refund receive fee for unused forward relaying - k.distributeFee(ctx, refundAddr, refundAddr, packetFee.Fee.RecvFee) - - // refund ack fee for unused reverse relaying - k.distributeFee(ctx, refundAddr, refundAddr, packetFee.Fee.AckFee) - // distribute fee for timeout relaying k.distributeFee(ctx, timeoutRelayer, refundAddr, packetFee.Fee.TimeoutFee) + + // refund unused amount from the escrowed fee + refundCoins := packetFee.Fee.Total().Sub(packetFee.Fee.TimeoutFee...) + k.distributeFee(ctx, refundAddr, refundAddr, refundCoins) } // distributeFee will attempt to distribute the escrowed fee to the receiver address. @@ -190,7 +189,7 @@ func (k Keeper) RefundFeesOnChannelClosure(ctx sdk.Context, portID, channelID st cacheCtx, writeFn := ctx.CacheContext() for _, identifiedPacketFee := range identifiedPacketFees { - var failedToSendCoins bool + var unRefundedFees []types.PacketFee for _, packetFee := range identifiedPacketFee.PacketFees { if !k.EscrowAccountHasBalance(cacheCtx, packetFee.Fee.Total()) { @@ -208,18 +207,22 @@ func (k Keeper) RefundFeesOnChannelClosure(ctx sdk.Context, portID, channelID st refundAddr, err := sdk.AccAddressFromBech32(packetFee.RefundAddress) if err != nil { - failedToSendCoins = true + unRefundedFees = append(unRefundedFees, packetFee) continue } // refund all fees to refund address if err = k.bankKeeper.SendCoinsFromModuleToAccount(cacheCtx, types.ModuleName, refundAddr, packetFee.Fee.Total()); err != nil { - failedToSendCoins = true + unRefundedFees = append(unRefundedFees, packetFee) continue } } - if !failedToSendCoins { + if len(unRefundedFees) > 0 { + // update packet fees to keep only the unrefunded fees + packetFees := types.NewPacketFees(unRefundedFees) + k.SetFeesInEscrow(cacheCtx, identifiedPacketFee.PacketId, packetFees) + } else { k.DeleteFeesInEscrow(cacheCtx, identifiedPacketFee.PacketId) } } diff --git a/modules/apps/29-fee/keeper/escrow_test.go b/modules/apps/29-fee/keeper/escrow_test.go index 928238163e0..206a7dfd2c7 100644 --- a/modules/apps/29-fee/keeper/escrow_test.go +++ b/modules/apps/29-fee/keeper/escrow_test.go @@ -55,8 +55,46 @@ func (suite *KeeperTestSuite) TestDistributeFee() { balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), forward, sdk.DefaultBondDenom) suite.Require().Equal(expectedForwardAccBal, balance) - // check if the refund acc has been refunded the timeoutFee - expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee[0].Add(defaultTimeoutFee[0])) + // check if the refund amount is zero + expectedRefundAccBal := refundAccBal + balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) + suite.Require().Equal(expectedRefundAccBal, balance) + + // check the module acc wallet is now empty + balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.DefaultBondDenom) + suite.Require().Equal(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(0)), balance) + }, + }, + { + "success: refund timeout_fee - (recv_fee + ack_fee)", + func() { + // set the timeout fee to be greater than recv + ack fee so that the refund amount is non-zero + fee.TimeoutFee = fee.Total().Add(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))) + + packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) + packetFees = []types.PacketFee{packetFee, packetFee} + }, + func() { + // check if fees has been deleted + packetID := channeltypes.NewPacketID(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) + suite.Require().False(suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID)) + + // check if the reverse relayer is paid + expectedReverseAccBal := reverseRelayerBal.Add(defaultAckFee[0]).Add(defaultAckFee[0]) + balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), reverseRelayer, sdk.DefaultBondDenom) + suite.Require().Equal(expectedReverseAccBal, balance) + + // check if the forward relayer is paid + forward, err := sdk.AccAddressFromBech32(forwardRelayer) + suite.Require().NoError(err) + + expectedForwardAccBal := forwardRelayerBal.Add(defaultRecvFee[0]).Add(defaultRecvFee[0]) + balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), forward, sdk.DefaultBondDenom) + suite.Require().Equal(expectedForwardAccBal, balance) + + // check if the refund amount is correct + refundCoins := fee.Total().Sub(defaultRecvFee[0]).Sub(defaultAckFee[0]).MulInt(sdkmath.NewInt(2)) + expectedRefundAccBal := refundAccBal.Add(refundCoins[0]) balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) suite.Require().Equal(expectedRefundAccBal, balance) @@ -68,6 +106,9 @@ func (suite *KeeperTestSuite) TestDistributeFee() { { "success: refund account is module account", func() { + // set the timeout fee to be greater than recv + ack fee so that the refund amount is non-zero + fee.TimeoutFee = fee.Total().Add(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))) + refundAcc = suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(mock.ModuleName) packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) @@ -78,8 +119,9 @@ func (suite *KeeperTestSuite) TestDistributeFee() { suite.Require().NoError(err) }, func() { - // check if the refund acc has been refunded the timeoutFee - expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee[0]).Add(defaultTimeoutFee[0]) + // check if the refund acc has been refunded the correct amount + refundCoins := fee.Total().Sub(defaultRecvFee[0]).Sub(defaultAckFee[0]).MulInt(sdkmath.NewInt(2)) + expectedRefundAccBal := refundAccBal.Add(refundCoins[0]) balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) suite.Require().Equal(expectedRefundAccBal, balance) }, @@ -113,8 +155,8 @@ func (suite *KeeperTestSuite) TestDistributeFee() { forwardRelayer = "invalid address" }, func() { - // check if the refund acc has been refunded the timeoutFee & recvFee - expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee[0]).Add(defaultRecvFee[0]).Add(defaultTimeoutFee[0]).Add(defaultRecvFee[0]) + // check if the refund acc has been refunded the recvFee + expectedRefundAccBal := refundAccBal.Add(defaultRecvFee[0]).Add(defaultRecvFee[0]) balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) suite.Require().Equal(expectedRefundAccBal, balance) }, @@ -129,7 +171,7 @@ func (suite *KeeperTestSuite) TestDistributeFee() { }, func() { // check if the refund acc has been refunded the timeoutFee & recvFee - expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee[0]).Add(defaultRecvFee[0]).Add(defaultTimeoutFee[0]).Add(defaultRecvFee[0]) + expectedRefundAccBal := refundAccBal.Add(defaultRecvFee[0]).Add(defaultRecvFee[0]) balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) suite.Require().Equal(expectedRefundAccBal, balance) }, @@ -143,15 +185,18 @@ func (suite *KeeperTestSuite) TestDistributeFee() { reverseRelayer = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress() }, func() { - // check if the refund acc has been refunded the timeoutFee & ackFee - expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee[0]).Add(defaultAckFee[0]).Add(defaultTimeoutFee[0]).Add(defaultAckFee[0]) + // check if the refund acc has been refunded the ackFee + expectedRefundAccBal := refundAccBal.Add(defaultAckFee[0]).Add(defaultAckFee[0]) balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) suite.Require().Equal(expectedRefundAccBal, balance) }, }, { - "invalid refund address: no-op, timeout fee remains in escrow", + "invalid refund address: no-op, timeout_fee - (recv_fee + ack_fee) remains in escrow", func() { + // set the timeout fee to be greater than recv + ack fee so that the refund amount is non-zero + fee.TimeoutFee = fee.Total().Add(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))) + packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) packetFees = []types.PacketFee{packetFee, packetFee} @@ -160,7 +205,8 @@ func (suite *KeeperTestSuite) TestDistributeFee() { }, func() { // check if the module acc contains the timeoutFee - expectedModuleAccBal := sdk.NewCoin(sdk.DefaultBondDenom, defaultTimeoutFee.Add(defaultTimeoutFee...).AmountOf(sdk.DefaultBondDenom)) + refundCoins := fee.Total().Sub(defaultRecvFee[0]).Sub(defaultAckFee[0]).MulInt(sdkmath.NewInt(2)) + expectedModuleAccBal := sdk.NewCoin(sdk.DefaultBondDenom, refundCoins.AmountOf(sdk.DefaultBondDenom)) balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.DefaultBondDenom) suite.Require().Equal(expectedModuleAccBal, balance) }, @@ -207,6 +253,7 @@ func (suite *KeeperTestSuite) TestDistributePacketFeesOnTimeout() { timeoutRelayerBal sdk.Coin refundAcc sdk.AccAddress refundAccBal sdk.Coin + fee types.Fee packetFee types.PacketFee packetFees []types.PacketFee ) @@ -217,7 +264,7 @@ func (suite *KeeperTestSuite) TestDistributePacketFeesOnTimeout() { expResult func() }{ { - "success", + "success: no refund", func() {}, func() { // check if the timeout relayer is paid @@ -225,8 +272,33 @@ func (suite *KeeperTestSuite) TestDistributePacketFeesOnTimeout() { balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), timeoutRelayer, sdk.DefaultBondDenom) suite.Require().Equal(expectedTimeoutAccBal, balance) - // check if the refund acc has been refunded the recv/ack fees - expectedRefundAccBal := refundAccBal.Add(defaultAckFee[0]).Add(defaultAckFee[0]).Add(defaultRecvFee[0]).Add(defaultRecvFee[0]) + // check if the refund amount is zero + expectedRefundAccBal := refundAccBal + balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) + suite.Require().Equal(expectedRefundAccBal, balance) + + // check the module acc wallet is now empty + balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.DefaultBondDenom) + suite.Require().Equal(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(0)), balance) + }, + }, + { + "success: refund (recv_fee + ack_fee) - timeout_fee", + func() { + // set the recv + ack fee to be greater than timeout fee so that the refund amount is non-zero + fee.RecvFee = fee.RecvFee.Add(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))) + packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) + packetFees = []types.PacketFee{packetFee, packetFee} + }, + func() { + // check if the timeout relayer is paid + expectedTimeoutAccBal := timeoutRelayerBal.Add(defaultTimeoutFee[0]).Add(defaultTimeoutFee[0]) + balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), timeoutRelayer, sdk.DefaultBondDenom) + suite.Require().Equal(expectedTimeoutAccBal, balance) + + // check if the refund amount is correct + refundCoins := fee.Total().Sub(defaultTimeoutFee[0]).MulInt(sdkmath.NewInt(2)) + expectedRefundAccBal := refundAccBal.Add(refundCoins[0]) balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) suite.Require().Equal(expectedRefundAccBal, balance) @@ -265,14 +337,21 @@ func (suite *KeeperTestSuite) TestDistributePacketFeesOnTimeout() { }, }, { - "invalid refund address: no-op, recv and ack fees remain in escrow", + "invalid refund address: no-op, (recv_fee + ack_fee) - timeout_fee remain in escrow", func() { + // set the recv + ack fee to be greater than timeout fee so that the refund amount is non-zero + fee.RecvFee = fee.RecvFee.Add(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))) + packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) + packetFees = []types.PacketFee{packetFee, packetFee} + packetFees[0].RefundAddress = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() packetFees[1].RefundAddress = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() }, func() { - // check if the module acc contains the timeoutFee - expectedModuleAccBal := sdk.NewCoin(sdk.DefaultBondDenom, defaultRecvFee.Add(defaultRecvFee[0]).Add(defaultAckFee[0]).Add(defaultAckFee[0]).AmountOf(sdk.DefaultBondDenom)) + // check if the module acc contains the correct amount of fees + refundCoins := fee.Total().Sub(defaultTimeoutFee[0]).MulInt(sdkmath.NewInt(2)) + + expectedModuleAccBal := refundCoins[0] balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.DefaultBondDenom) suite.Require().Equal(expectedModuleAccBal, balance) }, @@ -291,18 +370,18 @@ func (suite *KeeperTestSuite) TestDistributePacketFeesOnTimeout() { refundAcc = suite.chainA.SenderAccount.GetAddress() packetID := channeltypes.NewPacketID(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) - fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + fee = types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) // escrow the packet fees & store the fees in state packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) packetFees = []types.PacketFee{packetFee, packetFee} + tc.malleate() + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees(packetFees)) - err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, packetFee.Fee.Total().Add(packetFee.Fee.Total()...)) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total().Add(fee.Total()...)) suite.Require().NoError(err) - tc.malleate() - // fetch the account balances before fee distribution (forward, reverse, refund) timeoutRelayerBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), timeoutRelayer, sdk.DefaultBondDenom) refundAccBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) @@ -316,19 +395,17 @@ func (suite *KeeperTestSuite) TestDistributePacketFeesOnTimeout() { func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { var ( - expIdentifiedPacketFees []types.IdentifiedPacketFees - expEscrowBal sdk.Coins - expRefundBal sdk.Coins - refundAcc sdk.AccAddress - fee types.Fee - locked bool - expectEscrowFeesToBeDeleted bool + expIdentifiedPacketFees []types.IdentifiedPacketFees + expEscrowBal sdk.Coins + expRefundBal sdk.Coins + refundAcc sdk.AccAddress + fee types.Fee ) testCases := []struct { name string malleate func() - expPass bool + locked bool }{ { "success", func() { @@ -336,16 +413,13 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { // store the fee in state & update escrow account balance packetID := channeltypes.NewPacketID(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(i)) packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, refundAcc.String(), nil)}) - identifiedPacketFees := types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees) suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) suite.Require().NoError(err) - - expIdentifiedPacketFees = append(expIdentifiedPacketFees, identifiedPacketFees) } - }, true, + }, false, }, { "success with undistributed packet fees on a different channel", func() { @@ -353,14 +427,10 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { // store the fee in state & update escrow account balance packetID := channeltypes.NewPacketID(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(i)) packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, refundAcc.String(), nil)}) - identifiedPacketFees := types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees) - suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) suite.Require().NoError(err) - - expIdentifiedPacketFees = append(expIdentifiedPacketFees, identifiedPacketFees) } // set packet fee for a different channel @@ -374,12 +444,10 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { expEscrowBal = fee.Total() expRefundBal = expRefundBal.Sub(fee.Total()...) - }, true, + }, false, }, { "escrow account empty, module should become locked", func() { - locked = true - // store the fee in state without updating escrow account balance packetID := channeltypes.NewPacketID(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, refundAcc.String(), nil)}) @@ -388,13 +456,10 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) expIdentifiedPacketFees = []types.IdentifiedPacketFees{identifiedPacketFees} - }, - true, + }, true, }, { "escrow account goes negative on second packet, module should become locked", func() { - locked = true - // store 2 fees in state packetID1 := channeltypes.NewPacketID(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) packetID2 := channeltypes.NewPacketID(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(2)) @@ -415,42 +480,46 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { { "invalid refund acc address", func() { // store the fee in state & update escrow account balance - expectEscrowFeesToBeDeleted = false packetID := channeltypes.NewPacketID(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) - packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, "invalid refund address", nil)}) - identifiedPacketFees := types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees) - + packetFees := types.NewPacketFees([]types.PacketFee{ + types.NewPacketFee(fee, refundAcc.String(), nil), // this packet fee will be refunded, and will be deleted from state + types.NewPacketFee(fee, "invalid refund address", nil), + }) suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) - err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + // escrow twice the fee amount to account for the packet to have been incentivized twice + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total().MulInt(sdkmath.NewInt(2))) suite.Require().NoError(err) - expIdentifiedPacketFees = []types.IdentifiedPacketFees{identifiedPacketFees} + // only the first packet fee should be refunded, the second should remain in state + expIdentifiedPacketFees = []types.IdentifiedPacketFees{types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees[1:])} expEscrowBal = fee.Total() expRefundBal = expRefundBal.Sub(fee.Total()...) - }, true, + }, false, }, { "distributing to blocked address is skipped", func() { - expectEscrowFeesToBeDeleted = false blockedAddr := suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() // store the fee in state & update escrow account balance packetID := channeltypes.NewPacketID(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) - packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, blockedAddr, nil)}) - identifiedPacketFees := types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees) - + packetFees := types.NewPacketFees([]types.PacketFee{ + types.NewPacketFee(fee, refundAcc.String(), nil), // this packet fee will be refunded, and will be deleted from state + types.NewPacketFee(fee, blockedAddr, nil), + }) suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) - err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + // escrow twice the fee amount to account for the packet to have been incentivized twice + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total().MulInt(sdkmath.NewInt(2))) suite.Require().NoError(err) - expIdentifiedPacketFees = []types.IdentifiedPacketFees{identifiedPacketFees} + // only the first packet fee should be refunded, the second should remain in state + expIdentifiedPacketFees = []types.IdentifiedPacketFees{types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees[1:])} expEscrowBal = fee.Total() expRefundBal = expRefundBal.Sub(fee.Total()...) - }, true, + }, false, }, } @@ -460,10 +529,8 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { suite.Run(tc.name, func() { suite.SetupTest() // reset suite.coordinator.Setup(suite.path) // setup channel - expIdentifiedPacketFees = []types.IdentifiedPacketFees{} + expIdentifiedPacketFees = []types.IdentifiedPacketFees(nil) expEscrowBal = sdk.Coins{} - locked = false - expectEscrowFeesToBeDeleted = true // setup refundAcc = suite.chainA.SenderAccount.GetAddress() @@ -486,32 +553,22 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { originalEscrowBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), moduleAcc) err := suite.chainA.GetSimApp().IBCFeeKeeper.RefundFeesOnChannelClosure(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + suite.Require().NoError(err) // refundAcc balance after RefundFeesOnChannelClosure refundBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), refundAcc) escrowBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), moduleAcc) - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - - suite.Require().Equal(locked, suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(suite.chainA.GetContext())) + suite.Require().Equal(tc.locked, suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(suite.chainA.GetContext())) + suite.Require().Equal(expIdentifiedPacketFees, suite.chainA.GetSimApp().IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) - if locked || !tc.expPass { + if tc.locked { // refund account and escrow account balances should remain unchanged suite.Require().Equal(originalRefundBal, refundBal) suite.Require().Equal(originalEscrowBal, escrowBal) - - // ensure none of the fees were deleted - suite.Require().Equal(expIdentifiedPacketFees, suite.chainA.GetSimApp().IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) } else { suite.Require().Equal(expEscrowBal, escrowBal) // escrow balance should be empty suite.Require().Equal(expRefundBal, refundBal) // all packets should have been refunded - - // all fees in escrow should be deleted if expected for this channel - suite.Require().Equal(expectEscrowFeesToBeDeleted, len(suite.chainA.GetSimApp().IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) == 0) } }) } diff --git a/modules/apps/29-fee/keeper/events_test.go b/modules/apps/29-fee/keeper/events_test.go index a3b5a87e414..c33315c790b 100644 --- a/modules/apps/29-fee/keeper/events_test.go +++ b/modules/apps/29-fee/keeper/events_test.go @@ -161,7 +161,7 @@ func (suite *KeeperTestSuite) TestDistributeFeeEvent() { sdk.NewEvent( types.EventTypeDistributeFee, sdk.NewAttribute(types.AttributeKeyReceiver, suite.chainA.SenderAccount.GetAddress().String()), - sdk.NewAttribute(types.AttributeKeyFee, defaultTimeoutFee.String()), + sdk.NewAttribute(types.AttributeKeyFee, sdk.NewCoins().String()), ), }.ToABCIEvents() diff --git a/modules/apps/29-fee/keeper/export_test.go b/modules/apps/29-fee/keeper/export_test.go index 382dde7a805..e7fb25fb6c8 100644 --- a/modules/apps/29-fee/keeper/export_test.go +++ b/modules/apps/29-fee/keeper/export_test.go @@ -1,12 +1,18 @@ package keeper -/* - This file is to allow for unexported functions and fields to be accessible to the testing package. -*/ +import ( + sdk "github.com/cosmos/cosmos-sdk/types" -import porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" + "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" + porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" +) // GetICS4Wrapper is a getter for the keeper's ICS4Wrapper. func (k *Keeper) GetICS4Wrapper() porttypes.ICS4Wrapper { return k.ics4Wrapper } + +// LegacyTotal is a wrapper for the legacyTotal function for testing. +func LegacyTotal(f types.Fee) sdk.Coins { + return legacyTotal(f) +} diff --git a/modules/apps/29-fee/keeper/migrations.go b/modules/apps/29-fee/keeper/migrations.go new file mode 100644 index 00000000000..3eae34f7e1e --- /dev/null +++ b/modules/apps/29-fee/keeper/migrations.go @@ -0,0 +1,52 @@ +package keeper + +import ( + storetypes "cosmossdk.io/store/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" +) + +// Migrator is a struct for handling in-place store migrations. +type Migrator struct { + keeper Keeper +} + +// NewMigrator returns a new Migrator. +func NewMigrator(keeper Keeper) Migrator { + return Migrator{ + keeper: keeper, + } +} + +// Migrate1to2 migrates ibc-fee module from ConsensusVersion 1 to 2 +// by refunding leftover fees to the refund address. +func (m Migrator) Migrate1to2(ctx sdk.Context) error { + store := ctx.KVStore(m.keeper.storeKey) + iterator := storetypes.KVStorePrefixIterator(store, []byte(types.FeesInEscrowPrefix)) + defer sdk.LogDeferred(ctx.Logger(), func() error { return iterator.Close() }) + + for ; iterator.Valid(); iterator.Next() { + feesInEscrow := m.keeper.MustUnmarshalFees(iterator.Value()) + + for _, packetFee := range feesInEscrow.PacketFees { + refundCoins := legacyTotal(packetFee.Fee).Sub(packetFee.Fee.Total()...) + + refundAddr, err := sdk.AccAddressFromBech32(packetFee.RefundAddress) + if err != nil { + return err + } + + m.keeper.distributeFee(ctx, refundAddr, refundAddr, refundCoins) + } + } + + return nil +} + +// legacyTotal returns the legacy total amount for a given Fee +// The total amount is the RecvFee + AckFee + TimeoutFee +func legacyTotal(f types.Fee) sdk.Coins { + return f.RecvFee.Add(f.AckFee...).Add(f.TimeoutFee...) +} diff --git a/modules/apps/29-fee/keeper/migrations_test.go b/modules/apps/29-fee/keeper/migrations_test.go new file mode 100644 index 00000000000..ee7209c9cbc --- /dev/null +++ b/modules/apps/29-fee/keeper/migrations_test.go @@ -0,0 +1,201 @@ +package keeper_test + +import ( + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + + "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/keeper" + "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" +) + +func (suite *KeeperTestSuite) TestLegacyTotal() { + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + expLegacyTotal := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(600))) + + suite.Require().Equal(expLegacyTotal, keeper.LegacyTotal(fee)) +} + +func (suite *KeeperTestSuite) TestMigrate1to2() { + var ( + packetFee types.PacketFee + packetFees []types.PacketFee + packetID channeltypes.PacketId + packetID2 channeltypes.PacketId + moduleAcc sdk.AccAddress + refundAcc sdk.AccAddress + initRefundAccBal sdk.Coins + initModuleAccBal sdk.Coins + ) + + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + + testCases := []struct { + name string + malleate func() + assert func(error) + }{ + { + "success: no fees in escrow", + func() {}, + func(err error) { + suite.Require().NoError(err) + suite.Require().Empty(suite.chainA.GetSimApp().IBCFeeKeeper.GetAllIdentifiedPacketFees(suite.chainA.GetContext())) + + // refund account balance should not change + refundAccBal := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) + suite.Require().Equal(initRefundAccBal[0], refundAccBal) + + // module account balance should not change + moduleAccBal := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), moduleAcc, sdk.DefaultBondDenom) + suite.Require().True(moduleAccBal.IsZero()) + }, + }, + { + "success: one fee in escrow", + func() { + packetFees = []types.PacketFee{packetFee} + }, + func(err error) { + suite.Require().NoError(err) + + // ensure that the packet fees are unmodified + expPacketFees := []types.IdentifiedPacketFees{ + types.NewIdentifiedPacketFees(packetID, packetFees), + } + suite.Require().Equal(expPacketFees, suite.chainA.GetSimApp().IBCFeeKeeper.GetAllIdentifiedPacketFees(suite.chainA.GetContext())) + + unusedFee := keeper.LegacyTotal(fee).Sub(packetFee.Fee.Total()...)[0] + // refund account balance should increase + refundAccBal := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) + + suite.Require().Equal(initRefundAccBal.Add(unusedFee)[0], refundAccBal) + + // module account balance should decrease + moduleAccBal := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), moduleAcc, sdk.DefaultBondDenom) + suite.Require().Equal(initModuleAccBal.Sub(unusedFee)[0], moduleAccBal) + }, + }, + { + "success: many fees with multiple denoms in escrow", + func() { + // mint second denom tokens to the refund account + denom2 := "denom" + err := suite.chainA.GetSimApp().MintKeeper.MintCoins(suite.chainA.GetContext(), sdk.NewCoins(sdk.NewCoin(denom2, sdkmath.NewInt(1000)))) + suite.Require().NoError(err) + err = suite.chainA.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainA.GetContext(), minttypes.ModuleName, refundAcc, sdk.NewCoins(sdk.NewCoin(denom2, sdkmath.NewInt(1000)))) + suite.Require().NoError(err) + + // assemble second denom type packet + defaultFee2 := sdk.NewCoins(sdk.NewCoin(denom2, sdkmath.NewInt(100))) + fee2 := types.NewFee(defaultFee2, defaultFee2, defaultFee2) + packetFee2 := types.NewPacketFee(fee2, refundAcc.String(), []string(nil)) + + packetFees = []types.PacketFee{packetFee, packetFee2, packetFee} + }, + func(err error) { + denom2 := "denom" + + suite.Require().NoError(err) + + // ensure that the packet fees are unmodified + expPacketFees := []types.IdentifiedPacketFees{ + types.NewIdentifiedPacketFees(packetID, packetFees), + } + suite.Require().Equal(expPacketFees, suite.chainA.GetSimApp().IBCFeeKeeper.GetAllIdentifiedPacketFees(suite.chainA.GetContext())) + + unusedFee := sdk.NewCoins( + sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(600)), + sdk.NewCoin(denom2, sdkmath.NewInt(100)), + ) + // refund account balance should increase + refundAccBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), refundAcc) + suite.Require().Equal(initRefundAccBal.Add(unusedFee...), refundAccBal) + + // module account balance should decrease + moduleAccBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), moduleAcc) + suite.Require().Equal(initModuleAccBal.Sub(unusedFee...).Sort(), moduleAccBal) + }, + }, + { + "success: more than one packet", + func() { + packetFees = []types.PacketFee{packetFee} + + // add second packet to have escrowed fees + packetID2 = channeltypes.NewPacketID(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 2) + // escrow the packet fee for the second packet & store the fee in state + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID2, types.NewPacketFees(packetFees)) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, keeper.LegacyTotal(packetFee.Fee)) + suite.Require().NoError(err) + }, + func(err error) { + suite.Require().NoError(err) + + // ensure that the packet fees are unmodified + expPacketFees := []types.IdentifiedPacketFees{ + types.NewIdentifiedPacketFees(packetID, packetFees), + types.NewIdentifiedPacketFees(packetID2, packetFees), + } + suite.Require().Equal(expPacketFees, suite.chainA.GetSimApp().IBCFeeKeeper.GetAllIdentifiedPacketFees(suite.chainA.GetContext())) + + // 300 for each packet + unusedFee := keeper.LegacyTotal(fee).Sub(packetFee.Fee.Total()...).MulInt(sdkmath.NewInt(2))[0] + // refund account balance should increase + refundAccBal := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) + suite.Require().Equal(initRefundAccBal.Add(unusedFee)[0], refundAccBal) + + // module account balance should decrease + moduleAccBal := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), moduleAcc, sdk.DefaultBondDenom) + suite.Require().Equal(initModuleAccBal.Sub(unusedFee)[0], moduleAccBal) + }, + }, + { + "failure: invalid refund address", + func() { + packetFee = types.NewPacketFee(fee, "invalid", []string{}) + packetFees = []types.PacketFee{packetFee} + }, + func(err error) { + suite.Require().Error(err) + }, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.SetupTest() + suite.coordinator.Setup(suite.path) + + refundAcc = suite.chainA.SenderAccount.GetAddress() + packetFee = types.NewPacketFee(fee, refundAcc.String(), []string(nil)) + moduleAcc = suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(types.ModuleName) + packetID = channeltypes.NewPacketID(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) + packetFees = nil + + tc.malleate() + + feesToModule := sdk.NewCoins() + for _, packetFee := range packetFees { + feesToModule = feesToModule.Add(keeper.LegacyTotal(packetFee.Fee)...) + } + + if !feesToModule.IsZero() { + // escrow the packet fees & store the fees in state + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees(packetFees)) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, feesToModule) + suite.Require().NoError(err) + } + + initRefundAccBal = suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), refundAcc) + initModuleAccBal = suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), moduleAcc) + + migrator := keeper.NewMigrator(suite.chainA.GetSimApp().IBCFeeKeeper) + err := migrator.Migrate1to2(suite.chainA.GetContext()) + + tc.assert(err) + } +} diff --git a/modules/apps/29-fee/module.go b/modules/apps/29-fee/module.go index c627d82ec61..327522f5339 100644 --- a/modules/apps/29-fee/module.go +++ b/modules/apps/29-fee/module.go @@ -108,6 +108,11 @@ func NewAppModule(k keeper.Keeper) AppModule { func (am AppModule) RegisterServices(cfg module.Configurator) { types.RegisterMsgServer(cfg.MsgServer(), am.keeper) types.RegisterQueryServer(cfg.QueryServer(), am.keeper) + + m := keeper.NewMigrator(am.keeper) + if err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2); err != nil { + panic(fmt.Errorf("failed to migrate ibc-fee module from version 1 to 2 (refund leftover fees): %v", err)) + } } // InitGenesis performs genesis initialization for the ibc-29-fee module. It returns @@ -126,7 +131,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw } // ConsensusVersion implements AppModule/ConsensusVersion. -func (AppModule) ConsensusVersion() uint64 { return 1 } +func (AppModule) ConsensusVersion() uint64 { return 2 } // AppModuleSimulation functions diff --git a/modules/apps/29-fee/transfer_test.go b/modules/apps/29-fee/transfer_test.go index 287a5cad1b8..20cbe1edbbf 100644 --- a/modules/apps/29-fee/transfer_test.go +++ b/modules/apps/29-fee/transfer_test.go @@ -65,6 +65,117 @@ func (suite *FeeTestSuite) TestFeeTransfer() { ) suite.Require().Equal( - fee.AckFee.Add(fee.TimeoutFee...), // ack fee paid, timeout fee refunded + fee.AckFee, // ack fee paid, no refund needed since timeout_fee = recv_fee + ack_fee sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)).Sub(originalChainASenderAccountBalance[0])) } + +func (suite *FeeTestSuite) TestTransferFeeUpgrade() { + var path *ibctesting.Path + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + + // configure the initial path to create a regular transfer channel + path.EndpointA.ChannelConfig.PortID = transfertypes.PortID + path.EndpointB.ChannelConfig.PortID = transfertypes.PortID + path.EndpointA.ChannelConfig.Version = transfertypes.Version + path.EndpointB.ChannelConfig.Version = transfertypes.Version + + suite.coordinator.Setup(path) + + // configure the channel upgrade to upgrade to an incentivized fee enabled transfer channel + upgradeVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: transfertypes.Version})) + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion + + tc.malleate() + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeAck() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeConfirm() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeOpen() + suite.Require().NoError(err) + + expPass := tc.expError == nil + if expPass { + channelA := path.EndpointA.GetChannel() + suite.Require().Equal(upgradeVersion, channelA.Version) + + channelB := path.EndpointB.GetChannel() + suite.Require().Equal(upgradeVersion, channelB.Version) + + isFeeEnabled := suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(isFeeEnabled) + + isFeeEnabled = suite.chainB.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().True(isFeeEnabled) + + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + msgs := []sdk.Msg{ + types.NewMsgPayPacketFee(fee, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetAddress().String(), nil), + transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, ibctesting.TestCoin, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, ""), + } + + res, err := suite.chainA.SendMsgs(msgs...) + suite.Require().NoError(err) // message committed + + feeEscrowAddr := suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(types.ModuleName) + escrowBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), feeEscrowAddr, sdk.DefaultBondDenom) + suite.Require().Equal(escrowBalance.Amount, fee.Total().AmountOf(sdk.DefaultBondDenom)) + + packet, err := ibctesting.ParsePacketFromEvents(res.Events) + suite.Require().NoError(err) + + err = path.RelayPacket(packet) + suite.Require().NoError(err) // relay committed + + escrowBalance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), feeEscrowAddr, sdk.DefaultBondDenom) + suite.Require().True(escrowBalance.IsZero()) + } else { + suite.Require().Error(err) + suite.Require().ErrorIs(err, tc.expError) + } + }) + } +} + +func (suite *FeeTestSuite) TestOnesidedFeeMiddlewareTransferHandshake() { + RemoveFeeMiddleware(suite.chainB) // remove fee middleware from chainB + + path := ibctesting.NewPath(suite.chainA, suite.chainB) + feeTransferVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: transfertypes.Version})) + path.EndpointA.ChannelConfig.Version = feeTransferVersion // this will be renegotiated by the Try step + path.EndpointB.ChannelConfig.Version = "" // this will be overwritten by the Try step + path.EndpointA.ChannelConfig.PortID = transfertypes.PortID + path.EndpointB.ChannelConfig.PortID = transfertypes.PortID + + suite.coordinator.Setup(path) + + suite.Require().Equal(path.EndpointA.ChannelConfig.Version, transfertypes.Version) + suite.Require().Equal(path.EndpointB.ChannelConfig.Version, transfertypes.Version) +} diff --git a/modules/apps/29-fee/types/fee.go b/modules/apps/29-fee/types/fee.go index a34715db08e..6d8521bc1e7 100644 --- a/modules/apps/29-fee/types/fee.go +++ b/modules/apps/29-fee/types/fee.go @@ -59,9 +59,12 @@ func NewFee(recvFee, ackFee, timeoutFee sdk.Coins) Fee { } } -// Total returns the total amount for a given Fee +// Total returns the total amount for a given Fee. +// The total amount is the Max(RecvFee + AckFee, TimeoutFee), +// This is because either the packet is received and acknowledged or it timeouts func (f Fee) Total() sdk.Coins { - return f.RecvFee.Add(f.AckFee...).Add(f.TimeoutFee...) + // maximum returns the denomwise maximum of two sets of coins + return f.RecvFee.Add(f.AckFee...).Max(f.TimeoutFee) } // Validate asserts that each Fee is valid and all three Fees are not empty or zero diff --git a/modules/apps/29-fee/types/fee_test.go b/modules/apps/29-fee/types/fee_test.go index fe4e2b24d95..ab44e645d48 100644 --- a/modules/apps/29-fee/types/fee_test.go +++ b/modules/apps/29-fee/types/fee_test.go @@ -34,10 +34,95 @@ var ( const invalidAddress = "invalid-address" func TestFeeTotal(t *testing.T) { - fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + var fee types.Fee - total := fee.Total() - require.Equal(t, sdkmath.NewInt(600), total.AmountOf(sdk.DefaultBondDenom)) + testCases := []struct { + name string + malleate func() + expTotal sdk.Coins + }{ + { + "success", + func() {}, + sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(300))), + }, + { + "success: empty fees", + func() { + fee = types.NewFee(sdk.NewCoins(), sdk.NewCoins(), sdk.NewCoins()) + }, + sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(0))), + }, + { + "success: multiple denoms", + func() { + fee = types.NewFee( + sdk.NewCoins( + defaultRecvFee[0], + sdk.NewCoin("denom", sdkmath.NewInt(300)), + ), + sdk.NewCoins( + defaultAckFee[0], + sdk.NewCoin("denom", sdkmath.NewInt(200)), + ), + sdk.NewCoins( + defaultTimeoutFee[0], + sdk.NewCoin("denom", sdkmath.NewInt(100)), + ), + ) + }, + sdk.NewCoins( + sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(300)), + sdk.NewCoin("denom", sdkmath.NewInt(500)), + ), + }, + { + "success: many denoms", + func() { + fee = types.NewFee( + sdk.NewCoins( + defaultRecvFee[0], + sdk.NewCoin("denom", sdkmath.NewInt(200)), + sdk.NewCoin("denom4", sdkmath.NewInt(100)), + sdk.NewCoin("denom5", sdkmath.NewInt(300)), + ), + sdk.NewCoins( + defaultAckFee[0], + sdk.NewCoin("denom", sdkmath.NewInt(200)), + sdk.NewCoin("denom2", sdkmath.NewInt(100)), + sdk.NewCoin("denom3", sdkmath.NewInt(300)), + sdk.NewCoin("denom4", sdkmath.NewInt(100)), + ), + sdk.NewCoins( + defaultTimeoutFee[0], + sdk.NewCoin("denom", sdkmath.NewInt(100)), + sdk.NewCoin("denom2", sdkmath.NewInt(200)), + sdk.NewCoin("denom5", sdkmath.NewInt(300)), + ), + ) + }, + sdk.NewCoins( + sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(300)), + sdk.NewCoin("denom", sdkmath.NewInt(400)), + sdk.NewCoin("denom2", sdkmath.NewInt(200)), + sdk.NewCoin("denom3", sdkmath.NewInt(300)), + sdk.NewCoin("denom4", sdkmath.NewInt(200)), + sdk.NewCoin("denom5", sdkmath.NewInt(300)), + ), + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + fee = types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + + tc.malleate() // malleate mutates test data + + require.Equal(t, tc.expTotal, fee.Total()) + }) + } } func TestPacketFeeValidation(t *testing.T) { diff --git a/modules/apps/29-fee/types/msgs.go b/modules/apps/29-fee/types/msgs.go index af2a9287a65..4972e636cf7 100644 --- a/modules/apps/29-fee/types/msgs.go +++ b/modules/apps/29-fee/types/msgs.go @@ -46,10 +46,6 @@ func (msg MsgRegisterPayee) ValidateBasic() error { return err } - if msg.Relayer == msg.Payee { - return errorsmod.Wrap(ibcerrors.ErrInvalidRequest, "relayer address and payee must not be equal") - } - _, err := sdk.AccAddressFromBech32(msg.Relayer) if err != nil { return errorsmod.Wrap(err, "failed to create sdk.AccAddress from relayer address") diff --git a/modules/apps/29-fee/types/msgs_test.go b/modules/apps/29-fee/types/msgs_test.go index 6f1d2bce4eb..4ab67340246 100644 --- a/modules/apps/29-fee/types/msgs_test.go +++ b/modules/apps/29-fee/types/msgs_test.go @@ -28,24 +28,24 @@ func TestMsgRegisterPayeeValidation(t *testing.T) { true, }, { - "invalid portID", + "success: relayer and payee are equal", func() { - msg.PortId = "" + msg.Relayer = defaultAccAddress + msg.Payee = defaultAccAddress }, - false, + true, }, { - "invalid channelID", + "invalid portID", func() { - msg.ChannelId = "" + msg.PortId = "" }, false, }, { - "invalid request relayer and payee are equal", + "invalid channelID", func() { - msg.Relayer = defaultAccAddress - msg.Payee = defaultAccAddress + msg.ChannelId = "" }, false, }, diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 9796913cef6..40de608fc2d 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -24,6 +24,7 @@ import ( icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" ibctesting "github.com/cosmos/ibc-go/v8/testing" ibcmock "github.com/cosmos/ibc-go/v8/testing/mock" @@ -153,7 +154,7 @@ func (s *CallbacksTestSuite) SetupICATest() string { // RegisterInterchainAccount submits a MsgRegisterInterchainAccount and updates the controller endpoint with the // channel created. func (s *CallbacksTestSuite) RegisterInterchainAccount(owner string) { - msgRegister := icacontrollertypes.NewMsgRegisterInterchainAccount(s.path.EndpointA.ConnectionID, owner, s.path.EndpointA.ChannelConfig.Version) + msgRegister := icacontrollertypes.NewMsgRegisterInterchainAccountWithOrdering(s.path.EndpointA.ConnectionID, owner, s.path.EndpointA.ChannelConfig.Version, channeltypes.ORDERED) res, err := s.chainA.SendMsgs(msgRegister) s.Require().NotEmpty(res) @@ -264,8 +265,9 @@ func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallbackWithFee( sdk.NewCoins(GetSimApp(s.chainA).BankKeeper.GetBalance(s.chainA.GetContext(), s.chainB.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)), ) + refundCoins := fee.Total().Sub(fee.RecvFee...).Sub(fee.AckFee...) s.Require().Equal( - fee.AckFee.Add(fee.TimeoutFee...), // ack fee paid, timeout fee refunded + fee.AckFee.Add(refundCoins...), // ack fee paid, and refund processed sdk.NewCoins( GetSimApp(s.chainA).BankKeeper.GetBalance( s.chainA.GetContext(), s.chainA.SenderAccount.GetAddress(), diff --git a/modules/apps/callbacks/go.mod b/modules/apps/callbacks/go.mod index 11a3d2d4551..2c318b4a9e1 100644 --- a/modules/apps/callbacks/go.mod +++ b/modules/apps/callbacks/go.mod @@ -9,23 +9,23 @@ replace github.com/cosmos/ibc-go/v8 => ../../../ replace github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 require ( - cosmossdk.io/api v0.7.3 + cosmossdk.io/api v0.7.4 cosmossdk.io/client/v2 v2.0.0-beta.1 cosmossdk.io/core v0.11.0 cosmossdk.io/errors v1.0.1 cosmossdk.io/log v1.3.1 cosmossdk.io/math v1.3.0 - cosmossdk.io/store v1.0.2 + cosmossdk.io/store v1.1.0 cosmossdk.io/tools/confix v0.1.0 cosmossdk.io/x/circuit v0.1.0 cosmossdk.io/x/evidence v0.1.0 cosmossdk.io/x/feegrant v0.1.0 - cosmossdk.io/x/tx v0.13.1 + cosmossdk.io/x/tx v0.13.2 cosmossdk.io/x/upgrade v0.1.0 - github.com/cometbft/cometbft v0.38.5 + github.com/cometbft/cometbft v0.38.7 github.com/cosmos/cosmos-db v1.0.2 - github.com/cosmos/cosmos-sdk v0.50.5 - github.com/cosmos/gogoproto v1.4.11 + github.com/cosmos/cosmos-sdk v0.50.6 + github.com/cosmos/gogoproto v1.4.12 github.com/cosmos/ibc-go/modules/capability v1.0.0 github.com/cosmos/ibc-go/v8 v8.0.0 github.com/spf13/cast v1.6.0 @@ -34,6 +34,22 @@ require ( github.com/stretchr/testify v1.9.0 ) +require ( + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/klauspost/compress v1.17.7 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect + go.opentelemetry.io/otel v1.22.0 // indirect + go.opentelemetry.io/otel/metric v1.22.0 // indirect + go.opentelemetry.io/otel/trace v1.22.0 // indirect + go.uber.org/multierr v1.10.0 // indirect + golang.org/x/time v0.5.0 // indirect +) + require ( cloud.google.com/go v0.112.0 // indirect cloud.google.com/go/compute v1.24.0 // indirect @@ -55,7 +71,7 @@ require ( 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/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cockroachdb/apd/v2 v2.0.2 // indirect github.com/cockroachdb/errors v1.11.1 // indirect @@ -65,10 +81,10 @@ require ( github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/cometbft/cometbft-db v0.9.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect - github.com/cosmos/cosmos-proto v1.0.0-beta.4 // indirect + github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect - github.com/cosmos/iavl v1.0.1 // indirect + github.com/cosmos/iavl v1.1.2 // indirect github.com/cosmos/ics23/go v0.10.0 // indirect github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect github.com/creachadair/atomicfile v0.3.1 // indirect @@ -90,8 +106,6 @@ require ( 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/go-logr/logr v1.4.1 // indirect - github.com/go-logr/stdr v1.2.2 // 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 @@ -117,7 +131,7 @@ require ( github.com/hashicorp/go-getter v1.7.1 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-metrics v0.5.1 // indirect + github.com/hashicorp/go-metrics v0.5.3 // indirect github.com/hashicorp/go-plugin v1.5.2 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect github.com/hashicorp/go-version v1.6.0 // indirect @@ -131,12 +145,11 @@ require ( 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.17.7 // 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.8.12 // indirect + github.com/linxGnu/grocksdb v1.8.14 // 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 @@ -149,21 +162,18 @@ require ( github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect github.com/oklog/run v1.1.0 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect - github.com/petermattis/goid v0.0.0-20230904192822-1876fd5063bc // indirect + github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.18.0 // indirect - github.com/prometheus/client_model v0.6.0 // indirect - github.com/prometheus/common v0.47.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect + github.com/prometheus/client_golang v1.19.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.52.2 // indirect + github.com/prometheus/procfs v0.13.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/rs/cors v1.8.3 // indirect github.com/rs/zerolog v1.32.0 // indirect - github.com/sagikazarmark/locafero v0.4.0 // indirect - github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect - github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.6.0 // indirect @@ -175,27 +185,20 @@ require ( github.com/zondax/ledger-go v0.14.3 // indirect go.etcd.io/bbolt v1.3.8 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect - go.opentelemetry.io/otel v1.22.0 // indirect - go.opentelemetry.io/otel/metric v1.22.0 // indirect - go.opentelemetry.io/otel/trace v1.22.0 // indirect - go.uber.org/multierr v1.10.0 // indirect - golang.org/x/crypto v0.19.0 // indirect - golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect - golang.org/x/net v0.21.0 // indirect - golang.org/x/oauth2 v0.16.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.17.0 // indirect - golang.org/x/term v0.17.0 // indirect + golang.org/x/crypto v0.22.0 // indirect + golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.5.0 // indirect google.golang.org/api v0.162.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c // indirect - google.golang.org/grpc v1.62.0 // indirect + google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect + google.golang.org/grpc v1.63.2 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/modules/apps/callbacks/go.sum b/modules/apps/callbacks/go.sum index c36667be184..78a856773e8 100644 --- a/modules/apps/callbacks/go.sum +++ b/modules/apps/callbacks/go.sum @@ -184,8 +184,8 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cosmossdk.io/api v0.7.3 h1:V815i8YOwOAQa1rLCsSMjVG5Gnzs02JLq+l7ks8s1jk= -cosmossdk.io/api v0.7.3/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= +cosmossdk.io/api v0.7.4 h1:sPo8wKwCty1lht8kgL3J7YL1voJywP3YWuA5JKkBz30= +cosmossdk.io/api v0.7.4/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= cosmossdk.io/client/v2 v2.0.0-beta.1 h1:XkHh1lhrLYIT9zKl7cIOXUXg2hdhtjTPBUfqERNA1/Q= cosmossdk.io/client/v2 v2.0.0-beta.1/go.mod h1:JEUSu9moNZQ4kU3ir1DKD5eU4bllmAexrGWjmb9k8qU= cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s= @@ -200,8 +200,8 @@ cosmossdk.io/log v1.3.1 h1:UZx8nWIkfbbNEWusZqzAx3ZGvu54TZacWib3EzUYmGI= cosmossdk.io/log v1.3.1/go.mod h1:2/dIomt8mKdk6vl3OWJcPk2be3pGOS8OQaLUM/3/tCM= cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE= cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k= -cosmossdk.io/store v1.0.2 h1:lSg5BTvJBHUDwswNNyeh4K/CbqiHER73VU4nDNb8uk0= -cosmossdk.io/store v1.0.2/go.mod h1:EFtENTqVTuWwitGW1VwaBct+yDagk7oG/axBMPH+FXs= +cosmossdk.io/store v1.1.0 h1:LnKwgYMc9BInn9PhpTFEQVbL9UK475G2H911CGGnWHk= +cosmossdk.io/store v1.1.0/go.mod h1:oZfW/4Fc/zYqu3JmQcQdUJ3fqu5vnYTn3LZFFy8P8ng= cosmossdk.io/tools/confix v0.1.0 h1:2OOZTtQsDT5e7P3FM5xqM0bPfluAxZlAwxqaDmYBE+E= cosmossdk.io/tools/confix v0.1.0/go.mod h1:TdXKVYs4gEayav5wM+JHT+kTU2J7fozFNqoVaN+8CdY= cosmossdk.io/x/circuit v0.1.0 h1:IAej8aRYeuOMritczqTlljbUVHq1E85CpBqaCTwYgXs= @@ -210,8 +210,8 @@ cosmossdk.io/x/evidence v0.1.0 h1:J6OEyDl1rbykksdGynzPKG5R/zm6TacwW2fbLTW4nCk= cosmossdk.io/x/evidence v0.1.0/go.mod h1:hTaiiXsoiJ3InMz1uptgF0BnGqROllAN8mwisOMMsfw= cosmossdk.io/x/feegrant v0.1.0 h1:c7s3oAq/8/UO0EiN1H5BIjwVntujVTkYs35YPvvrdQk= cosmossdk.io/x/feegrant v0.1.0/go.mod h1:4r+FsViJRpcZif/yhTn+E0E6OFfg4n0Lx+6cCtnZElU= -cosmossdk.io/x/tx v0.13.1 h1:Mg+EMp67Pz+NukbJqYxuo8uRp7N/a9uR+oVS9pONtj8= -cosmossdk.io/x/tx v0.13.1/go.mod h1:CBCU6fsRVz23QGFIQBb1DNX2DztJCf3jWyEkHY2nJQ0= +cosmossdk.io/x/tx v0.13.2 h1:Kh90UH30bhnnUdJH+CmWLyaH8IKdY6BBGY3EkdOk82o= +cosmossdk.io/x/tx v0.13.2/go.mod h1:yhPokDCfXVIuAtyp49IFlWB5YAXUgD7Zek+ZHwsHzvU= cosmossdk.io/x/upgrade v0.1.0 h1:z1ZZG4UL9ICTNbJDYZ6jOnF9GdEK9wyoEFi4BUScHXE= cosmossdk.io/x/upgrade v0.1.0/go.mod h1:/6jjNGbiPCNtmA1N+rBtP601sr0g4ZXuj3yC6ClPCGY= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= @@ -292,8 +292,8 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA 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/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= @@ -335,8 +335,8 @@ github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/cometbft/cometbft v0.38.5 h1:4lOcK5VTPrfbLOhNHmPYe6c7eDXHtBdMCQuKbAfFJdU= -github.com/cometbft/cometbft v0.38.5/go.mod h1:0tqKin+KQs8zDwzYD8rPHzSBIDNPuB4NrwwGDNb/hUg= +github.com/cometbft/cometbft v0.38.7 h1:ULhIOJ9+LgSy6nLekhq9ae3juX3NnQUMMPyVdhZV6Hk= +github.com/cometbft/cometbft v0.38.7/go.mod h1:HIyf811dFMI73IE0F7RrnY/Fr+d1+HuJAgtkEpQjCMY= github.com/cometbft/cometbft-db v0.9.1 h1:MIhVX5ja5bXNHF8EYrThkG9F7r9kSfv8BX4LWaxWJ4M= github.com/cometbft/cometbft-db v0.9.1/go.mod h1:iliyWaoV0mRwBJoizElCwwRA9Tf7jZJOURcRZF9m60U= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= @@ -351,19 +351,19 @@ 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-db v1.0.2 h1:hwMjozuY1OlJs/uh6vddqnk9j7VamLv+0DBlbEXbAKs= github.com/cosmos/cosmos-db v1.0.2/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= -github.com/cosmos/cosmos-proto v1.0.0-beta.4 h1:aEL7tU/rLOmxZQ9z4i7mzxcLbSCY48OdY7lIWTLG7oU= -github.com/cosmos/cosmos-proto v1.0.0-beta.4/go.mod h1:oeB+FyVzG3XrQJbJng0EnV8Vljfk9XvTIpGILNU/9Co= -github.com/cosmos/cosmos-sdk v0.50.5 h1:MOEi+DKYgW67YaPgB+Pf+nHbD3V9S/ayitRKJYLfGIA= -github.com/cosmos/cosmos-sdk v0.50.5/go.mod h1:oV/k6GJgXV9QPoM2fsYDPPsyPBgQbdotv532O6Mz1OQ= +github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= +github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= +github.com/cosmos/cosmos-sdk v0.50.6 h1:efR3MsvMHX5sxS3be+hOobGk87IzlZbSpsI2x/Vw3hk= +github.com/cosmos/cosmos-sdk v0.50.6/go.mod h1:lVkRY6cdMJ0fG3gp8y4hFrsKZqF4z7y0M2UXFb9Yt40= 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.11 h1:LZcMHrx4FjUgrqQSWeaGC1v/TeuVFqSLa43CC6aWR2g= -github.com/cosmos/gogoproto v1.4.11/go.mod h1:/g39Mh8m17X8Q/GDEs5zYTSNaNnInBSohtaxzQnYq1Y= -github.com/cosmos/iavl v1.0.1 h1:D+mYbcRO2wptYzOM1Hxl9cpmmHU1ZEt9T2Wv5nZTeUw= -github.com/cosmos/iavl v1.0.1/go.mod h1:8xIUkgVvwvVrBu81scdPty+/Dx9GqwHnAvXz4cwF7RY= +github.com/cosmos/gogoproto v1.4.12 h1:vB6Lbe/rtnYGjQuFxkPiPYiCybqFT8QvLipDZP8JpFE= +github.com/cosmos/gogoproto v1.4.12/go.mod h1:LnZob1bXRdUoqMMtwYlcR3wjiElmlC+FkjaZRv1/eLY= +github.com/cosmos/iavl v1.1.2 h1:zL9FK7C4L/P4IF1Dm5fIwz0WXCnn7Bp1M2FxH0ayM7Y= +github.com/cosmos/iavl v1.1.2/go.mod h1:jLeUvm6bGT1YutCaL2fIar/8vGUE8cPZvh/gXEWDaDM= github.com/cosmos/ibc-go/modules/capability v1.0.0 h1:r/l++byFtn7jHYa09zlAdSeevo8ci1mVZNO9+V0xsLE= github.com/cosmos/ibc-go/modules/capability v1.0.0/go.mod h1:D81ZxzjZAe0ZO5ambnvn1qedsFQ8lOwtqicG6liLBco= github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= @@ -661,8 +661,8 @@ github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVH 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-metrics v0.5.1 h1:rfPwUqFU6uZXNvGl4hzjY8LEBsqFVU4si1H9/Hqck/U= -github.com/hashicorp/go-metrics v0.5.1/go.mod h1:KEjodfebIOuBYSAe/bHTm+HChmKSxAOXPBieMLYozDE= +github.com/hashicorp/go-metrics v0.5.3 h1:M5uADWMOGCTUNU1YuC4hfknOeHNaX54LDm4oYSucoNE= +github.com/hashicorp/go-metrics v0.5.3/go.mod h1:KEjodfebIOuBYSAe/bHTm+HChmKSxAOXPBieMLYozDE= 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-plugin v1.5.2 h1:aWv8eimFqWlsEiMrYZdPYl+FdHaBJSN4AWwGWfT1G2Y= @@ -763,8 +763,8 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6 github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/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.8.12 h1:1/pCztQUOa3BX/1gR3jSZDoaKFpeHFvQ1XrqZpSvZVo= -github.com/linxGnu/grocksdb v1.8.12/go.mod h1:xZCIb5Muw+nhbDK4Y5UJuOrin5MceOuiXkVUR7vp4WY= +github.com/linxGnu/grocksdb v1.8.14 h1:HTgyYalNwBSG/1qCQUIott44wU5b2Y9Kr3z7SK5OfGQ= +github.com/linxGnu/grocksdb v1.8.14/go.mod h1:QYiYypR2d4v63Wj1adOOfzglnoII0gLj3PNh4fZkcFA= 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= @@ -872,8 +872,8 @@ github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6 github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= 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-20230904192822-1876fd5063bc h1:8bQZVK1X6BJR/6nYUPxQEP+ReTsceJTKizeuwjWOPUA= -github.com/petermattis/goid v0.0.0-20230904192822-1876fd5063bc/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 h1:jik8PHtAIsPlCRJjJzl4udgEf7hawInF9texMeO2jrU= +github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67/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= @@ -894,32 +894,32 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn 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.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= 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.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= -github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.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.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k= -github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/common v0.52.2 h1:LW8Vk7BccEdONfrJBDffQGRtpSzi5CQaRZGtboOO2ck= +github.com/prometheus/common v0.52.2/go.mod h1:lrWtQx+iDfn2mbH5GUzlH9TSHyfZpHkSiG1W7y3sF2Q= 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.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o= +github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g= 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= @@ -1089,8 +1089,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U 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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= 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= @@ -1102,8 +1102,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 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-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= 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= @@ -1130,8 +1130,8 @@ 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.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1191,8 +1191,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug 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.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= 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= @@ -1218,8 +1218,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri 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.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= -golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= 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= @@ -1234,8 +1234,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ 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.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-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= @@ -1333,13 +1333,13 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= 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= @@ -1421,8 +1421,8 @@ 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.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= -golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= +golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= 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= @@ -1599,12 +1599,12 @@ google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqw 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-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= -google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= -google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 h1:x9PwdEgd11LgK+orcck69WVRo7DezSO4VUMPI4xpc8A= -google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c h1:NUsgEN92SQQqzfA+YtqYNqYmB3DMMYLlIwUZAQFVFbo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= 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= @@ -1646,8 +1646,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu 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.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= -google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= +google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= 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= diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index c7438df23be..1f1da0b6cde 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -20,6 +20,7 @@ import ( var ( _ porttypes.Middleware = (*IBCMiddleware)(nil) _ porttypes.PacketDataUnmarshaler = (*IBCMiddleware)(nil) + _ porttypes.UpgradableModule = (*IBCMiddleware)(nil) ) // IBCMiddleware implements the ICS26 callbacks for the ibc-callbacks middleware given @@ -363,6 +364,46 @@ func (im IBCMiddleware) OnChanCloseConfirm(ctx sdk.Context, portID, channelID st return im.app.OnChanCloseConfirm(ctx, portID, channelID) } +// OnChanUpgradeInit implements the IBCModule interface +func (im IBCMiddleware) OnChanUpgradeInit(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) (string, error) { + cbs, ok := im.app.(porttypes.UpgradableModule) + if !ok { + return "", errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack") + } + + return cbs.OnChanUpgradeInit(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion) +} + +// OnChanUpgradeTry implements the IBCModule interface +func (im IBCMiddleware) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, counterpartyVersion string) (string, error) { + cbs, ok := im.app.(porttypes.UpgradableModule) + if !ok { + return "", errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack") + } + + return cbs.OnChanUpgradeTry(ctx, portID, channelID, proposedOrder, proposedConnectionHops, counterpartyVersion) +} + +// OnChanUpgradeAck implements the IBCModule interface +func (im IBCMiddleware) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { + cbs, ok := im.app.(porttypes.UpgradableModule) + if !ok { + return errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack") + } + + return cbs.OnChanUpgradeAck(ctx, portID, channelID, counterpartyVersion) +} + +// OnChanUpgradeOpen implements the IBCModule interface +func (im IBCMiddleware) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) { + cbs, ok := im.app.(porttypes.UpgradableModule) + if !ok { + panic(errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack")) + } + + cbs.OnChanUpgradeOpen(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion) +} + // GetAppVersion implements the ICS4Wrapper interface. Callbacks has no version, // so the call is deferred to the underlying application. func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { diff --git a/modules/apps/callbacks/testing/simapp/app.go b/modules/apps/callbacks/testing/simapp/app.go index 56cce8c58d2..ab5669692a0 100644 --- a/modules/apps/callbacks/testing/simapp/app.go +++ b/modules/apps/callbacks/testing/simapp/app.go @@ -466,6 +466,7 @@ func NewSimApp( app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) + app.ICAHostKeeper.WithQueryRouter(app.GRPCQueryRouter()) // Create IBC Router ibcRouter := porttypes.NewRouter() diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index db1fc0d5b0a..4e49a1bbfdf 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -22,6 +22,7 @@ import ( var ( _ porttypes.IBCModule = (*IBCModule)(nil) _ porttypes.PacketDataUnmarshaler = (*IBCModule)(nil) + _ porttypes.UpgradableModule = (*IBCModule)(nil) ) // IBCModule implements the ICS26 interface for transfer given the transfer keeper. @@ -114,15 +115,17 @@ func (im IBCModule) OnChanOpenTry( return "", err } - if counterpartyVersion != types.Version { - return "", errorsmod.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: expected %s, got %s", types.Version, counterpartyVersion) - } - // OpenTry must claim the channelCapability that IBC passes into the callback if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { return "", err } + if counterpartyVersion != types.Version { + // Propose the current version + im.keeper.Logger(ctx).Debug("invalid counterparty version, proposing current app version", "counterpartyVersion", counterpartyVersion, "version", types.Version) + return types.Version, nil + } + return types.Version, nil } @@ -196,7 +199,7 @@ func (im IBCModule) OnRecvPacket( ackErr = err logger.Error(fmt.Sprintf("%s sequence %d", ackErr.Error(), packet.Sequence)) } else { - logger.Info("successfully handled ICS-20 packet sequence: %d", packet.Sequence) + logger.Info("successfully handled ICS-20 packet", "sequence", packet.Sequence) } } @@ -307,6 +310,45 @@ func (im IBCModule) OnTimeoutPacket( return nil } +// OnChanUpgradeInit implements the IBCModule interface +func (im IBCModule) OnChanUpgradeInit(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) (string, error) { + if err := ValidateTransferChannelParams(ctx, im.keeper, proposedOrder, portID, channelID); err != nil { + return "", err + } + + if proposedVersion != types.Version { + return "", errorsmod.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, proposedVersion) + } + + return proposedVersion, nil +} + +// OnChanUpgradeTry implements the IBCModule interface +func (im IBCModule) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, counterpartyVersion string) (string, error) { + if err := ValidateTransferChannelParams(ctx, im.keeper, proposedOrder, portID, channelID); err != nil { + return "", err + } + + if counterpartyVersion != types.Version { + return "", errorsmod.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, counterpartyVersion) + } + + return counterpartyVersion, nil +} + +// OnChanUpgradeAck implements the IBCModule interface +func (IBCModule) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { + if counterpartyVersion != types.Version { + return errorsmod.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, counterpartyVersion) + } + + return nil +} + +// OnChanUpgradeOpen implements the IBCModule interface +func (IBCModule) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) { +} + // UnmarshalPacketData attempts to unmarshal the provided packet data bytes // into a FungibleTokenPacketData. This function implements the optional // PacketDataUnmarshaler interface required for ADR 008 support. diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 81255a32670..d61cbf6259e 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -9,7 +9,9 @@ import ( capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" "github.com/cosmos/ibc-go/v8/modules/apps/transfer" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -30,6 +32,13 @@ func (suite *TransferTestSuite) TestOnChanOpenInit() { { "success", func() {}, true, }, + { + // connection hops is not used in the transfer application callback, + // it is already validated in the core OnChanUpgradeInit. + "success: invalid connection hops", func() { + path.EndpointA.ConnectionID = "invalid-connection-id" + }, true, + }, { "empty version string", func() { channel.Version = "" @@ -121,31 +130,32 @@ func (suite *TransferTestSuite) TestOnChanOpenTry() { "success", func() {}, true, }, { - "max channels reached", func() { + "success: invalid counterparty version proposes new version", func() { + // transfer module will propose the default version + counterpartyVersion = "version" + }, true, + }, + { + "failure: max channels reached", func() { path.EndpointA.ChannelID = channeltypes.FormatChannelIdentifier(math.MaxUint32 + 1) }, false, }, { - "capability already claimed", func() { + "failure: capability already claimed", func() { err := suite.chainA.GetSimApp().ScopedTransferKeeper.ClaimCapability(suite.chainA.GetContext(), chanCap, host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) suite.Require().NoError(err) }, false, }, { - "invalid order - ORDERED", func() { + "failure: invalid order - ORDERED", func() { channel.Ordering = channeltypes.ORDERED }, false, }, { - "invalid port ID", func() { + "failure: invalid port ID", func() { path.EndpointA.ChannelConfig.PortID = ibctesting.MockPort }, false, }, - { - "invalid counterparty version", func() { - counterpartyVersion = "version" - }, false, - }, } for _, tc := range testCases { @@ -242,6 +252,224 @@ func (suite *TransferTestSuite) TestOnChanOpenAck() { } } +func (suite *TransferTestSuite) TestOnChanUpgradeInit() { + var path *ibctesting.Path + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, // successful happy path for a standalone transfer app is swapping out the underlying connection + nil, + }, + { + "invalid upgrade connection", + func() { + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.ConnectionHops = []string{"connection-100"} + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.ConnectionHops = []string{"connection-100"} + }, + connectiontypes.ErrConnectionNotFound, + }, + { + "invalid upgrade ordering", + func() { + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Ordering = channeltypes.ORDERED + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Ordering = channeltypes.ORDERED + }, + channeltypes.ErrInvalidChannelOrdering, + }, + { + "invalid upgrade version", + func() { + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = ibctesting.InvalidID + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = ibctesting.InvalidID + }, + types.ErrInvalidVersion, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = NewTransferPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + // configure the channel upgrade to modify the underlying connection + upgradePath := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(upgradePath) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.ConnectionHops = []string{upgradePath.EndpointA.ConnectionID} + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.ConnectionHops = []string{upgradePath.EndpointB.ConnectionID} + + tc.malleate() + + err := path.EndpointA.ChanUpgradeInit() + + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err) + upgrade := path.EndpointA.GetChannelUpgrade() + suite.Require().Equal(upgradePath.EndpointA.ConnectionID, upgrade.Fields.ConnectionHops[0]) + } else { + suite.Require().Error(err) + suite.Require().Contains(err.Error(), tc.expError.Error()) + } + }) + } +} + +func (suite *TransferTestSuite) TestOnChanUpgradeTry() { + var ( + counterpartyUpgrade channeltypes.Upgrade + path *ibctesting.Path + ) + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, // successful happy path for a standalone transfer app is swapping out the underlying connection + nil, + }, + { + "invalid upgrade ordering", + func() { + counterpartyUpgrade.Fields.Ordering = channeltypes.ORDERED + }, + channeltypes.ErrInvalidChannelOrdering, + }, + { + "invalid upgrade version", + func() { + counterpartyUpgrade.Fields.Version = ibctesting.InvalidID + }, + types.ErrInvalidVersion, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = NewTransferPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + // configure the channel upgrade to modify the underlying connection + upgradePath := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(upgradePath) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.ConnectionHops = []string{upgradePath.EndpointA.ConnectionID} + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.ConnectionHops = []string{upgradePath.EndpointB.ConnectionID} + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + counterpartyUpgrade = path.EndpointA.GetChannelUpgrade() + + tc.malleate() + + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), types.PortID) + suite.Require().NoError(err) + + app, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) + + version, err := cbs.OnChanUpgradeTry( + suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, + counterpartyUpgrade.Fields.Ordering, counterpartyUpgrade.Fields.ConnectionHops, counterpartyUpgrade.Fields.Version, + ) + + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err) + suite.Require().Equal(types.Version, version) + } else { + suite.Require().Error(err) + suite.Require().Contains(err.Error(), tc.expError.Error()) + } + }) + } +} + +func (suite *TransferTestSuite) TestOnChanUpgradeAck() { + var path *ibctesting.Path + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, // successful happy path for a standalone transfer app is swapping out the underlying connection + nil, + }, + { + "invalid upgrade version", + func() { + path.EndpointB.ChannelConfig.Version = ibctesting.InvalidID + }, + types.ErrInvalidVersion, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = NewTransferPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + // configure the channel upgrade to modify the underlying connection + upgradePath := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(upgradePath) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.ConnectionHops = []string{upgradePath.EndpointA.ConnectionID} + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.ConnectionHops = []string{upgradePath.EndpointB.ConnectionID} + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + tc.malleate() + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), types.PortID) + suite.Require().NoError(err) + + app, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) + + err = cbs.OnChanUpgradeAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.Version) + + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + suite.Require().Contains(err.Error(), tc.expError.Error()) + } + }) + } +} + func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { var ( sender = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() diff --git a/modules/apps/transfer/keeper/migrations.go b/modules/apps/transfer/keeper/migrations.go index ae13ab7c80e..fb738a07831 100644 --- a/modules/apps/transfer/keeper/migrations.go +++ b/modules/apps/transfer/keeper/migrations.go @@ -98,7 +98,7 @@ func (m Migrator) MigrateTotalEscrowForDenom(ctx sdk.Context) error { m.keeper.SetTotalEscrowForDenom(ctx, totalEscrow) } - m.keeper.Logger(ctx).Info("successfully set total escrow for %d denominations", totalEscrowed.Len()) + m.keeper.Logger(ctx).Info("successfully set total escrow", "number of denominations", totalEscrowed.Len()) return nil } diff --git a/modules/apps/transfer/transfer_test.go b/modules/apps/transfer/transfer_test.go index 647a1b83665..08f5bc80026 100644 --- a/modules/apps/transfer/transfer_test.go +++ b/modules/apps/transfer/transfer_test.go @@ -32,6 +32,16 @@ func (suite *TransferTestSuite) SetupTest() { suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(3)) } +func NewTransferPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { + path := ibctesting.NewPath(chainA, chainB) + path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort + path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort + path.EndpointA.ChannelConfig.Version = types.Version + path.EndpointB.ChannelConfig.Version = types.Version + + return path +} + // Constructs the following sends based on the established channels/connections // 1 - from chainA to chainB // 2 - from chainB to chainC diff --git a/modules/apps/transfer/types/authz.pb.go b/modules/apps/transfer/types/authz.pb.go index e05cdc401e7..01928af5ac8 100644 --- a/modules/apps/transfer/types/authz.pb.go +++ b/modules/apps/transfer/types/authz.pb.go @@ -36,6 +36,9 @@ type Allocation struct { SpendLimit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=spend_limit,json=spendLimit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"spend_limit"` // allow list of receivers, an empty allow list permits any receiver address AllowList []string `protobuf:"bytes,4,rep,name=allow_list,json=allowList,proto3" json:"allow_list,omitempty"` + // allow list of memo strings, an empty list prohibits all memo strings; + // a list only with "*" permits any memo string + AllowedPacketData []string `protobuf:"bytes,5,rep,name=allowed_packet_data,json=allowedPacketData,proto3" json:"allowed_packet_data,omitempty"` } func (m *Allocation) Reset() { *m = Allocation{} } @@ -99,6 +102,13 @@ func (m *Allocation) GetAllowList() []string { return nil } +func (m *Allocation) GetAllowedPacketData() []string { + if m != nil { + return m.AllowedPacketData + } + return nil +} + // TransferAuthorization allows the grantee to spend up to spend_limit coins from // the granter's account for ibc transfer on a specific channel type TransferAuthorization struct { @@ -156,33 +166,35 @@ func init() { } var fileDescriptor_b1a28b55d17325aa = []byte{ - // 408 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x52, 0x3d, 0x8f, 0xd4, 0x30, - 0x10, 0x5d, 0xb3, 0x27, 0xa4, 0x75, 0x04, 0x45, 0x04, 0x52, 0xee, 0x04, 0xd9, 0xd5, 0x4a, 0xa0, - 0x34, 0x6b, 0x13, 0x28, 0x40, 0x74, 0xb7, 0xd7, 0x5e, 0x71, 0x44, 0x54, 0x34, 0x91, 0xe3, 0x35, - 0x89, 0x85, 0x93, 0x89, 0x62, 0x27, 0x88, 0xfb, 0x15, 0xf0, 0x37, 0xa8, 0xf9, 0x11, 0x27, 0xaa, - 0x2b, 0xa9, 0xf8, 0xd8, 0xfd, 0x23, 0x28, 0xb6, 0x17, 0x16, 0x21, 0x5d, 0x95, 0xe4, 0xe5, 0xcd, - 0xcc, 0x7b, 0x6f, 0x06, 0x27, 0xb2, 0xe0, 0x94, 0xb5, 0xad, 0x92, 0x9c, 0x19, 0x09, 0x8d, 0xa6, - 0xa6, 0x63, 0x8d, 0x7e, 0x2b, 0x3a, 0x3a, 0xa4, 0x94, 0xf5, 0xa6, 0xba, 0x24, 0x6d, 0x07, 0x06, - 0xc2, 0x07, 0xb2, 0xe0, 0xe4, 0x90, 0x49, 0xf6, 0x4c, 0x32, 0xa4, 0x27, 0xc7, 0x1c, 0x74, 0x0d, - 0x3a, 0xb7, 0x5c, 0xea, 0x3e, 0x5c, 0xe1, 0xc9, 0xbd, 0x12, 0x4a, 0x70, 0xf8, 0xf8, 0xe6, 0xd1, - 0xd8, 0x71, 0x68, 0xc1, 0xb4, 0xa0, 0x43, 0x5a, 0x08, 0xc3, 0x52, 0xca, 0x41, 0x36, 0xee, 0xff, - 0xf2, 0x17, 0xc2, 0xf8, 0x54, 0x29, 0x70, 0xc3, 0xc2, 0x39, 0x0e, 0x34, 0xf4, 0x1d, 0x17, 0x79, - 0x0b, 0x9d, 0x89, 0xd0, 0x02, 0x25, 0xb3, 0x0c, 0x3b, 0xe8, 0x02, 0x3a, 0x13, 0x3e, 0xc2, 0x77, - 0x3d, 0x81, 0x57, 0xac, 0x69, 0x84, 0x8a, 0x6e, 0x59, 0xce, 0x1d, 0x87, 0x9e, 0x39, 0x30, 0x54, - 0x38, 0xd0, 0xad, 0x68, 0x36, 0xb9, 0x92, 0xb5, 0x34, 0xd1, 0x74, 0x31, 0x4d, 0x82, 0xa7, 0xc7, - 0xc4, 0x0b, 0x1e, 0xc5, 0x10, 0x2f, 0x86, 0x9c, 0x81, 0x6c, 0xd6, 0x4f, 0xae, 0xbe, 0xcf, 0x27, - 0x9f, 0x7f, 0xcc, 0x93, 0x52, 0x9a, 0xaa, 0x2f, 0x08, 0x87, 0xda, 0xbb, 0xf3, 0x8f, 0x95, 0xde, - 0xbc, 0xa3, 0xe6, 0x43, 0x2b, 0xb4, 0x2d, 0xd0, 0x19, 0xb6, 0xfd, 0xcf, 0xc7, 0xf6, 0xe1, 0x43, - 0x8c, 0x99, 0x52, 0xf0, 0x3e, 0x57, 0x52, 0x9b, 0xe8, 0x68, 0x31, 0x4d, 0x66, 0xd9, 0xcc, 0x22, - 0xe7, 0x52, 0x9b, 0xe5, 0x27, 0x84, 0xef, 0xbf, 0xf6, 0x21, 0x9e, 0xf6, 0xa6, 0x82, 0x4e, 0x5e, - 0x3a, 0xbb, 0x17, 0x38, 0x60, 0x7f, 0xcc, 0xeb, 0x08, 0x59, 0x99, 0x09, 0xb9, 0x69, 0x05, 0xe4, - 0x6f, 0x5a, 0xeb, 0xa3, 0x51, 0x75, 0x76, 0xd8, 0xe2, 0xe5, 0xe3, 0xaf, 0x5f, 0x56, 0x4b, 0x6f, - 0xd3, 0xad, 0x75, 0xef, 0xf3, 0x9f, 0xc9, 0xeb, 0x57, 0x57, 0xdb, 0x18, 0x5d, 0x6f, 0x63, 0xf4, - 0x73, 0x1b, 0xa3, 0x8f, 0xbb, 0x78, 0x72, 0xbd, 0x8b, 0x27, 0xdf, 0x76, 0xf1, 0xe4, 0xcd, 0xf3, - 0xff, 0x23, 0x90, 0x05, 0x5f, 0x95, 0x40, 0x87, 0x17, 0xb4, 0x86, 0x4d, 0xaf, 0x84, 0x1e, 0x4f, - 0xe9, 0xe0, 0x84, 0x6c, 0x2e, 0xc5, 0x6d, 0xbb, 0xd1, 0x67, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, - 0xba, 0x7f, 0xf1, 0xfd, 0x6c, 0x02, 0x00, 0x00, + // 436 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0xcf, 0x8e, 0xd3, 0x30, + 0x10, 0xc6, 0x9b, 0xed, 0x82, 0x54, 0x57, 0x20, 0x11, 0x40, 0xca, 0xae, 0x20, 0xad, 0x2a, 0x81, + 0x72, 0xa9, 0x4d, 0xe1, 0x00, 0xe2, 0xb6, 0x5d, 0x8e, 0x7b, 0x28, 0x15, 0x27, 0x2e, 0x91, 0xe3, + 0x98, 0xd6, 0x5a, 0x27, 0x13, 0xc5, 0x93, 0x20, 0xf6, 0x29, 0xd8, 0xd7, 0xe0, 0xcc, 0x43, 0xac, + 0x38, 0xed, 0x91, 0x13, 0xa0, 0xf6, 0x45, 0x50, 0x6c, 0x17, 0x8a, 0x90, 0xf6, 0x94, 0xf8, 0x9b, + 0xcf, 0xf3, 0xe7, 0xe7, 0x21, 0x89, 0xca, 0x04, 0xe3, 0x55, 0xa5, 0x95, 0xe0, 0xa8, 0xa0, 0x34, + 0x0c, 0x6b, 0x5e, 0x9a, 0x0f, 0xb2, 0x66, 0xed, 0x8c, 0xf1, 0x06, 0xd7, 0x17, 0xb4, 0xaa, 0x01, + 0x21, 0x7c, 0xa4, 0x32, 0x41, 0xf7, 0x9d, 0x74, 0xe7, 0xa4, 0xed, 0xec, 0xf8, 0x48, 0x80, 0x29, + 0xc0, 0xa4, 0xd6, 0xcb, 0xdc, 0xc1, 0x5d, 0x3c, 0x7e, 0xb0, 0x82, 0x15, 0x38, 0xbd, 0xfb, 0xf3, + 0x6a, 0xec, 0x3c, 0x2c, 0xe3, 0x46, 0xb2, 0x76, 0x96, 0x49, 0xe4, 0x33, 0x26, 0x40, 0x95, 0x2e, + 0x3e, 0xb9, 0x3c, 0x20, 0xe4, 0x44, 0x6b, 0x70, 0xc5, 0xc2, 0x11, 0x19, 0x1a, 0x68, 0x6a, 0x21, + 0xd3, 0x0a, 0x6a, 0x8c, 0x82, 0x71, 0x90, 0x0c, 0x96, 0xc4, 0x49, 0x0b, 0xa8, 0x31, 0x7c, 0x42, + 0xee, 0x7a, 0x83, 0x58, 0xf3, 0xb2, 0x94, 0x3a, 0x3a, 0xb0, 0x9e, 0x3b, 0x4e, 0x3d, 0x75, 0x62, + 0xa8, 0xc9, 0xd0, 0x54, 0xb2, 0xcc, 0x53, 0xad, 0x0a, 0x85, 0x51, 0x7f, 0xdc, 0x4f, 0x86, 0xcf, + 0x8f, 0xa8, 0x6f, 0xb8, 0x6b, 0x86, 0xfa, 0x66, 0xe8, 0x29, 0xa8, 0x72, 0xfe, 0xec, 0xea, 0xc7, + 0xa8, 0xf7, 0xe5, 0xe7, 0x28, 0x59, 0x29, 0x5c, 0x37, 0x19, 0x15, 0x50, 0xf8, 0xe9, 0xfc, 0x67, + 0x6a, 0xf2, 0x73, 0x86, 0x9f, 0x2a, 0x69, 0xec, 0x05, 0xb3, 0x24, 0x36, 0xff, 0x59, 0x97, 0x3e, + 0x7c, 0x4c, 0x08, 0xd7, 0x1a, 0x3e, 0xa6, 0x5a, 0x19, 0x8c, 0x0e, 0xc7, 0xfd, 0x64, 0xb0, 0x1c, + 0x58, 0xe5, 0x4c, 0x19, 0x0c, 0x29, 0xb9, 0x6f, 0x0f, 0x32, 0x4f, 0x2b, 0x2e, 0xce, 0x25, 0xa6, + 0x39, 0x47, 0x1e, 0xdd, 0xb2, 0xbe, 0x7b, 0x3e, 0xb4, 0xb0, 0x91, 0x37, 0x1c, 0xf9, 0xe4, 0x32, + 0x20, 0x0f, 0xdf, 0x79, 0xe8, 0x27, 0x0d, 0xae, 0xa1, 0x56, 0x17, 0x0e, 0xcf, 0x82, 0x0c, 0xf9, + 0x1f, 0x58, 0x26, 0x0a, 0xec, 0x58, 0x09, 0xbd, 0xe9, 0xc9, 0xe8, 0x5f, 0xba, 0xf3, 0xc3, 0x6e, + 0xca, 0xe5, 0x7e, 0x8a, 0xd7, 0x4f, 0xbf, 0x7d, 0x9d, 0x4e, 0x3c, 0x16, 0xb7, 0x06, 0x3b, 0x2e, + 0xff, 0x54, 0x9e, 0xbf, 0xbd, 0xda, 0xc4, 0xc1, 0xf5, 0x26, 0x0e, 0x7e, 0x6d, 0xe2, 0xe0, 0xf3, + 0x36, 0xee, 0x5d, 0x6f, 0xe3, 0xde, 0xf7, 0x6d, 0xdc, 0x7b, 0xff, 0xf2, 0x7f, 0x64, 0x2a, 0x13, + 0xd3, 0x15, 0xb0, 0xf6, 0x15, 0x2b, 0x20, 0x6f, 0xb4, 0x34, 0xdd, 0xea, 0xed, 0xad, 0x9c, 0xe5, + 0x98, 0xdd, 0xb6, 0x1b, 0xf0, 0xe2, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcc, 0xb7, 0x0f, 0x97, + 0x9c, 0x02, 0x00, 0x00, } func (m *Allocation) Marshal() (dAtA []byte, err error) { @@ -205,6 +217,15 @@ func (m *Allocation) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.AllowedPacketData) > 0 { + for iNdEx := len(m.AllowedPacketData) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.AllowedPacketData[iNdEx]) + copy(dAtA[i:], m.AllowedPacketData[iNdEx]) + i = encodeVarintAuthz(dAtA, i, uint64(len(m.AllowedPacketData[iNdEx]))) + i-- + dAtA[i] = 0x2a + } + } if len(m.AllowList) > 0 { for iNdEx := len(m.AllowList) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.AllowList[iNdEx]) @@ -319,6 +340,12 @@ func (m *Allocation) Size() (n int) { n += 1 + l + sovAuthz(uint64(l)) } } + if len(m.AllowedPacketData) > 0 { + for _, s := range m.AllowedPacketData { + l = len(s) + n += 1 + l + sovAuthz(uint64(l)) + } + } return n } @@ -502,6 +529,38 @@ func (m *Allocation) Unmarshal(dAtA []byte) error { } m.AllowList = append(m.AllowList, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AllowedPacketData", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + 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 ErrInvalidLengthAuthz + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AllowedPacketData = append(m.AllowedPacketData, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipAuthz(dAtA[iNdEx:]) diff --git a/modules/apps/transfer/types/keys.go b/modules/apps/transfer/types/keys.go index 3ee859e2239..7e61ea61712 100644 --- a/modules/apps/transfer/types/keys.go +++ b/modules/apps/transfer/types/keys.go @@ -30,6 +30,9 @@ const ( // DenomPrefix is the prefix used for internal SDK coin representation. DenomPrefix = "ibc" + // AllowAllPacketDataKeys holds the string key that allows all memo strings in authz transfer messages + AllowAllPacketDataKeys = "*" + KeyTotalEscrowPrefix = "totalEscrowForDenom" ParamsKey = "params" diff --git a/modules/apps/transfer/types/transfer_authorization.go b/modules/apps/transfer/types/transfer_authorization.go index 82f40621efd..b5e4bbe23bc 100644 --- a/modules/apps/transfer/types/transfer_authorization.go +++ b/modules/apps/transfer/types/transfer_authorization.go @@ -3,6 +3,8 @@ package types import ( "context" "math/big" + "slices" + "strings" "github.com/cosmos/gogoproto/proto" @@ -50,6 +52,11 @@ func (a TransferAuthorization) Accept(ctx context.Context, msg proto.Message) (a return authz.AcceptResponse{}, errorsmod.Wrap(ibcerrors.ErrInvalidAddress, "not allowed receiver address for transfer") } + err := validateMemo(sdk.UnwrapSDKContext(ctx), msgTransfer.Memo, allocation.AllowedPacketData) + if err != nil { + return authz.AcceptResponse{}, err + } + // If the spend limit is set to the MaxUint256 sentinel value, do not subtract the amount from the spend limit. if allocation.SpendLimit.AmountOf(msgTransfer.Token.Denom).Equal(UnboundedSpendLimit()) { return authz.AcceptResponse{Accept: true, Delete: false, Updated: nil}, nil @@ -70,10 +77,11 @@ func (a TransferAuthorization) Accept(ctx context.Context, msg proto.Message) (a }}, nil } a.Allocations[index] = Allocation{ - SourcePort: allocation.SourcePort, - SourceChannel: allocation.SourceChannel, - SpendLimit: limitLeft, - AllowList: allocation.AllowList, + SourcePort: allocation.SourcePort, + SourceChannel: allocation.SourceChannel, + SpendLimit: limitLeft, + AllowList: allocation.AllowList, + AllowedPacketData: allocation.AllowedPacketData, } return authz.AcceptResponse{Accept: true, Delete: false, Updated: &TransferAuthorization{ @@ -145,6 +153,37 @@ func isAllowedAddress(ctx sdk.Context, receiver string, allowedAddrs []string) b return false } +// validateMemo returns a nil error indicating if the memo is valid for transfer. +func validateMemo(ctx sdk.Context, memo string, allowedMemos []string) error { + // if the allow list is empty, then the memo must be an empty string + if len(allowedMemos) == 0 { + if len(strings.TrimSpace(memo)) != 0 { + return errorsmod.Wrapf(ErrInvalidAuthorization, "memo must be empty because allowed packet data in allocation is empty") + } + + return nil + } + + // if allowedPacketDataList has only 1 element and it equals AllowAllPacketDataKeys + // then accept all the memo strings + if len(allowedMemos) == 1 && allowedMemos[0] == AllowAllPacketDataKeys { + return nil + } + + gasCostPerIteration := ctx.KVGasConfig().IterNextCostFlat + isMemoAllowed := slices.ContainsFunc(allowedMemos, func(allowedMemo string) bool { + ctx.GasMeter().ConsumeGas(gasCostPerIteration, "transfer authorization") + + return strings.TrimSpace(memo) == strings.TrimSpace(allowedMemo) + }) + + if !isMemoAllowed { + return errorsmod.Wrapf(ErrInvalidAuthorization, "not allowed memo: %s", memo) + } + + return nil +} + // UnboundedSpendLimit returns the sentinel value that can be used // as the amount for a denomination's spend limit for which spend limit updating // should be disabled. Please note that using this sentinel value means that a grantee diff --git a/modules/apps/transfer/types/transfer_authorization_test.go b/modules/apps/transfer/types/transfer_authorization_test.go index fdc877340e8..c5197a73720 100644 --- a/modules/apps/transfer/types/transfer_authorization_test.go +++ b/modules/apps/transfer/types/transfer_authorization_test.go @@ -1,6 +1,8 @@ package types_test import ( + "fmt" + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" @@ -11,6 +13,11 @@ import ( "github.com/cosmos/ibc-go/v8/testing/mock" ) +const ( + testMemo1 = `{"wasm":{"contract":"osmo1c3ljch9dfw5kf52nfwpxd2zmj2ese7agnx0p9tenkrryasrle5sqf3ftpg","msg":{"osmosis_swap":{"output_denom":"uosmo","slippage":{"twap":{"slippage_percentage":"20","window_seconds":10}},"receiver":"feeabs/feeabs1efd63aw40lxf3n4mhf7dzhjkr453axurwrhrrw","on_failed_delivery":"do_nothing"}}}}` + testMemo2 = `{"forward":{"channel":"channel-11","port":"transfer","receiver":"stars1twfv52yxcyykx2lcvgl42svw46hsm5dd4ww6xy","retries":2,"timeout":1712146014542131200}}` +) + func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { var ( msgTransfer types.MsgTransfer @@ -101,6 +108,73 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.Require().Nil(res.Updated) }, }, + { + "success: empty AllowedPacketData and empty memo", + func() { + allowedList := []string{} + transferAuthz.Allocations[0].AllowedPacketData = allowedList + }, + func(res authz.AcceptResponse, err error) { + suite.Require().NoError(err) + + suite.Require().True(res.Accept) + suite.Require().True(res.Delete) + suite.Require().Nil(res.Updated) + }, + }, + { + "success: AllowedPacketData allows any packet", + func() { + allowedList := []string{"*"} + transferAuthz.Allocations[0].AllowedPacketData = allowedList + msgTransfer.Memo = testMemo1 + }, + func(res authz.AcceptResponse, err error) { + suite.Require().NoError(err) + + suite.Require().True(res.Accept) + suite.Require().True(res.Delete) + suite.Require().Nil(res.Updated) + }, + }, + { + "success: transfer memo allowed", + func() { + allowedList := []string{testMemo1, testMemo2} + transferAuthz.Allocations[0].AllowedPacketData = allowedList + msgTransfer.Memo = testMemo1 + }, + func(res authz.AcceptResponse, err error) { + suite.Require().NoError(err) + + suite.Require().True(res.Accept) + suite.Require().True(res.Delete) + suite.Require().Nil(res.Updated) + }, + }, + { + "empty AllowedPacketData but not empty memo", + func() { + allowedList := []string{} + transferAuthz.Allocations[0].AllowedPacketData = allowedList + msgTransfer.Memo = testMemo1 + }, + func(res authz.AcceptResponse, err error) { + suite.Require().Error(err) + }, + }, + { + "memo not allowed", + func() { + allowedList := []string{testMemo1} + transferAuthz.Allocations[0].AllowedPacketData = allowedList + msgTransfer.Memo = testMemo2 + }, + func(res authz.AcceptResponse, err error) { + suite.Require().Error(err) + suite.Require().ErrorContains(err, fmt.Sprintf("not allowed memo: %s", testMemo2)) + }, + }, { "test multiple coins does not overspend", func() { @@ -241,6 +315,13 @@ func (suite *TypesTestSuite) TestTransferAuthorizationValidateBasic() { }, true, }, + { + "success: wildcard allowed packet data", + func() { + transferAuthz.Allocations[0].AllowedPacketData = []string{"*"} + }, + true, + }, { "empty allocations", func() { diff --git a/modules/capability/go.mod b/modules/capability/go.mod index 6ef71141154..308c9320b60 100644 --- a/modules/capability/go.mod +++ b/modules/capability/go.mod @@ -9,11 +9,11 @@ require ( cosmossdk.io/errors v1.0.1 cosmossdk.io/log v1.3.1 cosmossdk.io/math v1.3.0 - cosmossdk.io/store v1.0.2 - github.com/cometbft/cometbft v0.38.5 + cosmossdk.io/store v1.1.0 + github.com/cometbft/cometbft v0.38.7 github.com/cosmos/cosmos-db v1.0.2 - github.com/cosmos/cosmos-sdk v0.50.5 - github.com/cosmos/gogoproto v1.4.11 + github.com/cosmos/cosmos-sdk v0.50.6 + github.com/cosmos/gogoproto v1.4.12 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.9.0 @@ -21,10 +21,10 @@ require ( ) require ( - cosmossdk.io/api v0.7.3 // indirect + cosmossdk.io/api v0.7.4 // indirect cosmossdk.io/collections v0.4.0 // indirect cosmossdk.io/depinject v1.0.0-alpha.4 // indirect - cosmossdk.io/x/tx v0.13.1 // indirect + cosmossdk.io/x/tx v0.13.2 // 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 @@ -35,7 +35,7 @@ require ( 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/cespare/xxhash/v2 v2.3.0 // indirect github.com/cockroachdb/errors v1.11.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/pebble v1.1.0 // indirect @@ -43,10 +43,10 @@ require ( github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/cometbft/cometbft-db v0.9.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect - github.com/cosmos/cosmos-proto v1.0.0-beta.4 // indirect + github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect - github.com/cosmos/iavl v1.0.1 // indirect + github.com/cosmos/iavl v1.1.2 // indirect github.com/cosmos/ics23/go v0.10.0 // indirect github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect github.com/danieljoos/wincred v1.1.2 // indirect @@ -84,7 +84,7 @@ require ( github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-metrics v0.5.1 // indirect + github.com/hashicorp/go-metrics v0.5.3 // indirect github.com/hashicorp/go-plugin v1.5.2 // indirect github.com/hashicorp/go-uuid v1.0.2 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect @@ -100,7 +100,7 @@ require ( github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/linxGnu/grocksdb v1.8.12 // indirect + github.com/linxGnu/grocksdb v1.8.14 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -111,13 +111,13 @@ require ( github.com/oklog/run v1.1.0 // indirect github.com/onsi/ginkgo v1.16.4 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect - github.com/petermattis/goid v0.0.0-20230904192822-1876fd5063bc // indirect + github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.18.0 // indirect - github.com/prometheus/client_model v0.6.0 // indirect - github.com/prometheus/common v0.47.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect + github.com/prometheus/client_golang v1.19.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.52.2 // indirect + github.com/prometheus/procfs v0.13.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/rs/cors v1.8.3 // indirect @@ -139,17 +139,17 @@ require ( github.com/zondax/ledger-go v0.14.3 // indirect go.etcd.io/bbolt v1.3.8 // indirect go.uber.org/multierr v1.10.0 // indirect - golang.org/x/crypto v0.19.0 // indirect - golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect - golang.org/x/net v0.21.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.17.0 // indirect - golang.org/x/term v0.17.0 // indirect + golang.org/x/crypto v0.22.0 // indirect + golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c // indirect - google.golang.org/grpc v1.62.0 // indirect + google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect + google.golang.org/grpc v1.63.2 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/modules/capability/go.sum b/modules/capability/go.sum index cd6fac464bc..5cede605910 100644 --- a/modules/capability/go.sum +++ b/modules/capability/go.sum @@ -1,7 +1,7 @@ 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= -cosmossdk.io/api v0.7.3 h1:V815i8YOwOAQa1rLCsSMjVG5Gnzs02JLq+l7ks8s1jk= -cosmossdk.io/api v0.7.3/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= +cosmossdk.io/api v0.7.4 h1:sPo8wKwCty1lht8kgL3J7YL1voJywP3YWuA5JKkBz30= +cosmossdk.io/api v0.7.4/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s= cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0= cosmossdk.io/core v0.11.0 h1:vtIafqUi+1ZNAE/oxLOQQ7Oek2n4S48SWLG8h/+wdbo= @@ -14,10 +14,10 @@ cosmossdk.io/log v1.3.1 h1:UZx8nWIkfbbNEWusZqzAx3ZGvu54TZacWib3EzUYmGI= cosmossdk.io/log v1.3.1/go.mod h1:2/dIomt8mKdk6vl3OWJcPk2be3pGOS8OQaLUM/3/tCM= cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE= cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k= -cosmossdk.io/store v1.0.2 h1:lSg5BTvJBHUDwswNNyeh4K/CbqiHER73VU4nDNb8uk0= -cosmossdk.io/store v1.0.2/go.mod h1:EFtENTqVTuWwitGW1VwaBct+yDagk7oG/axBMPH+FXs= -cosmossdk.io/x/tx v0.13.1 h1:Mg+EMp67Pz+NukbJqYxuo8uRp7N/a9uR+oVS9pONtj8= -cosmossdk.io/x/tx v0.13.1/go.mod h1:CBCU6fsRVz23QGFIQBb1DNX2DztJCf3jWyEkHY2nJQ0= +cosmossdk.io/store v1.1.0 h1:LnKwgYMc9BInn9PhpTFEQVbL9UK475G2H911CGGnWHk= +cosmossdk.io/store v1.1.0/go.mod h1:oZfW/4Fc/zYqu3JmQcQdUJ3fqu5vnYTn3LZFFy8P8ng= +cosmossdk.io/x/tx v0.13.2 h1:Kh90UH30bhnnUdJH+CmWLyaH8IKdY6BBGY3EkdOk82o= +cosmossdk.io/x/tx v0.13.2/go.mod h1:yhPokDCfXVIuAtyp49IFlWB5YAXUgD7Zek+ZHwsHzvU= 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= @@ -82,8 +82,8 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA 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/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= @@ -111,8 +111,8 @@ github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/cometbft/cometbft v0.38.5 h1:4lOcK5VTPrfbLOhNHmPYe6c7eDXHtBdMCQuKbAfFJdU= -github.com/cometbft/cometbft v0.38.5/go.mod h1:0tqKin+KQs8zDwzYD8rPHzSBIDNPuB4NrwwGDNb/hUg= +github.com/cometbft/cometbft v0.38.7 h1:ULhIOJ9+LgSy6nLekhq9ae3juX3NnQUMMPyVdhZV6Hk= +github.com/cometbft/cometbft v0.38.7/go.mod h1:HIyf811dFMI73IE0F7RrnY/Fr+d1+HuJAgtkEpQjCMY= github.com/cometbft/cometbft-db v0.9.1 h1:MIhVX5ja5bXNHF8EYrThkG9F7r9kSfv8BX4LWaxWJ4M= github.com/cometbft/cometbft-db v0.9.1/go.mod h1:iliyWaoV0mRwBJoizElCwwRA9Tf7jZJOURcRZF9m60U= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -125,19 +125,19 @@ 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-db v1.0.2 h1:hwMjozuY1OlJs/uh6vddqnk9j7VamLv+0DBlbEXbAKs= github.com/cosmos/cosmos-db v1.0.2/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= -github.com/cosmos/cosmos-proto v1.0.0-beta.4 h1:aEL7tU/rLOmxZQ9z4i7mzxcLbSCY48OdY7lIWTLG7oU= -github.com/cosmos/cosmos-proto v1.0.0-beta.4/go.mod h1:oeB+FyVzG3XrQJbJng0EnV8Vljfk9XvTIpGILNU/9Co= -github.com/cosmos/cosmos-sdk v0.50.5 h1:MOEi+DKYgW67YaPgB+Pf+nHbD3V9S/ayitRKJYLfGIA= -github.com/cosmos/cosmos-sdk v0.50.5/go.mod h1:oV/k6GJgXV9QPoM2fsYDPPsyPBgQbdotv532O6Mz1OQ= +github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= +github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= +github.com/cosmos/cosmos-sdk v0.50.6 h1:efR3MsvMHX5sxS3be+hOobGk87IzlZbSpsI2x/Vw3hk= +github.com/cosmos/cosmos-sdk v0.50.6/go.mod h1:lVkRY6cdMJ0fG3gp8y4hFrsKZqF4z7y0M2UXFb9Yt40= 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.11 h1:LZcMHrx4FjUgrqQSWeaGC1v/TeuVFqSLa43CC6aWR2g= -github.com/cosmos/gogoproto v1.4.11/go.mod h1:/g39Mh8m17X8Q/GDEs5zYTSNaNnInBSohtaxzQnYq1Y= -github.com/cosmos/iavl v1.0.1 h1:D+mYbcRO2wptYzOM1Hxl9cpmmHU1ZEt9T2Wv5nZTeUw= -github.com/cosmos/iavl v1.0.1/go.mod h1:8xIUkgVvwvVrBu81scdPty+/Dx9GqwHnAvXz4cwF7RY= +github.com/cosmos/gogoproto v1.4.12 h1:vB6Lbe/rtnYGjQuFxkPiPYiCybqFT8QvLipDZP8JpFE= +github.com/cosmos/gogoproto v1.4.12/go.mod h1:LnZob1bXRdUoqMMtwYlcR3wjiElmlC+FkjaZRv1/eLY= +github.com/cosmos/iavl v1.1.2 h1:zL9FK7C4L/P4IF1Dm5fIwz0WXCnn7Bp1M2FxH0ayM7Y= +github.com/cosmos/iavl v1.1.2/go.mod h1:jLeUvm6bGT1YutCaL2fIar/8vGUE8cPZvh/gXEWDaDM= 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/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM= @@ -353,8 +353,8 @@ github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVH 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-metrics v0.5.1 h1:rfPwUqFU6uZXNvGl4hzjY8LEBsqFVU4si1H9/Hqck/U= -github.com/hashicorp/go-metrics v0.5.1/go.mod h1:KEjodfebIOuBYSAe/bHTm+HChmKSxAOXPBieMLYozDE= +github.com/hashicorp/go-metrics v0.5.3 h1:M5uADWMOGCTUNU1YuC4hfknOeHNaX54LDm4oYSucoNE= +github.com/hashicorp/go-metrics v0.5.3/go.mod h1:KEjodfebIOuBYSAe/bHTm+HChmKSxAOXPBieMLYozDE= 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-plugin v1.5.2 h1:aWv8eimFqWlsEiMrYZdPYl+FdHaBJSN4AWwGWfT1G2Y= @@ -442,8 +442,8 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6 github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/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.8.12 h1:1/pCztQUOa3BX/1gR3jSZDoaKFpeHFvQ1XrqZpSvZVo= -github.com/linxGnu/grocksdb v1.8.12/go.mod h1:xZCIb5Muw+nhbDK4Y5UJuOrin5MceOuiXkVUR7vp4WY= +github.com/linxGnu/grocksdb v1.8.14 h1:HTgyYalNwBSG/1qCQUIott44wU5b2Y9Kr3z7SK5OfGQ= +github.com/linxGnu/grocksdb v1.8.14/go.mod h1:QYiYypR2d4v63Wj1adOOfzglnoII0gLj3PNh4fZkcFA= 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= @@ -541,8 +541,8 @@ github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6 github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= 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-20230904192822-1876fd5063bc h1:8bQZVK1X6BJR/6nYUPxQEP+ReTsceJTKizeuwjWOPUA= -github.com/petermattis/goid v0.0.0-20230904192822-1876fd5063bc/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 h1:jik8PHtAIsPlCRJjJzl4udgEf7hawInF9texMeO2jrU= +github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67/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= @@ -563,32 +563,32 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn 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.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= 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.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= -github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.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.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k= -github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/common v0.52.2 h1:LW8Vk7BccEdONfrJBDffQGRtpSzi5CQaRZGtboOO2ck= +github.com/prometheus/common v0.52.2/go.mod h1:lrWtQx+iDfn2mbH5GUzlH9TSHyfZpHkSiG1W7y3sF2Q= 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.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o= +github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g= 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= @@ -725,13 +725,13 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= 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-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= 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= @@ -771,8 +771,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= 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-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -783,8 +783,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-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= @@ -839,12 +839,12 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.3.0/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= @@ -894,12 +894,12 @@ google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= -google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= -google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 h1:x9PwdEgd11LgK+orcck69WVRo7DezSO4VUMPI4xpc8A= -google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c h1:NUsgEN92SQQqzfA+YtqYNqYmB3DMMYLlIwUZAQFVFbo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= 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= @@ -917,8 +917,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= -google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= +google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= 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= diff --git a/modules/core/02-client/client/cli/tx.go b/modules/core/02-client/client/cli/tx.go index 19fd8b3f90b..92e6a5ec5e7 100644 --- a/modules/core/02-client/client/cli/tx.go +++ b/modules/core/02-client/client/cli/tx.go @@ -229,10 +229,10 @@ func newUpgradeClientCmd() *cobra.Command { } } - proofUpgradeClient := []byte(args[3]) - proofUpgradeConsensus := []byte(args[4]) + upgradeClientProof := []byte(args[3]) + upgradeConsensusProof := []byte(args[4]) - msg, err := types.NewMsgUpgradeClient(clientID, clientState, consensusState, proofUpgradeClient, proofUpgradeConsensus, clientCtx.GetFromAddress().String()) + msg, err := types.NewMsgUpgradeClient(clientID, clientState, consensusState, upgradeClientProof, upgradeConsensusProof, clientCtx.GetFromAddress().String()) if err != nil { return err } diff --git a/modules/core/02-client/keeper/client.go b/modules/core/02-client/keeper/client.go index db24eee27b6..da4d38229cf 100644 --- a/modules/core/02-client/keeper/client.go +++ b/modules/core/02-client/keeper/client.go @@ -115,7 +115,7 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, clientMsg exporte // UpgradeClient upgrades the client to a new client state if this new client was committed to // by the old client at the specified upgrade height func (k Keeper) UpgradeClient(ctx sdk.Context, clientID string, upgradedClient exported.ClientState, upgradedConsState exported.ConsensusState, - proofUpgradeClient, proofUpgradeConsState []byte, + upgradeClientProof, upgradeConsensusStateProof []byte, ) error { clientState, found := k.GetClientState(ctx, clientID) if !found { @@ -129,7 +129,7 @@ func (k Keeper) UpgradeClient(ctx sdk.Context, clientID string, upgradedClient e } if err := clientState.VerifyUpgradeAndUpdateState(ctx, k.cdc, clientStore, - upgradedClient, upgradedConsState, proofUpgradeClient, proofUpgradeConsState, + upgradedClient, upgradedConsState, upgradeClientProof, upgradeConsensusStateProof, ); err != nil { return errorsmod.Wrapf(err, "cannot upgrade client with ID %s", clientID) } diff --git a/modules/core/02-client/keeper/client_test.go b/modules/core/02-client/keeper/client_test.go index 0f0786fa873..368faa0dbf3 100644 --- a/modules/core/02-client/keeper/client_test.go +++ b/modules/core/02-client/keeper/client_test.go @@ -308,12 +308,12 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { func (suite *KeeperTestSuite) TestUpgradeClient() { var ( - path *ibctesting.Path - upgradedClient exported.ClientState - upgradedConsState exported.ConsensusState - lastHeight exported.Height - proofUpgradedClient, proofUpgradedConsState []byte - upgradedClientBz, upgradedConsStateBz []byte + path *ibctesting.Path + upgradedClient exported.ClientState + upgradedConsState exported.ConsensusState + lastHeight exported.Height + upgradedClientProof, upgradedConsensusStateProof []byte + upgradedClientBz, upgradedConsStateBz []byte ) testCases := []struct { @@ -341,8 +341,8 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) }, expPass: true, }, @@ -367,8 +367,8 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) path.EndpointA.ClientID = "wrongclientid" }, @@ -397,8 +397,8 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) // set frozen client in store tmClient, ok := cs.(*ibctm.ClientState) @@ -432,8 +432,37 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + }, + expPass: false, + }, + { + name: "unsuccessful upgrade: upgraded height is not greater than current height", + setup: func() { + // last Height is at next block + lastHeight = clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1)) + + // zero custom fields and store in upgrade store + err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + suite.Require().NoError(err) + err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) + suite.Require().NoError(err) + + // change upgradedClient height to be lower than current client state height + tmClient := upgradedClient.(*ibctm.ClientState) + tmClient.LatestHeight = clienttypes.NewHeight(0, 1) + upgradedClient = tmClient + + suite.coordinator.CommitBlock(suite.chainB) + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) + suite.Require().True(found) + + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) }, expPass: false, }, @@ -463,7 +492,7 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { tc.setup() - err = suite.chainA.App.GetIBCKeeper().ClientKeeper.UpgradeClient(suite.chainA.GetContext(), path.EndpointA.ClientID, upgradedClient, upgradedConsState, proofUpgradedClient, proofUpgradedConsState) + err = suite.chainA.App.GetIBCKeeper().ClientKeeper.UpgradeClient(suite.chainA.GetContext(), path.EndpointA.ClientID, upgradedClient, upgradedConsState, upgradedClientProof, upgradedConsensusStateProof) if tc.expPass { suite.Require().NoError(err, "verify upgrade failed on valid case: %s", tc.name) diff --git a/modules/core/02-client/keeper/grpc_query.go b/modules/core/02-client/keeper/grpc_query.go index 9ba5241fe57..4098cb77a56 100644 --- a/modules/core/02-client/keeper/grpc_query.go +++ b/modules/core/02-client/keeper/grpc_query.go @@ -386,6 +386,13 @@ func (k Keeper) VerifyMembership(c context.Context, req *types.QueryVerifyMember return nil, status.Error(codes.FailedPrecondition, errorsmod.Wrapf(types.ErrClientNotActive, "cannot verify membership using client (%s) with status %s", req.ClientId, clientStatus).Error()) } + // consume flat gas fee for proof verification queries. + // NOTE: consuming gas prior to method invocation also provides protection against recursive calls reaching stack overflow + ctx.GasMeter().ConsumeGas( + 3*ctx.KVGasConfig().ReadCostPerByte*uint64(len(req.Proof)), + "verify membership query", + ) + if err := clientState.VerifyMembership(cachedCtx, k.ClientStore(cachedCtx, req.ClientId), k.cdc, req.ProofHeight, req.TimeDelay, req.BlockDelay, req.Proof, req.MerklePath, req.Value); err != nil { k.Logger(ctx).Debug("proof verification failed", "key", req.MerklePath, "error", err) return &types.QueryVerifyMembershipResponse{ diff --git a/modules/core/02-client/keeper/grpc_query_test.go b/modules/core/02-client/keeper/grpc_query_test.go index b171df9697a..379e9ea2670 100644 --- a/modules/core/02-client/keeper/grpc_query_test.go +++ b/modules/core/02-client/keeper/grpc_query_test.go @@ -168,7 +168,6 @@ func (suite *KeeperTestSuite) TestQueryClientStates() { suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset - tc.malleate() ctx := suite.chainA.GetContext() diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index 026d60faea3..7db78c5539c 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -3,7 +3,6 @@ package keeper import ( "errors" "fmt" - "reflect" "strings" errorsmod "cosmossdk.io/errors" @@ -15,14 +14,9 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cometbft/cometbft/light" - "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" - ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" "github.com/cosmos/ibc-go/v8/modules/core/exported" - ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" localhost "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost" ) @@ -31,6 +25,7 @@ import ( type Keeper struct { storeKey storetypes.StoreKey cdc codec.BinaryCodec + consensusHost types.ConsensusHost legacySubspace types.ParamSubspace stakingKeeper types.StakingKeeper upgradeKeeper types.UpgradeKeeper @@ -63,6 +58,15 @@ func (k Keeper) UpdateLocalhostClient(ctx sdk.Context, clientState exported.Clie return clientState.UpdateState(ctx, k.cdc, k.ClientStore(ctx, exported.LocalhostClientID), nil) } +// SetConsensusHost sets a custom ConsensusHost for self client state and consensus state validation. +func (k *Keeper) SetConsensusHost(consensusHost types.ConsensusHost) { + if consensusHost == nil { + panic(fmt.Errorf("cannot set a nil self consensus host")) + } + + k.consensusHost = consensusHost +} + // GenerateClientIdentifier returns the next client identifier. func (k Keeper) GenerateClientIdentifier(ctx sdk.Context, clientType string) string { nextClientSeq := k.GetNextClientSequence(ctx) @@ -253,96 +257,15 @@ func (k Keeper) GetLatestClientConsensusState(ctx sdk.Context, clientID string) // and returns the expected consensus state at that height. // For now, can only retrieve self consensus states for the current revision func (k Keeper) GetSelfConsensusState(ctx sdk.Context, height exported.Height) (exported.ConsensusState, error) { - selfHeight, ok := height.(types.Height) - if !ok { - return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidType, "expected %T, got %T", types.Height{}, height) - } - // check that height revision matches chainID revision - revision := types.ParseChainID(ctx.ChainID()) - if revision != height.GetRevisionNumber() { - return nil, errorsmod.Wrapf(types.ErrInvalidHeight, "chainID revision number does not match height revision number: expected %d, got %d", revision, height.GetRevisionNumber()) - } - histInfo, err := k.stakingKeeper.GetHistoricalInfo(ctx, int64(selfHeight.RevisionHeight)) - if err != nil { - return nil, errorsmod.Wrapf(err, "height %d", selfHeight.RevisionHeight) - } - - consensusState := &ibctm.ConsensusState{ - Timestamp: histInfo.Header.Time, - Root: commitmenttypes.NewMerkleRoot(histInfo.Header.GetAppHash()), - NextValidatorsHash: histInfo.Header.NextValidatorsHash, - } - - return consensusState, nil + return k.consensusHost.GetSelfConsensusState(ctx, height) } -// ValidateSelfClient validates the client parameters for a client of the running chain -// This function is only used to validate the client state the counterparty stores for this chain -// Client must be in same revision as the executing chain +// ValidateSelfClient validates the client parameters for a client of the running chain. +// This function is only used to validate the client state the counterparty stores for this chain. +// NOTE: If the client type is not of type Tendermint then delegate to a custom client validator function. +// This allows support for non-Tendermint clients, for example 08-wasm clients. func (k Keeper) ValidateSelfClient(ctx sdk.Context, clientState exported.ClientState) error { - tmClient, ok := clientState.(*ibctm.ClientState) - if !ok { - return errorsmod.Wrapf(types.ErrInvalidClient, "client must be a Tendermint client, expected: %T, got: %T", - &ibctm.ClientState{}, tmClient) - } - - if !tmClient.FrozenHeight.IsZero() { - return types.ErrClientFrozen - } - - if ctx.ChainID() != tmClient.ChainId { - return errorsmod.Wrapf(types.ErrInvalidClient, "invalid chain-id. expected: %s, got: %s", - ctx.ChainID(), tmClient.ChainId) - } - - revision := types.ParseChainID(ctx.ChainID()) - - // client must be in the same revision as executing chain - if tmClient.LatestHeight.RevisionNumber != revision { - return errorsmod.Wrapf(types.ErrInvalidClient, "client is not in the same revision as the chain. expected revision: %d, got: %d", - tmClient.LatestHeight.RevisionNumber, revision) - } - - selfHeight := types.NewHeight(revision, uint64(ctx.BlockHeight())) - if tmClient.LatestHeight.GTE(selfHeight) { - return errorsmod.Wrapf(types.ErrInvalidClient, "client has LatestHeight %d greater than or equal to chain height %d", - tmClient.LatestHeight, selfHeight) - } - - expectedProofSpecs := commitmenttypes.GetSDKSpecs() - if !reflect.DeepEqual(expectedProofSpecs, tmClient.ProofSpecs) { - return errorsmod.Wrapf(types.ErrInvalidClient, "client has invalid proof specs. expected: %v got: %v", - expectedProofSpecs, tmClient.ProofSpecs) - } - - if err := light.ValidateTrustLevel(tmClient.TrustLevel.ToTendermint()); err != nil { - return errorsmod.Wrapf(types.ErrInvalidClient, "trust-level invalid: %v", err) - } - - expectedUbdPeriod, err := k.stakingKeeper.UnbondingTime(ctx) - if err != nil { - return errorsmod.Wrapf(err, "failed to retrieve unbonding period") - } - - if expectedUbdPeriod != tmClient.UnbondingPeriod { - return errorsmod.Wrapf(types.ErrInvalidClient, "invalid unbonding period. expected: %s, got: %s", - expectedUbdPeriod, tmClient.UnbondingPeriod) - } - - if tmClient.UnbondingPeriod < tmClient.TrustingPeriod { - return errorsmod.Wrapf(types.ErrInvalidClient, "unbonding period must be greater than trusting period. unbonding period (%d) < trusting period (%d)", - tmClient.UnbondingPeriod, tmClient.TrustingPeriod) - } - - if len(tmClient.UpgradePath) != 0 { - // For now, SDK IBC implementation assumes that upgrade path (if defined) is defined by SDK upgrade module - expectedUpgradePath := []string{upgradetypes.StoreKey, upgradetypes.KeyUpgradedIBCState} - if !reflect.DeepEqual(expectedUpgradePath, tmClient.UpgradePath) { - return errorsmod.Wrapf(types.ErrInvalidClient, "upgrade path must be the upgrade path defined by upgrade module. expected %v, got %v", - expectedUpgradePath, tmClient.UpgradePath) - } - } - return nil + return k.consensusHost.ValidateSelfClient(ctx, clientState) } // GetUpgradePlan executes the upgrade keeper GetUpgradePlan function. diff --git a/modules/core/02-client/keeper/keeper_test.go b/modules/core/02-client/keeper/keeper_test.go index 1a73391bd4d..94bc21b0372 100644 --- a/modules/core/02-client/keeper/keeper_test.go +++ b/modules/core/02-client/keeper/keeper_test.go @@ -23,7 +23,6 @@ import ( "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" "github.com/cosmos/ibc-go/v8/modules/core/exported" - solomachine "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine" ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" localhost "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost" ibctesting "github.com/cosmos/ibc-go/v8/testing" @@ -44,10 +43,7 @@ const ( maxClockDrift time.Duration = time.Second * 10 ) -var ( - testClientHeight = types.NewHeight(0, 5) - testClientHeightRevision1 = types.NewHeight(1, 5) -) +var testClientHeight = types.NewHeight(0, 5) type KeeperTestSuite struct { testifysuite.Suite @@ -144,91 +140,7 @@ func (suite *KeeperTestSuite) TestSetClientConsensusState() { suite.Require().Equal(suite.consensusState, tmConsState, "ConsensusState not stored correctly") } -func (suite *KeeperTestSuite) TestValidateSelfClient() { - testClientHeight := types.GetSelfHeight(suite.chainA.GetContext()) - testClientHeight.RevisionHeight-- - - testCases := []struct { - name string - clientState exported.ClientState - expPass bool - }{ - { - "success", - ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath), - true, - }, - { - "success with nil UpgradePath", - ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), nil), - true, - }, - { - "frozen client", - &ibctm.ClientState{ChainId: suite.chainA.ChainID, TrustLevel: ibctm.DefaultTrustLevel, TrustingPeriod: trustingPeriod, UnbondingPeriod: ubdPeriod, MaxClockDrift: maxClockDrift, FrozenHeight: testClientHeight, LatestHeight: testClientHeight, ProofSpecs: commitmenttypes.GetSDKSpecs(), UpgradePath: ibctesting.UpgradePath}, - false, - }, - { - "incorrect chainID", - ibctm.NewClientState("gaiatestnet", ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath), - false, - }, - { - "invalid client height", - ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.GetSelfHeight(suite.chainA.GetContext()).Increment().(types.Height), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath), - false, - }, - { - "invalid client type", - solomachine.NewClientState(0, &solomachine.ConsensusState{PublicKey: suite.solomachine.ConsensusState().PublicKey, Diversifier: suite.solomachine.Diversifier, Timestamp: suite.solomachine.Time}), - false, - }, - { - "invalid client revision", - ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeightRevision1, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath), - false, - }, - { - "invalid proof specs", - ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, nil, ibctesting.UpgradePath), - false, - }, - { - "invalid trust level", - ibctm.NewClientState(suite.chainA.ChainID, ibctm.Fraction{Numerator: 0, Denominator: 1}, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath), false, - }, - { - "invalid unbonding period", - ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod+10, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath), - false, - }, - { - "invalid trusting period", - ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, ubdPeriod+10, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath), - false, - }, - { - "invalid upgrade path", - ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), []string{"bad", "upgrade", "path"}), - false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - err := suite.chainA.App.GetIBCKeeper().ClientKeeper.ValidateSelfClient(suite.chainA.GetContext(), tc.clientState) - if tc.expPass { - suite.Require().NoError(err, "expected valid client for case: %s", tc.name) - } else { - suite.Require().Error(err, "expected invalid client for case: %s", tc.name) - } - }) - } -} - -func (suite KeeperTestSuite) TestGetAllGenesisClients() { //nolint:govet // this is a test, we are okay with copying locks +func (suite *KeeperTestSuite) TestGetAllGenesisClients() { clientIDs := []string{ exported.LocalhostClientID, testClientID2, testClientID3, testClientID, } @@ -251,7 +163,7 @@ func (suite KeeperTestSuite) TestGetAllGenesisClients() { //nolint:govet // this suite.Require().Equal(expGenClients.Sort(), genClients) } -func (suite KeeperTestSuite) TestGetAllGenesisMetadata() { //nolint:govet // this is a test, we are okay with copying locks +func (suite *KeeperTestSuite) TestGetAllGenesisMetadata() { //nolint:govet // this is a test, we are okay with copying locks expectedGenMetadata := []types.IdentifiedGenesisMetadata{ types.NewIdentifiedGenesisMetadata( "07-tendermint-1", @@ -281,35 +193,9 @@ func (suite KeeperTestSuite) TestGetAllGenesisMetadata() { //nolint:govet // thi suite.Require().Equal(expectedGenMetadata, actualGenMetadata, "retrieved metadata is unexpected") } -func (suite KeeperTestSuite) TestGetConsensusState() { //nolint:govet // this is a test, we are okay with copying locks - suite.ctx = suite.ctx.WithBlockHeight(10) - cases := []struct { - name string - height types.Height - expPass bool - }{ - {"zero height", types.ZeroHeight(), false}, - {"height > latest height", types.NewHeight(0, uint64(suite.ctx.BlockHeight())+1), false}, - {"latest height - 1", types.NewHeight(0, uint64(suite.ctx.BlockHeight())-1), true}, - {"latest height", types.GetSelfHeight(suite.ctx), true}, - } - - for i, tc := range cases { - tc := tc - cs, err := suite.keeper.GetSelfConsensusState(suite.ctx, tc.height) - if tc.expPass { - suite.Require().NoError(err, "Case %d should have passed: %s", i, tc.name) - suite.Require().NotNil(cs, "Case %d should have passed: %s", i, tc.name) - } else { - suite.Require().Error(err, "Case %d should have failed: %s", i, tc.name) - suite.Require().Nil(cs, "Case %d should have failed: %s", i, tc.name) - } - } -} - // 2 clients in total are created on chainA. The first client is updated so it contains an initial consensus state // and a consensus state at the update height. -func (suite KeeperTestSuite) TestGetAllConsensusStates() { //nolint:govet // this is a test, we are okay with copying locks +func (suite *KeeperTestSuite) TestGetAllConsensusStates() { //nolint:govet // this is a test, we are okay with copying locks path := ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(path) @@ -358,7 +244,7 @@ func (suite KeeperTestSuite) TestGetAllConsensusStates() { //nolint:govet // thi suite.Require().Equal(expConsensusStates, consStates, "%s \n\n%s", expConsensusStates, consStates) } -func (suite KeeperTestSuite) TestIterateClientStates() { //nolint:govet // this is a test, we are okay with copying locks +func (suite *KeeperTestSuite) TestIterateClientStates() { //nolint:govet // this is a test, we are okay with copying locks paths := []*ibctesting.Path{ ibctesting.NewPath(suite.chainA, suite.chainB), ibctesting.NewPath(suite.chainA, suite.chainB), diff --git a/modules/core/02-client/types/client.go b/modules/core/02-client/types/client.go index 31da1a54e70..2b1cb965b85 100644 --- a/modules/core/02-client/types/client.go +++ b/modules/core/02-client/types/client.go @@ -11,6 +11,7 @@ import ( errorsmod "cosmossdk.io/errors" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" @@ -21,6 +22,12 @@ var ( _ codectypes.UnpackInterfacesMessage = (*ConsensusStateWithHeight)(nil) ) +// ConsensusHost defines an interface used to validate an IBC ClientState and ConsensusState against the host chain's underlying consensus parameters. +type ConsensusHost interface { + GetSelfConsensusState(ctx sdk.Context, height exported.Height) (exported.ConsensusState, error) + ValidateSelfClient(ctx sdk.Context, clientState exported.ClientState) error +} + // NewIdentifiedClientState creates a new IdentifiedClientState instance func NewIdentifiedClientState(clientID string, clientState exported.ClientState) IdentifiedClientState { msg, ok := clientState.(proto.Message) diff --git a/modules/core/02-client/types/errors.go b/modules/core/02-client/types/errors.go index 3a726378cbc..3dc556901f8 100644 --- a/modules/core/02-client/types/errors.go +++ b/modules/core/02-client/types/errors.go @@ -36,4 +36,5 @@ var ( ErrClientNotActive = errorsmod.Register(SubModuleName, 29, "client state is not active") ErrFailedMembershipVerification = errorsmod.Register(SubModuleName, 30, "membership verification failed") ErrFailedNonMembershipVerification = errorsmod.Register(SubModuleName, 31, "non-membership verification failed") + ErrClientTypeNotSupported = errorsmod.Register(SubModuleName, 32, "client type not supported") ) diff --git a/modules/core/02-client/types/keys.go b/modules/core/02-client/types/keys.go index 86b132c5195..119fdc728d3 100644 --- a/modules/core/02-client/types/keys.go +++ b/modules/core/02-client/types/keys.go @@ -28,6 +28,10 @@ const ( // ParamsKey is the store key for the IBC client parameters ParamsKey = "clientParams" + + // AllowAllClients is the value that if set in AllowedClients param + // would allow any wired up light client modules to be allowed + AllowAllClients = "*" ) // FormatClientIdentifier returns the client identifier with the sequence appended. diff --git a/modules/core/02-client/types/legacy_proposal.go b/modules/core/02-client/types/legacy_proposal.go index 86629994d25..0a6df0dd323 100644 --- a/modules/core/02-client/types/legacy_proposal.go +++ b/modules/core/02-client/types/legacy_proposal.go @@ -1,5 +1,3 @@ -// Deprecated: The legacy v1beta1 gov types maintained in this file are deprecated and will be removed in a future release. -// Please use MsgIBCSoftwareUpgrade and MsgRecoverClient in favour of the legacy v1beta1 gov proposal types. package types import ( @@ -34,6 +32,9 @@ func init() { } // NewClientUpdateProposal creates a new client update proposal. +// +// Deprecated: The legacy v1beta1 gov ClientUpdateProposal is deprecated +// and will be removed in a future release. Please use MsgRecoverClient instead. func NewClientUpdateProposal(title, description, subjectClientID, substituteClientID string) govtypes.Content { return &ClientUpdateProposal{ Title: title, @@ -76,6 +77,9 @@ func (cup *ClientUpdateProposal) ValidateBasic() error { } // NewUpgradeProposal creates a new IBC breaking upgrade proposal. +// +// Deprecated: The legacy v1beta1 gov UpgradeProposal is deprecated +// and will be removed in a future release. Please use MsgIBCSoftwareUpgrade instead. func NewUpgradeProposal(title, description string, plan upgradetypes.Plan, upgradedClientState exported.ClientState) (govtypes.Content, error) { clientAny, err := PackClientState(upgradedClientState) if err != nil { diff --git a/modules/core/02-client/types/msgs.go b/modules/core/02-client/types/msgs.go index 1eb5472ca87..023e5d87b01 100644 --- a/modules/core/02-client/types/msgs.go +++ b/modules/core/02-client/types/msgs.go @@ -151,7 +151,7 @@ func (msg MsgUpdateClient) UnpackInterfaces(unpacker codectypes.AnyUnpacker) err // NewMsgUpgradeClient creates a new MsgUpgradeClient instance func NewMsgUpgradeClient(clientID string, clientState exported.ClientState, consState exported.ConsensusState, - proofUpgradeClient, proofUpgradeConsState []byte, signer string, + upgradeClientProof, upgradeConsensusStateProof []byte, signer string, ) (*MsgUpgradeClient, error) { anyClient, err := PackClientState(clientState) if err != nil { @@ -166,8 +166,8 @@ func NewMsgUpgradeClient(clientID string, clientState exported.ClientState, cons ClientId: clientID, ClientState: anyClient, ConsensusState: anyConsState, - ProofUpgradeClient: proofUpgradeClient, - ProofUpgradeConsensusState: proofUpgradeConsState, + ProofUpgradeClient: upgradeClientProof, + ProofUpgradeConsensusState: upgradeConsensusStateProof, Signer: signer, }, nil } diff --git a/modules/core/02-client/types/params.go b/modules/core/02-client/types/params.go index 2234f049e66..da5ce32ff46 100644 --- a/modules/core/02-client/types/params.go +++ b/modules/core/02-client/types/params.go @@ -4,12 +4,11 @@ import ( "fmt" "slices" "strings" - - "github.com/cosmos/ibc-go/v8/modules/core/exported" ) // DefaultAllowedClients are the default clients for the AllowedClients parameter. -var DefaultAllowedClients = []string{exported.Solomachine, exported.Tendermint, exported.Localhost} +// By default it allows all client types. +var DefaultAllowedClients = []string{AllowAllClients} // NewParams creates a new parameter configuration for the ibc client module func NewParams(allowedClients ...string) Params { @@ -30,15 +29,36 @@ func (p Params) Validate() error { // IsAllowedClient checks if the given client type is registered on the allowlist. func (p Params) IsAllowedClient(clientType string) bool { + // Still need to check for blank client type + if strings.TrimSpace(clientType) == "" { + return false + } + + // Check for allow all client wildcard + // If exist then allow all type of client + if len(p.AllowedClients) == 1 && p.AllowedClients[0] == AllowAllClients { + return true + } + return slices.Contains(p.AllowedClients, clientType) } -// validateClients checks that the given clients are not blank. +// validateClients checks that the given clients are not blank and there are no duplicates. +// If AllowAllClients wildcard (*) is used, then there should no other client types in the allow list func validateClients(clients []string) error { + if slices.Contains(clients, AllowAllClients) && len(clients) > 1 { + return fmt.Errorf("allow list must have only one element because the allow all clients wildcard (%s) is present", AllowAllClients) + } + + foundClients := make(map[string]bool, len(clients)) for i, clientType := range clients { if strings.TrimSpace(clientType) == "" { return fmt.Errorf("client type %d cannot be blank", i) } + if foundClients[clientType] { + return fmt.Errorf("duplicate client type: %s", clientType) + } + foundClients[clientType] = true } return nil diff --git a/modules/core/02-client/types/params_test.go b/modules/core/02-client/types/params_test.go index 404118c0528..347b913450f 100644 --- a/modules/core/02-client/types/params_test.go +++ b/modules/core/02-client/types/params_test.go @@ -19,6 +19,8 @@ func TestIsAllowedClient(t *testing.T) { {"success: valid client with custom params", exported.Tendermint, NewParams(exported.Tendermint), true}, {"success: invalid blank client", " ", DefaultParams(), false}, {"success: invalid client with custom params", exported.Localhost, NewParams(exported.Tendermint), false}, + {"success: wildcard allow all clients", "test-client-type", NewParams(AllowAllClients), true}, + {"success: wildcard allow all clients with blank client", " ", NewParams(AllowAllClients), false}, } for _, tc := range testCases { @@ -36,6 +38,8 @@ func TestValidateParams(t *testing.T) { {"default params", DefaultParams(), true}, {"custom params", NewParams(exported.Tendermint), true}, {"blank client", NewParams(" "), false}, + {"duplicate clients", NewParams(exported.Tendermint, exported.Tendermint), false}, + {"allow all clients plus valid client", NewParams(AllowAllClients, exported.Tendermint), false}, } for _, tc := range testCases { diff --git a/modules/core/03-connection/keeper/handshake.go b/modules/core/03-connection/keeper/handshake.go index e83ea803c9f..95e9947ae31 100644 --- a/modules/core/03-connection/keeper/handshake.go +++ b/modules/core/03-connection/keeper/handshake.go @@ -74,9 +74,9 @@ func (k Keeper) ConnOpenTry( clientID string, // clientID of chainA clientState exported.ClientState, // clientState that chainA has for chainB counterpartyVersions []*types.Version, // supported versions of chain A - proofInit []byte, // proof that chainA stored connectionEnd in state (on ConnOpenInit) - proofClient []byte, // proof that chainA stored a light client of chainB - proofConsensus []byte, // proof that chainA stored chainB's consensus state at consensus height + initProof []byte, // proof that chainA stored connectionEnd in state (on ConnOpenInit) + clientProof []byte, // proof that chainA stored a light client of chainB + consensusProof []byte, // proof that chainA stored chainB's consensus state at consensus height proofHeight exported.Height, // height at which relayer constructs proof of A storing connectionEnd in state consensusHeight exported.Height, // latest height of chain B which chain A has stored in its chain B client ) (string, error) { @@ -94,11 +94,11 @@ func (k Keeper) ConnOpenTry( } // validate client parameters of a chainB client stored on chainA - if err := k.clientKeeper.ValidateSelfClient(ctx, clientState); err != nil { + if err := k.consensusHost.ValidateSelfClient(ctx, clientState); err != nil { return "", err } - expectedConsensusState, err := k.clientKeeper.GetSelfConsensusState(ctx, consensusHeight) + expectedConsensusState, err := k.consensusHost.GetSelfConsensusState(ctx, consensusHeight) if err != nil { return "", errorsmod.Wrapf(err, "self consensus state not found for height %s", consensusHeight.String()) } @@ -123,20 +123,20 @@ func (k Keeper) ConnOpenTry( // Check that ChainA committed expectedConnectionEnd to its state if err := k.VerifyConnectionState( - ctx, connection, proofHeight, proofInit, counterparty.ConnectionId, + ctx, connection, proofHeight, initProof, counterparty.ConnectionId, expectedConnection, ); err != nil { return "", err } // Check that ChainA stored the clientState provided in the msg - if err := k.VerifyClientState(ctx, connection, proofHeight, proofClient, clientState); err != nil { + if err := k.VerifyClientState(ctx, connection, proofHeight, clientProof, clientState); err != nil { return "", err } // Check that ChainA stored the correct ConsensusState of chainB at the given consensusHeight if err := k.VerifyClientConsensusState( - ctx, connection, proofHeight, consensusHeight, proofConsensus, expectedConsensusState, + ctx, connection, proofHeight, consensusHeight, consensusProof, expectedConsensusState, ); err != nil { return "", err } @@ -166,9 +166,9 @@ func (k Keeper) ConnOpenAck( clientState exported.ClientState, // client state for chainA on chainB version *types.Version, // version that ChainB chose in ConnOpenTry counterpartyConnectionID string, - proofTry []byte, // proof that connectionEnd was added to ChainB state in ConnOpenTry - proofClient []byte, // proof of client state on chainB for chainA - proofConsensus []byte, // proof that chainB has stored ConsensusState of chainA on its client + tryProof []byte, // proof that connectionEnd was added to ChainB state in ConnOpenTry + clientProof []byte, // proof of client state on chainB for chainA + consensusProof []byte, // proof that chainB has stored ConsensusState of chainA on its client proofHeight exported.Height, // height that relayer constructed proofTry consensusHeight exported.Height, // latest height of chainA that chainB has stored on its chainA client ) error { @@ -205,12 +205,12 @@ func (k Keeper) ConnOpenAck( } // validate client parameters of a chainA client stored on chainB - if err := k.clientKeeper.ValidateSelfClient(ctx, clientState); err != nil { + if err := k.consensusHost.ValidateSelfClient(ctx, clientState); err != nil { return err } // Retrieve chainA's consensus state at consensusheight - expectedConsensusState, err := k.clientKeeper.GetSelfConsensusState(ctx, consensusHeight) + expectedConsensusState, err := k.consensusHost.GetSelfConsensusState(ctx, consensusHeight) if err != nil { return errorsmod.Wrapf(err, "self consensus state not found for height %s", consensusHeight.String()) } @@ -221,20 +221,20 @@ func (k Keeper) ConnOpenAck( // Ensure that ChainB stored expected connectionEnd in its state during ConnOpenTry if err := k.VerifyConnectionState( - ctx, connection, proofHeight, proofTry, counterpartyConnectionID, + ctx, connection, proofHeight, tryProof, counterpartyConnectionID, expectedConnection, ); err != nil { return err } // Check that ChainB stored the clientState provided in the msg - if err := k.VerifyClientState(ctx, connection, proofHeight, proofClient, clientState); err != nil { + if err := k.VerifyClientState(ctx, connection, proofHeight, clientProof, clientState); err != nil { return err } // Ensure that ChainB has stored the correct ConsensusState for chainA at the consensusHeight if err := k.VerifyClientConsensusState( - ctx, connection, proofHeight, consensusHeight, proofConsensus, expectedConsensusState, + ctx, connection, proofHeight, consensusHeight, consensusProof, expectedConsensusState, ); err != nil { return err } @@ -261,7 +261,7 @@ func (k Keeper) ConnOpenAck( func (k Keeper) ConnOpenConfirm( ctx sdk.Context, connectionID string, - proofAck []byte, // proof that connection opened on ChainA during ConnOpenAck + ackProof []byte, // proof that connection opened on ChainA during ConnOpenAck proofHeight exported.Height, // height that relayer constructed proofAck ) error { // Retrieve connection @@ -284,7 +284,7 @@ func (k Keeper) ConnOpenConfirm( // Check that connection on ChainA is open if err := k.VerifyConnectionState( - ctx, connection, proofHeight, proofAck, connection.Counterparty.ConnectionId, + ctx, connection, proofHeight, ackProof, connection.Counterparty.ConnectionId, expectedConnection, ); err != nil { return err diff --git a/modules/core/03-connection/keeper/handshake_test.go b/modules/core/03-connection/keeper/handshake_test.go index eaaa0ab3125..dba6f03e448 100644 --- a/modules/core/03-connection/keeper/handshake_test.go +++ b/modules/core/03-connection/keeper/handshake_test.go @@ -3,12 +3,15 @@ package keeper_test import ( "time" + sdk "github.com/cosmos/cosmos-sdk/types" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v8/testing" + "github.com/cosmos/ibc-go/v8/testing/mock" ) // TestConnOpenInit - chainA initializes (INIT state) a connection with @@ -218,6 +221,21 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { err := path.EndpointA.ConnOpenInit() suite.Require().NoError(err) }, false}, + {"override self consensus host", func() { + err := path.EndpointA.ConnOpenInit() + suite.Require().NoError(err) + + // retrieve client state of chainA to pass as counterpartyClient + counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID) + + mockValidator := mock.ConsensusHost{ + ValidateSelfClientFn: func(ctx sdk.Context, clientState exported.ClientState) error { + return mock.MockApplicationCallbackError + }, + } + + suite.chainB.App.GetIBCKeeper().SetConsensusHost(&mockValidator) + }, false}, } for _, tc := range testCases { @@ -240,22 +258,22 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { suite.Require().NoError(err) connectionKey := host.ConnectionKey(path.EndpointA.ConnectionID) - proofInit, proofHeight := suite.chainA.QueryProof(connectionKey) + initProof, proofHeight := suite.chainA.QueryProof(connectionKey) if consensusHeight.IsZero() { // retrieve consensus state height to provide proof for consensusHeight = counterpartyClient.GetLatestHeight() } consensusKey := host.FullConsensusStateKey(path.EndpointA.ClientID, consensusHeight) - proofConsensus, _ := suite.chainA.QueryProof(consensusKey) + consensusProof, _ := suite.chainA.QueryProof(consensusKey) // retrieve proof of counterparty clientstate on chainA clientKey := host.FullClientStateKey(path.EndpointA.ClientID) - proofClient, _ := suite.chainA.QueryProof(clientKey) + clientProof, _ := suite.chainA.QueryProof(clientKey) connectionID, err := suite.chainB.App.GetIBCKeeper().ConnectionKeeper.ConnOpenTry( suite.chainB.GetContext(), counterparty, delayPeriod, path.EndpointB.ClientID, counterpartyClient, - versions, proofInit, proofClient, proofConsensus, + versions, initProof, clientProof, consensusProof, proofHeight, consensusHeight, ) @@ -491,7 +509,7 @@ func (suite *KeeperTestSuite) TestConnOpenAck() { suite.Require().NoError(err) connectionKey := host.ConnectionKey(path.EndpointB.ConnectionID) - proofTry, proofHeight := suite.chainB.QueryProof(connectionKey) + tryProof, proofHeight := suite.chainB.QueryProof(connectionKey) if consensusHeight.IsZero() { // retrieve consensus state height to provide proof for @@ -499,15 +517,15 @@ func (suite *KeeperTestSuite) TestConnOpenAck() { consensusHeight = clientState.GetLatestHeight() } consensusKey := host.FullConsensusStateKey(path.EndpointB.ClientID, consensusHeight) - proofConsensus, _ := suite.chainB.QueryProof(consensusKey) + consensusProof, _ := suite.chainB.QueryProof(consensusKey) // retrieve proof of counterparty clientstate on chainA clientKey := host.FullClientStateKey(path.EndpointB.ClientID) - proofClient, _ := suite.chainB.QueryProof(clientKey) + clientProof, _ := suite.chainB.QueryProof(clientKey) err = suite.chainA.App.GetIBCKeeper().ConnectionKeeper.ConnOpenAck( suite.chainA.GetContext(), path.EndpointA.ConnectionID, counterpartyClient, version, path.EndpointB.ConnectionID, - proofTry, proofClient, proofConsensus, proofHeight, consensusHeight, + tryProof, clientProof, consensusProof, proofHeight, consensusHeight, ) if tc.expPass { @@ -570,10 +588,10 @@ func (suite *KeeperTestSuite) TestConnOpenConfirm() { suite.Require().NoError(err) connectionKey := host.ConnectionKey(path.EndpointA.ConnectionID) - proofAck, proofHeight := suite.chainA.QueryProof(connectionKey) + ackProof, proofHeight := suite.chainA.QueryProof(connectionKey) err = suite.chainB.App.GetIBCKeeper().ConnectionKeeper.ConnOpenConfirm( - suite.chainB.GetContext(), path.EndpointB.ConnectionID, proofAck, proofHeight, + suite.chainB.GetContext(), path.EndpointB.ConnectionID, ackProof, proofHeight, ) if tc.expPass { diff --git a/modules/core/03-connection/keeper/keeper.go b/modules/core/03-connection/keeper/keeper.go index cd18555f56e..6bb3af463dc 100644 --- a/modules/core/03-connection/keeper/keeper.go +++ b/modules/core/03-connection/keeper/keeper.go @@ -2,6 +2,7 @@ package keeper import ( "errors" + "fmt" errorsmod "cosmossdk.io/errors" "cosmossdk.io/log" @@ -26,6 +27,7 @@ type Keeper struct { legacySubspace types.ParamSubspace cdc codec.BinaryCodec clientKeeper types.ClientKeeper + consensusHost clienttypes.ConsensusHost } // NewKeeper creates a new IBC connection Keeper instance @@ -43,6 +45,15 @@ func (Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", "x/"+exported.ModuleName+"/"+types.SubModuleName) } +// SetConsensusHost sets a custom ConsensusHost for self client state and consensus state validation. +func (k *Keeper) SetConsensusHost(consensusHost clienttypes.ConsensusHost) { + if consensusHost == nil { + panic(fmt.Errorf("cannot set a nil self consensus host")) + } + + k.consensusHost = consensusHost +} + // GetCommitmentPrefix returns the IBC connection store prefix as a commitment // Prefix func (k Keeper) GetCommitmentPrefix() exported.Prefix { diff --git a/modules/core/03-connection/keeper/verify.go b/modules/core/03-connection/keeper/verify.go index bee3d460903..6b5b035a06e 100644 --- a/modules/core/03-connection/keeper/verify.go +++ b/modules/core/03-connection/keeper/verify.go @@ -366,6 +366,90 @@ func (k Keeper) VerifyNextSequenceRecv( return nil } +// VerifyChannelUpgradeError verifies a proof of the provided upgrade error receipt. +func (k Keeper) VerifyChannelUpgradeError( + ctx sdk.Context, + connection exported.ConnectionI, + height exported.Height, + proof []byte, + portID, + channelID string, + errorReceipt channeltypes.ErrorReceipt, +) error { + clientID := connection.GetClientID() + clientState, clientStore, err := k.getClientStateAndVerificationStore(ctx, clientID) + if err != nil { + return err + } + + if status := k.clientKeeper.GetClientStatus(ctx, clientState, clientID); status != exported.Active { + return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + } + + merklePath := commitmenttypes.NewMerklePath(host.ChannelUpgradeErrorPath(portID, channelID)) + merklePath, err = commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) + if err != nil { + return err + } + + bz, err := k.cdc.Marshal(&errorReceipt) + if err != nil { + return err + } + + if err := clientState.VerifyMembership( + ctx, clientStore, k.cdc, height, + 0, 0, // skip delay period checks for non-packet processing verification + proof, merklePath, bz, + ); err != nil { + return errorsmod.Wrapf(err, "failed upgrade error receipt verification for client (%s)", clientID) + } + + return nil +} + +// VerifyChannelUpgrade verifies the proof that a particular proposed upgrade has been stored in the upgrade path. +func (k Keeper) VerifyChannelUpgrade( + ctx sdk.Context, + connection exported.ConnectionI, + proofHeight exported.Height, + upgradeProof []byte, + portID, + channelID string, + upgrade channeltypes.Upgrade, +) error { + clientID := connection.GetClientID() + clientState, clientStore, err := k.getClientStateAndVerificationStore(ctx, clientID) + if err != nil { + return err + } + + if status := k.clientKeeper.GetClientStatus(ctx, clientState, clientID); status != exported.Active { + return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + } + + merklePath := commitmenttypes.NewMerklePath(host.ChannelUpgradePath(portID, channelID)) + merklePath, err = commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) + if err != nil { + return err + } + + bz, err := k.cdc.Marshal(&upgrade) + if err != nil { + return err + } + + if err := clientState.VerifyMembership( + ctx, clientStore, k.cdc, proofHeight, + 0, 0, // skip delay period checks for non-packet processing verification + upgradeProof, merklePath, bz, + ); err != nil { + return errorsmod.Wrapf(err, "failed upgrade verification for client (%s) on channel (%s)", clientID, channelID) + } + + return nil +} + // getBlockDelay calculates the block delay period from the time delay of the connection // and the maximum expected time per block. func (k Keeper) getBlockDelay(ctx sdk.Context, connection exported.ConnectionI) uint64 { diff --git a/modules/core/03-connection/keeper/verify_test.go b/modules/core/03-connection/keeper/verify_test.go index c42fb0e044b..8a8dd958b65 100644 --- a/modules/core/03-connection/keeper/verify_test.go +++ b/modules/core/03-connection/keeper/verify_test.go @@ -681,6 +681,168 @@ func (suite *KeeperTestSuite) TestVerifyNextSequenceRecv() { } } +func (suite *KeeperTestSuite) TestVerifyUpgradeErrorReceipt() { + var ( + path *ibctesting.Path + upgradeError *channeltypes.UpgradeError + ) + + cases := []struct { + name string + malleate func() + expPass bool + }{ + { + name: "success", + malleate: func() {}, + expPass: true, + }, + { + name: "fails when client state is frozen", + malleate: func() { + clientState := path.EndpointB.GetClientState().(*ibctm.ClientState) + clientState.FrozenHeight = clienttypes.NewHeight(0, 1) + path.EndpointB.SetClientState(clientState) + }, + expPass: false, + }, + { + name: "fails with bad client id", + malleate: func() { + connection := path.EndpointB.GetConnection() + connection.ClientId = ibctesting.InvalidID + path.EndpointB.SetConnection(connection) + }, + expPass: false, + }, + { + name: "verification fails when the key does not exist", + malleate: func() { + suite.chainA.DeleteKey(host.ChannelUpgradeErrorKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + suite.coordinator.CommitBlock(suite.chainA) + }, + expPass: false, + }, + { + name: "verification fails when message differs", + malleate: func() { + originalSequence := upgradeError.GetErrorReceipt().Sequence + upgradeError = channeltypes.NewUpgradeError(originalSequence, fmt.Errorf("new error")) + }, + expPass: false, + }, + } + + for _, tc := range cases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + upgradeError = channeltypes.NewUpgradeError(1, channeltypes.ErrInvalidChannel) + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.WriteErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, upgradeError) + + suite.chainA.Coordinator.CommitBlock(suite.chainA) + suite.Require().NoError(path.EndpointB.UpdateClient()) + + tc.malleate() + + upgradeErrorReceiptKey := host.ChannelUpgradeErrorKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + proof, proofHeight := suite.chainA.QueryProof(upgradeErrorReceiptKey) + + err := suite.chainB.GetSimApp().IBCKeeper.ConnectionKeeper.VerifyChannelUpgradeError(suite.chainB.GetContext(), path.EndpointB.GetConnection(), proofHeight, proof, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, upgradeError.GetErrorReceipt()) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestVerifyUpgrade() { + var ( + path *ibctesting.Path + upgrade channeltypes.Upgrade + ) + + cases := []struct { + name string + malleate func() + expPass bool + }{ + { + name: "success", + malleate: func() {}, + expPass: true, + }, + { + name: "fails when client state is frozen", + malleate: func() { + clientState := path.EndpointB.GetClientState().(*ibctm.ClientState) + clientState.FrozenHeight = clienttypes.NewHeight(0, 1) + path.EndpointB.SetClientState(clientState) + }, + expPass: false, + }, + { + name: "fails with bad client id", + malleate: func() { + connection := path.EndpointB.GetConnection() + connection.ClientId = ibctesting.InvalidID + path.EndpointB.SetConnection(connection) + }, + expPass: false, + }, + { + name: "fails when the upgrade field is different", + malleate: func() { + upgrade.Fields.Ordering = channeltypes.ORDERED + }, + expPass: false, + }, + } + + for _, tc := range cases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + upgrade = channeltypes.NewUpgrade( + channeltypes.NewUpgradeFields(channeltypes.UNORDERED, []string{path.EndpointA.ConnectionID}, "v1.0.0"), + channeltypes.NewTimeout(clienttypes.ZeroHeight(), 100000), + 0, + ) + + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, upgrade) + + suite.chainA.Coordinator.CommitBlock(suite.chainA) + suite.Require().NoError(path.EndpointB.UpdateClient()) + + tc.malleate() + + channelUpgradeKey := host.ChannelUpgradeKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + proof, proofHeight := suite.chainA.QueryProof(channelUpgradeKey) + + err := suite.chainB.GetSimApp().IBCKeeper.ConnectionKeeper.VerifyChannelUpgrade(suite.chainB.GetContext(), path.EndpointB.GetConnection(), proofHeight, proof, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, upgrade) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + func malleateHeight(height exported.Height, diff uint64) exported.Height { return clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+diff) } diff --git a/modules/core/03-connection/types/msgs.go b/modules/core/03-connection/types/msgs.go index c46c783767e..9d8db1fb548 100644 --- a/modules/core/03-connection/types/msgs.go +++ b/modules/core/03-connection/types/msgs.go @@ -89,7 +89,7 @@ func NewMsgConnectionOpenTry( counterpartyClient exported.ClientState, counterpartyPrefix commitmenttypes.MerklePrefix, counterpartyVersions []*Version, delayPeriod uint64, - proofInit, proofClient, proofConsensus []byte, + initProof, clientProof, consensusProof []byte, proofHeight, consensusHeight clienttypes.Height, signer string, ) *MsgConnectionOpenTry { counterparty := NewCounterparty(counterpartyClientID, counterpartyConnectionID, counterpartyPrefix) @@ -100,9 +100,9 @@ func NewMsgConnectionOpenTry( Counterparty: counterparty, CounterpartyVersions: counterpartyVersions, DelayPeriod: delayPeriod, - ProofInit: proofInit, - ProofClient: proofClient, - ProofConsensus: proofConsensus, + ProofInit: initProof, + ProofClient: clientProof, + ProofConsensus: consensusProof, ProofHeight: proofHeight, ConsensusHeight: consensusHeight, Signer: signer, @@ -179,7 +179,7 @@ func (msg MsgConnectionOpenTry) GetSigners() []sdk.AccAddress { // NewMsgConnectionOpenAck creates a new MsgConnectionOpenAck instance func NewMsgConnectionOpenAck( connectionID, counterpartyConnectionID string, counterpartyClient exported.ClientState, - proofTry, proofClient, proofConsensus []byte, + tryProof, clientProof, consensusProof []byte, proofHeight, consensusHeight clienttypes.Height, version *Version, signer string, @@ -189,9 +189,9 @@ func NewMsgConnectionOpenAck( ConnectionId: connectionID, CounterpartyConnectionId: counterpartyConnectionID, ClientState: protoAny, - ProofTry: proofTry, - ProofClient: proofClient, - ProofConsensus: proofConsensus, + ProofTry: tryProof, + ProofClient: clientProof, + ProofConsensus: consensusProof, ProofHeight: proofHeight, ConsensusHeight: consensusHeight, Version: version, @@ -255,12 +255,12 @@ func (msg MsgConnectionOpenAck) GetSigners() []sdk.AccAddress { // NewMsgConnectionOpenConfirm creates a new MsgConnectionOpenConfirm instance func NewMsgConnectionOpenConfirm( - connectionID string, proofAck []byte, proofHeight clienttypes.Height, + connectionID string, ackProof []byte, proofHeight clienttypes.Height, signer string, ) *MsgConnectionOpenConfirm { return &MsgConnectionOpenConfirm{ ConnectionId: connectionID, - ProofAck: proofAck, + ProofAck: ackProof, ProofHeight: proofHeight, Signer: signer, } diff --git a/modules/core/04-channel/client/cli/cli.go b/modules/core/04-channel/client/cli/cli.go index 0a2ed6313a7..202d63e9238 100644 --- a/modules/core/04-channel/client/cli/cli.go +++ b/modules/core/04-channel/client/cli/cli.go @@ -31,6 +31,9 @@ func GetQueryCmd() *cobra.Command { GetCmdQueryUnreceivedAcks(), GetCmdQueryNextSequenceReceive(), GetCmdQueryNextSequenceSend(), + GetCmdQueryUpgradeError(), + GetCmdQueryUpgrade(), + GetCmdChannelParams(), ) return queryCmd @@ -46,7 +49,10 @@ func NewTxCmd() *cobra.Command { RunE: client.ValidateCmd, } - txCmd.AddCommand() + txCmd.AddCommand( + newUpgradeChannelsTxCmd(), + newPruneAcknowledgementsTxCmd(), + ) return txCmd } diff --git a/modules/core/04-channel/client/cli/query.go b/modules/core/04-channel/client/cli/query.go index f255e620ab1..8872b594b49 100644 --- a/modules/core/04-channel/client/cli/query.go +++ b/modules/core/04-channel/client/cli/query.go @@ -491,3 +491,96 @@ func GetCmdQueryNextSequenceSend() *cobra.Command { return cmd } + +// GetCmdQueryUpgradeError defines the command to query for the error receipt associated with an upgrade +func GetCmdQueryUpgradeError() *cobra.Command { + cmd := &cobra.Command{ + Use: "upgrade-error [port-id] [channel-id]", + Short: "Query the upgrade error", + Long: "Query the upgrade error for a given channel", + Example: fmt.Sprintf( + "%s query %s %s upgrade-error [port-id] [channel-id]", version.AppName, ibcexported.ModuleName, types.SubModuleName, + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + portID := args[0] + channelID := args[1] + prove, _ := cmd.Flags().GetBool(flags.FlagProve) + + errRes, err := utils.QueryUpgradeError(clientCtx, portID, channelID, prove) + if err != nil { + return err + } + + clientCtx = clientCtx.WithHeight(int64(errRes.ProofHeight.RevisionHeight)) + return clientCtx.PrintProto(errRes) + }, + } + cmd.Flags().Bool(flags.FlagProve, true, "show proofs for the query results") + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// GetCmdQueryUpgrade defines the command to query for the upgrade associated with a port and channel id +func GetCmdQueryUpgrade() *cobra.Command { + cmd := &cobra.Command{ + Use: "upgrade [port-id] [channel-id]", + Short: "Query the upgrade", + Long: "Query the upgrade for a given channel", + Example: fmt.Sprintf( + "%s query %s %s upgrade [port-id] [channel-id]", version.AppName, ibcexported.ModuleName, types.SubModuleName, + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + portID := args[0] + channelID := args[1] + prove, _ := cmd.Flags().GetBool(flags.FlagProve) + + upgrade, err := utils.QueryUpgrade(clientCtx, portID, channelID, prove) + if err != nil { + return err + } + + clientCtx = clientCtx.WithHeight(int64(upgrade.ProofHeight.RevisionHeight)) + return clientCtx.PrintProto(upgrade) + }, + } + cmd.Flags().Bool(flags.FlagProve, false, "show proofs for the query results") + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// GetCmdChannelParams returns the command handler for ibc channel parameter querying. +func GetCmdChannelParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "params", + Short: "Query the current ibc channel parameters", + Long: "Query the current ibc channel parameters", + Args: cobra.NoArgs, + Example: fmt.Sprintf("%s query %s %s params", version.AppName, ibcexported.ModuleName, types.SubModuleName), + RunE: func(cmd *cobra.Command, _ []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + res, _ := queryClient.ChannelParams(cmd.Context(), &types.QueryChannelParamsRequest{}) + return clientCtx.PrintProto(res.Params) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/modules/core/04-channel/client/cli/tx.go b/modules/core/04-channel/client/cli/tx.go new file mode 100644 index 00000000000..4763ebe149c --- /dev/null +++ b/modules/core/04-channel/client/cli/tx.go @@ -0,0 +1,175 @@ +package cli + +import ( + "fmt" + "regexp" + "slices" + "strconv" + "strings" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/version" + govcli "github.com/cosmos/cosmos-sdk/x/gov/client/cli" + + "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" +) + +const ( + flagJSON = "json" + flagPortPattern = "port-pattern" + flagExpedited = "expedited" + flagChannelIDs = "channel-ids" +) + +// newPruneAcknowledgementsTxCmd returns the command to create a new MsgPruneAcknowledgements transaction +func newPruneAcknowledgementsTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "prune-acknowledgements [port] [channel] [limit]", + Short: "Prune expired packet acknowledgements stored in IBC state", + Long: `Prune expired packet acknowledgements and receipts stored in IBC state. Packet ackwnowledgements and + receipts are considered expired if a channel has been upgraded.`, + Example: fmt.Sprintf("%s tx %s %s prune-acknowledgements transfer channel-0 1000", version.AppName, ibcexported.ModuleName, types.SubModuleName), + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + portID, channelID := args[0], args[1] + limit, err := strconv.ParseUint(args[2], 10, 64) + if err != nil { + return err + } + + signer := clientCtx.GetFromAddress().String() + msg := types.NewMsgPruneAcknowledgements(portID, channelID, limit, signer) + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +func newUpgradeChannelsTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "upgrade-channels", + Short: "Upgrade IBC channels", + Long: `Submit a governance proposal to upgrade all open channels whose port matches a specified pattern +(the default is transfer), optionally, an exact list of comma separated channel IDs may be specified.`, + Args: cobra.ExactArgs(1), + Example: fmt.Sprintf(`%s tx %s %s upgrade-channels "{\"fee_version\":\"ics29-1\",\"app_version\":\"ics20-1\"}" --deposit 10stake`, version.AppName, ibcexported.ModuleName, types.SubModuleName), + RunE: func(cmd *cobra.Command, args []string) error { + versionStr := args[0] + + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + portPattern, err := cmd.Flags().GetString(flagPortPattern) + if err != nil { + return err + } + + commaSeparatedChannelIDs, err := cmd.Flags().GetString(flagChannelIDs) + if err != nil { + return err + } + + displayJSON, err := cmd.Flags().GetBool(flagJSON) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + resp, err := queryClient.Channels(cmd.Context(), &types.QueryChannelsRequest{}) + if err != nil { + return err + } + + channelIDs := getChannelIDs(commaSeparatedChannelIDs) + + var msgs []sdk.Msg + pattern := regexp.MustCompile(portPattern) + + for _, ch := range resp.Channels { + + if !channelShouldBeUpgraded(*ch, pattern, channelIDs) { + continue + } + + // construct a MsgChannelUpgradeInit which will upgrade the specified channel to a specific version. + msgUpgradeInit := types.NewMsgChannelUpgradeInit(ch.PortId, ch.ChannelId, types.NewUpgradeFields(ch.Ordering, ch.ConnectionHops, versionStr), clientCtx.GetFromAddress().String()) + msgs = append(msgs, msgUpgradeInit) + } + + if len(msgs) == 0 { + return fmt.Errorf("no channels would be upgraded with pattern %s", portPattern) + } + + msgSubmitProposal, err := govcli.ReadGovPropFlags(clientCtx, cmd.Flags()) + if err != nil { + return err + } + + if err := msgSubmitProposal.SetMsgs(msgs); err != nil { + return err + } + + dryRun, _ := cmd.Flags().GetBool(flags.FlagDryRun) + if displayJSON || dryRun { + out, err := clientCtx.Codec.MarshalJSON(msgSubmitProposal) + if err != nil { + return err + } + return clientCtx.PrintBytes(out) + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msgSubmitProposal) + }, + } + + flags.AddTxFlagsToCmd(cmd) + govcli.AddGovPropFlagsToCmd(cmd) + cmd.Flags().Bool(flagJSON, false, "specify true to output valid proposal.json contents, instead of submitting a governance proposal.") + cmd.Flags().String(flagPortPattern, "transfer", "The pattern to use to match port ids.") + cmd.Flags().String(flagChannelIDs, "", "a comma separated list of channel IDs to upgrade.") + cmd.Flags().Bool(flagExpedited, false, "set the expedited value for the governance proposal.") + + return cmd +} + +// getChannelIDs returns a slice of channel IDs based on a comma separated string of channel IDs. +func getChannelIDs(commaSeparatedList string) []string { + if strings.TrimSpace(commaSeparatedList) == "" { + return nil + } + return strings.Split(commaSeparatedList, ",") +} + +// channelShouldBeUpgraded returns a boolean indicating whether or not the given channel should be upgraded based +// on either the provided regex pattern or list of desired channel IDs. +func channelShouldBeUpgraded(channel types.IdentifiedChannel, pattern *regexp.Regexp, channelIDs []string) bool { + // skip any channel that is not open + if channel.State != types.OPEN { + return false + } + + // if specified, the channel ID must exactly match. + if len(channelIDs) > 0 { + return pattern.MatchString(channel.PortId) && slices.Contains(channelIDs, channel.ChannelId) + } + + // otherwise we only need the port pattern to match. + return pattern.MatchString(channel.PortId) +} diff --git a/modules/core/04-channel/client/utils/utils.go b/modules/core/04-channel/client/utils/utils.go index 6fd5a1b1cfc..c5118aa0011 100644 --- a/modules/core/04-channel/client/utils/utils.go +++ b/modules/core/04-channel/client/utils/utils.go @@ -231,6 +231,92 @@ func queryNextSequenceSendABCI(clientCtx client.Context, portID, channelID strin return types.NewQueryNextSequenceSendResponse(sequence, proofBz, proofHeight), nil } +// QueryUpgradeError returns the upgrade error. +// If prove is true, it performs an ABCI store query in order to retrieve the merkle proof. Otherwise, +// it uses the gRPC query client. +func QueryUpgradeError( + clientCtx client.Context, portID, channelID string, prove bool, +) (*types.QueryUpgradeErrorResponse, error) { + if prove { + return queryUpgradeErrorABCI(clientCtx, portID, channelID) + } + + queryClient := types.NewQueryClient(clientCtx) + req := &types.QueryUpgradeErrorRequest{ + PortId: portID, + ChannelId: channelID, + } + + return queryClient.UpgradeError(context.Background(), req) +} + +// QueryUpgrade returns the upgrade. +// If prove is true, it performs an ABCI store query in order to retrieve the merkle proof. Otherwise, +// it uses the gRPC query client. +func QueryUpgrade( + clientCtx client.Context, portID, channelID string, prove bool, +) (*types.QueryUpgradeResponse, error) { + if prove { + return queryUpgradeABCI(clientCtx, portID, channelID) + } + + queryClient := types.NewQueryClient(clientCtx) + req := &types.QueryUpgradeRequest{ + PortId: portID, + ChannelId: channelID, + } + + return queryClient.Upgrade(context.Background(), req) +} + +// queryUpgradeErrorABCI queries the upgrade error from the store. +func queryUpgradeErrorABCI(clientCtx client.Context, portID, channelID string) (*types.QueryUpgradeErrorResponse, error) { + key := host.ChannelUpgradeErrorKey(portID, channelID) + + value, proofBz, proofHeight, err := ibcclient.QueryTendermintProof(clientCtx, key) + if err != nil { + return nil, err + } + + // check if upgrade error exists + if len(value) == 0 { + return nil, errorsmod.Wrapf(types.ErrUpgradeErrorNotFound, "portID (%s), channelID (%s)", portID, channelID) + } + + cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) + + var receipt types.ErrorReceipt + if err := cdc.Unmarshal(value, &receipt); err != nil { + return nil, err + } + + return types.NewQueryUpgradeErrorResponse(receipt, proofBz, proofHeight), nil +} + +// queryUpgradeABCI queries the upgrade from the store. +func queryUpgradeABCI(clientCtx client.Context, portID, channelID string) (*types.QueryUpgradeResponse, error) { + key := host.ChannelUpgradeKey(portID, channelID) + + value, proofBz, proofHeight, err := ibcclient.QueryTendermintProof(clientCtx, key) + if err != nil { + return nil, err + } + + // check if upgrade exists + if len(value) == 0 { + return nil, errorsmod.Wrapf(types.ErrUpgradeErrorNotFound, "portID (%s), channelID (%s)", portID, channelID) + } + + cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) + + var upgrade types.Upgrade + if err := cdc.Unmarshal(value, &upgrade); err != nil { + return nil, err + } + + return types.NewQueryUpgradeResponse(upgrade, proofBz, proofHeight), nil +} + // QueryPacketCommitment returns a packet commitment. // If prove is true, it performs an ABCI store query in order to retrieve the merkle proof. Otherwise, // it uses the gRPC query client. diff --git a/modules/core/04-channel/genesis.go b/modules/core/04-channel/genesis.go index 48680d962cd..42481e558c1 100644 --- a/modules/core/04-channel/genesis.go +++ b/modules/core/04-channel/genesis.go @@ -1,6 +1,8 @@ package channel import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/v8/modules/core/04-channel/keeper" @@ -10,6 +12,10 @@ import ( // InitGenesis initializes the ibc channel submodule's state from a provided genesis // state. func InitGenesis(ctx sdk.Context, k keeper.Keeper, gs types.GenesisState) { + if err := gs.Params.Validate(); err != nil { + panic(fmt.Sprintf("invalid ibc channel genesis state parameters: %v", err)) + } + k.SetParams(ctx, gs.Params) for _, channel := range gs.Channels { ch := types.NewChannel(channel.State, channel.Ordering, channel.Counterparty, channel.ConnectionHops, channel.Version) k.SetChannel(ctx, channel.PortId, channel.ChannelId, ch) @@ -46,5 +52,6 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) types.GenesisState { RecvSequences: k.GetAllPacketRecvSeqs(ctx), AckSequences: k.GetAllPacketAckSeqs(ctx), NextChannelSequence: k.GetNextChannelSequence(ctx), + Params: k.GetParams(ctx), } } diff --git a/modules/core/04-channel/keeper/ante.go b/modules/core/04-channel/keeper/ante.go new file mode 100644 index 00000000000..ac387569c68 --- /dev/null +++ b/modules/core/04-channel/keeper/ante.go @@ -0,0 +1,24 @@ +package keeper + +import ( + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" +) + +// RecvPacketReCheckTx applies replay protection ensuring that when relay messages are +// re-executed in ReCheckTx, we can appropriately filter out redundant relay transactions. +func (k *Keeper) RecvPacketReCheckTx(ctx sdk.Context, packet types.Packet) error { + channel, found := k.GetChannel(ctx, packet.GetDestPort(), packet.GetDestChannel()) + if !found { + return errorsmod.Wrap(types.ErrChannelNotFound, packet.GetDestChannel()) + } + + if err := k.applyReplayProtection(ctx, packet, channel); err != nil { + return err + } + + return nil +} diff --git a/modules/core/04-channel/keeper/ante_test.go b/modules/core/04-channel/keeper/ante_test.go new file mode 100644 index 00000000000..95831d50edd --- /dev/null +++ b/modules/core/04-channel/keeper/ante_test.go @@ -0,0 +1,64 @@ +package keeper_test + +import ( + "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v8/testing" +) + +func (suite *KeeperTestSuite) TestRecvPacketReCheckTx() { + var ( + path *ibctesting.Path + packet types.Packet + ) + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + "channel not found", + func() { + packet.DestinationPort = "invalid-port" //nolint:goconst + }, + types.ErrChannelNotFound, + }, + { + "redundant relay", + func() { + err := suite.chainB.App.GetIBCKeeper().ChannelKeeper.RecvPacketReCheckTx(suite.chainB.GetContext(), packet) + suite.Require().NoError(err) + }, + types.ErrNoOpMsg, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() // reset + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + + tc.malleate() + + err = suite.chainB.App.GetIBCKeeper().ChannelKeeper.RecvPacketReCheckTx(suite.chainB.GetContext(), packet) + + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err) + } else { + suite.Require().ErrorIs(err, tc.expError) + } + }) + } +} diff --git a/modules/core/04-channel/keeper/events.go b/modules/core/04-channel/keeper/events.go index 3d86db32d9f..486630f36a6 100644 --- a/modules/core/04-channel/keeper/events.go +++ b/modules/core/04-channel/keeper/events.go @@ -270,3 +270,188 @@ func emitChannelClosedEvent(ctx sdk.Context, packet exported.PacketI, channel ty ), }) } + +// EmitChannelUpgradeInitEvent emits a channel upgrade init event +func EmitChannelUpgradeInitEvent(ctx sdk.Context, portID string, channelID string, currentChannel types.Channel, upgrade types.Upgrade) { + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelUpgradeInit, + sdk.NewAttribute(types.AttributeKeyPortID, portID), + sdk.NewAttribute(types.AttributeKeyChannelID, channelID), + sdk.NewAttribute(types.AttributeCounterpartyPortID, currentChannel.Counterparty.PortId), + sdk.NewAttribute(types.AttributeCounterpartyChannelID, currentChannel.Counterparty.ChannelId), + sdk.NewAttribute(types.AttributeKeyConnectionHops, upgrade.Fields.ConnectionHops[0]), + sdk.NewAttribute(types.AttributeVersion, upgrade.Fields.Version), + sdk.NewAttribute(types.AttributeKeyOrdering, upgrade.Fields.Ordering.String()), + sdk.NewAttribute(types.AttributeKeyUpgradeSequence, fmt.Sprintf("%d", currentChannel.UpgradeSequence)), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) +} + +// EmitChannelUpgradeTryEvent emits a channel upgrade try event +func EmitChannelUpgradeTryEvent(ctx sdk.Context, portID string, channelID string, currentChannel types.Channel, upgrade types.Upgrade) { + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelUpgradeTry, + sdk.NewAttribute(types.AttributeKeyPortID, portID), + sdk.NewAttribute(types.AttributeKeyChannelID, channelID), + sdk.NewAttribute(types.AttributeCounterpartyPortID, currentChannel.Counterparty.PortId), + sdk.NewAttribute(types.AttributeCounterpartyChannelID, currentChannel.Counterparty.ChannelId), + sdk.NewAttribute(types.AttributeKeyConnectionHops, upgrade.Fields.ConnectionHops[0]), + sdk.NewAttribute(types.AttributeVersion, upgrade.Fields.Version), + sdk.NewAttribute(types.AttributeKeyOrdering, upgrade.Fields.Ordering.String()), + sdk.NewAttribute(types.AttributeKeyUpgradeSequence, fmt.Sprintf("%d", currentChannel.UpgradeSequence)), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) +} + +// EmitChannelUpgradeAckEvent emits a channel upgrade ack event +func EmitChannelUpgradeAckEvent(ctx sdk.Context, portID string, channelID string, currentChannel types.Channel, upgrade types.Upgrade) { + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelUpgradeAck, + sdk.NewAttribute(types.AttributeKeyPortID, portID), + sdk.NewAttribute(types.AttributeKeyChannelID, channelID), + sdk.NewAttribute(types.AttributeCounterpartyPortID, currentChannel.Counterparty.PortId), + sdk.NewAttribute(types.AttributeCounterpartyChannelID, currentChannel.Counterparty.ChannelId), + sdk.NewAttribute(types.AttributeKeyConnectionHops, upgrade.Fields.ConnectionHops[0]), + sdk.NewAttribute(types.AttributeVersion, upgrade.Fields.Version), + sdk.NewAttribute(types.AttributeKeyOrdering, upgrade.Fields.Ordering.String()), + sdk.NewAttribute(types.AttributeKeyUpgradeSequence, fmt.Sprintf("%d", currentChannel.UpgradeSequence)), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) +} + +// EmitChannelUpgradeConfirmEvent emits a channel upgrade confirm event +func EmitChannelUpgradeConfirmEvent(ctx sdk.Context, portID, channelID string, currentChannel types.Channel) { + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelUpgradeConfirm, + sdk.NewAttribute(types.AttributeKeyPortID, portID), + sdk.NewAttribute(types.AttributeKeyChannelID, channelID), + sdk.NewAttribute(types.AttributeKeyChannelState, currentChannel.State.String()), + sdk.NewAttribute(types.AttributeCounterpartyPortID, currentChannel.Counterparty.PortId), + sdk.NewAttribute(types.AttributeCounterpartyChannelID, currentChannel.Counterparty.ChannelId), + sdk.NewAttribute(types.AttributeKeyUpgradeSequence, fmt.Sprintf("%d", currentChannel.UpgradeSequence)), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) +} + +// EmitChannelUpgradeOpenEvent emits a channel upgrade open event +func EmitChannelUpgradeOpenEvent(ctx sdk.Context, portID string, channelID string, currentChannel types.Channel) { + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelUpgradeOpen, + sdk.NewAttribute(types.AttributeKeyPortID, portID), + sdk.NewAttribute(types.AttributeKeyChannelID, channelID), + sdk.NewAttribute(types.AttributeKeyChannelState, currentChannel.State.String()), + sdk.NewAttribute(types.AttributeCounterpartyPortID, currentChannel.Counterparty.PortId), + sdk.NewAttribute(types.AttributeCounterpartyChannelID, currentChannel.Counterparty.ChannelId), + sdk.NewAttribute(types.AttributeKeyConnectionHops, currentChannel.ConnectionHops[0]), + sdk.NewAttribute(types.AttributeVersion, currentChannel.Version), + sdk.NewAttribute(types.AttributeKeyOrdering, currentChannel.Ordering.String()), + sdk.NewAttribute(types.AttributeKeyUpgradeSequence, fmt.Sprintf("%d", currentChannel.UpgradeSequence)), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) +} + +// EmitChannelUpgradeTimeoutEvent emits an upgrade timeout event. +func EmitChannelUpgradeTimeoutEvent(ctx sdk.Context, portID string, channelID string, currentChannel types.Channel, upgrade types.Upgrade) { + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelUpgradeTimeout, + sdk.NewAttribute(types.AttributeKeyPortID, portID), + sdk.NewAttribute(types.AttributeKeyChannelID, channelID), + sdk.NewAttribute(types.AttributeCounterpartyPortID, currentChannel.Counterparty.PortId), + sdk.NewAttribute(types.AttributeCounterpartyChannelID, currentChannel.Counterparty.ChannelId), + sdk.NewAttribute(types.AttributeKeyConnectionHops, upgrade.Fields.ConnectionHops[0]), + sdk.NewAttribute(types.AttributeVersion, upgrade.Fields.Version), + sdk.NewAttribute(types.AttributeKeyOrdering, upgrade.Fields.Ordering.String()), + sdk.NewAttribute(types.AttributeKeyUpgradeTimeoutHeight, upgrade.Timeout.Height.String()), + sdk.NewAttribute(types.AttributeKeyUpgradeTimeoutTimestamp, fmt.Sprintf("%d", upgrade.Timeout.Timestamp)), + sdk.NewAttribute(types.AttributeKeyUpgradeSequence, fmt.Sprintf("%d", currentChannel.UpgradeSequence)), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) +} + +// EmitErrorReceiptEvent emits an error receipt event +func EmitErrorReceiptEvent(ctx sdk.Context, portID string, channelID string, currentChannel types.Channel, err error) { + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelUpgradeError, + sdk.NewAttribute(types.AttributeKeyPortID, portID), + sdk.NewAttribute(types.AttributeKeyChannelID, channelID), + sdk.NewAttribute(types.AttributeCounterpartyPortID, currentChannel.Counterparty.PortId), + sdk.NewAttribute(types.AttributeCounterpartyChannelID, currentChannel.Counterparty.ChannelId), + sdk.NewAttribute(types.AttributeKeyUpgradeSequence, fmt.Sprintf("%d", currentChannel.UpgradeSequence)), + sdk.NewAttribute(types.AttributeKeyErrorReceipt, err.Error()), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) +} + +// EmitChannelUpgradeCancelEvent emits an upgraded cancelled event. +func EmitChannelUpgradeCancelEvent(ctx sdk.Context, portID string, channelID string, currentChannel types.Channel, upgrade types.Upgrade) { + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelUpgradeCancel, + sdk.NewAttribute(types.AttributeKeyPortID, portID), + sdk.NewAttribute(types.AttributeKeyChannelID, channelID), + sdk.NewAttribute(types.AttributeCounterpartyPortID, currentChannel.Counterparty.PortId), + sdk.NewAttribute(types.AttributeCounterpartyChannelID, currentChannel.Counterparty.ChannelId), + sdk.NewAttribute(types.AttributeKeyConnectionHops, upgrade.Fields.ConnectionHops[0]), + sdk.NewAttribute(types.AttributeVersion, upgrade.Fields.Version), + sdk.NewAttribute(types.AttributeKeyOrdering, upgrade.Fields.Ordering.String()), + sdk.NewAttribute(types.AttributeKeyUpgradeSequence, fmt.Sprintf("%d", currentChannel.UpgradeSequence)), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) +} + +// emitChannelFlushCompleteEvents emits an flushing event. +func emitChannelFlushCompleteEvent(ctx sdk.Context, portID string, channelID string, currentChannel types.Channel) { + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelFlushComplete, + sdk.NewAttribute(types.AttributeKeyPortID, portID), + sdk.NewAttribute(types.AttributeKeyChannelID, channelID), + sdk.NewAttribute(types.AttributeCounterpartyPortID, currentChannel.Counterparty.PortId), + sdk.NewAttribute(types.AttributeCounterpartyChannelID, currentChannel.Counterparty.ChannelId), + sdk.NewAttribute(types.AttributeKeyChannelState, currentChannel.State.String()), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) +} diff --git a/modules/core/04-channel/keeper/export_test.go b/modules/core/04-channel/keeper/export_test.go new file mode 100644 index 00000000000..f6f17f7d931 --- /dev/null +++ b/modules/core/04-channel/keeper/export_test.go @@ -0,0 +1,36 @@ +package keeper + +/* + This file is to allow for unexported functions to be accessible to the testing package. +*/ + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" +) + +// StartFlushing is a wrapper around startFlushing to allow the function to be directly called in tests. +func (k Keeper) StartFlushing(ctx sdk.Context, portID, channelID string, upgrade *types.Upgrade) error { + return k.startFlushing(ctx, portID, channelID, upgrade) +} + +// ValidateSelfUpgradeFields is a wrapper around validateSelfUpgradeFields to allow the function to be directly called in tests. +func (k Keeper) ValidateSelfUpgradeFields(ctx sdk.Context, proposedUpgrade types.UpgradeFields, currentChannel types.Channel) error { + return k.validateSelfUpgradeFields(ctx, proposedUpgrade, currentChannel) +} + +// CheckForUpgradeCompatibility is a wrapper around checkForUpgradeCompatibility to allow the function to be directly called in tests. +func (k Keeper) CheckForUpgradeCompatibility(ctx sdk.Context, upgradeFields, counterpartyUpgradeFields types.UpgradeFields) error { + return k.checkForUpgradeCompatibility(ctx, upgradeFields, counterpartyUpgradeFields) +} + +// SetUpgradeErrorReceipt is a wrapper around setUpgradeErrorReceipt to allow the function to be directly called in tests. +func (k Keeper) SetUpgradeErrorReceipt(ctx sdk.Context, portID, channelID string, errorReceipt types.ErrorReceipt) { + k.setUpgradeErrorReceipt(ctx, portID, channelID, errorReceipt) +} + +// SetRecvStartSequence is a wrapper around setRecvStartSequence to allow the function to be directly called in tests. +func (k Keeper) SetRecvStartSequence(ctx sdk.Context, portID, channelID string, sequence uint64) { + k.setRecvStartSequence(ctx, portID, channelID, sequence) +} diff --git a/modules/core/04-channel/keeper/grpc_query.go b/modules/core/04-channel/keeper/grpc_query.go index 1802b2f4a1e..130edbc9614 100644 --- a/modules/core/04-channel/keeper/grpc_query.go +++ b/modules/core/04-channel/keeper/grpc_query.go @@ -566,6 +566,78 @@ func (k Keeper) NextSequenceSend(c context.Context, req *types.QueryNextSequence return types.NewQueryNextSequenceSendResponse(sequence, nil, selfHeight), nil } +// UpgradeErrorReceipt implements the Query/UpgradeErrorReceipt gRPC method +func (k Keeper) UpgradeErrorReceipt(c context.Context, req *types.QueryUpgradeErrorRequest) (*types.QueryUpgradeErrorResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + if err := validategRPCRequest(req.PortId, req.ChannelId); err != nil { + return nil, err + } + + ctx := sdk.UnwrapSDKContext(c) + found := k.HasChannel(ctx, req.PortId, req.ChannelId) + if !found { + return nil, status.Error( + codes.NotFound, + errorsmod.Wrapf(types.ErrChannelNotFound, "port-id: %s, channel-id %s", req.PortId, req.ChannelId).Error(), + ) + } + + receipt, found := k.GetUpgradeErrorReceipt(ctx, req.PortId, req.ChannelId) + if !found { + return nil, status.Error( + codes.NotFound, + errorsmod.Wrapf(types.ErrUpgradeErrorNotFound, "port-id %s, channel-id %s", req.PortId, req.ChannelId).Error(), + ) + } + + selfHeight := clienttypes.GetSelfHeight(ctx) + return types.NewQueryUpgradeErrorResponse(receipt, nil, selfHeight), nil +} + +// Upgrade implements the Query/UpgradeSequence gRPC method +func (k Keeper) Upgrade(c context.Context, req *types.QueryUpgradeRequest) (*types.QueryUpgradeResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + if err := validategRPCRequest(req.PortId, req.ChannelId); err != nil { + return nil, err + } + + ctx := sdk.UnwrapSDKContext(c) + found := k.HasChannel(ctx, req.PortId, req.ChannelId) + if !found { + return nil, status.Error( + codes.NotFound, + errorsmod.Wrapf(types.ErrChannelNotFound, "port-id: %s, channel-id %s", req.PortId, req.ChannelId).Error(), + ) + } + + upgrade, found := k.GetUpgrade(ctx, req.PortId, req.ChannelId) + if !found { + return nil, status.Error( + codes.NotFound, + errorsmod.Wrapf(types.ErrUpgradeNotFound, "port-id: %s, channel-id %s", req.PortId, req.ChannelId).Error(), + ) + } + + selfHeight := clienttypes.GetSelfHeight(ctx) + return types.NewQueryUpgradeResponse(upgrade, nil, selfHeight), nil +} + +// ChannelParams implements the Query/ChannelParams gRPC method. +func (k Keeper) ChannelParams(c context.Context, req *types.QueryChannelParamsRequest) (*types.QueryChannelParamsResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + params := k.GetParams(ctx) + + return &types.QueryChannelParamsResponse{ + Params: ¶ms, + }, nil +} + func validategRPCRequest(portID, channelID string) error { if err := host.PortIdentifierValidator(portID); err != nil { return status.Error(codes.InvalidArgument, err.Error()) diff --git a/modules/core/04-channel/keeper/grpc_query_test.go b/modules/core/04-channel/keeper/grpc_query_test.go index 6603c972dc2..6461e07b4c3 100644 --- a/modules/core/04-channel/keeper/grpc_query_test.go +++ b/modules/core/04-channel/keeper/grpc_query_test.go @@ -8,8 +8,10 @@ import ( clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v8/testing" + "github.com/cosmos/ibc-go/v8/testing/mock" ) const doesnotexist = "doesnotexist" @@ -1701,3 +1703,195 @@ func (suite *KeeperTestSuite) TestQueryNextSequenceSend() { }) } } + +func (suite *KeeperTestSuite) TestQueryUpgradeError() { + var ( + req *types.QueryUpgradeErrorRequest + upgradeErr *types.UpgradeError + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = nil + }, + false, + }, + { + "invalid port ID", + func() { + req = &types.QueryUpgradeErrorRequest{ + PortId: "", + ChannelId: "test-channel-id", + } + }, + false, + }, + { + "invalid channel ID", + func() { + req = &types.QueryUpgradeErrorRequest{ + PortId: "test-port-id", + ChannelId: "", + } + }, + false, + }, + { + "channel not found", + func() { + req = &types.QueryUpgradeErrorRequest{ + PortId: "test-port-id", + ChannelId: "test-channel-id", + } + }, + false, + }, + { + "success", + func() { + path := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + upgradeErr = types.NewUpgradeError(uint64(1), fmt.Errorf("test error")) + suite.chainA.App.GetIBCKeeper().ChannelKeeper.WriteErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, upgradeErr) + + req = &types.QueryUpgradeErrorRequest{ + PortId: path.EndpointA.ChannelConfig.PortID, + ChannelId: path.EndpointA.ChannelID, + } + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + tc.malleate() + + ctx := suite.chainA.GetContext() + res, err := suite.chainA.QueryServer.UpgradeError(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(upgradeErr.GetErrorReceipt(), res.ErrorReceipt) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestQueryUpgrade() { + var ( + req *types.QueryUpgradeRequest + expectedUpgrade types.Upgrade + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = nil + }, + false, + }, + { + "invalid port ID", + func() { + req = &types.QueryUpgradeRequest{ + PortId: "", + ChannelId: "test-channel-id", + } + }, + false, + }, + { + "invalid channel ID", + func() { + req = &types.QueryUpgradeRequest{ + PortId: "test-port-id", + ChannelId: "", + } + }, + false, + }, + { + "channel not found", + func() { + req = &types.QueryUpgradeRequest{ + PortId: "test-port-id", + ChannelId: "test-channel-id", + } + }, + false, + }, + { + "upgrade not found", + func() { + storeKey := suite.chainA.GetSimApp().GetKey(exported.StoreKey) + kvStore := suite.chainA.GetContext().KVStore(storeKey) + kvStore.Delete(host.ChannelUpgradeKey(req.PortId, req.ChannelId)) + }, + false, + }, + { + "success", + func() { + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + path := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + expectedUpgrade = types.NewUpgrade( + types.NewUpgradeFields(types.UNORDERED, []string{ibctesting.FirstConnectionID}, mock.Version), + types.NewTimeout(clienttypes.ZeroHeight(), 1000000), + 0, + ) + + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, expectedUpgrade) + + req = &types.QueryUpgradeRequest{ + PortId: path.EndpointA.ChannelConfig.PortID, + ChannelId: path.EndpointA.ChannelID, + } + + tc.malleate() + + ctx := suite.chainA.GetContext() + res, err := suite.chainA.QueryServer.Upgrade(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(expectedUpgrade, res.Upgrade) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestQueryChannelParams() { + ctx := suite.chainA.GetContext() + expParams := types.DefaultParams() + res, _ := suite.chainA.QueryServer.ChannelParams(ctx, &types.QueryChannelParamsRequest{}) + suite.Require().Equal(&expParams, res.Params) +} diff --git a/modules/core/04-channel/keeper/handshake.go b/modules/core/04-channel/keeper/handshake.go index 30420a67270..a3b2389df1f 100644 --- a/modules/core/04-channel/keeper/handshake.go +++ b/modules/core/04-channel/keeper/handshake.go @@ -111,7 +111,7 @@ func (k Keeper) ChanOpenTry( portCap *capabilitytypes.Capability, counterparty types.Counterparty, counterpartyVersion string, - proofInit []byte, + initProof []byte, proofHeight exported.Height, ) (string, *capabilitytypes.Capability, error) { // connection hops only supports a single connection @@ -166,7 +166,7 @@ func (k Keeper) ChanOpenTry( ) if err := k.connectionKeeper.VerifyChannelState( - ctx, connectionEnd, proofHeight, proofInit, + ctx, connectionEnd, proofHeight, initProof, counterparty.PortId, counterparty.ChannelId, expectedChannel, ); err != nil { return "", nil, err @@ -221,7 +221,7 @@ func (k Keeper) ChanOpenAck( chanCap *capabilitytypes.Capability, counterpartyVersion, counterpartyChannelID string, - proofTry []byte, + tryProof []byte, proofHeight exported.Height, ) error { channel, found := k.GetChannel(ctx, portID, channelID) @@ -259,7 +259,7 @@ func (k Keeper) ChanOpenAck( ) return k.connectionKeeper.VerifyChannelState( - ctx, connectionEnd, proofHeight, proofTry, + ctx, connectionEnd, proofHeight, tryProof, channel.Counterparty.PortId, counterpartyChannelID, expectedChannel) } @@ -297,7 +297,7 @@ func (k Keeper) ChanOpenConfirm( portID, channelID string, chanCap *capabilitytypes.Capability, - proofAck []byte, + ackProof []byte, proofHeight exported.Height, ) error { channel, found := k.GetChannel(ctx, portID, channelID) @@ -336,8 +336,10 @@ func (k Keeper) ChanOpenConfirm( counterpartyHops, channel.Version, ) + // NOTE: If the counterparty has initialized an upgrade in the same block as performing the + // ACK handshake step, this channel end will be incapable of opening. return k.connectionKeeper.VerifyChannelState( - ctx, connectionEnd, proofHeight, proofAck, + ctx, connectionEnd, proofHeight, ackProof, channel.Counterparty.PortId, channel.Counterparty.ChannelId, expectedChannel) } @@ -385,7 +387,7 @@ func (k Keeper) ChanCloseInit( return errorsmod.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) } - if channel.IsClosed() { + if channel.State == types.CLOSED { return errorsmod.Wrap(types.ErrInvalidChannelState, "channel is already CLOSED") } @@ -429,8 +431,26 @@ func (k Keeper) ChanCloseConfirm( portID, channelID string, chanCap *capabilitytypes.Capability, - proofInit []byte, + initProof []byte, proofHeight exported.Height, +) error { + return k.ChanCloseConfirmWithCounterpartyUpgradeSequence(ctx, portID, channelID, chanCap, initProof, proofHeight, 0) +} + +// ChanCloseConfirmWithCounterpartyUpgradeSequence is called by the counterparty module to +// close their end of the channel, since the other end has been closed. The difference with +// ChanCloseConfirm is that it accepts an extra argument counterpartyUpgradeSequence that was +// needed for channel upgradability. +// +// This function will be removed in ibc-go v9.0.0 and the API of ChanCloseConfirm will be updated. +func (k Keeper) ChanCloseConfirmWithCounterpartyUpgradeSequence( + ctx sdk.Context, + portID, + channelID string, + chanCap *capabilitytypes.Capability, + initProof []byte, + proofHeight exported.Height, + counterpartyUpgradeSequence uint64, ) error { if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) { return errorsmod.Wrap(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel, port ID (%s) channel ID (%s)") @@ -441,7 +461,7 @@ func (k Keeper) ChanCloseConfirm( return errorsmod.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) } - if channel.IsClosed() { + if channel.State == types.CLOSED { return errorsmod.Wrap(types.ErrInvalidChannelState, "channel is already CLOSED") } @@ -460,13 +480,17 @@ func (k Keeper) ChanCloseConfirm( counterpartyHops := []string{connectionEnd.GetCounterparty().GetConnectionID()} counterparty := types.NewCounterparty(portID, channelID) - expectedChannel := types.NewChannel( - types.CLOSED, channel.Ordering, counterparty, - counterpartyHops, channel.Version, - ) + expectedChannel := types.Channel{ + State: types.CLOSED, + Ordering: channel.Ordering, + Counterparty: counterparty, + ConnectionHops: counterpartyHops, + Version: channel.Version, + UpgradeSequence: counterpartyUpgradeSequence, + } if err := k.connectionKeeper.VerifyChannelState( - ctx, connectionEnd, proofHeight, proofInit, + ctx, connectionEnd, proofHeight, initProof, channel.Counterparty.PortId, channel.Counterparty.ChannelId, expectedChannel, ); err != nil { diff --git a/modules/core/04-channel/keeper/handshake_test.go b/modules/core/04-channel/keeper/handshake_test.go index c775e7e6297..b38bc2d3ad9 100644 --- a/modules/core/04-channel/keeper/handshake_test.go +++ b/modules/core/04-channel/keeper/handshake_test.go @@ -10,6 +10,7 @@ import ( host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v8/testing" + "github.com/cosmos/ibc-go/v8/testing/mock" ) type testCase = struct { @@ -718,9 +719,10 @@ func (suite *KeeperTestSuite) TestChanCloseInit() { // bypassed on chainA by setting the channel state in the ChannelKeeper. func (suite *KeeperTestSuite) TestChanCloseConfirm() { var ( - path *ibctesting.Path - channelCap *capabilitytypes.Capability - heightDiff uint64 + path *ibctesting.Path + channelCap *capabilitytypes.Capability + heightDiff uint64 + counterpartyUpgradeSequence uint64 ) testCases := []testCase{ @@ -794,13 +796,32 @@ func (suite *KeeperTestSuite) TestChanCloseConfirm() { channelCap = capabilitytypes.NewCapability(3) }, false}, + { + "failure: invalid counterparty upgrade sequence", + func() { + suite.coordinator.Setup(path) + channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + + // trigger upgradeInit on B which will bump the counterparty upgrade sequence. + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + err := path.EndpointB.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointA.SetChannelState(types.CLOSED) + suite.Require().NoError(err) + + channelCap = capabilitytypes.NewCapability(3) + }, + false, + }, } for _, tc := range testCases { tc := tc suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { - suite.SetupTest() // reset - heightDiff = 0 // must explicitly be changed + suite.SetupTest() // reset + heightDiff = 0 // must explicitly be changed + counterpartyUpgradeSequence = 0 // must explicitly be changed path = ibctesting.NewPath(suite.chainA, suite.chainB) tc.malleate() @@ -808,9 +829,9 @@ func (suite *KeeperTestSuite) TestChanCloseConfirm() { channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, ibctesting.FirstChannelID) proof, proofHeight := suite.chainA.QueryProof(channelKey) - err := suite.chainB.App.GetIBCKeeper().ChannelKeeper.ChanCloseConfirm( + err := suite.chainB.App.GetIBCKeeper().ChannelKeeper.ChanCloseConfirmWithCounterpartyUpgradeSequence( suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, ibctesting.FirstChannelID, channelCap, - proof, malleateHeight(proofHeight, heightDiff), + proof, malleateHeight(proofHeight, heightDiff), counterpartyUpgradeSequence, ) if tc.expPass { diff --git a/modules/core/04-channel/keeper/keeper.go b/modules/core/04-channel/keeper/keeper.go index f285839799a..8474f42b706 100644 --- a/modules/core/04-channel/keeper/keeper.go +++ b/modules/core/04-channel/keeper/keeper.go @@ -194,6 +194,12 @@ func (k Keeper) SetPacketReceipt(ctx sdk.Context, portID, channelID string, sequ store.Set(host.PacketReceiptKey(portID, channelID, sequence), []byte{byte(1)}) } +// deletePacketReceipt deletes a packet receipt from the store +func (k Keeper) deletePacketReceipt(ctx sdk.Context, portID, channelID string, sequence uint64) { + store := ctx.KVStore(k.storeKey) + store.Delete(host.PacketReceiptKey(portID, channelID, sequence)) +} + // GetPacketCommitment gets the packet commitment hash from the store func (k Keeper) GetPacketCommitment(ctx sdk.Context, portID, channelID string, sequence uint64) []byte { store := ctx.KVStore(k.storeKey) @@ -240,6 +246,12 @@ func (k Keeper) HasPacketAcknowledgement(ctx sdk.Context, portID, channelID stri return store.Has(host.PacketAcknowledgementKey(portID, channelID, sequence)) } +// deletePacketAcknowledgement deletes the packet ack hash from the store +func (k Keeper) deletePacketAcknowledgement(ctx sdk.Context, portID, channelID string, sequence uint64) { + store := ctx.KVStore(k.storeKey) + store.Delete(host.PacketAcknowledgementKey(portID, channelID, sequence)) +} + // IteratePacketSequence provides an iterator over all send, receive or ack sequences. // For each sequence, cb will be called. If the cb returns true, the iterator // will close and stop. @@ -481,6 +493,119 @@ func (k Keeper) LookupModuleByChannel(ctx sdk.Context, portID, channelID string) return porttypes.GetModuleOwner(modules), capability, nil } +// GetUpgradeErrorReceipt returns the upgrade error receipt for the provided port and channel identifiers. +func (k Keeper) GetUpgradeErrorReceipt(ctx sdk.Context, portID, channelID string) (types.ErrorReceipt, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(host.ChannelUpgradeErrorKey(portID, channelID)) + if bz == nil { + return types.ErrorReceipt{}, false + } + + var errorReceipt types.ErrorReceipt + k.cdc.MustUnmarshal(bz, &errorReceipt) + + return errorReceipt, true +} + +// setUpgradeErrorReceipt sets the provided error receipt in store using the port and channel identifiers. +func (k Keeper) setUpgradeErrorReceipt(ctx sdk.Context, portID, channelID string, errorReceipt types.ErrorReceipt) { + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshal(&errorReceipt) + store.Set(host.ChannelUpgradeErrorKey(portID, channelID), bz) +} + +// hasUpgrade returns true if a proposed upgrade exists in store +func (k Keeper) hasUpgrade(ctx sdk.Context, portID, channelID string) bool { + store := ctx.KVStore(k.storeKey) + return store.Has(host.ChannelUpgradeKey(portID, channelID)) +} + +// GetUpgrade returns the proposed upgrade for the provided port and channel identifiers. +func (k Keeper) GetUpgrade(ctx sdk.Context, portID, channelID string) (types.Upgrade, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(host.ChannelUpgradeKey(portID, channelID)) + if bz == nil { + return types.Upgrade{}, false + } + + var upgrade types.Upgrade + k.cdc.MustUnmarshal(bz, &upgrade) + + return upgrade, true +} + +// SetUpgrade sets the proposed upgrade using the provided port and channel identifiers. +func (k Keeper) SetUpgrade(ctx sdk.Context, portID, channelID string, upgrade types.Upgrade) { + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshal(&upgrade) + store.Set(host.ChannelUpgradeKey(portID, channelID), bz) +} + +// deleteUpgrade deletes the upgrade for the provided port and channel identifiers. +func (k Keeper) deleteUpgrade(ctx sdk.Context, portID, channelID string) { + store := ctx.KVStore(k.storeKey) + store.Delete(host.ChannelUpgradeKey(portID, channelID)) +} + +// hasCounterpartyUpgrade returns true if a counterparty upgrade exists in store +func (k Keeper) hasCounterpartyUpgrade(ctx sdk.Context, portID, channelID string) bool { + store := ctx.KVStore(k.storeKey) + return store.Has(host.ChannelCounterpartyUpgradeKey(portID, channelID)) +} + +// GetCounterpartyUpgrade gets the counterparty upgrade from the store. +func (k Keeper) GetCounterpartyUpgrade(ctx sdk.Context, portID, channelID string) (types.Upgrade, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(host.ChannelCounterpartyUpgradeKey(portID, channelID)) + if bz == nil { + return types.Upgrade{}, false + } + + var upgrade types.Upgrade + k.cdc.MustUnmarshal(bz, &upgrade) + + return upgrade, true +} + +// SetCounterpartyUpgrade sets the counterparty upgrade in the store. +func (k Keeper) SetCounterpartyUpgrade(ctx sdk.Context, portID, channelID string, upgrade types.Upgrade) { + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshal(&upgrade) + store.Set(host.ChannelCounterpartyUpgradeKey(portID, channelID), bz) +} + +// deleteCounterpartyUpgrade deletes the counterparty upgrade in the store. +func (k Keeper) deleteCounterpartyUpgrade(ctx sdk.Context, portID, channelID string) { + store := ctx.KVStore(k.storeKey) + store.Delete(host.ChannelCounterpartyUpgradeKey(portID, channelID)) +} + +// deleteUpgradeInfo deletes all auxiliary upgrade information. +func (k Keeper) deleteUpgradeInfo(ctx sdk.Context, portID, channelID string) { + k.deleteUpgrade(ctx, portID, channelID) + k.deleteCounterpartyUpgrade(ctx, portID, channelID) +} + +// SetParams sets the channel parameters. +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshal(¶ms) + store.Set([]byte(types.ParamsKey), bz) +} + +// GetParams returns the total set of the channel parameters. +func (k Keeper) GetParams(ctx sdk.Context) types.Params { + store := ctx.KVStore(k.storeKey) + bz := store.Get([]byte(types.ParamsKey)) + if bz == nil { // only panic on unset params and not on empty params + panic(errors.New("channel params are not set in store")) + } + + var params types.Params + k.cdc.MustUnmarshal(bz, ¶ms) + return params +} + // common functionality for IteratePacketCommitment and IteratePacketAcknowledgement func (Keeper) iterateHashes(ctx sdk.Context, iterator db.Iterator, cb func(portID, channelID string, sequence uint64, hash []byte) bool) { defer sdk.LogDeferred(ctx.Logger(), func() error { return iterator.Close() }) @@ -500,3 +625,96 @@ func (Keeper) iterateHashes(ctx sdk.Context, iterator db.Iterator, cb func(portI } } } + +// HasInflightPackets returns true if there are packet commitments stored at the specified +// port and channel, and false otherwise. +func (k Keeper) HasInflightPackets(ctx sdk.Context, portID, channelID string) bool { + iterator := storetypes.KVStorePrefixIterator(ctx.KVStore(k.storeKey), []byte(host.PacketCommitmentPrefixPath(portID, channelID))) + defer sdk.LogDeferred(ctx.Logger(), func() error { return iterator.Close() }) + + return iterator.Valid() +} + +// setRecvStartSequence sets the channel's recv start sequence to the store. +func (k Keeper) setRecvStartSequence(ctx sdk.Context, portID, channelID string, sequence uint64) { + store := ctx.KVStore(k.storeKey) + bz := sdk.Uint64ToBigEndian(sequence) + store.Set(host.RecvStartSequenceKey(portID, channelID), bz) +} + +// GetRecvStartSequence gets a channel's recv start sequence from the store. +// The recv start sequence will be set to the counterparty's next sequence send +// upon a successful channel upgrade. It will be used for replay protection of +// historical packets and as the upper bound for pruning stale packet receives. +func (k Keeper) GetRecvStartSequence(ctx sdk.Context, portID, channelID string) (uint64, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(host.RecvStartSequenceKey(portID, channelID)) + if len(bz) == 0 { + return 0, false + } + + return sdk.BigEndianToUint64(bz), true +} + +// SetPruningSequenceStart sets a channel's pruning sequence start to the store. +func (k Keeper) SetPruningSequenceStart(ctx sdk.Context, portID, channelID string, sequence uint64) { + store := ctx.KVStore(k.storeKey) + bz := sdk.Uint64ToBigEndian(sequence) + store.Set(host.PruningSequenceStartKey(portID, channelID), bz) +} + +// GetPruningSequenceStart gets a channel's pruning sequence start from the store. +func (k Keeper) GetPruningSequenceStart(ctx sdk.Context, portID, channelID string) (uint64, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(host.PruningSequenceStartKey(portID, channelID)) + if len(bz) == 0 { + return 0, false + } + + return sdk.BigEndianToUint64(bz), true +} + +// HasPruningSequenceStart returns true if the pruning sequence start is set for the specified channel. +func (k Keeper) HasPruningSequenceStart(ctx sdk.Context, portID, channelID string) bool { + store := ctx.KVStore(k.storeKey) + return store.Has(host.PruningSequenceStartKey(portID, channelID)) +} + +// PruneAcknowledgements prunes packet acknowledgements and receipts that have a sequence number less than pruning sequence end. +// The number of packet acks/receipts pruned is bounded by the limit. Pruning can only occur after a channel has been upgraded. +// +// Pruning sequence start keeps track of the packet ack/receipt that can be pruned next. When it reaches pruningSequenceEnd, +// pruning is complete. +func (k Keeper) PruneAcknowledgements(ctx sdk.Context, portID, channelID string, limit uint64) (uint64, uint64, error) { + pruningSequenceStart, found := k.GetPruningSequenceStart(ctx, portID, channelID) + if !found { + return 0, 0, errorsmod.Wrapf(types.ErrPruningSequenceStartNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + pruningSequenceEnd, found := k.GetRecvStartSequence(ctx, portID, channelID) + if !found { + return 0, 0, errorsmod.Wrapf(types.ErrRecvStartSequenceNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + + start := pruningSequenceStart + end := pruningSequenceStart + limit + for ; start < end; start++ { + // stop pruning if pruningSequenceStart has reached pruningSequenceEnd, pruningSequenceEnd is + // set to be equal to the _next_ sequence to be sent by the counterparty. + if start >= pruningSequenceEnd { + break + } + + k.deletePacketAcknowledgement(ctx, portID, channelID, start) + + // NOTE: packet receipts are only relevant for unordered channels. + k.deletePacketReceipt(ctx, portID, channelID, start) + } + + // set pruning sequence start to the updated value + k.SetPruningSequenceStart(ctx, portID, channelID, start) + + totalPruned := start - pruningSequenceStart + totalRemaining := pruningSequenceEnd - start + + return totalPruned, totalRemaining, nil +} diff --git a/modules/core/04-channel/keeper/keeper_test.go b/modules/core/04-channel/keeper/keeper_test.go index 94917b92d00..3674ae2c457 100644 --- a/modules/core/04-channel/keeper/keeper_test.go +++ b/modules/core/04-channel/keeper/keeper_test.go @@ -1,13 +1,17 @@ package keeper_test import ( + "fmt" "reflect" "testing" testifysuite "github.com/stretchr/testify/suite" transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + "github.com/cosmos/ibc-go/v8/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v8/testing" ibcmock "github.com/cosmos/ibc-go/v8/testing/mock" ) @@ -465,3 +469,455 @@ func (suite *KeeperTestSuite) TestSetPacketAcknowledgement() { suite.Require().Equal(ackHash, storedAckHash) suite.Require().True(suite.chainA.App.GetIBCKeeper().ChannelKeeper.HasPacketAcknowledgement(ctxA, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, seq)) } + +func (suite *KeeperTestSuite) TestSetUpgradeErrorReceipt() { + path := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + suite.coordinator.CreateChannels(path) + + errorReceipt, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetUpgradeErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().False(found) + suite.Require().Empty(errorReceipt) + + expError := types.NewUpgradeError(1, fmt.Errorf("testing")) + suite.chainA.App.GetIBCKeeper().ChannelKeeper.WriteErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, expError) + + errorReceipt, found = suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetUpgradeErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(expError.GetErrorReceipt(), errorReceipt) +} + +// TestDefaultSetParams tests the default params set are what is expected +func (suite *KeeperTestSuite) TestDefaultSetParams() { + expParams := types.DefaultParams() + + channelKeeper := suite.chainA.App.GetIBCKeeper().ChannelKeeper + params := channelKeeper.GetParams(suite.chainA.GetContext()) + + suite.Require().Equal(expParams, params) + suite.Require().Equal(expParams.UpgradeTimeout, channelKeeper.GetParams(suite.chainA.GetContext()).UpgradeTimeout) +} + +// TestParams tests that Param setting and retrieval works properly +func (suite *KeeperTestSuite) TestParams() { + testCases := []struct { + name string + input types.Params + expPass bool + }{ + {"success: set default params", types.DefaultParams(), true}, + {"success: zero timeout height", types.NewParams(types.NewTimeout(clienttypes.ZeroHeight(), 10000)), true}, + {"fail: zero timeout timestamp", types.NewParams(types.NewTimeout(clienttypes.NewHeight(1, 1000), 0)), false}, + {"fail: zero timeout", types.NewParams(types.NewTimeout(clienttypes.ZeroHeight(), 0)), false}, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + ctx := suite.chainA.GetContext() + err := tc.input.Validate() + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetParams(ctx, tc.input) + if tc.expPass { + suite.Require().NoError(err) + expected := tc.input + p := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetParams(ctx) + suite.Require().Equal(expected, p) + } else { + suite.Require().Error(err) + } + }) + } +} + +// TestUnsetParams tests that trying to get params that are not set panics. +func (suite *KeeperTestSuite) TestUnsetParams() { + suite.SetupTest() + ctx := suite.chainA.GetContext() + store := ctx.KVStore(suite.chainA.GetSimApp().GetKey(exported.StoreKey)) + store.Delete([]byte(types.ParamsKey)) + + suite.Require().Panics(func() { + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetParams(ctx) + }) +} + +func (suite *KeeperTestSuite) TestPruneAcknowledgements() { + var ( + path *ibctesting.Path + limit uint64 + upgradeFields types.UpgradeFields + + // postPruneExpState is a helper function to verify the expected state after pruning. Argument expLeft + // denotes the expected amount of packet acks and receipts left after pruning. Argument expSequenceStart + // denotes the expected value of PruneSequenceStart. + postPruneExpState = func(expAcksLen, expReceiptsLen, expPruningSequenceStart uint64) { + acks := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetAllPacketAcks(suite.chainA.GetContext()) + suite.Require().Len(acks, int(expAcksLen)) + + receipts := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetAllPacketReceipts(suite.chainA.GetContext()) + suite.Require().Len(receipts, int(expReceiptsLen)) + + start, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetPruningSequenceStart(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(start, expPruningSequenceStart) + } + ) + + testCases := []struct { + name string + pre func() + malleate func() + post func(pruned, left uint64) + expError error + }{ + { + "success: no packets sent, no stale packet state pruned", + func() {}, + func() {}, + func(pruned, left uint64) { + // Assert that PruneSequenceStart and PruneSequenceEnd are both set to 1. + start, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetPruningSequenceStart(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + end, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetRecvStartSequence(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + + suite.Require().Equal(uint64(1), start) + suite.Require().Equal(uint64(1), end) + + // We expect 0 to be pruned and 0 left. + suite.Require().Equal(uint64(0), pruned) + suite.Require().Equal(uint64(0), left) + }, + nil, + }, + { + "success: stale packet state pruned up to limit", + func() { + // Send 10 packets from B -> A, creating 10 packet receipts and 10 packet acks on A. + suite.sendMockPackets(path, 10, true) + }, + func() {}, + func(pruned, left uint64) { + sequenceEnd, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetRecvStartSequence(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + + // We expect nothing to be left and sequenceStart == sequenceEnd. + postPruneExpState(0, 0, sequenceEnd) + + // We expect 10 to be pruned and 0 left. + suite.Require().Equal(uint64(10), pruned) + suite.Require().Equal(uint64(0), left) + }, + nil, + }, + { + "success: stale packet state partially pruned", + func() { + // Send 10 packets from B -> A, creating 10 packet receipts and 10 packet acks on A. + suite.sendMockPackets(path, 10, true) + }, + func() { + // Prune only 6 packet acks. + limit = 6 + }, + func(pruned, left uint64) { + // We expect 4 to be left and sequenceStart == 7. + postPruneExpState(4, 4, 7) + + // We expect 6 to be pruned and 4 left. + suite.Require().Equal(uint64(6), pruned) + suite.Require().Equal(uint64(4), left) + }, + nil, + }, + { + "success: stale packet state with a higher limit", + func() { + // Send 10 packets from B -> A, creating 10 packet receipts and 10 packet acks on A. + suite.sendMockPackets(path, 10, true) + }, + func() { + // Prune 13 packets acks > 10 packets sent. + limit = 13 + }, + func(pruned, left uint64) { + // We expect 0 to be left and sequenceStart == 11. + postPruneExpState(0, 0, 11) + + // We expect 10 to be pruned and 0 left. + suite.Require().Equal(uint64(10), pruned) + suite.Require().Equal(uint64(0), left) + }, + nil, + }, + { + "success: stale packet state pruned, two upgrades", + func() { + // Send 10 packets from B -> A, creating 10 packet receipts and 10 packet acks on A. + // This is _before_ the first upgrade. + suite.sendMockPackets(path, 10, true) + }, + func() { + // Previous upgrade is complete, send additional packets and do yet another upgrade. + // This is _after_ the first upgrade. + suite.sendMockPackets(path, 5, true) + + // Do another upgrade. + upgradeFields = types.UpgradeFields{Version: fmt.Sprintf("%s-v3", ibcmock.Version)} + suite.UpgradeChannel(path, upgradeFields) + + // set limit to 15, get them all in one go. + limit = 15 + }, + func(pruned, left uint64) { + sequenceEnd, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetRecvStartSequence(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + + // We expect nothing to be left and sequenceStart == sequenceEnd. + postPruneExpState(0, 0, sequenceEnd) + + // We expect 15 to be pruned and 0 left. + suite.Require().Equal(uint64(15), pruned) + suite.Require().Equal(uint64(0), left) + }, + nil, + }, + { + "success: stale packet state partially pruned, upgrade, prune again", + func() { + // Send 10 packets from B -> A, creating 10 packet receipts and 10 packet acks on A. + // This is _before_ the first upgrade. + suite.sendMockPackets(path, 10, true) + }, + func() { + // Prune 5 on A. + pruned, left, err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.PruneAcknowledgements( + suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + 4, // limit == 4 + ) + suite.Require().NoError(err) + + // We expect 4 to be pruned and 6 left. + suite.Require().Equal(uint64(4), pruned) + suite.Require().Equal(uint64(6), left) + + // Check state post-prune + postPruneExpState(6, 6, 5) + + // Previous upgrade is complete, send additional packets and do yet another upgrade. + // This is _after_ the first upgrade. + suite.sendMockPackets(path, 10, true) + + // Do another upgrade. + upgradeFields = types.UpgradeFields{Version: fmt.Sprintf("%s-v3", ibcmock.Version)} + suite.UpgradeChannel(path, upgradeFields) + + // A total of 16 stale acks/receipts exist on A. Prune 10 of them (default in test). + }, + func(pruned, left uint64) { + // Expected state should be 6 acks/receipts left, sequenceStart == 15. + postPruneExpState(6, 6, 15) + + // We expect 10 to be pruned and 6 left. + suite.Require().Equal(uint64(10), pruned) + suite.Require().Equal(uint64(6), left) + }, + nil, + }, + { + "success: unordered -> ordered -> unordered, acksLen != receiptsLen after packet sends", + func() { + // Send 5 packets from B -> A, creating 5 packet receipts and 5 packet acks on A. + // This is _before_ the first upgrade. + suite.sendMockPackets(path, 5, true) + + // Set Order for upgrade to Ordered. + upgradeFields = types.UpgradeFields{Version: fmt.Sprintf("%s-v2", ibcmock.Version), Ordering: types.ORDERED} + }, + func() { + // Previous upgrade is complete, send additional packets now on ordered channel (only acks!) + suite.sendMockPackets(path, 10, true) + + // Do another upgrade (go back to Unordered) + upgradeFields = types.UpgradeFields{Version: fmt.Sprintf("%s-v3", ibcmock.Version), Ordering: types.UNORDERED} + suite.UpgradeChannel(path, upgradeFields) + }, + func(pruned, left uint64) { + // After pruning 10 sequences we should be left with 5 acks and zero receipts. + postPruneExpState(5, 0, 11) + + // We expect 10 to be pruned and 5 left. + suite.Require().Equal(uint64(10), pruned) + suite.Require().Equal(uint64(5), left) + }, + nil, + }, + { + "success: packets sent before upgrade are pruned, after upgrade are not", + func() { + // Send 5 packets from B -> A, creating 5 packet receipts and 5 packet acks on A. + suite.sendMockPackets(path, 5, true) + }, + func() {}, + func(pruned, left uint64) { + // We expect 5 to be pruned and 0 left. + suite.Require().Equal(uint64(5), pruned) + suite.Require().Equal(uint64(0), left) + + // channel upgraded, send additional packets and try and prune. + suite.sendMockPackets(path, 12, true) + + // attempt to prune 5. + pruned, left, err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.PruneAcknowledgements( + suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + 5, + ) + suite.Require().NoError(err) + // We expect 0 to be pruned and 0 left. + suite.Require().Equal(uint64(0), pruned) + suite.Require().Equal(uint64(0), left) + + // we _do not_ expect error, simply a fast return + postPruneExpState(12, 12, 6) + }, + nil, + }, + { + "success: packets sent with 2 middle sequences that don't have an ack stored", + func() { + // Send 12 packets from B -> A with 2 packets that timeout + suite.sendMockPackets(path, 5, true) + suite.sendMockPackets(path, 2, false) + suite.sendMockPackets(path, 5, true) + }, + func() { + limit = 7 + }, + func(pruned, left uint64) { + // After pruning 7 sequences we should be left with 5 acks and 5 receipts, + // because the 2 packets that timeout are still counted as pruned, even though + // there was nothing to prune since both packets timed out + postPruneExpState(5, 5, 8) + + // We expect 7 to be pruned and 5 left. + suite.Require().Equal(uint64(7), pruned) + suite.Require().Equal(uint64(5), left) + }, + nil, + }, + { + "failure: packet sequence start not set", + func() {}, + func() { + path.EndpointA.ChannelConfig.PortID = "portidone" + }, + func(_, _ uint64) {}, + types.ErrPruningSequenceStartNotFound, + }, + { + "failure: packet sequence end not set", + func() {}, + func() { + store := suite.chainA.GetContext().KVStore(suite.chainA.GetSimApp().GetKey(exported.StoreKey)) + store.Delete(host.RecvStartSequenceKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + }, + func(_, _ uint64) {}, + types.ErrRecvStartSequenceNotFound, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + // Defaults will be filled in for rest. + upgradeFields = types.UpgradeFields{Version: ibcmock.UpgradeVersion} + limit = 10 + + // perform pre upgrade ops. + tc.pre() + + suite.UpgradeChannel(path, upgradeFields) + + tc.malleate() + + pruned, left, err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.PruneAcknowledgements( + suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + limit, + ) + + suite.Require().ErrorIs(err, tc.expError) + + // check on post state. + tc.post(pruned, left) + }) + } +} + +// UpgradeChannel performs a channel upgrade given a specific set of upgrade fields. +// Question(jim): setup.coordinator.UpgradeChannel() wen? +func (suite *KeeperTestSuite) UpgradeChannel(path *ibctesting.Path, upgradeFields types.UpgradeFields) { + // configure the channel upgrade version on testing endpoints + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields = upgradeFields + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields = upgradeFields + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeAck() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeConfirm() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeOpen() + suite.Require().NoError(err) + + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) +} + +// sendMockPacket sends a packet from source to dest and acknowledges it on the source (completing the packet lifecycle) +// if acknowledge is true. If acknowledge is false, then the packet will be sent, but timed out. +// Question(jim): find a nicer home for this? +func (suite *KeeperTestSuite) sendMockPackets(path *ibctesting.Path, numPackets int, acknowledge bool) { + for i := 0; i < numPackets; i++ { + + timeoutHeight := clienttypes.NewHeight(1, 1000) + timeoutTimestamp := disabledTimeoutTimestamp + if !acknowledge { + timeoutTimestamp = uint64(suite.chainA.GetContext().BlockTime().UnixNano()) + } + + sequence, err := path.EndpointB.SendPacket(timeoutHeight, timeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + + packet := types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, timeoutHeight, timeoutTimestamp) + + if acknowledge { + err = path.RelayPacket(packet) + suite.Require().NoError(err) + } else { + err = path.EndpointB.UpdateClient() + suite.Require().NoError(err) + + err = path.EndpointB.TimeoutPacket(packet) + suite.Require().NoError(err) + } + } +} diff --git a/modules/core/04-channel/keeper/migrations.go b/modules/core/04-channel/keeper/migrations.go new file mode 100644 index 00000000000..5bc0fcf0a41 --- /dev/null +++ b/modules/core/04-channel/keeper/migrations.go @@ -0,0 +1,25 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" +) + +// Migrator is a struct for handling in-place store migrations. +type Migrator struct { + keeper Keeper +} + +// NewMigrator returns a new Migrator. +func NewMigrator(keeper Keeper) Migrator { + return Migrator{keeper: keeper} +} + +// MigrateParams migrates params to the default channel params. +func (m Migrator) MigrateParams(ctx sdk.Context) error { + params := channeltypes.DefaultParams() + m.keeper.SetParams(ctx, params) + m.keeper.Logger(ctx).Info("successfully migrated ibc channel params") + return nil +} diff --git a/modules/core/04-channel/keeper/migrations_test.go b/modules/core/04-channel/keeper/migrations_test.go new file mode 100644 index 00000000000..944aac49ce1 --- /dev/null +++ b/modules/core/04-channel/keeper/migrations_test.go @@ -0,0 +1,34 @@ +package keeper_test + +import ( + "github.com/cosmos/ibc-go/v8/modules/core/04-channel/keeper" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" +) + +// TestMigrateDefaultParams tests the migration for the channel params +func (suite *KeeperTestSuite) TestMigrateDefaultParams() { + testCases := []struct { + name string + expectedParams channeltypes.Params + }{ + { + "success: default params", + channeltypes.DefaultParams(), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + ctx := suite.chainA.GetContext() + migrator := keeper.NewMigrator(suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper) + err := migrator.MigrateParams(ctx) + suite.Require().NoError(err) + + params := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetParams(ctx) + suite.Require().Equal(tc.expectedParams, params) + }) + } +} diff --git a/modules/core/04-channel/keeper/packet.go b/modules/core/04-channel/keeper/packet.go index 28fdbe7a13e..698dc952a35 100644 --- a/modules/core/04-channel/keeper/packet.go +++ b/modules/core/04-channel/keeper/packet.go @@ -2,8 +2,8 @@ package keeper import ( "bytes" + "slices" "strconv" - "time" errorsmod "cosmossdk.io/errors" @@ -34,11 +34,8 @@ func (k Keeper) SendPacket( return 0, errorsmod.Wrap(types.ErrChannelNotFound, sourceChannel) } - if !channel.IsOpen() { - return 0, errorsmod.Wrapf( - types.ErrInvalidChannelState, - "channel state is not OPEN (got %s)", channel.State.String(), - ) + if channel.State != types.OPEN { + return 0, errorsmod.Wrapf(types.ErrInvalidChannelState, "channel is not OPEN (got %s)", channel.State) } if !k.scopedKeeper.AuthenticateCapability(ctx, channelCap, host.ChannelCapabilityPath(sourcePort, sourceChannel)) { @@ -76,25 +73,16 @@ func (k Keeper) SendPacket( return 0, errorsmod.Wrapf(clienttypes.ErrClientNotActive, "cannot send packet using client (%s) with status %s", connectionEnd.GetClientID(), status) } - // check if packet is timed out on the receiving chain latestHeight := clientState.GetLatestHeight() - if !timeoutHeight.IsZero() && latestHeight.GTE(timeoutHeight) { - return 0, errorsmod.Wrapf( - types.ErrPacketTimeout, - "receiving chain block height >= packet timeout height (%s >= %s)", latestHeight, timeoutHeight, - ) - } - latestTimestamp, err := k.connectionKeeper.GetTimestampAtHeight(ctx, connectionEnd, latestHeight) if err != nil { return 0, err } - if packet.GetTimeoutTimestamp() != 0 && latestTimestamp >= packet.GetTimeoutTimestamp() { - return 0, errorsmod.Wrapf( - types.ErrPacketTimeout, - "receiving chain block timestamp >= packet timeout timestamp (%s >= %s)", time.Unix(0, int64(latestTimestamp)).UTC(), time.Unix(0, int64(packet.GetTimeoutTimestamp())).UTC(), - ) + // check if packet is timed out on the receiving chain + timeout := types.NewTimeout(packet.GetTimeoutHeight().(clienttypes.Height), packet.GetTimeoutTimestamp()) + if timeout.Elapsed(latestHeight.(clienttypes.Height), latestTimestamp) { + return 0, errorsmod.Wrap(timeout.ErrTimeoutElapsed(latestHeight.(clienttypes.Height), latestTimestamp), "invalid packet timeout") } commitment := types.CommitPacket(k.cdc, packet) @@ -130,11 +118,21 @@ func (k Keeper) RecvPacket( return errorsmod.Wrap(types.ErrChannelNotFound, packet.GetDestChannel()) } - if !channel.IsOpen() { - return errorsmod.Wrapf( - types.ErrInvalidChannelState, - "channel state is not OPEN (got %s)", channel.State.String(), - ) + if !slices.Contains([]types.State{types.OPEN, types.FLUSHING, types.FLUSHCOMPLETE}, channel.State) { + return errorsmod.Wrapf(types.ErrInvalidChannelState, "expected channel state to be one of [%s, %s, %s], but got %s", types.OPEN, types.FLUSHING, types.FLUSHCOMPLETE, channel.State) + } + + // If counterpartyUpgrade is stored we need to ensure that the + // packet sequence is < counterparty next sequence send. If the + // counterparty is implemented correctly, this may only occur + // when we are in FLUSHCOMPLETE and the counterparty has already + // completed the channel upgrade. + counterpartyUpgrade, found := k.GetCounterpartyUpgrade(ctx, packet.GetDestPort(), packet.GetDestChannel()) + if found { + counterpartyNextSequenceSend := counterpartyUpgrade.NextSequenceSend + if packet.GetSequence() >= counterpartyNextSequenceSend { + return errorsmod.Wrapf(types.ErrInvalidPacket, "cannot flush packet at sequence greater than or equal to counterparty next sequence send (%d) ≥ (%d).", packet.GetSequence(), counterpartyNextSequenceSend) + } } // Authenticate capability to ensure caller has authority to receive packet on this channel @@ -176,22 +174,11 @@ func (k Keeper) RecvPacket( ) } - // check if packet timeouted by comparing it with the latest height of the chain - selfHeight := clienttypes.GetSelfHeight(ctx) - timeoutHeight := packet.GetTimeoutHeight() - if !timeoutHeight.IsZero() && selfHeight.GTE(timeoutHeight) { - return errorsmod.Wrapf( - types.ErrPacketTimeout, - "block height >= packet timeout height (%s >= %s)", selfHeight, timeoutHeight, - ) - } - - // check if packet timeouted by comparing it with the latest timestamp of the chain - if packet.GetTimeoutTimestamp() != 0 && uint64(ctx.BlockTime().UnixNano()) >= packet.GetTimeoutTimestamp() { - return errorsmod.Wrapf( - types.ErrPacketTimeout, - "block timestamp >= packet timeout timestamp (%s >= %s)", ctx.BlockTime(), time.Unix(0, int64(packet.GetTimeoutTimestamp())).UTC(), - ) + // check if packet timed out by comparing it with the latest height of the chain + selfHeight, selfTimestamp := clienttypes.GetSelfHeight(ctx), uint64(ctx.BlockTime().UnixNano()) + timeout := types.NewTimeout(packet.GetTimeoutHeight().(clienttypes.Height), packet.GetTimeoutTimestamp()) + if timeout.Elapsed(selfHeight, selfTimestamp) { + return errorsmod.Wrap(timeout.ErrTimeoutElapsed(selfHeight, selfTimestamp), "packet timeout elapsed") } commitment := types.CommitPacket(k.cdc, packet) @@ -205,9 +192,43 @@ func (k Keeper) RecvPacket( return errorsmod.Wrap(err, "couldn't verify counterparty packet commitment") } + if err := k.applyReplayProtection(ctx, packet, channel); err != nil { + return err + } + + // log that a packet has been received & executed + k.Logger(ctx).Info( + "packet received", + "sequence", strconv.FormatUint(packet.GetSequence(), 10), + "src_port", packet.GetSourcePort(), + "src_channel", packet.GetSourceChannel(), + "dst_port", packet.GetDestPort(), + "dst_channel", packet.GetDestChannel(), + ) + + // emit an event that the relayer can query for + emitRecvPacketEvent(ctx, packet, channel) + + return nil +} + +// applyReplayProtection ensures a packet has not already been received +// and performs the necessary state changes to ensure it cannot be received again. +func (k *Keeper) applyReplayProtection(ctx sdk.Context, packet exported.PacketI, channel types.Channel) error { + // REPLAY PROTECTION: The recvStartSequence will prevent historical proofs from allowing replay + // attacks on packets processed in previous lifecycles of a channel. After a successful channel + // upgrade all packets under the recvStartSequence will have been processed and thus should be + // rejected. + recvStartSequence, _ := k.GetRecvStartSequence(ctx, packet.GetDestPort(), packet.GetDestChannel()) + if packet.GetSequence() < recvStartSequence { + return errorsmod.Wrap(types.ErrPacketReceived, "packet already processed in previous channel upgrade") + } + switch channel.Ordering { case types.UNORDERED: - // check if the packet receipt has been received already for unordered channels + // REPLAY PROTECTION: Packet receipts will indicate that a packet has already been received + // on unordered channels. Packet receipts must not be pruned, unless it has been marked stale + // by the increase of the recvStartSequence. _, found := k.GetPacketReceipt(ctx, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) if found { emitRecvPacketEvent(ctx, packet, channel) @@ -220,7 +241,7 @@ func (k Keeper) RecvPacket( // All verification complete, update state // For unordered channels we must set the receipt so it can be verified on the other side. // This receipt does not contain any data, since the packet has not yet been processed, - // it's just a single store key set to an empty string to indicate that the packet has been received + // it's just a single store key set to a single byte to indicate that the packet has been received k.SetPacketReceipt(ctx, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) case types.ORDERED: @@ -241,6 +262,8 @@ func (k Keeper) RecvPacket( return types.ErrNoOpMsg } + // REPLAY PROTECTION: Ordered channels require packets to be received in a strict order. + // Any out of order or previously received packets are rejected. if packet.GetSequence() != nextSequenceRecv { return errorsmod.Wrapf( types.ErrPacketSequenceOutOfOrder, @@ -255,22 +278,8 @@ func (k Keeper) RecvPacket( // incrementing nextSequenceRecv and storing under this chain's channelEnd identifiers // Since this is the receiving chain, our channelEnd is packet's destination port and channel k.SetNextSequenceRecv(ctx, packet.GetDestPort(), packet.GetDestChannel(), nextSequenceRecv) - } - // log that a packet has been received & executed - k.Logger(ctx).Info( - "packet received", - "sequence", strconv.FormatUint(packet.GetSequence(), 10), - "src_port", packet.GetSourcePort(), - "src_channel", packet.GetSourceChannel(), - "dst_port", packet.GetDestPort(), - "dst_channel", packet.GetDestChannel(), - ) - - // emit an event that the relayer can query for - emitRecvPacketEvent(ctx, packet, channel) - return nil } @@ -296,11 +305,8 @@ func (k Keeper) WriteAcknowledgement( return errorsmod.Wrap(types.ErrChannelNotFound, packet.GetDestChannel()) } - if !channel.IsOpen() { - return errorsmod.Wrapf( - types.ErrInvalidChannelState, - "channel state is not OPEN (got %s)", channel.State.String(), - ) + if !slices.Contains([]types.State{types.OPEN, types.FLUSHING, types.FLUSHCOMPLETE}, channel.State) { + return errorsmod.Wrapf(types.ErrInvalidChannelState, "expected one of [%s, %s, %s], got %s", types.OPEN, types.FLUSHING, types.FLUSHCOMPLETE, channel.State) } // Authenticate capability to ensure caller has authority to receive packet on this channel @@ -371,11 +377,8 @@ func (k Keeper) AcknowledgePacket( ) } - if !channel.IsOpen() { - return errorsmod.Wrapf( - types.ErrInvalidChannelState, - "channel state is not OPEN (got %s)", channel.State.String(), - ) + if !slices.Contains([]types.State{types.OPEN, types.FLUSHING}, channel.State) { + return errorsmod.Wrapf(types.ErrInvalidChannelState, "packets cannot be acknowledged on channel with state (%s)", channel.State) } // Authenticate capability to ensure caller has authority to receive packet on this channel @@ -481,5 +484,29 @@ func (k Keeper) AcknowledgePacket( // emit an event marking that we have processed the acknowledgement emitAcknowledgePacketEvent(ctx, packet, channel) + // if an upgrade is in progress, handling packet flushing and update channel state appropriately + if channel.State == types.FLUSHING { + // counterparty upgrade is written in the OnChanUpgradeAck step. + counterpartyUpgrade, found := k.GetCounterpartyUpgrade(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) + if found { + timeout := counterpartyUpgrade.Timeout + selfHeight, selfTimestamp := clienttypes.GetSelfHeight(ctx), uint64(ctx.BlockTime().UnixNano()) + + if timeout.Elapsed(selfHeight, selfTimestamp) { + // packet flushing timeout has expired, abort the upgrade and return nil, + // committing an error receipt to state, restoring the channel and successfully acknowledging the packet. + k.MustAbortUpgrade(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), timeout.ErrTimeoutElapsed(selfHeight, selfTimestamp)) + return nil + } + + // set the channel state to flush complete if all packets have been acknowledged/flushed. + if !k.HasInflightPackets(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) { + channel.State = types.FLUSHCOMPLETE + k.SetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), channel) + emitChannelFlushCompleteEvent(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), channel) + } + } + } + return nil } diff --git a/modules/core/04-channel/keeper/packet_test.go b/modules/core/04-channel/keeper/packet_test.go index bd361cb2466..f34b169cd1e 100644 --- a/modules/core/04-channel/keeper/packet_test.go +++ b/modules/core/04-channel/keeper/packet_test.go @@ -3,6 +3,8 @@ package keeper_test import ( "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" @@ -215,6 +217,34 @@ func (suite *KeeperTestSuite) TestSendPacket() { channelCap = capabilitytypes.NewCapability(5) }, false}, + { + "channel is in FLUSH_COMPLETE state", + func() { + suite.coordinator.Setup(path) + sourceChannel = path.EndpointA.ChannelID + + channel := path.EndpointA.GetChannel() + channel.State = types.FLUSHCOMPLETE + path.EndpointA.SetChannel(channel) + }, + false, + }, + { + "channel is in FLUSHING state", + func() { + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + + err := path.EndpointB.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeTry() + suite.Require().NoError(err) + }, + false, + }, } for i, tc := range testCases { @@ -291,6 +321,38 @@ func (suite *KeeperTestSuite) TestRecvPacket() { }, nil, }, + { + "success UNORDERED channel in FLUSHING", + func() { + // setup uses an UNORDERED channel + suite.coordinator.Setup(path) + channel := path.EndpointB.GetChannel() + channel.State = types.FLUSHING + path.EndpointB.SetChannel(channel) + + sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + }, + nil, + }, + { + "success UNORDERED channel in FLUSHCOMPLETE", + func() { + // setup uses an UNORDERED channel + suite.coordinator.Setup(path) + channel := path.EndpointB.GetChannel() + channel.State = types.FLUSHCOMPLETE + path.EndpointB.SetChannel(channel) + + sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + }, + nil, + }, { "success with out of order packet: UNORDERED channel", func() { @@ -307,6 +369,62 @@ func (suite *KeeperTestSuite) TestRecvPacket() { }, nil, }, + { + "success with counterpartyNextSequenceSend higher than packet sequence", + func() { + suite.coordinator.Setup(path) + sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + + channel := path.EndpointB.GetChannel() + channel.State = types.FLUSHING + path.EndpointB.SetChannel(channel) + + // set upgrade next sequence send to sequence + 1 + counterpartyUpgrade := types.Upgrade{NextSequenceSend: sequence + 1} + path.EndpointB.SetChannelCounterpartyUpgrade(counterpartyUpgrade) + }, + nil, + }, + { + "success with counterparty upgrade not found", + func() { + suite.coordinator.Setup(path) + sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + + channel := path.EndpointB.GetChannel() + channel.State = types.FLUSHING + path.EndpointB.SetChannel(channel) + }, + nil, + }, + { + "failure while upgrading channel, packet sequence ≥ counterparty next send sequence", + func() { + suite.coordinator.Setup(path) + // send 2 packets so that when NextSequenceSend is set to sequence - 1, it is not 0. + _, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + + channel := path.EndpointB.GetChannel() + channel.State = types.FLUSHING + path.EndpointB.SetChannel(channel) + + // set upgrade next sequence send to sequence - 1 + counterpartyUpgrade := types.Upgrade{NextSequenceSend: sequence - 1} + path.EndpointB.SetChannelCounterpartyUpgrade(counterpartyUpgrade) + }, + types.ErrInvalidPacket, + }, { "packet already relayed ORDERED channel (no-op)", func() { @@ -459,7 +577,7 @@ func (suite *KeeperTestSuite) TestRecvPacket() { packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.GetSelfHeight(suite.chainB.GetContext()), disabledTimeoutTimestamp) channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, - types.ErrPacketTimeout, + types.ErrTimeoutElapsed, }, { "timeout timestamp passed", @@ -469,7 +587,7 @@ func (suite *KeeperTestSuite) TestRecvPacket() { packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, disabledTimeoutHeight, uint64(suite.chainB.GetContext().BlockTime().UnixNano())) channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, - types.ErrPacketTimeout, + types.ErrTimeoutElapsed, }, { "next receive sequence is not found", @@ -501,6 +619,21 @@ func (suite *KeeperTestSuite) TestRecvPacket() { }, types.ErrSequenceReceiveNotFound, }, + { + "packet already received", + func() { + suite.coordinator.Setup(path) + + sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + + // set recv seq start to indicate packet was processed in previous upgrade + suite.chainB.App.GetIBCKeeper().ChannelKeeper.SetRecvStartSequence(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sequence+1) + }, + types.ErrPacketReceived, + }, { "receipt already stored", func() { @@ -584,6 +717,32 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() { }, true, }, + { + "success: channel flushing", + func() { + suite.coordinator.Setup(path) + packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + ack = ibcmock.MockAcknowledgement + + err := path.EndpointB.SetChannelState(types.FLUSHING) + suite.Require().NoError(err) + channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + }, + true, + }, + { + "success: channel flush complete", + func() { + suite.coordinator.Setup(path) + packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + ack = ibcmock.MockAcknowledgement + + err := path.EndpointB.SetChannelState(types.FLUSHCOMPLETE) + suite.Require().NoError(err) + channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + }, + true, + }, {"channel not found", func() { // use wrong channel naming suite.coordinator.Setup(path) @@ -675,6 +834,7 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { name string malleate func() expResult func(commitment []byte, err error) + expEvents func(path *ibctesting.Path) map[string]map[string]string }{ { name: "success on ordered channel", @@ -728,6 +888,144 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { suite.Require().Equal(uint64(1), nextSequenceAck, "sequence incremented for UNORDERED channel") }, }, + { + name: "success on channel in flushing state", + malleate: func() { + // setup uses an UNORDERED channel + suite.coordinator.Setup(path) + + // create packet commitment + sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + + // create packet receipt and acknowledgement + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + err = path.EndpointB.RecvPacket(packet) + suite.Require().NoError(err) + + channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + + channel := path.EndpointA.GetChannel() + channel.State = types.FLUSHING + path.EndpointA.SetChannel(channel) + }, + expResult: func(commitment []byte, err error) { + suite.Require().NoError(err) + suite.Require().Nil(commitment) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(types.FLUSHING, channel.State) + + nextSequenceAck, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceAck(suite.chainA.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel()) + suite.Require().True(found) + suite.Require().Equal(uint64(1), nextSequenceAck, "sequence incremented for UNORDERED channel") + }, + }, + { + name: "success on channel in flushing state with valid timeout", + malleate: func() { + // setup uses an UNORDERED channel + suite.coordinator.Setup(path) + + // create packet commitment + sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + + // create packet receipt and acknowledgement + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + err = path.EndpointB.RecvPacket(packet) + suite.Require().NoError(err) + + channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + + channel := path.EndpointA.GetChannel() + channel.State = types.FLUSHING + + path.EndpointA.SetChannel(channel) + + counterpartyUpgrade := types.Upgrade{ + Timeout: types.NewTimeout(suite.chainB.GetTimeoutHeight(), 0), + } + + path.EndpointA.SetChannelCounterpartyUpgrade(counterpartyUpgrade) + }, + expResult: func(commitment []byte, err error) { + suite.Require().NoError(err) + suite.Require().Nil(commitment) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(types.FLUSHCOMPLETE, channel.State) + + nextSequenceAck, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceAck(suite.chainA.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel()) + suite.Require().True(found) + suite.Require().Equal(uint64(1), nextSequenceAck, "sequence incremented for UNORDERED channel") + }, + expEvents: func(path *ibctesting.Path) map[string]map[string]string { + return ibctesting.EventsMap{ + types.EventTypeChannelFlushComplete: { + types.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + types.AttributeKeyChannelID: path.EndpointA.ChannelID, + types.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + types.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + types.AttributeKeyChannelState: path.EndpointA.GetChannel().State.String(), + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: types.AttributeValueCategory, + }, + } + }, + }, + { + name: "success on channel in flushing state with timeout passed", + malleate: func() { + // setup uses an UNORDERED channel + suite.coordinator.Setup(path) + + // create packet commitment + sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + + // create packet receipt and acknowledgement + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + err = path.EndpointB.RecvPacket(packet) + suite.Require().NoError(err) + + channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + + channel := path.EndpointA.GetChannel() + channel.State = types.FLUSHING + + path.EndpointA.SetChannel(channel) + + upgrade := types.Upgrade{ + Fields: types.NewUpgradeFields(types.UNORDERED, []string{ibctesting.FirstConnectionID}, ibcmock.UpgradeVersion), + Timeout: types.NewTimeout(clienttypes.ZeroHeight(), 1), + } + + counterpartyUpgrade := types.Upgrade{ + Fields: types.NewUpgradeFields(types.UNORDERED, []string{ibctesting.FirstConnectionID}, ibcmock.UpgradeVersion), + Timeout: types.NewTimeout(clienttypes.ZeroHeight(), 1), + } + + path.EndpointA.SetChannelUpgrade(upgrade) + path.EndpointA.SetChannelCounterpartyUpgrade(counterpartyUpgrade) + }, + expResult: func(commitment []byte, err error) { + suite.Require().NoError(err) + suite.Require().Nil(commitment) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(types.OPEN, channel.State) + + nextSequenceAck, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceAck(suite.chainA.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel()) + suite.Require().True(found) + suite.Require().Equal(uint64(1), nextSequenceAck, "sequence incremented for UNORDERED channel") + + errorReceipt, found := path.EndpointA.Chain.App.GetIBCKeeper().ChannelKeeper.GetUpgradeErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().NotEmpty(errorReceipt) + }, + }, { name: "packet already acknowledged ordered channel (no-op)", malleate: func() { @@ -819,6 +1117,24 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { suite.Require().NotNil(commitment) }, }, + { + name: "channel in flush complete state", + malleate: func() { + suite.coordinator.Setup(path) + packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + + channel := path.EndpointA.GetChannel() + channel.State = types.FLUSHCOMPLETE + + path.EndpointA.SetChannel(channel) + }, + expResult: func(commitment []byte, err error) { + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrInvalidChannelState) + suite.Require().Nil(commitment) + }, + }, { name: "capability authentication failed ORDERED", malleate: func() { @@ -1057,16 +1373,24 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { suite.SetupTest() // reset path = ibctesting.NewPath(suite.chainA, suite.chainB) + ctx := suite.chainA.GetContext() tc.malleate() packetKey := host.PacketAcknowledgementKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) proof, proofHeight := path.EndpointB.QueryProof(packetKey) - err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.AcknowledgePacket(suite.chainA.GetContext(), channelCap, packet, ack.Acknowledgement(), proof, proofHeight) + err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.AcknowledgePacket(ctx, channelCap, packet, ack.Acknowledgement(), proof, proofHeight) - commitment := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, packet.GetSequence()) + commitment := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, packet.GetSequence()) tc.expResult(commitment, err) + if tc.expEvents != nil { + events := ctx.EventManager().ABCIEvents() + + expEvents := tc.expEvents(path) + + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + } }) } } diff --git a/modules/core/04-channel/keeper/timeout.go b/modules/core/04-channel/keeper/timeout.go index a3334d2fcdd..510e32ab3e8 100644 --- a/modules/core/04-channel/keeper/timeout.go +++ b/modules/core/04-channel/keeper/timeout.go @@ -9,6 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" @@ -67,10 +68,9 @@ func (k Keeper) TimeoutPacket( return err } - timeoutHeight := packet.GetTimeoutHeight() - if (timeoutHeight.IsZero() || proofHeight.LT(timeoutHeight)) && - (packet.GetTimeoutTimestamp() == 0 || proofTimestamp < packet.GetTimeoutTimestamp()) { - return errorsmod.Wrap(types.ErrPacketTimeout, "packet timeout has not been reached for height or timestamp") + timeout := types.NewTimeout(packet.GetTimeoutHeight().(clienttypes.Height), packet.GetTimeoutTimestamp()) + if !timeout.Elapsed(proofHeight.(clienttypes.Height), proofTimestamp) { + return errorsmod.Wrap(timeout.ErrTimeoutNotReached(proofHeight.(clienttypes.Height), proofTimestamp), "packet timeout not reached") } commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) @@ -84,13 +84,6 @@ func (k Keeper) TimeoutPacket( return types.ErrNoOpMsg } - if !channel.IsOpen() { - return errorsmod.Wrapf( - types.ErrInvalidChannelState, - "channel state is not OPEN (got %s)", channel.State.String(), - ) - } - packetCommitment := types.CommitPacket(k.cdc, packet) // verify we sent the packet and haven't cleared it out yet @@ -132,6 +125,9 @@ func (k Keeper) TimeoutPacket( // TimeoutExecuted deletes the commitment send from this chain after it verifies timeout. // If the timed-out packet came from an ORDERED channel then this channel will be closed. +// If the channel is in the FLUSHING state and there is a counterparty upgrade, then the +// upgrade will be aborted if the upgrade has timed out. Otherwise, if there are no more inflight packets, +// then the channel will be set to the FLUSHCOMPLETE state. // // CONTRACT: this function must be called in the IBC handler func (k Keeper) TimeoutExecuted( @@ -154,9 +150,39 @@ func (k Keeper) TimeoutExecuted( k.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + // if an upgrade is in progress, handling packet flushing and update channel state appropriately + if channel.State == types.FLUSHING && channel.Ordering == types.UNORDERED { + counterpartyUpgrade, found := k.GetCounterpartyUpgrade(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) + // once we have received the counterparty timeout in the channel UpgradeAck or UpgradeConfirm handshake steps + // then we can move to flushing complete if the timeout has not passed and there are no in-flight packets + if found { + timeout := counterpartyUpgrade.Timeout + selfHeight, selfTimestamp := clienttypes.GetSelfHeight(ctx), uint64(ctx.BlockTime().UnixNano()) + + if timeout.Elapsed(selfHeight, selfTimestamp) { + // packet flushing timeout has expired, abort the upgrade and return nil, + // committing an error receipt to state, restoring the channel and successfully timing out the packet. + k.MustAbortUpgrade(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), timeout.ErrTimeoutElapsed(selfHeight, selfTimestamp)) + } else if !k.HasInflightPackets(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) { + // set the channel state to flush complete if all packets have been flushed. + channel.State = types.FLUSHCOMPLETE + k.SetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), channel) + emitChannelFlushCompleteEvent(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), channel) + } + } + } + if channel.Ordering == types.ORDERED { + // NOTE: if the channel is ORDERED and a packet is timed out in FLUSHING state then + // the upgrade is aborted and the channel is set to CLOSED. + if channel.State == types.FLUSHING { + // an error receipt is written to state and the channel is restored to OPEN + k.MustAbortUpgrade(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), errorsmod.Wrap(types.ErrTimeoutElapsed, "packet timeout elapsed on ORDERED channel")) + } + channel.State = types.CLOSED k.SetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), channel) + emitChannelClosedEvent(ctx, packet, channel) } k.Logger(ctx).Info( @@ -171,10 +197,6 @@ func (k Keeper) TimeoutExecuted( // emit an event marking that we have processed the timeout emitTimeoutPacketEvent(ctx, packet, channel) - if channel.Ordering == types.ORDERED && channel.IsClosed() { - emitChannelClosedEvent(ctx, packet, channel) - } - return nil } @@ -186,9 +208,30 @@ func (k Keeper) TimeoutOnClose( chanCap *capabilitytypes.Capability, packet exported.PacketI, proof, - proofClosed []byte, + closedProof []byte, proofHeight exported.Height, nextSequenceRecv uint64, +) error { + return k.TimeoutOnCloseWithCounterpartyUpgradeSequence(ctx, chanCap, packet, proof, closedProof, proofHeight, nextSequenceRecv, 0) +} + +// TimeoutOnCloseWithCounterpartyUpgradeSequence is called by a module in order +// to prove that the channel to which an unreceived packet was addressed has +// been closed, so the packet will never be received (even if the timeoutHeight +// has not yet been reached). The difference with TimeoutOnClose is that it +// accepts an extra argument counterpartyUpgradeSequence that was needed for +// channel upgradability. +// +// This function will be removed in ibc-go v9.0.0 and the API of TimeoutOnClose will be updated. +func (k Keeper) TimeoutOnCloseWithCounterpartyUpgradeSequence( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + packet exported.PacketI, + proof, + closedProof []byte, + proofHeight exported.Height, + nextSequenceRecv uint64, + counterpartyUpgradeSequence uint64, ) error { channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) if !found { @@ -243,13 +286,18 @@ func (k Keeper) TimeoutOnClose( counterpartyHops := []string{connectionEnd.GetCounterparty().GetConnectionID()} counterparty := types.NewCounterparty(packet.GetSourcePort(), packet.GetSourceChannel()) - expectedChannel := types.NewChannel( - types.CLOSED, channel.Ordering, counterparty, counterpartyHops, channel.Version, - ) + expectedChannel := types.Channel{ + State: types.CLOSED, + Ordering: channel.Ordering, + Counterparty: counterparty, + ConnectionHops: counterpartyHops, + Version: channel.Version, + UpgradeSequence: counterpartyUpgradeSequence, + } // check that the opposing channel end has closed if err := k.connectionKeeper.VerifyChannelState( - ctx, connectionEnd, proofHeight, proofClosed, + ctx, connectionEnd, proofHeight, closedProof, channel.Counterparty.PortId, channel.Counterparty.ChannelId, expectedChannel, ); err != nil { diff --git a/modules/core/04-channel/keeper/timeout_test.go b/modules/core/04-channel/keeper/timeout_test.go index adaf237cf42..18df05efc54 100644 --- a/modules/core/04-channel/keeper/timeout_test.go +++ b/modules/core/04-channel/keeper/timeout_test.go @@ -6,6 +6,8 @@ import ( errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" @@ -13,6 +15,7 @@ import ( host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v8/testing" + "github.com/cosmos/ibc-go/v8/testing/mock" ) // TestTimeoutPacket test the TimeoutPacket call on chainA by ensuring the timeout has passed @@ -98,22 +101,6 @@ func (suite *KeeperTestSuite) TestTimeoutPacket() { suite.coordinator.Setup(path) packet = types.NewPacket(ibctesting.MockPacketData, 1, ibctesting.InvalidID, ibctesting.InvalidID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) }, false}, - {"channel not open", func() { - expError = types.ErrInvalidChannelState - suite.coordinator.Setup(path) - - timeoutHeight := path.EndpointA.GetClientState().GetLatestHeight().Increment().(clienttypes.Height) - - sequence, err := path.EndpointA.SendPacket(timeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) - suite.Require().NoError(err) - packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, disabledTimeoutTimestamp) - // need to update chainA's client representing chainB to prove missing ack - err = path.EndpointA.UpdateClient() - suite.Require().NoError(err) - - err = path.EndpointA.SetChannelState(types.CLOSED) - suite.Require().NoError(err) - }, false}, {"packet destination port ≠ channel counterparty port", func() { expError = types.ErrInvalidPacket suite.coordinator.Setup(path) @@ -137,7 +124,7 @@ func (suite *KeeperTestSuite) TestTimeoutPacket() { packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) }, false}, {"timeout", func() { - expError = types.ErrPacketTimeout + expError = types.ErrTimeoutNotReached suite.coordinator.Setup(path) sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) suite.Require().NoError(err) @@ -205,9 +192,9 @@ func (suite *KeeperTestSuite) TestTimeoutPacket() { }, false}, } - for i, tc := range testCases { + for _, tc := range testCases { tc := tc - suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() { + suite.Run(tc.msg, func() { var ( proof []byte proofHeight exported.Height @@ -246,8 +233,9 @@ func (suite *KeeperTestSuite) TestTimeoutPacket() { } } -// TestTimeoutExectued verifies that packet commitments are deleted on chainA after the -// channel capabilities are verified. +// TestTimeoutExecuted verifies that packet commitments are deleted on chainA after the +// channel capabilities are verified. In addition, the test verifies that the channel state +// after a timeout is updated accordingly. func (suite *KeeperTestSuite) TestTimeoutExecuted() { var ( path *ibctesting.Path @@ -255,38 +243,276 @@ func (suite *KeeperTestSuite) TestTimeoutExecuted() { chanCap *capabilitytypes.Capability ) - testCases := []testCase{ - {"success ORDERED", func() { - path.SetChannelOrdered() - suite.coordinator.Setup(path) + testCases := []struct { + msg string + malleate func() + expResult func(packetCommitment []byte, err error) + expEvents func(path *ibctesting.Path) map[string]map[string]string + }{ + { + "success ORDERED", + func() { + path.SetChannelOrdered() + suite.coordinator.Setup(path) + + timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) + timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano()) + + sequence, err := path.EndpointA.SendPacket(timeoutHeight, timeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) - timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) - timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano()) + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) + chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + }, + func(packetCommitment []byte, err error) { + suite.Require().NoError(err) + suite.Require().Nil(packetCommitment) + + // Check channel has been closed + channel := path.EndpointA.GetChannel() + suite.Require().Equal(channel.State, types.CLOSED) + }, + nil, + }, + { + "channel not found", + func() { + // use wrong channel naming + suite.coordinator.Setup(path) + packet = types.NewPacket(ibctesting.MockPacketData, 1, ibctesting.InvalidID, ibctesting.InvalidID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + }, + func(packetCommitment []byte, err error) { + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrChannelNotFound) + + // packet never sent. + suite.Require().Nil(packetCommitment) + }, + nil, + }, + { + "incorrect capability ORDERED", + func() { + path.SetChannelOrdered() + suite.coordinator.Setup(path) + + timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) + timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano()) + + sequence, err := path.EndpointA.SendPacket(timeoutHeight, timeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) - sequence, err := path.EndpointA.SendPacket(timeoutHeight, timeoutTimestamp, ibctesting.MockPacketData) - suite.Require().NoError(err) + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) + chanCap = capabilitytypes.NewCapability(100) + }, + func(packetCommitment []byte, err error) { + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrChannelCapabilityNotFound) + + // packet sent, never deleted. + suite.Require().NotNil(packetCommitment) + }, + nil, + }, + { + "set to flush complete with no inflight packets", + func() { + suite.coordinator.Setup(path) + + chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + + channel := path.EndpointA.GetChannel() + channel.State = types.FLUSHING + path.EndpointA.SetChannel(channel) + path.EndpointA.SetChannelCounterpartyUpgrade(types.Upgrade{ + Timeout: types.NewTimeout(clienttypes.ZeroHeight(), uint64(suite.chainA.GetContext().BlockTime().UnixNano())+types.DefaultTimeout.Timestamp), + }) + }, + func(packetCommitment []byte, err error) { + suite.Require().NoError(err) - packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) - chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - }, true}, - {"channel not found", func() { - // use wrong channel naming - suite.coordinator.Setup(path) - packet = types.NewPacket(ibctesting.MockPacketData, 1, ibctesting.InvalidID, ibctesting.InvalidID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - }, false}, - {"incorrect capability ORDERED", func() { - path.SetChannelOrdered() - suite.coordinator.Setup(path) + channel := path.EndpointA.GetChannel() + suite.Require().Equal(types.FLUSHCOMPLETE, channel.State, "channel state should still be set to FLUSHCOMPLETE") + }, + func(path *ibctesting.Path) map[string]map[string]string { + return ibctesting.EventsMap{ + types.EventTypeChannelFlushComplete: { + types.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + types.AttributeKeyChannelID: path.EndpointA.ChannelID, + types.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + types.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + types.AttributeKeyChannelState: path.EndpointA.GetChannel().State.String(), + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: types.AttributeValueCategory, + }, + } + }, + }, + { + "conterparty upgrade timeout is invalid", + func() { + suite.coordinator.Setup(path) - timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) - timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano()) + timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) + timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano()) - sequence, err := path.EndpointA.SendPacket(timeoutHeight, timeoutTimestamp, ibctesting.MockPacketData) - suite.Require().NoError(err) + sequence, err := path.EndpointA.SendPacket(timeoutHeight, timeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) - packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) - chanCap = capabilitytypes.NewCapability(100) - }, false}, + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) + chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + + channel := path.EndpointA.GetChannel() + channel.State = types.FLUSHING + path.EndpointA.SetChannel(channel) + }, + func(packetCommitment []byte, err error) { + suite.Require().NoError(err) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(types.FLUSHING, channel.State, "channel state should still be FLUSHING") + }, + nil, + }, + { + "conterparty upgrade timed out (abort)", + func() { + suite.coordinator.Setup(path) + + timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) + timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano()) + + sequence, err := path.EndpointA.SendPacket(timeoutHeight, timeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) + chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + + channel := path.EndpointA.GetChannel() + channel.State = types.FLUSHING + path.EndpointA.SetChannel(channel) + path.EndpointA.SetChannelUpgrade(types.Upgrade{ + Fields: path.EndpointA.GetProposedUpgrade().Fields, + Timeout: types.NewTimeout(clienttypes.ZeroHeight(), 1), + }) + path.EndpointA.SetChannelCounterpartyUpgrade(types.Upgrade{ + Timeout: types.NewTimeout(clienttypes.ZeroHeight(), 1), + }) + }, + func(packetCommitment []byte, err error) { + suite.Require().NoError(err) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(types.OPEN, channel.State, "channel state should still be OPEN") + + upgrade, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().False(found, "upgrade should not be present") + suite.Require().Equal(types.Upgrade{}, upgrade, "upgrade should be zero value") + + upgrade, found = suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetCounterpartyUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().False(found, "counterparty upgrade should not be present") + suite.Require().Equal(types.Upgrade{}, upgrade, "counterparty upgrade should be zero value") + + errorReceipt, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetUpgradeErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found, "error receipt should be present") + suite.Require().Equal(channel.UpgradeSequence, errorReceipt.Sequence, "error receipt sequence should be equal to channel upgrade sequence") + }, + nil, + }, + { + "conterparty upgrade has not timed out with in-flight packets", + func() { + suite.coordinator.Setup(path) + + timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) + timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano()) + + // we are sending two packets here as one will be removed in TimeoutExecuted. This is to ensure that + // there is still an in-flight packet so that the channel remains in the flushing state. + _, err := path.EndpointA.SendPacket(timeoutHeight, timeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + + sequence, err := path.EndpointA.SendPacket(timeoutHeight, timeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) + chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + + channel := path.EndpointA.GetChannel() + channel.State = types.FLUSHING + path.EndpointA.SetChannel(channel) + path.EndpointA.SetChannelUpgrade(types.Upgrade{ + Fields: path.EndpointA.GetProposedUpgrade().Fields, + Timeout: types.NewTimeout(clienttypes.ZeroHeight(), uint64(suite.chainA.GetContext().BlockTime().UnixNano())+types.DefaultTimeout.Timestamp), + }) + path.EndpointA.SetChannelCounterpartyUpgrade(types.Upgrade{ + Timeout: types.NewTimeout(clienttypes.ZeroHeight(), uint64(suite.chainB.GetContext().BlockTime().UnixNano())+types.DefaultTimeout.Timestamp), + }) + }, + func(packetCommitment []byte, err error) { + suite.Require().NoError(err) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(types.FLUSHING, channel.State, "channel state should still be FLUSHING") + + _, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found, "upgrade should not be deleted") + + _, found = suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetCounterpartyUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found, "counterparty upgrade should not be deleted") + + _, found = suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetUpgradeErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().False(found, "error receipt should not be written") + }, + nil, + }, + { + "ordered channel is closed and upgrade is aborted when timeout is executed", + func() { + path.SetChannelOrdered() + suite.coordinator.Setup(path) + + timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) + timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano()) + + sequence, err := path.EndpointA.SendPacket(timeoutHeight, timeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) + chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + + channel := path.EndpointA.GetChannel() + channel.State = types.FLUSHING + path.EndpointA.SetChannel(channel) + path.EndpointA.SetChannelUpgrade(types.Upgrade{ + Fields: path.EndpointA.GetProposedUpgrade().Fields, + Timeout: types.NewTimeout(clienttypes.ZeroHeight(), 1), + }) + path.EndpointA.SetChannelCounterpartyUpgrade(types.Upgrade{ + Timeout: types.NewTimeout(clienttypes.ZeroHeight(), 1), + }) + }, + func(packetCommitment []byte, err error) { + suite.Require().NoError(err) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(types.CLOSED, channel.State, "channel state should be CLOSED") + + upgrade, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().False(found, "upgrade should not be present") + suite.Require().Equal(types.Upgrade{}, upgrade, "upgrade should be zero value") + + upgrade, found = suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetCounterpartyUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().False(found, "counterparty upgrade should not be present") + suite.Require().Equal(types.Upgrade{}, upgrade, "counterparty upgrade should be zero value") + + errorReceipt, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetUpgradeErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found, "error receipt should be present") + suite.Require().Equal(channel.UpgradeSequence, errorReceipt.Sequence, "error receipt sequence should be equal to channel upgrade sequence") + }, + nil, + }, } for i, tc := range testCases { @@ -294,17 +520,20 @@ func (suite *KeeperTestSuite) TestTimeoutExecuted() { suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() { suite.SetupTest() // reset path = ibctesting.NewPath(suite.chainA, suite.chainB) + ctx := suite.chainA.GetContext() tc.malleate() - err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.TimeoutExecuted(suite.chainA.GetContext(), chanCap, packet) - pc := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(suite.chainA.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.TimeoutExecuted(ctx, chanCap, packet) + pc := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - if tc.expPass { - suite.NoError(err) - suite.Nil(pc) - } else { - suite.Error(err) + tc.expResult(pc, err) + if tc.expEvents != nil { + events := ctx.EventManager().ABCIEvents() + + expEvents := tc.expEvents(path) + + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) } }) } @@ -314,11 +543,12 @@ func (suite *KeeperTestSuite) TestTimeoutExecuted() { // channel on chainB after the packet commitment has been created. func (suite *KeeperTestSuite) TestTimeoutOnClose() { var ( - path *ibctesting.Path - packet types.Packet - chanCap *capabilitytypes.Capability - nextSeqRecv uint64 - ordered bool + path *ibctesting.Path + packet types.Packet + chanCap *capabilitytypes.Capability + nextSeqRecv uint64 + counterpartyUpgradeSequence uint64 + ordered bool ) testCases := []testCase{ @@ -483,6 +713,34 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.GetSelfHeight(suite.chainB.GetContext()), uint64(suite.chainB.GetContext().BlockTime().UnixNano())) chanCap = capabilitytypes.NewCapability(100) }, false}, + { + "failure: invalid counterparty upgrade sequence", + func() { + ordered = false + suite.coordinator.Setup(path) + + timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) + + sequence, err := path.EndpointA.SendPacket(timeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + + // trigger upgradeInit on B which will bump the counterparty upgrade sequence. + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + err = path.EndpointB.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.SetChannelState(types.CLOSED) + suite.Require().NoError(err) + + // need to update chainA's client representing chainB to prove missing ack + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, disabledTimeoutTimestamp) + chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + }, + false, + }, } for i, tc := range testCases { @@ -490,8 +748,9 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() { var proof []byte - suite.SetupTest() // reset - nextSeqRecv = 1 // must be explicitly changed + suite.SetupTest() // reset + nextSeqRecv = 1 // must be explicitly changed + counterpartyUpgradeSequence = 0 // must be explicitly changed path = ibctesting.NewPath(suite.chainA, suite.chainB) tc.malleate() @@ -500,7 +759,7 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { unorderedPacketKey := host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) orderedPacketKey := host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel()) - proofClosed, proofHeight := suite.chainB.QueryProof(channelKey) + closedProof, proofHeight := suite.chainB.QueryProof(channelKey) if ordered { proof, _ = suite.chainB.QueryProof(orderedPacketKey) @@ -508,7 +767,16 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { proof, _ = suite.chainB.QueryProof(unorderedPacketKey) } - err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.TimeoutOnClose(suite.chainA.GetContext(), chanCap, packet, proof, proofClosed, proofHeight, nextSeqRecv) + err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.TimeoutOnCloseWithCounterpartyUpgradeSequence( + suite.chainA.GetContext(), + chanCap, + packet, + proof, + closedProof, + proofHeight, + nextSeqRecv, + counterpartyUpgradeSequence, + ) if tc.expPass { suite.Require().NoError(err) diff --git a/modules/core/04-channel/keeper/upgrade.go b/modules/core/04-channel/keeper/upgrade.go new file mode 100644 index 00000000000..1dae7f7a862 --- /dev/null +++ b/modules/core/04-channel/keeper/upgrade.go @@ -0,0 +1,1049 @@ +package keeper + +import ( + "fmt" + "reflect" + "slices" + + errorsmod "cosmossdk.io/errors" + + "github.com/cosmos/cosmos-sdk/telemetry" + sdk "github.com/cosmos/cosmos-sdk/types" + + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v8/modules/core/exported" +) + +// ChanUpgradeInit is called by a module to initiate a channel upgrade handshake with +// a module on another chain. +func (k Keeper) ChanUpgradeInit( + ctx sdk.Context, + portID string, + channelID string, + upgradeFields types.UpgradeFields, +) (types.Upgrade, error) { + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return types.Upgrade{}, errorsmod.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + + if channel.State != types.OPEN { + return types.Upgrade{}, errorsmod.Wrapf(types.ErrInvalidChannelState, "expected %s, got %s", types.OPEN, channel.State) + } + + if err := k.validateSelfUpgradeFields(ctx, upgradeFields, channel); err != nil { + return types.Upgrade{}, err + } + + // NOTE: the Upgrade returned here is intentionally not fully populated. The Timeout remains unset + // until the counterparty calls ChanUpgradeTry. + return types.Upgrade{Fields: upgradeFields}, nil +} + +// WriteUpgradeInitChannel writes a channel which has successfully passed the UpgradeInit handshake step. +// An event is emitted for the handshake step. +func (k Keeper) WriteUpgradeInitChannel(ctx sdk.Context, portID, channelID string, upgrade types.Upgrade, upgradeVersion string) (types.Channel, types.Upgrade) { + defer telemetry.IncrCounter(1, "ibc", "channel", "upgrade-init") + + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + panic(fmt.Errorf("could not find existing channel when updating channel state in successful ChanUpgradeInit step, channelID: %s, portID: %s", channelID, portID)) + } + + if k.hasUpgrade(ctx, portID, channelID) { + // invalidating previous upgrade + k.deleteUpgradeInfo(ctx, portID, channelID) + k.WriteErrorReceipt(ctx, portID, channelID, types.NewUpgradeError(channel.UpgradeSequence, types.ErrInvalidUpgrade)) + } + + channel.UpgradeSequence++ + + upgrade.Fields.Version = upgradeVersion + + k.SetChannel(ctx, portID, channelID, channel) + k.SetUpgrade(ctx, portID, channelID, upgrade) + + k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "state", channel.State, "upgrade-sequence", fmt.Sprintf("%d", channel.UpgradeSequence)) + + return channel, upgrade +} + +// ChanUpgradeTry is called by a module to accept the first step of a channel upgrade handshake initiated by +// a module on another chain. If this function is successful, the proposed upgrade will be returned. If the upgrade fails, the upgrade sequence will still be incremented but an error will be returned. +func (k Keeper) ChanUpgradeTry( + ctx sdk.Context, + portID, + channelID string, + proposedConnectionHops []string, + counterpartyUpgradeFields types.UpgradeFields, + counterpartyUpgradeSequence uint64, + channelProof, + upgradeProof []byte, + proofHeight clienttypes.Height, +) (types.Channel, types.Upgrade, error) { + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return types.Channel{}, types.Upgrade{}, errorsmod.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + + if channel.State != types.OPEN { + return types.Channel{}, types.Upgrade{}, errorsmod.Wrapf(types.ErrInvalidChannelState, "expected %s, got %s", types.OPEN, channel.State) + } + + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return types.Channel{}, types.Upgrade{}, errorsmod.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0]) + } + + if connection.GetState() != int32(connectiontypes.OPEN) { + return types.Channel{}, types.Upgrade{}, errorsmod.Wrapf( + connectiontypes.ErrInvalidConnectionState, "connection state is not OPEN (got %s)", connectiontypes.State(connection.GetState()).String(), + ) + } + + // construct expected counterparty channel from information in state + // only the counterpartyUpgradeSequence is provided by the relayer + counterpartyConnectionHops := []string{connection.GetCounterparty().GetConnectionID()} + counterpartyChannel := types.Channel{ + State: types.OPEN, + Ordering: channel.Ordering, + Counterparty: types.NewCounterparty(portID, channelID), + ConnectionHops: counterpartyConnectionHops, + Version: channel.Version, + UpgradeSequence: counterpartyUpgradeSequence, // provided by the relayer + } + + // verify the counterparty channel state containing the upgrade sequence + if err := k.connectionKeeper.VerifyChannelState( + ctx, + connection, + proofHeight, channelProof, + channel.Counterparty.PortId, + channel.Counterparty.ChannelId, + counterpartyChannel, + ); err != nil { + return types.Channel{}, types.Upgrade{}, errorsmod.Wrap(err, "failed to verify counterparty channel state") + } + + var ( + err error + upgrade types.Upgrade + isCrossingHello bool + expectedUpgradeSequence uint64 + ) + + upgrade, isCrossingHello = k.GetUpgrade(ctx, portID, channelID) + if isCrossingHello { + expectedUpgradeSequence = channel.UpgradeSequence + } else { + // at the end of the TRY step, the current upgrade sequence will be incremented in the non-crossing + // hello case due to calling chanUpgradeInit, we should use this expected upgrade sequence for + // sequence mismatch comparison + expectedUpgradeSequence = channel.UpgradeSequence + 1 + } + if counterpartyUpgradeSequence < expectedUpgradeSequence { + // In this case, the counterparty upgrade is outdated. We want to force the counterparty + // to abort their upgrade and come back to sync with our own upgrade sequence. + + // In the crossing hello case, we already have an upgrade but it is at a higher sequence than the counterparty. + // Thus, our upgrade should take priority. We force the counterparty to abort their upgrade by invalidating all counterparty + // upgrade attempts below our own sequence by setting errorReceipt to upgradeSequence - 1. + // Since our channel upgrade sequence was incremented in the previous step, the counterparty will be forced to abort their upgrade + // and we will be able to proceed with our own upgrade. + // The upgrade handshake may then proceed on the counterparty with our sequence + // In the non-crossing hello (i.e. upgrade does not exist on our side), + // the sequence on both sides should move to a fresh sequence on the next upgrade attempt. + // Thus, we write an error receipt with our own upgrade sequence which will cause the counterparty + // to cancel their upgrade and move to the same sequence. When a new upgrade attempt is started from either + // side, it will be a fresh sequence for both sides (i.e. channel.upgradeSequence + 1). + // Note that expectedUpgradeSequence - 1 == channel.UpgradeSequence in the non-crossing hello case. + + // NOTE: Two possible outcomes may occur in this scenario. + // The ChanUpgradeCancel datagram may reach the counterparty first, which will cause the counterparty to cancel. The counterparty + // may then receive a TRY with our channel upgrade sequence and correctly increment their sequence to become synced with our upgrade attempt. + // The ChanUpgradeTry message may arrive first, in this case, **IF** the upgrade fields are mutually compatible; the counterparty will simply + // fast forward their sequence to our own and continue the upgrade. The following ChanUpgradeCancel message will be rejected as it is below the current sequence. + + return channel, upgrade, types.NewUpgradeError(expectedUpgradeSequence-1, errorsmod.Wrapf( + types.ErrInvalidUpgradeSequence, "counterparty upgrade sequence < current upgrade sequence (%d < %d)", counterpartyUpgradeSequence, channel.UpgradeSequence, + )) + } + + // verifies the proof that a particular proposed upgrade has been stored in the upgrade path of the counterparty + if err := k.connectionKeeper.VerifyChannelUpgrade( + ctx, + connection, + proofHeight, upgradeProof, + channel.Counterparty.PortId, + channel.Counterparty.ChannelId, + types.NewUpgrade(counterpartyUpgradeFields, types.Timeout{}, 0), + ); err != nil { + return types.Channel{}, types.Upgrade{}, errorsmod.Wrap(err, "failed to verify counterparty upgrade") + } + + // construct counterpartyChannel from existing information and provided counterpartyUpgradeSequence + // create upgrade fields from counterparty proposed upgrade and own verified connection hops + proposedUpgradeFields := types.UpgradeFields{ + Ordering: counterpartyUpgradeFields.Ordering, + ConnectionHops: proposedConnectionHops, + Version: counterpartyUpgradeFields.Version, + } + + // NOTE: if an upgrade exists (crossing hellos) then use existing upgrade fields + // otherwise, run the upgrade init sub-protocol + if isCrossingHello { + proposedUpgradeFields = upgrade.Fields + } else { + // NOTE: OnChanUpgradeInit will not be executed by the application + upgrade, err = k.ChanUpgradeInit(ctx, portID, channelID, proposedUpgradeFields) + if err != nil { + return types.Channel{}, types.Upgrade{}, errorsmod.Wrap(err, "failed to initialize upgrade") + } + + channel, upgrade = k.WriteUpgradeInitChannel(ctx, portID, channelID, upgrade, upgrade.Fields.Version) + } + + if err := k.checkForUpgradeCompatibility(ctx, proposedUpgradeFields, counterpartyUpgradeFields); err != nil { + return types.Channel{}, types.Upgrade{}, errorsmod.Wrap(err, "failed upgrade compatibility check") + } + + // if the counterparty sequence is greater than the current sequence, we fast-forward to the counterparty sequence. + if counterpartyUpgradeSequence > channel.UpgradeSequence { + channel.UpgradeSequence = counterpartyUpgradeSequence + k.SetChannel(ctx, portID, channelID, channel) + } + + if err := k.startFlushing(ctx, portID, channelID, &upgrade); err != nil { + return types.Channel{}, types.Upgrade{}, err + } + + return channel, upgrade, nil +} + +// WriteUpgradeTryChannel writes the channel end and upgrade to state after successfully passing the UpgradeTry handshake step. +// An event is emitted for the handshake step. +func (k Keeper) WriteUpgradeTryChannel(ctx sdk.Context, portID, channelID string, upgrade types.Upgrade, upgradeVersion string) (types.Channel, types.Upgrade) { + defer telemetry.IncrCounter(1, "ibc", "channel", "upgrade-try") + + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + panic(fmt.Errorf("could not find existing channel when updating channel state in successful ChanUpgradeTry step, channelID: %s, portID: %s", channelID, portID)) + } + + upgrade.Fields.Version = upgradeVersion + k.SetUpgrade(ctx, portID, channelID, upgrade) + + k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", types.OPEN, "new-state", channel.State) + + return channel, upgrade +} + +// ChanUpgradeAck is called by a module to accept the ACKUPGRADE handshake step of the channel upgrade protocol. +// This method should only be called by the IBC core msg server. +// This method will verify that the counterparty has called the ChanUpgradeTry handler. +// and that its own upgrade is compatible with the selected counterparty version. +// NOTE: the channel may be in either the OPEN or FLUSHING state. +// The channel may be in OPEN if we are in the happy path. +// +// A -> Init (OPEN), B -> Try (FLUSHING), A -> Ack (begins in OPEN) +// +// The channel may be in FLUSHING if we are in a crossing hellos situation. +// +// A -> Init (OPEN), B -> Init (OPEN) -> A -> Try (FLUSHING), B -> Try (FLUSHING), A -> Ack (begins in FLUSHING) +func (k Keeper) ChanUpgradeAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyUpgrade types.Upgrade, + channelProof, + upgradeProof []byte, + proofHeight clienttypes.Height, +) error { + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return errorsmod.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + + if !slices.Contains([]types.State{types.OPEN, types.FLUSHING}, channel.State) { + return errorsmod.Wrapf(types.ErrInvalidChannelState, "expected one of [%s, %s], got %s", types.OPEN, types.FLUSHING, channel.State) + } + + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return errorsmod.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0]) + } + + if connection.GetState() != int32(connectiontypes.OPEN) { + return errorsmod.Wrapf(connectiontypes.ErrInvalidConnectionState, "connection state is not OPEN (got %s)", connectiontypes.State(connection.GetState()).String()) + } + + counterpartyHops := []string{connection.GetCounterparty().GetConnectionID()} + counterpartyChannel := types.Channel{ + State: types.FLUSHING, + Ordering: channel.Ordering, + ConnectionHops: counterpartyHops, + Counterparty: types.NewCounterparty(portID, channelID), + Version: channel.Version, + UpgradeSequence: channel.UpgradeSequence, + } + + // verify the counterparty channel state containing the upgrade sequence + if err := k.connectionKeeper.VerifyChannelState( + ctx, + connection, + proofHeight, channelProof, + channel.Counterparty.PortId, + channel.Counterparty.ChannelId, + counterpartyChannel, + ); err != nil { + return errorsmod.Wrap(err, "failed to verify counterparty channel state") + } + + // verifies the proof that a particular proposed upgrade has been stored in the upgrade path of the counterparty + if err := k.connectionKeeper.VerifyChannelUpgrade( + ctx, + connection, + proofHeight, upgradeProof, + channel.Counterparty.PortId, + channel.Counterparty.ChannelId, + counterpartyUpgrade, + ); err != nil { + return errorsmod.Wrap(err, "failed to verify counterparty upgrade") + } + + // if we have cancelled our upgrade after performing UpgradeInit + // or UpgradeTry, the lack of a stored upgrade will prevent us from + // continuing the upgrade handshake + upgrade, found := k.GetUpgrade(ctx, portID, channelID) + if !found { + return errorsmod.Wrapf(types.ErrUpgradeNotFound, "failed to retrieve channel upgrade: port ID (%s) channel ID (%s)", portID, channelID) + } + + // optimistically accept version that TRY chain proposes and pass this to callback for confirmation + // in the crossing hello case, we do not modify version that our TRY call returned and instead enforce + // that both TRY calls returned the same version. It is possible that this will fail in the OnChanUpgradeAck + // callback if the version is invalid. + if channel.State == types.OPEN { + upgrade.Fields.Version = counterpartyUpgrade.Fields.Version + } + + // if upgrades are not compatible by ACK step, then we restore the channel + if err := k.checkForUpgradeCompatibility(ctx, upgrade.Fields, counterpartyUpgrade.Fields); err != nil { + return types.NewUpgradeError(channel.UpgradeSequence, err) + } + + if channel.State == types.OPEN { + if err := k.startFlushing(ctx, portID, channelID, &upgrade); err != nil { + return err + } + } + + timeout := counterpartyUpgrade.Timeout + selfHeight, selfTimestamp := clienttypes.GetSelfHeight(ctx), uint64(ctx.BlockTime().UnixNano()) + + if timeout.Elapsed(selfHeight, selfTimestamp) { + return types.NewUpgradeError(channel.UpgradeSequence, errorsmod.Wrap(timeout.ErrTimeoutElapsed(selfHeight, selfTimestamp), "counterparty upgrade timeout elapsed")) + } + + return nil +} + +// WriteUpgradeAckChannel writes a channel which has successfully passed the UpgradeAck handshake step as well as +// setting the upgrade for that channel. +// An event is emitted for the handshake step. +func (k Keeper) WriteUpgradeAckChannel(ctx sdk.Context, portID, channelID string, counterpartyUpgrade types.Upgrade) (types.Channel, types.Upgrade) { + defer telemetry.IncrCounter(1, "ibc", "channel", "upgrade-ack") + + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + panic(fmt.Errorf("could not find existing channel when updating channel state in successful ChanUpgradeAck step, channelID: %s, portID: %s", channelID, portID)) + } + + if !k.HasInflightPackets(ctx, portID, channelID) { + previousState := channel.State + channel.State = types.FLUSHCOMPLETE + k.SetChannel(ctx, portID, channelID, channel) + k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", previousState, "new-state", channel.State) + } + + upgrade, found := k.GetUpgrade(ctx, portID, channelID) + if !found { + panic(fmt.Errorf("could not find existing upgrade when updating channel state in successful ChanUpgradeAck step, channelID: %s, portID: %s", channelID, portID)) + } + + upgrade.Fields.Version = counterpartyUpgrade.Fields.Version + + k.SetUpgrade(ctx, portID, channelID, upgrade) + k.SetCounterpartyUpgrade(ctx, portID, channelID, counterpartyUpgrade) + + return channel, upgrade +} + +// ChanUpgradeConfirm is called on the chain which is on FLUSHING after chanUpgradeAck is called on the counterparty. +// This will inform the TRY chain of the timeout set on ACK by the counterparty. If the timeout has already exceeded, we will write an error receipt and restore. +func (k Keeper) ChanUpgradeConfirm( + ctx sdk.Context, + portID, + channelID string, + counterpartyChannelState types.State, + counterpartyUpgrade types.Upgrade, + channelProof, + upgradeProof []byte, + proofHeight clienttypes.Height, +) error { + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return errorsmod.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + + if channel.State != types.FLUSHING { + return errorsmod.Wrapf(types.ErrInvalidChannelState, "expected %s, got %s", types.FLUSHING, channel.State) + } + + if !slices.Contains([]types.State{types.FLUSHING, types.FLUSHCOMPLETE}, counterpartyChannelState) { + return errorsmod.Wrapf(types.ErrInvalidCounterparty, "expected one of [%s, %s], got %s", types.FLUSHING, types.FLUSHCOMPLETE, counterpartyChannelState) + } + + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return errorsmod.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0]) + } + + if connection.GetState() != int32(connectiontypes.OPEN) { + return errorsmod.Wrapf(connectiontypes.ErrInvalidConnectionState, "connection state is not OPEN (got %s)", connectiontypes.State(connection.GetState()).String()) + } + + counterpartyHops := []string{connection.GetCounterparty().GetConnectionID()} + counterpartyChannel := types.Channel{ + State: counterpartyChannelState, + Ordering: channel.Ordering, + ConnectionHops: counterpartyHops, + Counterparty: types.NewCounterparty(portID, channelID), + Version: channel.Version, + UpgradeSequence: channel.UpgradeSequence, + } + + if err := k.connectionKeeper.VerifyChannelState( + ctx, + connection, + proofHeight, channelProof, + channel.Counterparty.PortId, + channel.Counterparty.ChannelId, + counterpartyChannel, + ); err != nil { + return errorsmod.Wrap(err, "failed to verify counterparty channel state") + } + + if err := k.connectionKeeper.VerifyChannelUpgrade( + ctx, + connection, + proofHeight, upgradeProof, + channel.Counterparty.PortId, + channel.Counterparty.ChannelId, + counterpartyUpgrade, + ); err != nil { + return errorsmod.Wrap(err, "failed to verify counterparty upgrade") + } + + timeout := counterpartyUpgrade.Timeout + selfHeight, selfTimestamp := clienttypes.GetSelfHeight(ctx), uint64(ctx.BlockTime().UnixNano()) + + if timeout.Elapsed(selfHeight, selfTimestamp) { + return types.NewUpgradeError(channel.UpgradeSequence, errorsmod.Wrap(timeout.ErrTimeoutElapsed(selfHeight, selfTimestamp), "counterparty upgrade timeout elapsed")) + } + + return nil +} + +// WriteUpgradeConfirmChannel writes a channel which has successfully passed the ChanUpgradeConfirm handshake step. +// If the channel has no in-flight packets, its state is updated to indicate that flushing has completed. Otherwise, the counterparty upgrade is set +// and the channel state is left unchanged. +// An event is emitted for the handshake step. +func (k Keeper) WriteUpgradeConfirmChannel(ctx sdk.Context, portID, channelID string, counterpartyUpgrade types.Upgrade) types.Channel { + defer telemetry.IncrCounter(1, "ibc", "channel", "upgrade-confirm") + + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + panic(fmt.Errorf("could not find existing channel when updating channel state in successful ChanUpgradeConfirm step, channelID: %s, portID: %s", channelID, portID)) + } + + if !k.HasInflightPackets(ctx, portID, channelID) { + previousState := channel.State + channel.State = types.FLUSHCOMPLETE + k.SetChannel(ctx, portID, channelID, channel) + k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", previousState, "new-state", channel.State) + } + + k.SetCounterpartyUpgrade(ctx, portID, channelID, counterpartyUpgrade) + return channel +} + +// ChanUpgradeOpen is called by a module to complete the channel upgrade handshake and move the channel back to an OPEN state. +// This method should only be called after both channels have flushed any in-flight packets. +// This method should only be called directly by the core IBC message server. +func (k Keeper) ChanUpgradeOpen( + ctx sdk.Context, + portID, + channelID string, + counterpartyChannelState types.State, + counterpartyUpgradeSequence uint64, + channelProof []byte, + proofHeight clienttypes.Height, +) error { + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return errorsmod.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + + if channel.State != types.FLUSHCOMPLETE { + return errorsmod.Wrapf(types.ErrInvalidChannelState, "expected %s, got %s", types.FLUSHCOMPLETE, channel.State) + } + + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return errorsmod.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0]) + } + + if connection.GetState() != int32(connectiontypes.OPEN) { + return errorsmod.Wrapf(connectiontypes.ErrInvalidConnectionState, "connection state is not OPEN (got %s)", connectiontypes.State(connection.GetState()).String()) + } + + var counterpartyChannel types.Channel + switch counterpartyChannelState { + case types.OPEN: + upgrade, found := k.GetUpgrade(ctx, portID, channelID) + if !found { + return errorsmod.Wrapf(types.ErrUpgradeNotFound, "failed to retrieve channel upgrade: port ID (%s) channel ID (%s)", portID, channelID) + } + // If counterparty has reached OPEN, we must use the upgraded connection to verify the counterparty channel + upgradeConnection, found := k.connectionKeeper.GetConnection(ctx, upgrade.Fields.ConnectionHops[0]) + if !found { + return errorsmod.Wrap(connectiontypes.ErrConnectionNotFound, upgrade.Fields.ConnectionHops[0]) + } + + if upgradeConnection.GetState() != int32(connectiontypes.OPEN) { + return errorsmod.Wrapf(connectiontypes.ErrInvalidConnectionState, "connection state is not OPEN (got %s)", connectiontypes.State(upgradeConnection.GetState()).String()) + } + + // The counterparty upgrade sequence must be greater than or equal to + // the channel upgrade sequence. It should normally be equivalent, but + // in the unlikely case a new upgrade is initiated after it reopens, + // then the upgrade sequence will be greater than our upgrade sequence. + if counterpartyUpgradeSequence < channel.UpgradeSequence { + return errorsmod.Wrapf(types.ErrInvalidUpgradeSequence, "counterparty channel upgrade sequence (%d) must be greater than or equal to current upgrade sequence (%d)", counterpartyUpgradeSequence, channel.UpgradeSequence) + } + + counterpartyChannel = types.Channel{ + State: types.OPEN, + Ordering: upgrade.Fields.Ordering, + ConnectionHops: []string{upgradeConnection.GetCounterparty().GetConnectionID()}, + Counterparty: types.NewCounterparty(portID, channelID), + Version: upgrade.Fields.Version, + UpgradeSequence: counterpartyUpgradeSequence, + } + + case types.FLUSHCOMPLETE: + counterpartyChannel = types.Channel{ + State: types.FLUSHCOMPLETE, + Ordering: channel.Ordering, + ConnectionHops: []string{connection.GetCounterparty().GetConnectionID()}, + Counterparty: types.NewCounterparty(portID, channelID), + Version: channel.Version, + UpgradeSequence: channel.UpgradeSequence, + } + + default: + return errorsmod.Wrapf(types.ErrInvalidCounterparty, "counterparty channel state must be one of [%s, %s], got %s", types.OPEN, types.FLUSHCOMPLETE, counterpartyChannelState) + } + + if err := k.connectionKeeper.VerifyChannelState( + ctx, + connection, + proofHeight, channelProof, + channel.Counterparty.PortId, + channel.Counterparty.ChannelId, + counterpartyChannel, + ); err != nil { + return errorsmod.Wrap(err, "failed to verify counterparty channel") + } + + return nil +} + +// WriteUpgradeOpenChannel writes the agreed upon upgrade fields to the channel, and sets the channel state back to OPEN. This can be called in one of two cases: +// - In the UpgradeConfirm step of the handshake if both sides have already flushed all in-flight packets. +// - In the UpgradeOpen step of the handshake. +func (k Keeper) WriteUpgradeOpenChannel(ctx sdk.Context, portID, channelID string) types.Channel { + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + panic(fmt.Errorf("could not find existing channel when updating channel state, channelID: %s, portID: %s", channelID, portID)) + } + + upgrade, found := k.GetUpgrade(ctx, portID, channelID) + if !found { + panic(fmt.Errorf("could not find upgrade when updating channel state, channelID: %s, portID: %s", channelID, portID)) + } + + counterpartyUpgrade, found := k.GetCounterpartyUpgrade(ctx, portID, channelID) + if !found { + panic(fmt.Errorf("could not find counterparty upgrade when updating channel state, channelID: %s, portID: %s", channelID, portID)) + } + + // next seq recv and ack is used for ordered channels to verify the packet has been received/acked in the correct order + // this is no longer necessary if the channel is UNORDERED and should be reset to 1 + if channel.Ordering == types.ORDERED && upgrade.Fields.Ordering == types.UNORDERED { + k.SetNextSequenceRecv(ctx, portID, channelID, 1) + k.SetNextSequenceAck(ctx, portID, channelID, 1) + } + + // next seq recv and ack should updated when moving from UNORDERED to ORDERED using the counterparty NextSequenceSend as set just after blocking new packet sends. + // we can be sure that the next packet we are set to receive will be the first packet the counterparty sends after reopening. + // we can be sure that our next acknowledgement will be our first packet sent after upgrade, as the counterparty processed all sent packets after flushing completes. + if channel.Ordering == types.UNORDERED && upgrade.Fields.Ordering == types.ORDERED { + k.SetNextSequenceRecv(ctx, portID, channelID, counterpartyUpgrade.NextSequenceSend) + k.SetNextSequenceAck(ctx, portID, channelID, upgrade.NextSequenceSend) + } + + // Set the counterparty next sequence send as the recv start sequence. + // This will be the upper bound for pruning and it will allow for replay + // protection of historical packets. + k.setRecvStartSequence(ctx, portID, channelID, counterpartyUpgrade.NextSequenceSend) + + // First upgrade for this channel will set the pruning sequence to 1, the starting sequence for pruning. + // Subsequent upgrades will not modify the pruning sequence thereby allowing pruning to continue from the last + // pruned sequence. + if !k.HasPruningSequenceStart(ctx, portID, channelID) { + k.SetPruningSequenceStart(ctx, portID, channelID, 1) + } + + // Switch channel fields to upgrade fields and set channel state to OPEN + previousState := channel.State + channel.Ordering = upgrade.Fields.Ordering + channel.Version = upgrade.Fields.Version + channel.ConnectionHops = upgrade.Fields.ConnectionHops + channel.State = types.OPEN + + k.SetChannel(ctx, portID, channelID, channel) + + // delete state associated with upgrade which is no longer required. + k.deleteUpgradeInfo(ctx, portID, channelID) + + k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", previousState.String(), "new-state", types.OPEN.String()) + return channel +} + +// ChanUpgradeCancel is called by the msg server to prove that an error receipt was written on the counterparty +// which constitutes a valid situation where the upgrade should be cancelled. An error is returned if sufficient evidence +// for cancelling the upgrade has not been provided. +func (k Keeper) ChanUpgradeCancel(ctx sdk.Context, portID, channelID string, errorReceipt types.ErrorReceipt, errorReceiptProof []byte, proofHeight clienttypes.Height) error { + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return errorsmod.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + + _, found = k.GetUpgrade(ctx, portID, channelID) + if !found { + return errorsmod.Wrapf(types.ErrUpgradeNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + + // an error receipt proof must be provided. + if len(errorReceiptProof) == 0 { + return errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty error receipt proof unless the sender is authorized to cancel upgrades AND channel is not in FLUSHCOMPLETE") + } + + // REPLAY PROTECTION: The error receipt MUST have a sequence greater than or equal to the current upgrade sequence, + // except when the channel state is FLUSHCOMPLETE, in which case the sequences MUST match. This is required + // to guarantee that when a counterparty successfully completes an upgrade and moves to OPEN, this channel + // cannot cancel its upgrade. Without this strict sequence check, it would be possible for the counterparty + // to complete its upgrade, move to OPEN, initiate a new upgrade (and thus increment the upgrade sequence) and + // then cancel the new upgrade, all in the same block. This results in a valid error receipt being written at channel.UpgradeSequence + 1. + // The desired behaviour in this circumstance is for this channel to complete its current upgrade despite proof + // of an error receipt at a greater upgrade sequence + if channel.State == types.FLUSHCOMPLETE && errorReceipt.Sequence != channel.UpgradeSequence { + return errorsmod.Wrapf(types.ErrInvalidUpgradeSequence, "error receipt sequence (%d) must be equal to current upgrade sequence (%d) when the channel is in FLUSHCOMPLETE", errorReceipt.Sequence, channel.UpgradeSequence) + } + if errorReceipt.Sequence < channel.UpgradeSequence { + return errorsmod.Wrapf(types.ErrInvalidUpgradeSequence, "error receipt sequence (%d) must be greater than or equal to current upgrade sequence (%d)", errorReceipt.Sequence, channel.UpgradeSequence) + } + + // get underlying connection for proof verification + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return errorsmod.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0]) + } + + if connection.GetState() != int32(connectiontypes.OPEN) { + return errorsmod.Wrapf( + connectiontypes.ErrInvalidConnectionState, + "connection state is not OPEN (got %s)", connectiontypes.State(connection.GetState()).String(), + ) + } + + if err := k.connectionKeeper.VerifyChannelUpgradeError( + ctx, + connection, + proofHeight, + errorReceiptProof, + channel.Counterparty.PortId, + channel.Counterparty.ChannelId, + errorReceipt, + ); err != nil { + return errorsmod.Wrap(err, "failed to verify counterparty error receipt") + } + + return nil +} + +// WriteUpgradeCancelChannel writes a channel which has canceled the upgrade process.Auxiliary upgrade state is +// also deleted. +func (k Keeper) WriteUpgradeCancelChannel(ctx sdk.Context, portID, channelID string, sequence uint64) { + defer telemetry.IncrCounter(1, "ibc", "channel", "upgrade-cancel") + + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + panic(fmt.Errorf("could not find existing channel when updating channel state, channelID: %s, portID: %s", channelID, portID)) + } + + previousState := channel.State + + channel = k.restoreChannel(ctx, portID, channelID, sequence, channel) + k.WriteErrorReceipt(ctx, portID, channelID, types.NewUpgradeError(sequence, types.ErrInvalidUpgrade)) + + k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", previousState, "new-state", types.OPEN.String()) +} + +// ChanUpgradeTimeout times out an outstanding upgrade. +// This should be used by the initialising chain when the counterparty chain has not responded to an upgrade proposal within the specified timeout period. +func (k Keeper) ChanUpgradeTimeout( + ctx sdk.Context, + portID, channelID string, + counterpartyChannel types.Channel, + counterpartyChannelProof []byte, + proofHeight exported.Height, +) error { + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return errorsmod.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + + if !slices.Contains([]types.State{types.FLUSHING, types.FLUSHCOMPLETE}, channel.State) { + return errorsmod.Wrapf(types.ErrInvalidChannelState, "expected one of [%s, %s], got %s", types.FLUSHING, types.FLUSHCOMPLETE, channel.State) + } + + upgrade, found := k.GetUpgrade(ctx, portID, channelID) + if !found { + return errorsmod.Wrapf(types.ErrUpgradeNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return errorsmod.Wrap( + connectiontypes.ErrConnectionNotFound, + channel.ConnectionHops[0], + ) + } + + if connection.GetState() != int32(connectiontypes.OPEN) { + return errorsmod.Wrapf( + connectiontypes.ErrInvalidConnectionState, + "connection state is not OPEN (got %s)", connectiontypes.State(connection.GetState()).String(), + ) + } + + proofTimestamp, err := k.connectionKeeper.GetTimestampAtHeight(ctx, connection, proofHeight) + if err != nil { + return err + } + + // proof must be from a height after timeout has elapsed. Either timeoutHeight or timeoutTimestamp must be defined. + // if timeoutHeight is defined and proof is from before timeout height, abort transaction + if !upgrade.Timeout.Elapsed(proofHeight.(clienttypes.Height), proofTimestamp) { + return errorsmod.Wrap(upgrade.Timeout.ErrTimeoutNotReached(proofHeight.(clienttypes.Height), proofTimestamp), "upgrade timeout not reached") + } + + // counterparty channel must be proved to still be in OPEN state or FLUSHING state. + if !slices.Contains([]types.State{types.OPEN, types.FLUSHING}, counterpartyChannel.State) { + return errorsmod.Wrapf(types.ErrInvalidCounterparty, "expected one of [%s, %s], got %s", types.OPEN, types.FLUSHING, counterpartyChannel.State) + } + + if counterpartyChannel.State == types.OPEN { + upgradeConnection, found := k.connectionKeeper.GetConnection(ctx, upgrade.Fields.ConnectionHops[0]) + if !found { + return errorsmod.Wrap( + connectiontypes.ErrConnectionNotFound, + upgrade.Fields.ConnectionHops[0], + ) + } + counterpartyHops := []string{upgradeConnection.GetCounterparty().GetConnectionID()} + + upgradeAlreadyComplete := upgrade.Fields.Version == counterpartyChannel.Version && upgrade.Fields.Ordering == counterpartyChannel.Ordering && upgrade.Fields.ConnectionHops[0] == counterpartyHops[0] + if upgradeAlreadyComplete { + // counterparty has already successfully upgraded so we cannot timeout + return errorsmod.Wrap(types.ErrUpgradeTimeoutFailed, "counterparty channel is already upgraded") + } + } + + if counterpartyChannel.UpgradeSequence < channel.UpgradeSequence { + return errorsmod.Wrapf(types.ErrInvalidUpgradeSequence, "counterparty channel upgrade sequence (%d) must be greater than or equal to current upgrade sequence (%d)", counterpartyChannel.UpgradeSequence, channel.UpgradeSequence) + } + + // NOTE: The counterpartyChannel upgrade fields are not checked in the case + // the counterpartyChannel is in FLUSHING. This is not required because + // we prove that the upgrade timeout has elapsed on the counterparty, + // thus no historical proofs can be submitted. It is not possible for the + // counterparty to have upgraded if they were in FLUSHING and the upgrade + // timeout elapsed. Do not make use of the relayer provided fields without + // verifying them. + + // verify the counterparty channel state + if err := k.connectionKeeper.VerifyChannelState( + ctx, + connection, + proofHeight, counterpartyChannelProof, + channel.Counterparty.PortId, + channel.Counterparty.ChannelId, + counterpartyChannel, + ); err != nil { + return errorsmod.Wrap(err, "failed to verify counterparty channel state") + } + + return nil +} + +// WriteUpgradeTimeoutChannel restores the channel state of an initialising chain in the event that the counterparty chain has passed the timeout set in ChanUpgradeInit to the state before the upgrade was proposed. +// Auxiliary upgrade state is also deleted. +// An event is emitted for the handshake step. +func (k Keeper) WriteUpgradeTimeoutChannel( + ctx sdk.Context, + portID, channelID string, +) (types.Channel, types.Upgrade) { + defer telemetry.IncrCounter(1, "ibc", "channel", "upgrade-timeout") + + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + panic(fmt.Errorf("could not find existing channel when updating channel state in successful ChanUpgradeTimeout step, channelID: %s, portID: %s", channelID, portID)) + } + + upgrade, found := k.GetUpgrade(ctx, portID, channelID) + if !found { + panic(fmt.Errorf("could not find existing upgrade when cancelling channel upgrade, channelID: %s, portID: %s", channelID, portID)) + } + + channel = k.restoreChannel(ctx, portID, channelID, channel.UpgradeSequence, channel) + k.WriteErrorReceipt(ctx, portID, channelID, types.NewUpgradeError(channel.UpgradeSequence, types.ErrUpgradeTimeout)) + + k.Logger(ctx).Info("channel state restored", "port-id", portID, "channel-id", channelID) + + return channel, upgrade +} + +// startFlushing will set the upgrade last packet send and continue blocking the upgrade from continuing until all +// in-flight packets have been flushed. +func (k Keeper) startFlushing(ctx sdk.Context, portID, channelID string, upgrade *types.Upgrade) error { + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return errorsmod.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return errorsmod.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0]) + } + + if connection.GetState() != int32(connectiontypes.OPEN) { + return errorsmod.Wrapf(connectiontypes.ErrInvalidConnectionState, "connection state is not OPEN (got %s)", connectiontypes.State(connection.GetState()).String()) + } + + channel.State = types.FLUSHING + k.SetChannel(ctx, portID, channelID, channel) + + nextSequenceSend, found := k.GetNextSequenceSend(ctx, portID, channelID) + if !found { + return errorsmod.Wrapf(types.ErrSequenceSendNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + + upgrade.NextSequenceSend = nextSequenceSend + upgrade.Timeout = k.getAbsoluteUpgradeTimeout(ctx) + k.SetUpgrade(ctx, portID, channelID, *upgrade) + + return nil +} + +// getAbsoluteUpgradeTimeout returns the absolute timeout for the given upgrade. +func (k Keeper) getAbsoluteUpgradeTimeout(ctx sdk.Context) types.Timeout { + upgradeTimeout := k.GetParams(ctx).UpgradeTimeout + return types.NewTimeout(clienttypes.ZeroHeight(), uint64(ctx.BlockTime().UnixNano())+upgradeTimeout.Timestamp) +} + +// checkForUpgradeCompatibility checks performs stateful validation of self upgrade fields relative to counterparty upgrade. +func (k Keeper) checkForUpgradeCompatibility(ctx sdk.Context, upgradeFields, counterpartyUpgradeFields types.UpgradeFields) error { + // assert that both sides propose the same channel ordering + if upgradeFields.Ordering != counterpartyUpgradeFields.Ordering { + return errorsmod.Wrapf(types.ErrIncompatibleCounterpartyUpgrade, "expected upgrade ordering (%s) to match counterparty upgrade ordering (%s)", upgradeFields.Ordering, counterpartyUpgradeFields.Ordering) + } + + if upgradeFields.Version != counterpartyUpgradeFields.Version { + return errorsmod.Wrapf(types.ErrIncompatibleCounterpartyUpgrade, "expected upgrade version (%s) to match counterparty upgrade version (%s)", upgradeFields.Version, counterpartyUpgradeFields.Version) + } + + connection, found := k.connectionKeeper.GetConnection(ctx, upgradeFields.ConnectionHops[0]) + if !found { + // NOTE: this error is expected to be unreachable as the proposed upgrade connectionID should have been + // validated in the upgrade INIT and TRY handlers + return errorsmod.Wrap(connectiontypes.ErrConnectionNotFound, upgradeFields.ConnectionHops[0]) + } + + if connection.GetState() != int32(connectiontypes.OPEN) { + // NOTE: this error is expected to be unreachable as the proposed upgrade connectionID should have been + // validated in the upgrade INIT and TRY handlers + return errorsmod.Wrapf(connectiontypes.ErrInvalidConnectionState, "expected proposed connection to be OPEN (got %s)", connectiontypes.State(connection.GetState()).String()) + } + + // connectionHops can change in a channelUpgrade, however both sides must still be each other's counterparty. + if counterpartyUpgradeFields.ConnectionHops[0] != connection.GetCounterparty().GetConnectionID() { + return errorsmod.Wrapf( + types.ErrIncompatibleCounterpartyUpgrade, "counterparty upgrade connection end is not a counterparty of self proposed connection end (%s != %s)", counterpartyUpgradeFields.ConnectionHops[0], connection.GetCounterparty().GetConnectionID()) + } + + return nil +} + +// validateSelfUpgradeFields validates the proposed upgrade fields against the existing channel. +// It returns an error if the following constraints are not met: +// - there exists at least one valid proposed change to the existing channel fields +// - the proposed connection hops do not exist +// - the proposed version is non-empty (checked in UpgradeFields.ValidateBasic()) +// - the proposed connection hops are not open +func (k Keeper) validateSelfUpgradeFields(ctx sdk.Context, proposedUpgrade types.UpgradeFields, currentChannel types.Channel) error { + currentFields := extractUpgradeFields(currentChannel) + + if reflect.DeepEqual(proposedUpgrade, currentFields) { + return errorsmod.Wrapf(types.ErrInvalidUpgrade, "existing channel end is identical to proposed upgrade channel end: got %s", proposedUpgrade) + } + + connectionID := proposedUpgrade.ConnectionHops[0] + connection, found := k.connectionKeeper.GetConnection(ctx, connectionID) + if !found { + return errorsmod.Wrapf(connectiontypes.ErrConnectionNotFound, "failed to retrieve connection: %s", connectionID) + } + + if connection.GetState() != int32(connectiontypes.OPEN) { + return errorsmod.Wrapf( + connectiontypes.ErrInvalidConnectionState, + "connection state is not OPEN (got %s)", connectiontypes.State(connection.GetState()).String(), + ) + } + + getVersions := connection.GetVersions() + if len(getVersions) != 1 { + return errorsmod.Wrapf( + connectiontypes.ErrInvalidVersion, + "single version must be negotiated on connection before opening channel, got: %v", + getVersions, + ) + } + + if !connectiontypes.VerifySupportedFeature(getVersions[0], proposedUpgrade.Ordering.String()) { + return errorsmod.Wrapf( + connectiontypes.ErrInvalidVersion, + "connection version %s does not support channel ordering: %s", + getVersions[0], proposedUpgrade.Ordering.String(), + ) + } + + return nil +} + +// extractUpgradeFields returns the upgrade fields from the provided channel. +func extractUpgradeFields(channel types.Channel) types.UpgradeFields { + return types.UpgradeFields{ + Ordering: channel.Ordering, + ConnectionHops: channel.ConnectionHops, + Version: channel.Version, + } +} + +// MustAbortUpgrade will restore the channel state to its pre-upgrade state so that upgrade is aborted. +// Any unnecessary state is deleted and an error receipt is written. +// This function is expected to always succeed, a panic will occur if an error occurs. +func (k Keeper) MustAbortUpgrade(ctx sdk.Context, portID, channelID string, err error) { + if err := k.abortUpgrade(ctx, portID, channelID, err); err != nil { + panic(err) + } +} + +// abortUpgrade will restore the channel state to its pre-upgrade state so that upgrade is aborted. +// All upgrade information associated with the upgrade attempt is deleted and an upgrade error +// receipt is written for that upgrade attempt. This prevents the upgrade handshake from continuing +// on our side and provides proof for the counterparty to safely abort the upgrade. +func (k Keeper) abortUpgrade(ctx sdk.Context, portID, channelID string, err error) error { + if err == nil { + return errorsmod.Wrap(types.ErrInvalidUpgradeError, "cannot abort upgrade handshake with nil error") + } + + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return errorsmod.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + + // in the case of application callbacks, the error may not be an upgrade error. + // in this case we need to construct one in order to write the error receipt. + upgradeError, ok := err.(*types.UpgradeError) + if !ok { + upgradeError = types.NewUpgradeError(channel.UpgradeSequence, err) + } + + // the channel upgrade sequence has already been updated in ChannelUpgradeTry, so we can pass + // its updated value. + k.restoreChannel(ctx, portID, channelID, channel.UpgradeSequence, channel) + k.WriteErrorReceipt(ctx, portID, channelID, upgradeError) + + return nil +} + +// restoreChannel will restore the channel state to its pre-upgrade state so that upgrade is aborted. +// When an upgrade attempt is aborted, the upgrade information must be deleted. This prevents us +// from continuing an upgrade handshake after we cancel an upgrade attempt. +func (k Keeper) restoreChannel(ctx sdk.Context, portID, channelID string, upgradeSequence uint64, channel types.Channel) types.Channel { + channel.State = types.OPEN + channel.UpgradeSequence = upgradeSequence + + k.SetChannel(ctx, portID, channelID, channel) + + // delete state associated with upgrade which is no longer required. + k.deleteUpgradeInfo(ctx, portID, channelID) + + return channel +} + +// WriteErrorReceipt will write an error receipt from the provided UpgradeError. +func (k Keeper) WriteErrorReceipt(ctx sdk.Context, portID, channelID string, upgradeError *types.UpgradeError) { + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + panic(errorsmod.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID)) + } + + errorReceiptToWrite := upgradeError.GetErrorReceipt() + + existingErrorReceipt, found := k.GetUpgradeErrorReceipt(ctx, portID, channelID) + if found && existingErrorReceipt.Sequence >= errorReceiptToWrite.Sequence { + panic(errorsmod.Wrapf(types.ErrInvalidUpgradeSequence, "error receipt sequence (%d) must be greater than existing error receipt sequence (%d)", errorReceiptToWrite.Sequence, existingErrorReceipt.Sequence)) + } + + // Ensure that no upgrade attempt exists for the same sequence we are + // writing an error receipt for. This could lead to divergent behaviour + // on the counterparty. + if channel.UpgradeSequence <= errorReceiptToWrite.Sequence { + upgradeFound := k.hasUpgrade(ctx, portID, channelID) + counterpartyUpgradeFound := k.hasCounterpartyUpgrade(ctx, portID, channelID) + if upgradeFound || counterpartyUpgradeFound { + panic(errorsmod.Wrapf(types.ErrInvalidUpgradeSequence, "attempting to write error receipt at sequence (%d) while upgrade information exists at the same sequence", errorReceiptToWrite.Sequence)) + } + } + + k.setUpgradeErrorReceipt(ctx, portID, channelID, errorReceiptToWrite) + EmitErrorReceiptEvent(ctx, portID, channelID, channel, upgradeError) +} diff --git a/modules/core/04-channel/keeper/upgrade_test.go b/modules/core/04-channel/keeper/upgrade_test.go new file mode 100644 index 00000000000..a67ffa12682 --- /dev/null +++ b/modules/core/04-channel/keeper/upgrade_test.go @@ -0,0 +1,2859 @@ +package keeper_test + +import ( + "fmt" + "math" + "testing" + + errorsmod "cosmossdk.io/errors" + + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + "github.com/cosmos/ibc-go/v8/modules/core/exported" + ibctesting "github.com/cosmos/ibc-go/v8/testing" + "github.com/cosmos/ibc-go/v8/testing/mock" +) + +func (suite *KeeperTestSuite) TestChanUpgradeInit() { + var ( + path *ibctesting.Path + expSequence uint64 + upgradeFields types.UpgradeFields + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "success with later upgrade sequence", + func() { + channel := path.EndpointA.GetChannel() + channel.UpgradeSequence = 4 + path.EndpointA.SetChannel(channel) + expSequence = 5 + }, + true, + }, + { + "upgrade fields are identical to channel end", + func() { + channel := path.EndpointA.GetChannel() + upgradeFields = types.NewUpgradeFields(channel.Ordering, channel.ConnectionHops, channel.Version) + }, + false, + }, + { + "channel not found", + func() { + path.EndpointA.ChannelID = "invalid-channel" + path.EndpointA.ChannelConfig.PortID = "invalid-port" + }, + false, + }, + { + "channel state is not in OPEN state", + func() { + suite.Require().NoError(path.EndpointA.SetChannelState(types.CLOSED)) + }, + false, + }, + { + "proposed channel connection not found", + func() { + upgradeFields.ConnectionHops = []string{"connection-100"} + }, + false, + }, + { + "invalid proposed channel connection state", + func() { + connectionEnd := path.EndpointA.GetConnection() + connectionEnd.State = connectiontypes.UNINITIALIZED + + suite.chainA.GetSimApp().GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chainA.GetContext(), "connection-100", connectionEnd) + upgradeFields.ConnectionHops = []string{"connection-100"} + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + expSequence = 1 + + upgradeFields = types.NewUpgradeFields(types.UNORDERED, []string{path.EndpointA.ConnectionID}, mock.UpgradeVersion) + + tc.malleate() + + upgrade, err := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.ChanUpgradeInit( + suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, upgradeFields, + ) + + if tc.expPass { + ctx := suite.chainA.GetContext() + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.WriteUpgradeInitChannel(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, upgrade, upgrade.Fields.Version) + channel := path.EndpointA.GetChannel() + + suite.Require().NoError(err) + suite.Require().Equal(expSequence, channel.UpgradeSequence) + suite.Require().Equal(mock.Version, channel.Version) + suite.Require().Equal(types.OPEN, channel.State) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestChanUpgradeTry() { + var ( + path *ibctesting.Path + proposedUpgrade types.Upgrade + counterpartyUpgrade types.Upgrade + ) + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + "success: crossing hellos", + func() { + err := path.EndpointB.ChanUpgradeInit() + suite.Require().NoError(err) + }, + nil, + }, + { + "success: upgrade sequence is fast forwarded to counterparty upgrade sequence", + func() { + channel := path.EndpointA.GetChannel() + channel.UpgradeSequence = 5 + path.EndpointA.SetChannel(channel) + + suite.coordinator.CommitBlock(suite.chainA) + }, + nil, + }, + { + "channel not found", + func() { + path.EndpointB.ChannelID = ibctesting.InvalidID + }, + types.ErrChannelNotFound, + }, + { + "channel state is not in OPEN state", + func() { + suite.Require().NoError(path.EndpointB.SetChannelState(types.CLOSED)) + }, + types.ErrInvalidChannelState, + }, + { + "connection not found", + func() { + channel := path.EndpointB.GetChannel() + channel.ConnectionHops = []string{"connection-100"} + path.EndpointB.SetChannel(channel) + }, + connectiontypes.ErrConnectionNotFound, + }, + { + "invalid connection state", + func() { + connectionEnd := path.EndpointB.GetConnection() + connectionEnd.State = connectiontypes.UNINITIALIZED + suite.chainB.GetSimApp().GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chainB.GetContext(), path.EndpointB.ConnectionID, connectionEnd) + }, + connectiontypes.ErrInvalidConnectionState, + }, + { + "initializing handshake fails, proposed connection hops do not exist", + func() { + proposedUpgrade.Fields.ConnectionHops = []string{ibctesting.InvalidID} + }, + connectiontypes.ErrConnectionNotFound, + }, + { + "fails due to proof verification failure, counterparty channel ordering does not match expected ordering", + func() { + channel := path.EndpointB.GetChannel() + channel.Ordering = types.ORDERED + path.EndpointB.SetChannel(channel) + }, + commitmenttypes.ErrInvalidProof, + }, + { + "fails due to proof verification failure, counterparty upgrade connection hops are tampered with", + func() { + counterpartyUpgrade.Fields.ConnectionHops = []string{ibctesting.InvalidID} + }, + commitmenttypes.ErrInvalidProof, + }, + { + "fails due to incompatible upgrades, chainB proposes a new connection hop that does not match counterparty", + func() { + // reuse existing connection to create a new connection in a non OPEN state + connection := path.EndpointB.GetConnection() + // ensure counterparty connectionID does not match connectionID set in counterparty proposed upgrade + connection.Counterparty.ConnectionId = "connection-50" + + // set proposed connection in state + proposedConnectionID := "connection-100" //nolint:goconst + suite.chainB.GetSimApp().GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chainB.GetContext(), proposedConnectionID, connection) + proposedUpgrade.Fields.ConnectionHops[0] = proposedConnectionID + }, + types.ErrIncompatibleCounterpartyUpgrade, + }, + { + "fails due to mismatch in upgrade sequences", + func() { + channel := path.EndpointB.GetChannel() + channel.UpgradeSequence = 5 + path.EndpointB.SetChannel(channel) + }, + // channel sequence will be returned so that counterparty inits on completely fresh sequence for both sides + types.NewUpgradeError(5, types.ErrInvalidUpgradeSequence), + }, + { + "fails due to mismatch in upgrade sequences: chainB is on incremented sequence without an upgrade indicating it has already processed upgrade at this sequence.", + func() { + channel := path.EndpointB.GetChannel() + channel.UpgradeSequence = 1 + errorReceipt := types.NewUpgradeError(1, types.ErrInvalidUpgrade) + suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.WriteErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, errorReceipt) + path.EndpointB.SetChannel(channel) + }, + types.NewUpgradeError(1, types.ErrInvalidUpgradeSequence), + }, + { + "fails due to mismatch in upgrade sequences, crossing hello with the TRY chain having a higher sequence", + func() { + channel := path.EndpointB.GetChannel() + channel.UpgradeSequence = 4 + path.EndpointB.SetChannel(channel) + + // upgrade sequence is 5 after this call + err := path.EndpointB.ChanUpgradeInit() + suite.Require().NoError(err) + }, + types.NewUpgradeError(4, types.ErrInvalidUpgradeSequence), + }, + { + // ChainA(Sequence: 0, mock-version-v2), ChainB(Sequence: 0, mock-version-v3) + // ChainA.INIT(Sequence: 1) + // ChainB.INIT(Sequence: 1) + // ChainA.TRY => error (incompatible versions) + // ChainB.TRY => error (incompatible versions) + "crossing hellos: fails due to incompatible version", + func() { + // use incompatible version + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = fmt.Sprintf("%s-v3", mock.Version) + proposedUpgrade = path.EndpointB.GetProposedUpgrade() + + err := path.EndpointB.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeTry() + suite.Require().Error(err) + suite.Require().ErrorContains(err, "incompatible counterparty upgrade") + suite.Require().Equal(uint64(1), path.EndpointA.GetChannel().UpgradeSequence) + }, + types.ErrIncompatibleCounterpartyUpgrade, + }, + { + // ChainA(Sequence: 0, mock-version-v2), ChainB(Sequence: 4, mock-version-v3) + // ChainA.INIT(Sequence: 1) + // ChainB.INIT(Sequence: 5) + // ChainA.TRY => error (incompatible versions) + // ChainB.TRY(ErrorReceipt: 4) + "crossing hellos: upgrade starts with mismatching upgrade sequences and try fails on counterparty due to incompatible version", + func() { + channel := path.EndpointB.GetChannel() + channel.UpgradeSequence = 4 + path.EndpointB.SetChannel(channel) + + // use incompatible version + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = fmt.Sprintf("%s-v3", mock.Version) + proposedUpgrade = path.EndpointB.GetProposedUpgrade() + + err := path.EndpointB.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeTry() + suite.Require().Error(err) + suite.Require().ErrorContains(err, "incompatible counterparty upgrade") + suite.Require().Equal(uint64(1), path.EndpointA.GetChannel().UpgradeSequence) + }, + types.NewUpgradeError(4, types.ErrInvalidUpgradeSequence), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + expPass := tc.expError == nil + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + proposedUpgrade = path.EndpointB.GetProposedUpgrade() + + var found bool + counterpartyUpgrade, found = path.EndpointA.Chain.GetSimApp().IBCKeeper.ChannelKeeper.GetUpgrade(path.EndpointA.Chain.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + + tc.malleate() + + // ensure clients are up to date to receive valid proofs + suite.Require().NoError(path.EndpointB.UpdateClient()) + + channelProof, upgradeProof, proofHeight := path.EndpointA.QueryChannelUpgradeProof() + + _, upgrade, err := suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.ChanUpgradeTry( + suite.chainB.GetContext(), + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + proposedUpgrade.Fields.ConnectionHops, + counterpartyUpgrade.Fields, + path.EndpointA.GetChannel().UpgradeSequence, + channelProof, + upgradeProof, + proofHeight, + ) + + if expPass { + suite.Require().NoError(err) + suite.Require().NotEmpty(upgrade) + suite.Require().Equal(proposedUpgrade.Fields, upgrade.Fields) + + nextSequenceSend, found := path.EndpointB.Chain.GetSimApp().IBCKeeper.ChannelKeeper.GetNextSequenceSend(path.EndpointB.Chain.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().True(found) + suite.Require().Equal(nextSequenceSend, upgrade.NextSequenceSend) + } else { + suite.assertUpgradeError(err, tc.expError) + } + }) + } +} + +// TestChanUpgrade_CrossingHellos_UpgradeSucceeds_AfterCancel verifies that under crossing hellos if upgrade +// sequences become out of sync, the upgrade can still be performed successfully after the upgrade is cancelled. +// ChainA(Sequence: 0), ChainB(Sequence 4) +// ChainA.INIT(Sequence: 1) +// ChainB.INIT(Sequence: 5) +// ChainB.TRY(ErrorReceipt: 4) +// ChainA.Cancel(Sequence: 4) +// ChainA.TRY(Sequence: 5) // fastforward +// ChainB.ACK => Success +// ChainA.Confirm => Success +// ChainB.Open => Success +func (suite *KeeperTestSuite) TestChanUpgrade_CrossingHellos_UpgradeSucceeds_AfterCancel() { + var path *ibctesting.Path + + suite.Run("setup path", func() { + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + }) + + suite.Run("chainA upgrade init", func() { + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + }) + + suite.Run("set chainB upgrade sequence ahead of counterparty", func() { + channel := path.EndpointB.GetChannel() + channel.UpgradeSequence = 4 + path.EndpointB.SetChannel(channel) + }) + + suite.Run("chainB upgrade init (crossing hello)", func() { + err := path.EndpointB.ChanUpgradeInit() + suite.Require().NoError(err) + }) + + suite.Run("chainB upgrade try fails with invalid sequence", func() { + err := path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + errorReceipt, found := path.EndpointB.Chain.GetSimApp().GetIBCKeeper().ChannelKeeper.GetUpgradeErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().True(found) + suite.Require().Equal(uint64(4), errorReceipt.Sequence) + }) + + suite.Run("cancel upgrade on chainA and fast forward upgrade sequence", func() { + err := path.EndpointA.ChanUpgradeCancel() + suite.Require().NoError(err) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(types.OPEN, channel.State) + suite.Require().Equal(uint64(4), channel.UpgradeSequence) + }) + + suite.Run("try chainA upgrade now succeeds with synchronized upgrade sequences", func() { + err := path.EndpointA.ChanUpgradeTry() + suite.Require().NoError(err) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(types.FLUSHING, channel.State) + suite.Require().Equal(uint64(5), channel.UpgradeSequence) + }) + + suite.Run("upgrade handshake completes successfully", func() { + err := path.EndpointB.ChanUpgradeAck() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeConfirm() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeOpen() + suite.Require().NoError(err) + }) + + suite.Run("assert successful upgrade expected channel state", func() { + channelA := path.EndpointA.GetChannel() + suite.Require().Equal(types.OPEN, channelA.State, "channel should be in OPEN state") + suite.Require().Equal(mock.UpgradeVersion, channelA.Version, "version should be correctly upgraded") + suite.Require().Equal(mock.UpgradeVersion, path.EndpointB.GetChannel().Version, "version should be correctly upgraded") + suite.Require().Equal(uint64(5), channelA.UpgradeSequence, "upgrade sequence should be incremented") + + channelB := path.EndpointB.GetChannel() + suite.Require().Equal(types.OPEN, channelB.State, "channel should be in OPEN state") + suite.Require().Equal(mock.UpgradeVersion, channelB.Version, "version should be correctly upgraded") + suite.Require().Equal(mock.UpgradeVersion, channelB.Version, "version should be correctly upgraded") + suite.Require().Equal(uint64(5), channelB.UpgradeSequence, "upgrade sequence should be incremented") + }) +} + +// TestChanUpgrade_CrossingHellos_UpgradeSucceeds_AfterCancelErrors verifies that under crossing hellos if upgrade +// sequences become out of sync, the upgrade can still be performed successfully after the cancel fails. +// ChainA(Sequence: 0), ChainB(Sequence 4) +// ChainA.INIT(Sequence: 1) +// ChainB.INIT(Sequence: 5) +// ChainA.TRY(Sequence: 5) // fastforward +// ChainB.TRY(ErrorReceipt: 4) +// ChainA.Cancel => Error (errorReceipt.Sequence < channel.UpgradeSequence) +// ChainB.ACK => Success +// ChainA.Confirm => Success +// ChainB.Open => Success +func (suite *KeeperTestSuite) TestChanUpgrade_CrossingHellos_UpgradeSucceeds_AfterCancelErrors() { + var ( + historicalChannelProof []byte + historicalUpgradeProof []byte + proofHeight clienttypes.Height + path *ibctesting.Path + ) + + suite.Run("setup path", func() { + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + }) + + suite.Run("chainA upgrade init", func() { + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(uint64(1), channel.UpgradeSequence) + }) + + suite.Run("set chainB upgrade sequence ahead of counterparty", func() { + channel := path.EndpointB.GetChannel() + channel.UpgradeSequence = 4 + path.EndpointB.SetChannel(channel) + }) + + suite.Run("chainB upgrade init (crossing hello)", func() { + err := path.EndpointB.ChanUpgradeInit() + suite.Require().NoError(err) + + channel := path.EndpointB.GetChannel() + suite.Require().Equal(uint64(5), channel.UpgradeSequence) + }) + + suite.Run("query proofs at chainA upgrade sequence 1", func() { + // commit block and update client on chainB + suite.coordinator.CommitBlock(suite.chainA, suite.chainB) + suite.Require().NoError(path.EndpointB.UpdateClient()) + // use proofs when chain A has not executed TRY yet and use them when executing TRY on chain B + historicalChannelProof, historicalUpgradeProof, proofHeight = path.EndpointA.QueryChannelUpgradeProof() + }) + + suite.Run("chainA upgrade try (fast-forwards sequence)", func() { + err := path.EndpointA.ChanUpgradeTry() + suite.Require().NoError(err) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(uint64(5), channel.UpgradeSequence) + }) + + suite.Run("chainB upgrade try fails with written error receipt (4)", func() { + // NOTE: ante handlers are bypassed here and the handler is invoked directly. + // Thus, we set the upgrade error receipt explicitly below + _, _, err := suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.ChanUpgradeTry( + suite.chainB.GetContext(), + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + path.EndpointB.GetChannelUpgrade().Fields.ConnectionHops, + path.EndpointA.GetChannelUpgrade().Fields, + 1, // proofs queried at chainA upgrade sequence 1 + historicalChannelProof, + historicalUpgradeProof, + proofHeight, + ) + suite.Require().Error(err) + suite.assertUpgradeError(err, types.NewUpgradeError(4, types.ErrInvalidUpgradeSequence)) + + suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.WriteErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, err.(*types.UpgradeError)) + suite.coordinator.CommitBlock(suite.chainB) + }) + + suite.Run("chainA upgrade cancellation fails for invalid sequence", func() { + err := path.EndpointA.ChanUpgradeCancel() + suite.Require().Error(err) + suite.Require().ErrorContains(err, "invalid upgrade sequence") + + // assert channel remains in flushing state at upgrade sequence 5 + channel := path.EndpointA.GetChannel() + suite.Require().Equal(types.FLUSHING, channel.State) + suite.Require().Equal(uint64(5), channel.UpgradeSequence) + }) + + suite.Run("upgrade handshake completes successfully", func() { + err := path.EndpointB.ChanUpgradeAck() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeConfirm() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeOpen() + suite.Require().NoError(err) + }) + + suite.Run("assert successful upgrade expected channel state", func() { + channelA := path.EndpointA.GetChannel() + suite.Require().Equal(types.OPEN, channelA.State, "channel should be in OPEN state") + suite.Require().Equal(mock.UpgradeVersion, channelA.Version, "version should be correctly upgraded") + suite.Require().Equal(mock.UpgradeVersion, path.EndpointB.GetChannel().Version, "version should be correctly upgraded") + suite.Require().Equal(uint64(5), channelA.UpgradeSequence, "upgrade sequence should be incremented") + + channelB := path.EndpointB.GetChannel() + suite.Require().Equal(types.OPEN, channelB.State, "channel should be in OPEN state") + suite.Require().Equal(mock.UpgradeVersion, channelB.Version, "version should be correctly upgraded") + suite.Require().Equal(mock.UpgradeVersion, channelB.Version, "version should be correctly upgraded") + suite.Require().Equal(uint64(5), channelB.UpgradeSequence, "upgrade sequence should be incremented") + }) +} + +func (suite *KeeperTestSuite) TestWriteUpgradeTry() { + var ( + path *ibctesting.Path + proposedUpgrade types.Upgrade + ) + + testCases := []struct { + name string + malleate func() + }{ + { + "success with no packet commitments", + func() {}, + }, + { + "success with packet commitments", + func() { + // manually set packet commitment + sequence, err := path.EndpointB.SendPacket(suite.chainB.GetTimeoutHeight(), 0, ibctesting.MockPacketData) + suite.Require().NoError(err) + suite.Require().Equal(uint64(1), sequence) + }, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + proposedUpgrade = path.EndpointB.GetProposedUpgrade() + + tc.malleate() + + ctx := suite.chainB.GetContext() + upgradedChannelEnd, upgradeWithAppCallbackVersion := suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.WriteUpgradeTryChannel( + ctx, + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + proposedUpgrade, + proposedUpgrade.Fields.Version, + ) + + channel := path.EndpointB.GetChannel() + suite.Require().Equal(upgradedChannelEnd, channel) + + upgrade, found := suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.GetUpgrade(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().True(found) + suite.Require().Equal(upgradeWithAppCallbackVersion, upgrade) + }) + } +} + +func (suite *KeeperTestSuite) TestChanUpgradeAck() { + var ( + path *ibctesting.Path + counterpartyUpgrade types.Upgrade + ) + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + "success with later upgrade sequence", + func() { + channel := path.EndpointA.GetChannel() + channel.UpgradeSequence = 10 + path.EndpointA.SetChannel(channel) + + channel = path.EndpointB.GetChannel() + channel.UpgradeSequence = 10 + path.EndpointB.SetChannel(channel) + + suite.coordinator.CommitBlock(suite.chainA, suite.chainB) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + }, + nil, + }, + { + "failure if initializing chain reinitializes before ACK", + func() { + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + }, + commitmenttypes.ErrInvalidProof, // sequences are out of sync + }, + { + "channel not found", + func() { + path.EndpointA.ChannelID = ibctesting.InvalidID + path.EndpointA.ChannelConfig.PortID = ibctesting.InvalidID + }, + types.ErrChannelNotFound, + }, + { + "channel state is not in FLUSHING state", + func() { + suite.Require().NoError(path.EndpointA.SetChannelState(types.CLOSED)) + }, + types.ErrInvalidChannelState, + }, + { + "connection not found", + func() { + channel := path.EndpointA.GetChannel() + channel.ConnectionHops = []string{"connection-100"} + path.EndpointA.SetChannel(channel) + }, + connectiontypes.ErrConnectionNotFound, + }, + { + "invalid connection state", + func() { + connectionEnd := path.EndpointA.GetConnection() + connectionEnd.State = connectiontypes.UNINITIALIZED + path.EndpointA.SetConnection(connectionEnd) + }, + connectiontypes.ErrInvalidConnectionState, + }, + { + "upgrade not found", + func() { + store := suite.chainA.GetContext().KVStore(suite.chainA.GetSimApp().GetKey(exported.ModuleName)) + store.Delete(host.ChannelUpgradeKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + }, + types.ErrUpgradeNotFound, + }, + { + "fails due to upgrade incompatibility", + func() { + // Need to set counterparty upgrade in state and update clients to ensure + // proofs submitted reflect the altered upgrade. + counterpartyUpgrade.Fields.ConnectionHops = []string{ibctesting.InvalidID} + path.EndpointB.SetChannelUpgrade(counterpartyUpgrade) + + suite.coordinator.CommitBlock(suite.chainB) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + }, + types.NewUpgradeError(1, types.ErrIncompatibleCounterpartyUpgrade), + }, + { + "fails due to proof verification failure, counterparty channel ordering does not match expected ordering", + func() { + channel := path.EndpointA.GetChannel() + channel.Ordering = types.ORDERED + path.EndpointA.SetChannel(channel) + }, + commitmenttypes.ErrInvalidProof, + }, + { + "fails due to proof verification failure, counterparty update has unexpected sequence", + func() { + // Decrementing NextSequenceSend is sufficient to cause the proof to fail. + counterpartyUpgrade.NextSequenceSend-- + }, + commitmenttypes.ErrInvalidProof, + }, + { + "fails due to mismatch in upgrade ordering", + func() { + upgrade := path.EndpointA.GetChannelUpgrade() + upgrade.Fields.Ordering = types.NONE + + path.EndpointA.SetChannelUpgrade(upgrade) + }, + types.NewUpgradeError(1, types.ErrIncompatibleCounterpartyUpgrade), + }, + { + "counterparty timeout has elapsed", + func() { + // Need to set counterparty upgrade in state and update clients to ensure + // proofs submitted reflect the altered upgrade. + counterpartyUpgrade.Timeout = types.NewTimeout(clienttypes.NewHeight(0, 1), 0) + path.EndpointB.SetChannelUpgrade(counterpartyUpgrade) + + err := path.EndpointB.UpdateClient() + suite.Require().NoError(err) + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + }, + types.NewUpgradeError(1, types.ErrTimeoutElapsed), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + // manually set packet commitment so that the chainB channel state is FLUSHING + sequence, err := path.EndpointB.SendPacket(suite.chainB.GetTimeoutHeight(), 0, ibctesting.MockPacketData) + suite.Require().NoError(err) + suite.Require().Equal(uint64(1), sequence) + + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + // ensure client is up to date to receive valid proofs + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + counterpartyUpgrade = path.EndpointB.GetChannelUpgrade() + + tc.malleate() + + channelProof, upgradeProof, proofHeight := path.EndpointB.QueryChannelUpgradeProof() + + err = suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.ChanUpgradeAck( + suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, counterpartyUpgrade, + channelProof, upgradeProof, proofHeight, + ) + + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err) + + channel := path.EndpointA.GetChannel() + // ChanUpgradeAck will set the channel state to FLUSHING + // It will be set to FLUSHING_COMPLETE in the write function. + suite.Require().Equal(types.FLUSHING, channel.State) + } else { + suite.assertUpgradeError(err, tc.expError) + } + }) + } +} + +func (suite *KeeperTestSuite) TestWriteChannelUpgradeAck() { + var ( + path *ibctesting.Path + proposedUpgrade types.Upgrade + ) + + testCases := []struct { + name string + malleate func() + hasPacketCommitments bool + }{ + { + "success with no packet commitments", + func() {}, + false, + }, + { + "success with packet commitments", + func() { + // manually set packet commitment + sequence, err := path.EndpointA.SendPacket(suite.chainB.GetTimeoutHeight(), 0, ibctesting.MockPacketData) + suite.Require().NoError(err) + suite.Require().Equal(uint64(1), sequence) + }, + true, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + + tc.malleate() + + // perform the upgrade handshake. + suite.Require().NoError(path.EndpointA.ChanUpgradeInit()) + + suite.Require().NoError(path.EndpointB.ChanUpgradeTry()) + + ctx := suite.chainA.GetContext() + proposedUpgrade = path.EndpointB.GetChannelUpgrade() + + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.WriteUpgradeAckChannel(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, proposedUpgrade) + + channel := path.EndpointA.GetChannel() + upgrade := path.EndpointA.GetChannelUpgrade() + suite.Require().Equal(mock.UpgradeVersion, upgrade.Fields.Version) + + if !tc.hasPacketCommitments { + suite.Require().Equal(types.FLUSHCOMPLETE, channel.State) + } + counterpartyUpgrade, ok := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetCounterpartyUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(ok) + suite.Require().Equal(proposedUpgrade, counterpartyUpgrade) + }) + } +} + +func (suite *KeeperTestSuite) TestChanUpgrade_ReinitializedBeforeAck() { + var path *ibctesting.Path + suite.Run("setup path", func() { + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + }) + + suite.Run("chainA upgrade init", func() { + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(uint64(1), channel.UpgradeSequence) + }) + + suite.Run("chainB upgrade try", func() { + err := path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + }) + + suite.Run("chainA upgrade init reinitialized after ack", func() { + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(uint64(2), channel.UpgradeSequence) + }) + + suite.Run("chan upgrade ack fails", func() { + err := path.EndpointA.ChanUpgradeAck() + suite.Require().Error(err) + }) + + suite.Run("chainB upgrade cancel", func() { + err := path.EndpointB.ChanUpgradeCancel() + suite.Require().NoError(err) + }) + + suite.Run("upgrade handshake succeeds on new upgrade attempt", func() { + err := path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeAck() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeConfirm() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeOpen() + suite.Require().NoError(err) + }) + + suite.Run("assert successful upgrade expected channel state", func() { + channelA := path.EndpointA.GetChannel() + suite.Require().Equal(types.OPEN, channelA.State, "channel should be in OPEN state") + suite.Require().Equal(mock.UpgradeVersion, channelA.Version, "version should be correctly upgraded") + suite.Require().Equal(mock.UpgradeVersion, path.EndpointB.GetChannel().Version, "version should be correctly upgraded") + suite.Require().Equal(uint64(2), channelA.UpgradeSequence, "upgrade sequence should be incremented") + + channelB := path.EndpointB.GetChannel() + suite.Require().Equal(types.OPEN, channelB.State, "channel should be in OPEN state") + suite.Require().Equal(mock.UpgradeVersion, channelB.Version, "version should be correctly upgraded") + suite.Require().Equal(mock.UpgradeVersion, channelB.Version, "version should be correctly upgraded") + suite.Require().Equal(uint64(2), channelB.UpgradeSequence, "upgrade sequence should be incremented") + }) +} + +func (suite *KeeperTestSuite) TestChanUpgradeConfirm() { + var ( + path *ibctesting.Path + counterpartyChannelState types.State + counterpartyUpgrade types.Upgrade + ) + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + "success with later upgrade sequence", + func() { + channel := path.EndpointA.GetChannel() + channel.UpgradeSequence = 10 + path.EndpointA.SetChannel(channel) + + channel = path.EndpointB.GetChannel() + channel.UpgradeSequence = 10 + path.EndpointB.SetChannel(channel) + + suite.coordinator.CommitBlock(suite.chainA, suite.chainB) + + err := path.EndpointB.UpdateClient() + suite.Require().NoError(err) + }, + nil, + }, + { + "success with in-flight packets on init chain", + func() { + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + seq, err := path.EndpointA.SendPacket(defaultTimeoutHeight, 0, ibctesting.MockPacketData) + suite.Require().Equal(uint64(1), seq) + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeAck() + suite.Require().NoError(err) + + err = path.EndpointB.UpdateClient() + suite.Require().NoError(err) + + counterpartyChannelState = path.EndpointA.GetChannel().State + counterpartyUpgrade = path.EndpointA.GetChannelUpgrade() + }, + nil, + }, + { + "success with in-flight packets on try chain", + func() { + portID, channelID := path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID + suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), portID, channelID, 1, []byte("hash")) + }, + nil, + }, + { + "channel not found", + func() { + path.EndpointB.ChannelID = ibctesting.InvalidID + path.EndpointB.ChannelConfig.PortID = ibctesting.InvalidID + }, + types.ErrChannelNotFound, + }, + { + "channel is not in FLUSHING state", + func() { + err := path.EndpointB.SetChannelState(types.CLOSED) + suite.Require().NoError(err) + }, + types.ErrInvalidChannelState, + }, + { + "invalid counterparty channel state", + func() { + counterpartyChannelState = types.CLOSED + }, + types.ErrInvalidCounterparty, + }, + { + "connection not found", + func() { + channel := path.EndpointB.GetChannel() + channel.ConnectionHops = []string{"connection-100"} + path.EndpointB.SetChannel(channel) + }, + connectiontypes.ErrConnectionNotFound, + }, + { + "invalid connection state", + func() { + connectionEnd := path.EndpointB.GetConnection() + connectionEnd.State = connectiontypes.UNINITIALIZED + path.EndpointB.SetConnection(connectionEnd) + }, + connectiontypes.ErrInvalidConnectionState, + }, + { + "fails due to proof verification failure, counterparty channel ordering does not match expected ordering", + func() { + channel := path.EndpointA.GetChannel() + channel.Ordering = types.ORDERED + path.EndpointA.SetChannel(channel) + + suite.coordinator.CommitBlock(suite.chainA) + + err := path.EndpointB.UpdateClient() + suite.Require().NoError(err) + }, + commitmenttypes.ErrInvalidProof, + }, + { + "fails due to mismatch in upgrade ordering", + func() { + upgrade := path.EndpointA.GetChannelUpgrade() + upgrade.Fields.Ordering = types.NONE + + path.EndpointA.SetChannelUpgrade(upgrade) + + suite.coordinator.CommitBlock(suite.chainA) + + err := path.EndpointB.UpdateClient() + suite.Require().NoError(err) + }, + commitmenttypes.ErrInvalidProof, + }, + { + "counterparty timeout has elapsed", + func() { + // Need to set counterparty upgrade in state and update clients to ensure + // proofs submitted reflect the altered upgrade. + counterpartyUpgrade.Timeout = types.NewTimeout(clienttypes.NewHeight(0, 1), 0) + path.EndpointA.SetChannelUpgrade(counterpartyUpgrade) + + suite.coordinator.CommitBlock(suite.chainA) + + err := path.EndpointB.UpdateClient() + suite.Require().NoError(err) + }, + types.NewUpgradeError(1, types.ErrTimeoutElapsed), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeAck() + suite.Require().NoError(err) + + err = path.EndpointB.UpdateClient() + suite.Require().NoError(err) + + counterpartyChannelState = path.EndpointA.GetChannel().State + counterpartyUpgrade = path.EndpointA.GetChannelUpgrade() + + tc.malleate() + + channelProof, upgradeProof, proofHeight := path.EndpointA.QueryChannelUpgradeProof() + + err = suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.ChanUpgradeConfirm( + suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, counterpartyChannelState, counterpartyUpgrade, + channelProof, upgradeProof, proofHeight, + ) + + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err) + } else { + suite.assertUpgradeError(err, tc.expError) + } + }) + } +} + +func (suite *KeeperTestSuite) TestWriteUpgradeConfirm() { + var ( + path *ibctesting.Path + proposedUpgrade types.Upgrade + ) + + testCases := []struct { + name string + malleate func() + hasPacketCommitments bool + }{ + { + "success with no packet commitments", + func() {}, + false, + }, + { + "success with packet commitments", + func() { + // manually set packet commitment + sequence, err := path.EndpointA.SendPacket(suite.chainB.GetTimeoutHeight(), 0, ibctesting.MockPacketData) + suite.Require().NoError(err) + suite.Require().Equal(uint64(1), sequence) + }, + true, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + + tc.malleate() + + // perform the upgrade handshake. + suite.Require().NoError(path.EndpointB.ChanUpgradeInit()) + + suite.Require().NoError(path.EndpointA.ChanUpgradeTry()) + + suite.Require().NoError(path.EndpointB.ChanUpgradeAck()) + + ctx := suite.chainA.GetContext() + proposedUpgrade = path.EndpointB.GetChannelUpgrade() + + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.WriteUpgradeConfirmChannel(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, proposedUpgrade) + + channel := path.EndpointA.GetChannel() + upgrade := path.EndpointA.GetChannelUpgrade() + suite.Require().Equal(mock.UpgradeVersion, upgrade.Fields.Version) + + if !tc.hasPacketCommitments { + suite.Require().Equal(types.FLUSHCOMPLETE, channel.State) + } else { + suite.Require().Equal(types.FLUSHING, channel.State) + } + counterpartyUpgrade, ok := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetCounterpartyUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(ok, "counterparty upgrade should be present") + suite.Require().Equal(proposedUpgrade, counterpartyUpgrade) + }) + } +} + +func (suite *KeeperTestSuite) TestChanUpgradeOpen() { + var path *ibctesting.Path + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + "success: counterparty in flushcomplete", + func() { + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + + // Need to create a packet commitment on A so as to keep it from going to FLUSHCOMPLETE if no inflight packets exist. + sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + packet := types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + err = path.EndpointB.RecvPacket(packet) + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeAck() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeConfirm() + suite.Require().NoError(err) + + err = path.EndpointA.AcknowledgePacket(packet, ibctesting.MockAcknowledgement) + suite.Require().NoError(err) + + // cause the packet commitment on chain A to be deleted and the channel state to be updated to FLUSHCOMPLETE. + suite.coordinator.CommitBlock(suite.chainA, suite.chainB) + suite.Require().NoError(path.EndpointA.UpdateClient()) + }, + nil, + }, + { + "success: counterparty initiated new upgrade after opening", + func() { + // create reason to upgrade + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + "additional upgrade" + + err := path.EndpointB.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + }, + nil, + }, + { + "success: counterparty upgrade sequence is incorrect", + func() { + counterpartyCh := path.EndpointB.GetChannel() + counterpartyCh.UpgradeSequence-- + path.EndpointB.SetChannel(counterpartyCh) + }, + types.ErrInvalidUpgradeSequence, + }, + { + "channel not found", + func() { + path.EndpointA.ChannelConfig.PortID = ibctesting.InvalidID + }, + types.ErrChannelNotFound, + }, + { + "channel state is not FLUSHCOMPLETE", + func() { + channel := path.EndpointA.GetChannel() + channel.State = types.FLUSHING + path.EndpointA.SetChannel(channel) + }, + types.ErrInvalidChannelState, + }, + { + "connection not found", + func() { + channel := path.EndpointA.GetChannel() + channel.ConnectionHops = []string{"connection-100"} + path.EndpointA.SetChannel(channel) + }, + connectiontypes.ErrConnectionNotFound, + }, + { + "invalid connection state", + func() { + connectionEnd := path.EndpointA.GetConnection() + connectionEnd.State = connectiontypes.UNINITIALIZED + path.EndpointA.SetConnection(connectionEnd) + }, + connectiontypes.ErrInvalidConnectionState, + }, + { + "invalid counterparty channel state", + func() { + channel := path.EndpointB.GetChannel() + channel.State = types.CLOSED + path.EndpointB.SetChannel(channel) + }, + types.ErrInvalidCounterparty, + }, + } + + // Create an initial path used only to invoke a ChanOpenInit handshake. + // This bumps the channel identifier generated for chain A on the + // next path used to run the upgrade handshake. + // See issue 4062. + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + suite.Require().NoError(path.EndpointA.ChanOpenInit()) + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeAck() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeConfirm() + suite.Require().NoError(err) + + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + tc.malleate() + + channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channelProof, proofHeight := path.EndpointB.QueryProof(channelKey) + + err = suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.ChanUpgradeOpen( + suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, + path.EndpointB.GetChannel().State, path.EndpointB.GetChannel().UpgradeSequence, channelProof, proofHeight, + ) + + if tc.expError == nil { + suite.Require().NoError(err) + } else { + suite.Require().ErrorIs(err, tc.expError) + } + }) + } +} + +func (suite *KeeperTestSuite) TestWriteUpgradeOpenChannel() { + var path *ibctesting.Path + + testCases := []struct { + name string + malleate func() + expPanic bool + }{ + { + name: "success", + malleate: func() {}, + expPanic: false, + }, + { + name: "channel not found", + malleate: func() { + path.EndpointA.Chain.DeleteKey(host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + }, + expPanic: true, + }, + { + name: "upgrade not found", + malleate: func() { + path.EndpointA.Chain.DeleteKey(host.ChannelUpgradeKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + }, + expPanic: true, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + // Need to create a packet commitment on A so as to keep it from going to OPEN if no inflight packets exist. + sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + packet := types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + err = path.EndpointB.RecvPacket(packet) + suite.Require().NoError(err) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + + suite.Require().NoError(path.EndpointA.ChanUpgradeInit()) + suite.Require().NoError(path.EndpointB.ChanUpgradeTry()) + suite.Require().NoError(path.EndpointA.ChanUpgradeAck()) + suite.Require().NoError(path.EndpointB.ChanUpgradeConfirm()) + + // Ack packet to delete packet commitment before calling WriteUpgradeOpenChannel + err = path.EndpointA.AcknowledgePacket(packet, ibctesting.MockAcknowledgement) + suite.Require().NoError(err) + + ctx := suite.chainA.GetContext() + + tc.malleate() + + if tc.expPanic { + suite.Require().Panics(func() { + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.WriteUpgradeOpenChannel(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + }) + } else { + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.WriteUpgradeOpenChannel(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channel := path.EndpointA.GetChannel() + + // Assert that channel state has been updated + suite.Require().Equal(types.OPEN, channel.State) + suite.Require().Equal(mock.UpgradeVersion, channel.Version) + + // Assert that state stored for upgrade has been deleted + upgrade, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().Equal(types.Upgrade{}, upgrade) + suite.Require().False(found) + + counterpartyUpgrade, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetCounterpartyUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().Equal(types.Upgrade{}, counterpartyUpgrade) + suite.Require().False(found) + } + }) + } +} + +func (suite *KeeperTestSuite) TestWriteUpgradeOpenChannel_Ordering() { + var path *ibctesting.Path + + testCases := []struct { + name string + malleate func() + preUpgrade func() + postUpgrade func() + }{ + { + name: "success: ORDERED -> UNORDERED", + malleate: func() { + path.EndpointA.ChannelConfig.Order = types.ORDERED + path.EndpointB.ChannelConfig.Order = types.ORDERED + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Ordering = types.UNORDERED + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Ordering = types.UNORDERED + }, + preUpgrade: func() { + ctx := suite.chainA.GetContext() + + // assert that NextSeqAck is incremented to 2 because channel is still ordered + seq, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetNextSequenceAck(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(uint64(2), seq) + + // assert that NextSeqRecv is incremented to 2 because channel is still ordered + seq, found = suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetNextSequenceRecv(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(uint64(2), seq) + + // Assert that pruning sequence start has not been initialized. + suite.Require().False(suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.HasPruningSequenceStart(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + + // Assert that recv start sequence has not been set + counterpartyNextSequenceSend, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetRecvStartSequence(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().False(found) + suite.Require().Equal(uint64(0), counterpartyNextSequenceSend) + }, + postUpgrade: func() { + channel := path.EndpointA.GetChannel() + ctx := suite.chainA.GetContext() + + // Assert that channel state has been updated + suite.Require().Equal(types.OPEN, channel.State) + suite.Require().Equal(types.UNORDERED, channel.Ordering) + + // assert that NextSeqRecv is now 1, because channel is now UNORDERED + seq, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetNextSequenceRecv(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(uint64(1), seq) + + // assert that NextSeqAck is now 1, because channel is now UNORDERED + seq, found = suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetNextSequenceAck(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(uint64(1), seq) + + // Assert that pruning sequence start has been initialized (set to 1) + suite.Require().True(suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.HasPruningSequenceStart(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + pruningSeq, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetPruningSequenceStart(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(uint64(1), pruningSeq) + + // Assert that the recv start sequence has been set correctly + counterpartySequenceSend, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetRecvStartSequence(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(uint64(2), counterpartySequenceSend) + }, + }, + { + name: "success: UNORDERED -> ORDERED", + malleate: func() { + path.EndpointA.ChannelConfig.Order = types.UNORDERED + path.EndpointB.ChannelConfig.Order = types.UNORDERED + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Ordering = types.ORDERED + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Ordering = types.ORDERED + }, + preUpgrade: func() { + ctx := suite.chainA.GetContext() + + // assert that NextSeqRecv is 1 because channel is UNORDERED + seq, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetNextSequenceRecv(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(uint64(1), seq) + + // assert that NextSeqAck is 1 because channel is UNORDERED + seq, found = suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetNextSequenceAck(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(uint64(1), seq) + + // Assert that pruning sequence start has not been initialized. + suite.Require().False(suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.HasPruningSequenceStart(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + + // Assert that recv start sequence has not been set + counterpartyNextSequenceSend, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetRecvStartSequence(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().False(found) + suite.Require().Equal(uint64(0), counterpartyNextSequenceSend) + }, + postUpgrade: func() { + channel := path.EndpointA.GetChannel() + ctx := suite.chainA.GetContext() + + // Assert that channel state has been updated + suite.Require().Equal(types.OPEN, channel.State) + suite.Require().Equal(types.ORDERED, channel.Ordering) + + // assert that NextSeqRecv is incremented to 2, because channel is now ORDERED + // NextSeqRecv updated in WriteUpgradeOpenChannel to latest sequence (one packet sent) + 1 + seq, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetNextSequenceRecv(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(uint64(2), seq) + + // assert that NextSeqAck is incremented to 2 because channel is now ORDERED + seq, found = suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetNextSequenceAck(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(uint64(2), seq) + + // Assert that pruning sequence start has been initialized (set to 1) + suite.Require().True(suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.HasPruningSequenceStart(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + pruningSeq, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetPruningSequenceStart(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(uint64(1), pruningSeq) + + // Assert that the recv start sequence has been set correctly + counterpartySequenceSend, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetRecvStartSequence(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(uint64(2), counterpartySequenceSend) + }, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + + tc.malleate() + + suite.coordinator.Setup(path) + + // Need to create a packet commitment on A so as to keep it from going to OPEN if no inflight packets exist. + sequenceA, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + packetA := types.NewPacket(ibctesting.MockPacketData, sequenceA, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + err = path.EndpointB.RecvPacket(packetA) + suite.Require().NoError(err) + + // send second packet from B to A + sequenceB, err := path.EndpointB.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + packetB := types.NewPacket(ibctesting.MockPacketData, sequenceB, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + err = path.EndpointA.RecvPacket(packetB) + suite.Require().NoError(err) + + suite.Require().NoError(path.EndpointA.ChanUpgradeInit()) + suite.Require().NoError(path.EndpointB.ChanUpgradeTry()) + suite.Require().NoError(path.EndpointA.ChanUpgradeAck()) + suite.Require().NoError(path.EndpointB.ChanUpgradeConfirm()) + + // Ack packets to delete packet commitments before calling WriteUpgradeOpenChannel + err = path.EndpointA.AcknowledgePacket(packetA, ibctesting.MockAcknowledgement) + suite.Require().NoError(err) + + err = path.EndpointB.AcknowledgePacket(packetB, ibctesting.MockAcknowledgement) + suite.Require().NoError(err) + + // pre upgrade assertions + tc.preUpgrade() + + tc.malleate() + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.WriteUpgradeOpenChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + + // post upgrade assertions + tc.postUpgrade() + + // Assert that state stored for upgrade has been deleted + upgrade, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().Equal(types.Upgrade{}, upgrade) + suite.Require().False(found) + + counterpartyUpgrade, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetCounterpartyUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().Equal(types.Upgrade{}, counterpartyUpgrade) + suite.Require().False(found) + }) + } +} + +func (suite *KeeperTestSuite) TestChanUpgradeCancel() { + var ( + path *ibctesting.Path + errorReceipt types.ErrorReceipt + errorReceiptProof []byte + proofHeight clienttypes.Height + ) + + tests := []struct { + name string + malleate func() + expError error + }{ + { + name: "success with flushing state", + malleate: func() { + }, + expError: nil, + }, + { + name: "success with flush complete state", + malleate: func() { + err := path.EndpointA.SetChannelState(types.FLUSHCOMPLETE) + suite.Require().NoError(err) + + var ok bool + errorReceipt, ok = suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.GetUpgradeErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().True(ok) + + // the error receipt upgrade sequence and the channel upgrade sequence must match + errorReceipt.Sequence = path.EndpointA.GetChannel().UpgradeSequence + + suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.SetUpgradeErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, errorReceipt) + + suite.coordinator.CommitBlock(suite.chainB) + + suite.Require().NoError(path.EndpointA.UpdateClient()) + + upgradeErrorReceiptKey := host.ChannelUpgradeErrorKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + errorReceiptProof, proofHeight = suite.chainB.QueryProof(upgradeErrorReceiptKey) + }, + expError: nil, + }, + { + name: "upgrade cannot be cancelled in FLUSHCOMPLETE with invalid error receipt", + malleate: func() { + err := path.EndpointA.SetChannelState(types.FLUSHCOMPLETE) + suite.Require().NoError(err) + + errorReceiptProof = nil + }, + expError: commitmenttypes.ErrInvalidProof, + }, + { + name: "channel not found", + malleate: func() { + path.EndpointA.Chain.DeleteKey(host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + }, + expError: types.ErrChannelNotFound, + }, + { + name: "upgrade not found", + malleate: func() { + path.EndpointA.Chain.DeleteKey(host.ChannelUpgradeKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + }, + expError: types.ErrUpgradeNotFound, + }, + { + name: "error receipt sequence less than channel upgrade sequence", + malleate: func() { + var ok bool + errorReceipt, ok = suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.GetUpgradeErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().True(ok) + + errorReceipt.Sequence = path.EndpointA.GetChannel().UpgradeSequence - 1 + + suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.SetUpgradeErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, errorReceipt) + + suite.coordinator.CommitBlock(suite.chainB) + + suite.Require().NoError(path.EndpointA.UpdateClient()) + + upgradeErrorReceiptKey := host.ChannelUpgradeErrorKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + errorReceiptProof, proofHeight = suite.chainB.QueryProof(upgradeErrorReceiptKey) + }, + expError: types.ErrInvalidUpgradeSequence, + }, + { + name: "error receipt sequence greater than channel upgrade sequence when channel in FLUSHCOMPLETE", + malleate: func() { + err := path.EndpointA.SetChannelState(types.FLUSHCOMPLETE) + suite.Require().NoError(err) + }, + expError: types.ErrInvalidUpgradeSequence, + }, + { + name: "error receipt sequence smaller than channel upgrade sequence when channel in FLUSHCOMPLETE", + malleate: func() { + channel := path.EndpointA.GetChannel() + channel.State = types.FLUSHCOMPLETE + path.EndpointA.SetChannel(channel) + + var ok bool + errorReceipt, ok = suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.GetUpgradeErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().True(ok) + + errorReceipt.Sequence = path.EndpointA.GetChannel().UpgradeSequence - 1 + + suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.SetUpgradeErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, errorReceipt) + + suite.coordinator.CommitBlock(suite.chainB) + + suite.Require().NoError(path.EndpointA.UpdateClient()) + + upgradeErrorReceiptKey := host.ChannelUpgradeErrorKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + errorReceiptProof, proofHeight = suite.chainB.QueryProof(upgradeErrorReceiptKey) + }, + expError: types.ErrInvalidUpgradeSequence, + }, + { + name: "connection not found", + malleate: func() { + channel := path.EndpointA.GetChannel() + channel.ConnectionHops = []string{"connection-100"} + path.EndpointA.SetChannel(channel) + }, + expError: connectiontypes.ErrConnectionNotFound, + }, + { + name: "channel is in flush complete, error verification failed", + malleate: func() { + var ok bool + errorReceipt, ok = suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.GetUpgradeErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().True(ok) + + errorReceipt.Message = ibctesting.InvalidID + + suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.SetUpgradeErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, errorReceipt) + suite.coordinator.CommitBlock(suite.chainB) + }, + expError: commitmenttypes.ErrInvalidProof, + }, + { + name: "error verification failed", + malleate: func() { + var ok bool + errorReceipt, ok = suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.GetUpgradeErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().True(ok) + + errorReceipt.Message = ibctesting.InvalidID + suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.SetUpgradeErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, errorReceipt) + suite.coordinator.CommitBlock(suite.chainB) + }, + expError: commitmenttypes.ErrInvalidProof, + }, + { + name: "error verification failed with empty proof", + malleate: func() { + errorReceiptProof = nil + }, + expError: commitmenttypes.ErrInvalidProof, + }, + } + + for _, tc := range tests { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + + suite.Require().NoError(path.EndpointA.ChanUpgradeInit()) + + // cause the upgrade to fail on chain b so an error receipt is written. + // if the counterparty (chain A) upgrade sequence is less than the current sequence, (chain B) + // an upgrade error will be returned by chain B during ChanUpgradeTry. + channel := path.EndpointA.GetChannel() + channel.UpgradeSequence = 1 + path.EndpointA.SetChannel(channel) + + channel = path.EndpointB.GetChannel() + channel.UpgradeSequence = 2 + path.EndpointB.SetChannel(channel) + + suite.Require().NoError(path.EndpointA.UpdateClient()) + suite.Require().NoError(path.EndpointB.UpdateClient()) + + // error receipt is written to chain B here. + suite.Require().NoError(path.EndpointB.ChanUpgradeTry()) + + suite.Require().NoError(path.EndpointA.UpdateClient()) + + upgradeErrorReceiptKey := host.ChannelUpgradeErrorKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + errorReceiptProof, proofHeight = suite.chainB.QueryProof(upgradeErrorReceiptKey) + + var ok bool + errorReceipt, ok = suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.GetUpgradeErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().True(ok) + + channel = path.EndpointA.GetChannel() + channel.State = types.FLUSHING + path.EndpointA.SetChannel(channel) + + tc.malleate() + + err := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.ChanUpgradeCancel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, errorReceipt, errorReceiptProof, proofHeight) + + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err) + } else { + suite.Require().ErrorIs(err, tc.expError) + } + }) + } +} + +// TestChanUpgrade_UpgradeSucceeds_AfterCancel verifies that if upgrade sequences +// become out of sync, the upgrade can still be performed successfully after the upgrade is cancelled. +func (suite *KeeperTestSuite) TestChanUpgrade_UpgradeSucceeds_AfterCancel() { + path := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + + suite.Require().NoError(path.EndpointA.ChanUpgradeInit()) + + // cause the upgrade to fail on chain b so an error receipt is written. + // if the counterparty (chain A) upgrade sequence is less than the current sequence, (chain B) + // an upgrade error will be returned by chain B during ChanUpgradeTry. + channel := path.EndpointA.GetChannel() + channel.UpgradeSequence = 1 + path.EndpointA.SetChannel(channel) + + channel = path.EndpointB.GetChannel() + channel.UpgradeSequence = 5 + path.EndpointB.SetChannel(channel) + + suite.Require().NoError(path.EndpointA.UpdateClient()) + suite.Require().NoError(path.EndpointB.UpdateClient()) + + // error receipt is written to chain B here. + suite.Require().NoError(path.EndpointB.ChanUpgradeTry()) + + suite.Require().NoError(path.EndpointA.UpdateClient()) + + var errorReceipt types.ErrorReceipt + suite.T().Run("error receipt written", func(t *testing.T) { + var ok bool + errorReceipt, ok = suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.GetUpgradeErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().True(ok) + }) + + suite.T().Run("upgrade cancelled successfully", func(t *testing.T) { + upgradeErrorReceiptKey := host.ChannelUpgradeErrorKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + errorReceiptProof, proofHeight := suite.chainB.QueryProof(upgradeErrorReceiptKey) + + err := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.ChanUpgradeCancel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, errorReceipt, errorReceiptProof, proofHeight) + suite.Require().NoError(err) + + // need to explicitly call WriteUpgradeOpenChannel as this usually would happen in the msg server layer. + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.WriteUpgradeCancelChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, errorReceipt.Sequence) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(types.OPEN, channel.State) + + suite.T().Run("verify upgrade sequence fastforwards to channelB sequence", func(t *testing.T) { + suite.Require().Equal(uint64(5), channel.UpgradeSequence) + }) + }) + + suite.T().Run("successfully completes upgrade", func(t *testing.T) { + suite.Require().NoError(path.EndpointA.ChanUpgradeInit()) + suite.Require().NoError(path.EndpointB.ChanUpgradeTry()) + suite.Require().NoError(path.EndpointA.ChanUpgradeAck()) + suite.Require().NoError(path.EndpointB.ChanUpgradeConfirm()) + suite.Require().NoError(path.EndpointA.ChanUpgradeOpen()) + }) + + suite.T().Run("channel in expected state", func(t *testing.T) { + channel := path.EndpointA.GetChannel() + suite.Require().Equal(types.OPEN, channel.State, "channel should be in OPEN state") + suite.Require().Equal(mock.UpgradeVersion, channel.Version, "version should be correctly upgraded") + suite.Require().Equal(mock.UpgradeVersion, path.EndpointB.GetChannel().Version, "version should be correctly upgraded") + suite.Require().Equal(uint64(6), channel.UpgradeSequence, "upgrade sequence should be incremented") + suite.Require().Equal(uint64(6), path.EndpointB.GetChannel().UpgradeSequence, "upgrade sequence should be incremented on counterparty") + }) +} + +func (suite *KeeperTestSuite) TestWriteUpgradeCancelChannel() { + var path *ibctesting.Path + + testCases := []struct { + name string + malleate func() + expPanic bool + }{ + { + name: "success", + malleate: func() {}, + expPanic: false, + }, + { + name: "channel not found", + malleate: func() { + path.EndpointA.Chain.DeleteKey(host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + }, + expPanic: true, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + + suite.Require().NoError(path.EndpointA.ChanUpgradeInit()) + + // cause the upgrade to fail on chain b so an error receipt is written. + // if the counterparty (chain A) upgrade sequence is less than the current sequence, (chain B) + // an upgrade error will be returned by chain B during ChanUpgradeTry. + channel := path.EndpointA.GetChannel() + channel.UpgradeSequence = 1 + path.EndpointA.SetChannel(channel) + + channel = path.EndpointB.GetChannel() + channel.UpgradeSequence = 2 + path.EndpointB.SetChannel(channel) + + err := path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + errorReceipt, ok := suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.GetUpgradeErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().True(ok) + + ctx := suite.chainA.GetContext() + tc.malleate() + + if tc.expPanic { + suite.Require().Panics(func() { + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.WriteUpgradeCancelChannel(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, errorReceipt.Sequence) + }) + } else { + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.WriteUpgradeCancelChannel(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, errorReceipt.Sequence) + + channel = path.EndpointA.GetChannel() + + // Verify that channel has been restored to previous state + suite.Require().Equal(types.OPEN, channel.State) + suite.Require().Equal(mock.Version, channel.Version) + suite.Require().Equal(errorReceipt.Sequence, channel.UpgradeSequence) + + // Assert that state stored for upgrade has been deleted + upgrade, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().Equal(types.Upgrade{}, upgrade) + suite.Require().False(found) + + counterpartyUpgrade, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetCounterpartyUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().Equal(types.Upgrade{}, counterpartyUpgrade) + suite.Require().False(found) + } + }) + } +} + +func (suite *KeeperTestSuite) TestChanUpgradeTimeout() { + var ( + path *ibctesting.Path + channelProof []byte + proofHeight exported.Height + ) + + timeoutUpgrade := func() { + upgrade := path.EndpointA.GetProposedUpgrade() + upgrade.Timeout = types.NewTimeout(clienttypes.ZeroHeight(), 1) + path.EndpointA.SetChannelUpgrade(upgrade) + suite.Require().NoError(path.EndpointB.UpdateClient()) + } + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success: proof timestamp has passed", + func() { + timeoutUpgrade() + + channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channelProof, proofHeight = path.EndpointB.QueryProof(channelKey) + }, + nil, + }, + { + "channel not found", + func() { + path.EndpointA.ChannelID = ibctesting.InvalidID + }, + types.ErrChannelNotFound, + }, + { + "channel state is not in FLUSHING or FLUSHINGCOMPLETE state", + func() { + suite.Require().NoError(path.EndpointA.SetChannelState(types.OPEN)) + }, + types.ErrInvalidChannelState, + }, + { + "current upgrade not found", + func() { + suite.chainA.DeleteKey(host.ChannelUpgradeKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + }, + types.ErrUpgradeNotFound, + }, + { + "connection not found", + func() { + channel := path.EndpointA.GetChannel() + channel.ConnectionHops[0] = ibctesting.InvalidID + path.EndpointA.SetChannel(channel) + }, + connectiontypes.ErrConnectionNotFound, + }, + { + "connection not open", + func() { + connectionEnd := path.EndpointA.GetConnection() + connectionEnd.State = connectiontypes.UNINITIALIZED + path.EndpointA.SetConnection(connectionEnd) + }, + connectiontypes.ErrInvalidConnectionState, + }, + { + "unable to retrieve timestamp at proof height", + func() { + // TODO: revert this when the upgrade timeout is not hard coded to 1000 + proofHeight = clienttypes.NewHeight(clienttypes.ParseChainID(suite.chainA.ChainID), uint64(suite.chainA.GetContext().BlockHeight())+1000) + }, + clienttypes.ErrConsensusStateNotFound, + }, + { + "invalid channel state proof", + func() { + channel := path.EndpointB.GetChannel() + channel.State = types.OPEN + path.EndpointB.SetChannel(channel) + + timeoutUpgrade() + + suite.Require().NoError(path.EndpointA.UpdateClient()) + + channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channelProof, proofHeight = path.EndpointB.QueryProof(channelKey) + + // modify state so the proof becomes invalid. + channel.State = types.FLUSHING + path.EndpointB.SetChannel(channel) + suite.coordinator.CommitNBlocks(suite.chainB, 1) + }, + commitmenttypes.ErrInvalidProof, + }, + { + "invalid counterparty upgrade sequence", + func() { + channel := path.EndpointB.GetChannel() + channel.UpgradeSequence = path.EndpointA.GetChannel().UpgradeSequence - 1 + path.EndpointB.SetChannel(channel) + + timeoutUpgrade() + + suite.Require().NoError(path.EndpointA.UpdateClient()) + + channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channelProof, proofHeight = path.EndpointB.QueryProof(channelKey) + }, + types.ErrInvalidUpgradeSequence, + }, + { + "timeout timestamp has not passed", + func() { + upgrade := path.EndpointA.GetProposedUpgrade() + upgrade.Timeout.Timestamp = math.MaxUint64 + path.EndpointA.SetChannelUpgrade(upgrade) + + suite.Require().NoError(path.EndpointB.UpdateClient()) + + channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channelProof, proofHeight = path.EndpointB.QueryProof(channelKey) + }, + types.ErrTimeoutNotReached, + }, + { + "counterparty channel state is not OPEN or FLUSHING (crossing hellos)", + func() { + channel := path.EndpointB.GetChannel() + channel.State = types.FLUSHCOMPLETE + path.EndpointB.SetChannel(channel) + + timeoutUpgrade() + + suite.Require().NoError(path.EndpointA.UpdateClient()) + + channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channelProof, proofHeight = path.EndpointB.QueryProof(channelKey) + }, + types.ErrInvalidCounterparty, + }, + { + "counterparty proposed connection invalid", + func() { + channel := path.EndpointB.GetChannel() + channel.State = types.OPEN + path.EndpointB.SetChannel(channel) + + timeoutUpgrade() + + upgrade := path.EndpointA.GetChannelUpgrade() + upgrade.Fields.ConnectionHops = []string{"connection-100"} + path.EndpointA.SetChannelUpgrade(upgrade) + + suite.Require().NoError(path.EndpointA.UpdateClient()) + suite.Require().NoError(path.EndpointB.UpdateClient()) + + channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channelProof, proofHeight = path.EndpointB.QueryProof(channelKey) + }, + connectiontypes.ErrConnectionNotFound, + }, + { + "counterparty channel already upgraded", + func() { + // put chainA channel into OPEN state since both sides are in FLUSHCOMPLETE + suite.Require().NoError(path.EndpointB.ChanUpgradeConfirm()) + + timeoutUpgrade() + + suite.Require().NoError(path.EndpointA.UpdateClient()) + + channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channelProof, proofHeight = path.EndpointB.QueryProof(channelKey) + }, + types.ErrUpgradeTimeoutFailed, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + expPass := tc.expError == nil + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + + suite.Require().NoError(path.EndpointA.ChanUpgradeInit()) + suite.Require().NoError(path.EndpointB.ChanUpgradeTry()) + suite.Require().NoError(path.EndpointA.ChanUpgradeAck()) + + channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channelProof, proofHeight = path.EndpointB.QueryProof(channelKey) + + tc.malleate() + + err := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.ChanUpgradeTimeout( + suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + path.EndpointB.GetChannel(), + channelProof, + proofHeight, + ) + + if expPass { + suite.Require().NoError(err) + } else { + suite.assertUpgradeError(err, tc.expError) + } + }) + } +} + +func (suite *KeeperTestSuite) TestStartFlush() { + var path *ibctesting.Path + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + "channel not found", + func() { + path.EndpointB.ChannelID = "invalid-channel" + path.EndpointB.ChannelConfig.PortID = "invalid-port" + }, + types.ErrChannelNotFound, + }, + { + "connection not found", + func() { + channel := path.EndpointB.GetChannel() + channel.ConnectionHops[0] = ibctesting.InvalidID + path.EndpointB.SetChannel(channel) + }, + connectiontypes.ErrConnectionNotFound, + }, + { + "connection state is not in OPEN state", + func() { + conn := path.EndpointB.GetConnection() + conn.State = connectiontypes.INIT + path.EndpointB.SetConnection(conn) + }, + connectiontypes.ErrInvalidConnectionState, + }, + { + "next sequence send not found", + func() { + // Delete next sequence send key from store + store := suite.chainB.GetContext().KVStore(suite.chainB.GetSimApp().GetKey(exported.StoreKey)) + store.Delete(host.NextSequenceSendKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) + }, + types.ErrSequenceSendNotFound, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + // crossing hellos so that the upgrade is created on chain B. + // the ChanUpgradeInit sub protocol is also called when it is not a crossing hello situation. + err = path.EndpointB.ChanUpgradeInit() + suite.Require().NoError(err) + + upgrade := path.EndpointB.GetChannelUpgrade() + + tc.malleate() + + err = suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.StartFlushing( + suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, &upgrade, + ) + + if tc.expError != nil { + suite.assertUpgradeError(err, tc.expError) + } else { + channel := path.EndpointB.GetChannel() + + nextSequenceSend, ok := suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.GetNextSequenceSend(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().True(ok) + + suite.Require().Equal(types.FLUSHING, channel.State) + suite.Require().Equal(nextSequenceSend, upgrade.NextSequenceSend) + + expectedTimeoutTimestamp := types.DefaultTimeout.Timestamp + uint64(suite.chainB.GetContext().BlockTime().UnixNano()) + suite.Require().Equal(expectedTimeoutTimestamp, upgrade.Timeout.Timestamp) + suite.Require().Equal(clienttypes.ZeroHeight(), upgrade.Timeout.Height, "only timestamp should be set") + suite.Require().NoError(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestValidateUpgradeFields() { + var ( + proposedUpgrade *types.UpgradeFields + path *ibctesting.Path + ) + tests := []struct { + name string + malleate func() + expPass bool + }{ + { + name: "change channel version", + malleate: func() { + proposedUpgrade.Version = mock.UpgradeVersion + }, + expPass: true, + }, + { + name: "change connection hops", + malleate: func() { + path := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + proposedUpgrade.ConnectionHops = []string{path.EndpointA.ConnectionID} + }, + expPass: true, + }, + { + name: "fails with unmodified fields", + malleate: func() {}, + expPass: false, + }, + { + name: "fails when connection is not set", + malleate: func() { + storeKey := suite.chainA.GetSimApp().GetKey(exported.StoreKey) + kvStore := suite.chainA.GetContext().KVStore(storeKey) + kvStore.Delete(host.ConnectionKey(ibctesting.FirstConnectionID)) + }, + expPass: false, + }, + { + name: "fails when connection is not open", + malleate: func() { + connection := path.EndpointA.GetConnection() + connection.State = connectiontypes.UNINITIALIZED + path.EndpointA.SetConnection(connection) + }, + expPass: false, + }, + { + name: "fails when connection versions do not exist", + malleate: func() { + // update channel version first so that existing channel end is not identical to proposed upgrade + proposedUpgrade.Version = mock.UpgradeVersion + + connection := path.EndpointA.GetConnection() + connection.Versions = []*connectiontypes.Version{} + path.EndpointA.SetConnection(connection) + }, + expPass: false, + }, + { + name: "fails when connection version does not support the new ordering", + malleate: func() { + // update channel version first so that existing channel end is not identical to proposed upgrade + proposedUpgrade.Version = mock.UpgradeVersion + + connection := path.EndpointA.GetConnection() + connection.Versions = []*connectiontypes.Version{ + connectiontypes.NewVersion("1", []string{"ORDER_ORDERED"}), + } + path.EndpointA.SetConnection(connection) + }, + expPass: false, + }, + } + + for _, tc := range tests { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + existingChannel := path.EndpointA.GetChannel() + proposedUpgrade = &types.UpgradeFields{ + Ordering: existingChannel.Ordering, + ConnectionHops: existingChannel.ConnectionHops, + Version: existingChannel.Version, + } + + tc.malleate() + + err := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.ValidateSelfUpgradeFields(suite.chainA.GetContext(), *proposedUpgrade, existingChannel) + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) assertUpgradeError(actualError, expError error) { + suite.Require().Error(actualError) + + if expUpgradeError, ok := expError.(*types.UpgradeError); ok { + upgradeError, ok := actualError.(*types.UpgradeError) + suite.Require().True(ok) + suite.Require().Equal(expUpgradeError.GetErrorReceipt(), upgradeError.GetErrorReceipt()) + } + + suite.Require().True(errorsmod.IsOf(actualError, expError), fmt.Sprintf("expected error: %s, actual error: %s", expError, actualError)) +} + +// TestAbortUpgrade tests that when the channel handshake is aborted, the channel state +// is restored the previous state and that an error receipt is written, and upgrade state which +// is no longer required is deleted. +func (suite *KeeperTestSuite) TestAbortUpgrade() { + var ( + path *ibctesting.Path + upgradeError error + ) + + tests := []struct { + name string + malleate func() + expPass bool + }{ + { + name: "success", + malleate: func() {}, + expPass: true, + }, + { + name: "regular error", + malleate: func() { + // in app callbacks error receipts should still be written if a regular error is returned. + // i.e. not an instance of `types.UpgradeError` + upgradeError = types.ErrInvalidUpgrade + }, + expPass: true, + }, + { + name: "channel does not exist", + malleate: func() { + suite.chainA.DeleteKey(host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + }, + expPass: false, + }, + { + name: "fails with nil upgrade error", + malleate: func() { + upgradeError = nil + }, + expPass: false, + }, + } + + for _, tc := range tests { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + channelKeeper := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper + + path.EndpointA.ChannelConfig.Version = mock.UpgradeVersion + suite.Require().NoError(path.EndpointA.ChanUpgradeInit()) + + // fetch the upgrade before abort for assertions later on. + actualUpgrade, ok := channelKeeper.GetUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(ok, "upgrade should be found") + + upgradeError = types.NewUpgradeError(1, types.ErrInvalidChannel) + + tc.malleate() + + if tc.expPass { + + ctx := suite.chainA.GetContext() + + suite.Require().NotPanics(func() { + channelKeeper.MustAbortUpgrade(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, upgradeError) + }) + + channel, found := channelKeeper.GetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found, "channel should be found") + + suite.Require().Equal(types.OPEN, channel.State, "channel state should be %s", types.OPEN.String()) + + _, found = channelKeeper.GetUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().False(found, "upgrade info should be deleted") + + errorReceipt, found := channelKeeper.GetUpgradeErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found, "error receipt should be found") + + if ue, ok := upgradeError.(*types.UpgradeError); ok { + suite.Require().Equal(ue.GetErrorReceipt(), errorReceipt, "error receipt does not match expected error receipt") + } + } else { + + suite.Require().Panics(func() { + channelKeeper.MustAbortUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, upgradeError) + }) + + channel, found := channelKeeper.GetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + if found { // test cases uses a channel that exists + suite.Require().Equal(types.OPEN, channel.State, "channel state should not be restored to %s", types.OPEN.String()) + } + + _, found = channelKeeper.GetUpgradeErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().False(found, "error receipt should not be found") + + upgrade, found := channelKeeper.GetUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + if found { // this should be all test cases except for when the upgrade is explicitly deleted. + suite.Require().Equal(actualUpgrade, upgrade, "upgrade info should not be deleted") + } + } + }) + } +} + +func (suite *KeeperTestSuite) TestCheckForUpgradeCompatibility() { + var ( + path *ibctesting.Path + upgradeFields types.UpgradeFields + counterpartyUpgradeFields types.UpgradeFields + ) + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + "upgrade ordering is not the same on both sides", + func() { + upgradeFields.Ordering = types.ORDERED + }, + types.ErrIncompatibleCounterpartyUpgrade, + }, + { + "proposed connection is not found", + func() { + upgradeFields.ConnectionHops[0] = ibctesting.InvalidID + }, + connectiontypes.ErrConnectionNotFound, + }, + { + "proposed connection is not in OPEN state", + func() { + // reuse existing connection to create a new connection in a non OPEN state + connectionEnd := path.EndpointB.GetConnection() + connectionEnd.State = connectiontypes.UNINITIALIZED + connectionEnd.Counterparty.ConnectionId = counterpartyUpgradeFields.ConnectionHops[0] // both sides must be each other's counterparty + + // set proposed connection in state + proposedConnectionID := "connection-100" + suite.chainB.GetSimApp().GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chainB.GetContext(), proposedConnectionID, connectionEnd) + upgradeFields.ConnectionHops[0] = proposedConnectionID + }, + connectiontypes.ErrInvalidConnectionState, + }, + { + "proposed connection ends are not each other's counterparty", + func() { + // reuse existing connection to create a new connection in a non OPEN state + connectionEnd := path.EndpointB.GetConnection() + // ensure counterparty connectionID does not match connectionID set in counterparty proposed upgrade + connectionEnd.Counterparty.ConnectionId = "connection-50" + + // set proposed connection in state + proposedConnectionID := "connection-100" + suite.chainB.GetSimApp().GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chainB.GetContext(), proposedConnectionID, connectionEnd) + upgradeFields.ConnectionHops[0] = proposedConnectionID + }, + types.ErrIncompatibleCounterpartyUpgrade, + }, + { + "proposed upgrade version is not the same on both sides", + func() { + upgradeFields.Version = mock.Version + }, + types.ErrIncompatibleCounterpartyUpgrade, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + upgradeFields = path.EndpointA.GetProposedUpgrade().Fields + counterpartyUpgradeFields = path.EndpointB.GetProposedUpgrade().Fields + + tc.malleate() + + err = suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.CheckForUpgradeCompatibility(suite.chainB.GetContext(), upgradeFields, counterpartyUpgradeFields) + if tc.expError != nil { + suite.Require().ErrorIs(err, tc.expError) + } else { + suite.Require().NoError(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestChanUpgradeCrossingHelloWithHistoricalProofs() { + var path *ibctesting.Path + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + "counterparty (chain B) has already progressed to ACK step", + func() { + err := path.EndpointB.ChanUpgradeAck() + suite.Require().NoError(err) + }, + types.ErrInvalidChannelState, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeInit() + suite.Require().NoError(err) + + suite.coordinator.CommitBlock(suite.chainA, suite.chainB) + + err = path.EndpointB.UpdateClient() + suite.Require().NoError(err) + + historicalChannelProof, historicalUpgradeProof, proofHeight := path.EndpointA.QueryChannelUpgradeProof() + + err = path.EndpointA.ChanUpgradeTry() + suite.Require().NoError(err) + + tc.malleate() + + _, upgrade, err := suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.ChanUpgradeTry( + suite.chainB.GetContext(), + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + path.EndpointB.GetChannelUpgrade().Fields.ConnectionHops, + path.EndpointA.GetChannelUpgrade().Fields, + 1, + historicalChannelProof, + historicalUpgradeProof, + proofHeight, + ) + + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err) + suite.Require().NotEmpty(upgrade) + } else { + suite.Require().ErrorIs(err, tc.expError) + } + }) + } +} + +func (suite *KeeperTestSuite) TestWriteErrorReceipt() { + var path *ibctesting.Path + var upgradeError *types.UpgradeError + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + "success: existing error receipt found at a lower sequence", + func() { + // write an error sequence with a lower sequence number + previousUpgradeError := types.NewUpgradeError(upgradeError.GetErrorReceipt().Sequence-1, types.ErrInvalidUpgrade) + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.WriteErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, previousUpgradeError) + }, + nil, + }, + { + "failure: existing error receipt found at a higher sequence", + func() { + // write an error sequence with a higher sequence number + previousUpgradeError := types.NewUpgradeError(upgradeError.GetErrorReceipt().Sequence+1, types.ErrInvalidUpgrade) + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.WriteErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, previousUpgradeError) + }, + errorsmod.Wrap(types.ErrInvalidUpgradeSequence, "error receipt sequence (10) must be greater than existing error receipt sequence (11)"), + }, + { + "failure: upgrade exists for error receipt being written", + func() { + // attempt to write error receipt for existing upgrade without deleting upgrade info + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + ch := path.EndpointA.GetChannel() + upgradeError = types.NewUpgradeError(ch.UpgradeSequence, types.ErrInvalidUpgrade) + }, + errorsmod.Wrap(types.ErrInvalidUpgradeSequence, "attempting to write error receipt at sequence (1) while upgrade information exists at the same sequence"), + }, + { + "failure: channel not found", + func() { + suite.chainA.DeleteKey(host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + }, + errorsmod.Wrap(types.ErrChannelNotFound, "port ID (mock) channel ID (channel-0)"), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + channelKeeper := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper + + upgradeError = types.NewUpgradeError(10, types.ErrInvalidUpgrade) + + tc.malleate() + + expPass := tc.expError == nil + if expPass { + suite.NotPanics(func() { + channelKeeper.WriteErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, upgradeError) + }) + } else { + suite.PanicsWithError(tc.expError.Error(), func() { + channelKeeper.WriteErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, upgradeError) + }) + } + }) + } +} diff --git a/modules/core/04-channel/types/acknowledgement.go b/modules/core/04-channel/types/acknowledgement.go index 27617d391f5..bfe7247f9cc 100644 --- a/modules/core/04-channel/types/acknowledgement.go +++ b/modules/core/04-channel/types/acknowledgement.go @@ -26,6 +26,26 @@ func NewResultAcknowledgement(result []byte) Acknowledgement { } } +// NewErrorAcknowledgementWithCodespace returns a new instance of Acknowledgement using an Acknowledgement_Error +// type in the Response field. +// NOTE: The error includes the ABCI codespace and code in the error string to provide more information about the module +// that generated the error. This is useful for debugging but can potentially introduce non-determinism if care is +// not taken to ensure the codespace doesn't change in non state-machine breaking versions. +func NewErrorAcknowledgementWithCodespace(err error) Acknowledgement { + // The ABCI code is included in the abcitypes.ResponseDeliverTx hash + // constructed in Tendermint and is therefore deterministic. + // However, a code without codespace is incomplete information (e.g. sdk/5 and wasm/5 are + // different errors). We add this codespace here, in oder to provide a meaningful error + // identifier which means changing the codespace of an error becomes a consensus breaking change. + codespace, code, _ := errorsmod.ABCIInfo(err, false) + + return Acknowledgement{ + Response: &Acknowledgement_Error{ + Error: fmt.Sprintf("ABCI error: %s/%d: %s", codespace, code, ackErrorString), + }, + } +} + // NewErrorAcknowledgement returns a new instance of Acknowledgement using an Acknowledgement_Error // type in the Response field. // NOTE: Acknowledgements are written into state and thus, changes made to error strings included in packet acknowledgements diff --git a/modules/core/04-channel/types/acknowledgement_test.go b/modules/core/04-channel/types/acknowledgement_test.go index 71234065321..e6d30873deb 100644 --- a/modules/core/04-channel/types/acknowledgement_test.go +++ b/modules/core/04-channel/types/acknowledgement_test.go @@ -141,3 +141,35 @@ func (suite *TypesTestSuite) TestAcknowledgementError() { suite.Require().Equal(ack, ackSameABCICode) suite.Require().NotEqual(ack, ackDifferentABCICode) } + +func (suite TypesTestSuite) TestAcknowledgementWithCodespace() { //nolint:govet // this is a test, we are okay with copying locks + testCases := []struct { + name string + ack types.Acknowledgement + expBytes []byte + }{ + { + "valid failed ack", + types.NewErrorAcknowledgementWithCodespace(ibcerrors.ErrInsufficientFunds), + []byte(`{"error":"ABCI error: ibc/3: error handling packet: see events for details"}`), + }, + { + "unknown error", + types.NewErrorAcknowledgementWithCodespace(fmt.Errorf("unknown error")), + []byte(`{"error":"ABCI error: undefined/1: error handling packet: see events for details"}`), + }, + { + "nil error", + types.NewErrorAcknowledgementWithCodespace(nil), + []byte(`{"error":"ABCI error: /0: error handling packet: see events for details"}`), + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.Require().Equal(tc.expBytes, tc.ack.Acknowledgement()) + }) + } +} diff --git a/modules/core/04-channel/types/channel.go b/modules/core/04-channel/types/channel.go index d288a2a8842..21b7bf3b658 100644 --- a/modules/core/04-channel/types/channel.go +++ b/modules/core/04-channel/types/channel.go @@ -23,6 +23,8 @@ func NewChannel( Counterparty: counterparty, ConnectionHops: hops, Version: version, + // UpgradeSequence is intentionally left empty as a new channel has not performed an upgrade. + UpgradeSequence: 0, } } @@ -115,13 +117,14 @@ func (c Counterparty) ValidateBasic() error { // NewIdentifiedChannel creates a new IdentifiedChannel instance func NewIdentifiedChannel(portID, channelID string, ch Channel) IdentifiedChannel { return IdentifiedChannel{ - State: ch.State, - Ordering: ch.Ordering, - Counterparty: ch.Counterparty, - ConnectionHops: ch.ConnectionHops, - Version: ch.Version, - PortId: portID, - ChannelId: channelID, + State: ch.State, + Ordering: ch.Ordering, + Counterparty: ch.Counterparty, + ConnectionHops: ch.ConnectionHops, + Version: ch.Version, + UpgradeSequence: ch.UpgradeSequence, + PortId: portID, + ChannelId: channelID, } } diff --git a/modules/core/04-channel/types/channel.pb.go b/modules/core/04-channel/types/channel.pb.go index 4e6c985b8db..39a11872ca0 100644 --- a/modules/core/04-channel/types/channel.pb.go +++ b/modules/core/04-channel/types/channel.pb.go @@ -25,7 +25,7 @@ var _ = math.Inf const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // State defines if a channel is in one of the following states: -// CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. +// CLOSED, INIT, TRYOPEN, OPEN, FLUSHING, FLUSHCOMPLETE or UNINITIALIZED. type State int32 const ( @@ -41,6 +41,10 @@ const ( // A channel has been closed and can no longer be used to send or receive // packets. CLOSED State = 4 + // A channel has just accepted the upgrade handshake attempt and is flushing in-flight packets. + FLUSHING State = 5 + // A channel has just completed flushing any in-flight packets. + FLUSHCOMPLETE State = 6 ) var State_name = map[int32]string{ @@ -49,6 +53,8 @@ var State_name = map[int32]string{ 2: "STATE_TRYOPEN", 3: "STATE_OPEN", 4: "STATE_CLOSED", + 5: "STATE_FLUSHING", + 6: "STATE_FLUSHCOMPLETE", } var State_value = map[string]int32{ @@ -57,6 +63,8 @@ var State_value = map[string]int32{ "STATE_TRYOPEN": 2, "STATE_OPEN": 3, "STATE_CLOSED": 4, + "STATE_FLUSHING": 5, + "STATE_FLUSHCOMPLETE": 6, } func (x State) String() string { @@ -115,6 +123,9 @@ type Channel struct { ConnectionHops []string `protobuf:"bytes,4,rep,name=connection_hops,json=connectionHops,proto3" json:"connection_hops,omitempty"` // opaque channel version, which is agreed upon during the handshake Version string `protobuf:"bytes,5,opt,name=version,proto3" json:"version,omitempty"` + // upgrade sequence indicates the latest upgrade attempt performed by this channel + // the value of 0 indicates the channel has never been upgraded + UpgradeSequence uint64 `protobuf:"varint,6,opt,name=upgrade_sequence,json=upgradeSequence,proto3" json:"upgrade_sequence,omitempty"` } func (m *Channel) Reset() { *m = Channel{} } @@ -168,6 +179,9 @@ type IdentifiedChannel struct { PortId string `protobuf:"bytes,6,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` // channel identifier ChannelId string `protobuf:"bytes,7,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + // upgrade sequence indicates the latest upgrade attempt performed by this channel + // the value of 0 indicates the channel has never been upgraded + UpgradeSequence uint64 `protobuf:"varint,8,opt,name=upgrade_sequence,json=upgradeSequence,proto3" json:"upgrade_sequence,omitempty"` } func (m *IdentifiedChannel) Reset() { *m = IdentifiedChannel{} } @@ -543,6 +557,52 @@ func (m *Timeout) GetTimestamp() uint64 { return 0 } +// Params defines the set of IBC channel parameters. +type Params struct { + // the relative timeout after which channel upgrades will time out. + UpgradeTimeout Timeout `protobuf:"bytes,1,opt,name=upgrade_timeout,json=upgradeTimeout,proto3" json:"upgrade_timeout"` +} + +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_c3a07336710636a0, []int{8} +} +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 (m *Params) GetUpgradeTimeout() Timeout { + if m != nil { + return m.UpgradeTimeout + } + return Timeout{} +} + func init() { proto.RegisterEnum("ibc.core.channel.v1.State", State_name, State_value) proto.RegisterEnum("ibc.core.channel.v1.Order", Order_name, Order_value) @@ -554,65 +614,72 @@ func init() { proto.RegisterType((*PacketId)(nil), "ibc.core.channel.v1.PacketId") proto.RegisterType((*Acknowledgement)(nil), "ibc.core.channel.v1.Acknowledgement") proto.RegisterType((*Timeout)(nil), "ibc.core.channel.v1.Timeout") + proto.RegisterType((*Params)(nil), "ibc.core.channel.v1.Params") } func init() { proto.RegisterFile("ibc/core/channel/v1/channel.proto", fileDescriptor_c3a07336710636a0) } var fileDescriptor_c3a07336710636a0 = []byte{ - // 842 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x55, 0xcd, 0x8e, 0xdb, 0x54, - 0x14, 0xb6, 0x33, 0xce, 0xdf, 0xc9, 0x64, 0x26, 0x73, 0x0b, 0x83, 0x65, 0x15, 0xc7, 0x1d, 0x81, - 0x08, 0x45, 0x8d, 0x3b, 0x05, 0xa1, 0xc2, 0x6e, 0x26, 0x31, 0xc4, 0x62, 0x94, 0x44, 0x4e, 0x66, - 0x41, 0x37, 0x91, 0x63, 0x5f, 0x12, 0xab, 0x89, 0xaf, 0xb1, 0x6f, 0x52, 0x55, 0xbc, 0x40, 0xc9, - 0x8a, 0x17, 0x88, 0x84, 0xc4, 0x43, 0xf0, 0x0a, 0x95, 0xd8, 0x74, 0xd9, 0x15, 0x42, 0x33, 0x2f, - 0x82, 0x7c, 0xef, 0xf5, 0x24, 0xa9, 0x46, 0x23, 0x84, 0xc4, 0x8a, 0x55, 0xee, 0xf9, 0xce, 0x77, - 0xbe, 0x73, 0xfc, 0x1d, 0xc7, 0x17, 0x1e, 0x04, 0x63, 0xcf, 0xf4, 0x48, 0x8c, 0x4d, 0x6f, 0xea, - 0x86, 0x21, 0x9e, 0x99, 0xcb, 0xd3, 0xec, 0xd8, 0x8c, 0x62, 0x42, 0x09, 0xba, 0x17, 0x8c, 0xbd, - 0x66, 0x4a, 0x69, 0x66, 0xf8, 0xf2, 0x54, 0x7b, 0x6f, 0x42, 0x26, 0x84, 0xe5, 0xcd, 0xf4, 0xc4, - 0xa9, 0x5a, 0x7d, 0xa3, 0x36, 0x0b, 0x70, 0x48, 0x99, 0x18, 0x3b, 0x71, 0xc2, 0xc9, 0xcf, 0x39, - 0x28, 0xb6, 0xb8, 0x0a, 0x7a, 0x0c, 0xf9, 0x84, 0xba, 0x14, 0xab, 0xb2, 0x21, 0x37, 0x0e, 0x9e, - 0x68, 0xcd, 0x5b, 0xfa, 0x34, 0x07, 0x29, 0xc3, 0xe1, 0x44, 0xf4, 0x25, 0x94, 0x48, 0xec, 0xe3, - 0x38, 0x08, 0x27, 0x6a, 0xee, 0x8e, 0xa2, 0x5e, 0x4a, 0x72, 0x6e, 0xb8, 0xe8, 0x3b, 0xd8, 0xf7, - 0xc8, 0x22, 0xa4, 0x38, 0x8e, 0xdc, 0x98, 0xbe, 0x54, 0xf7, 0x0c, 0xb9, 0x51, 0x79, 0xf2, 0xe0, - 0xd6, 0xda, 0xd6, 0x16, 0xf1, 0x5c, 0x79, 0xfd, 0x67, 0x5d, 0x72, 0x76, 0x8a, 0xd1, 0x27, 0x70, - 0xe8, 0x91, 0x30, 0xc4, 0x1e, 0x0d, 0x48, 0x38, 0x9a, 0x92, 0x28, 0x51, 0x15, 0x63, 0xaf, 0x51, - 0x76, 0x0e, 0x36, 0x70, 0x87, 0x44, 0x09, 0x52, 0xa1, 0xb8, 0xc4, 0x71, 0x12, 0x90, 0x50, 0xcd, - 0x1b, 0x72, 0xa3, 0xec, 0x64, 0xe1, 0xd7, 0xca, 0xab, 0x5f, 0xeb, 0xd2, 0xc9, 0x1f, 0x39, 0x38, - 0xb2, 0x7d, 0x1c, 0xd2, 0xe0, 0x87, 0x00, 0xfb, 0xff, 0x7b, 0x57, 0xd0, 0x07, 0x50, 0x8c, 0x48, - 0x4c, 0x47, 0x81, 0xaf, 0x16, 0x58, 0xa6, 0x90, 0x86, 0xb6, 0x8f, 0x3e, 0x04, 0x10, 0xa3, 0xa4, - 0xb9, 0x22, 0xcb, 0x95, 0x05, 0x62, 0xfb, 0xc2, 0xcd, 0x0b, 0xd8, 0xdf, 0x1e, 0x72, 0x5b, 0x4d, - 0xbe, 0x43, 0x2d, 0x77, 0xbb, 0xda, 0xdb, 0x1c, 0x14, 0xfa, 0xae, 0xf7, 0x1c, 0x53, 0xa4, 0x41, - 0x29, 0xc1, 0x3f, 0x2e, 0x70, 0xe8, 0xf1, 0x9d, 0x28, 0xce, 0x4d, 0x8c, 0xea, 0x50, 0x49, 0xc8, - 0x22, 0xf6, 0xf0, 0x28, 0x15, 0x17, 0x62, 0xc0, 0xa1, 0x3e, 0x89, 0x29, 0xfa, 0x18, 0x0e, 0x04, - 0x41, 0x74, 0x60, 0x2e, 0x97, 0x9d, 0x2a, 0x47, 0xb3, 0xa5, 0x7f, 0x0a, 0x35, 0x1f, 0x27, 0x34, - 0x08, 0x5d, 0x66, 0x1f, 0x13, 0x53, 0x18, 0xf1, 0x70, 0x0b, 0x67, 0x8a, 0x26, 0xdc, 0xdb, 0xa6, - 0x66, 0xb2, 0xdc, 0x4b, 0xb4, 0x95, 0xca, 0xb4, 0x11, 0x28, 0xbe, 0x4b, 0x5d, 0xe6, 0xe9, 0xbe, - 0xc3, 0xce, 0xe8, 0x5b, 0x38, 0xa0, 0xc1, 0x1c, 0x93, 0x05, 0x1d, 0x4d, 0x71, 0x30, 0x99, 0x52, - 0xe6, 0x6a, 0x65, 0xe7, 0xc5, 0xe1, 0x7f, 0xdb, 0xe5, 0x69, 0xb3, 0xc3, 0x18, 0x62, 0xeb, 0x55, - 0x51, 0xc7, 0x41, 0xf4, 0x19, 0x1c, 0x65, 0x42, 0xe9, 0x6f, 0x42, 0xdd, 0x79, 0xa4, 0x96, 0x98, - 0x4b, 0x35, 0x91, 0x18, 0x66, 0xb8, 0xb0, 0xf6, 0x27, 0xa8, 0x70, 0x67, 0xd9, 0x4b, 0xfc, 0x6f, - 0xf7, 0xb4, 0xb3, 0x96, 0xbd, 0x77, 0xd6, 0x92, 0x3d, 0xb2, 0xb2, 0x79, 0x64, 0xd1, 0xdc, 0x87, - 0x12, 0x6f, 0x6e, 0xfb, 0xff, 0x45, 0x67, 0xd1, 0xa5, 0x07, 0x87, 0x67, 0xde, 0xf3, 0x90, 0xbc, - 0x98, 0x61, 0x7f, 0x82, 0xe7, 0x38, 0xa4, 0x48, 0x85, 0x42, 0x8c, 0x93, 0xc5, 0x8c, 0xaa, 0xef, - 0xa7, 0x43, 0x75, 0x24, 0x47, 0xc4, 0xe8, 0x18, 0xf2, 0x38, 0x8e, 0x49, 0xac, 0x1e, 0xa7, 0x8d, - 0x3a, 0x92, 0xc3, 0xc3, 0x73, 0x80, 0x52, 0x8c, 0x93, 0x88, 0x84, 0x09, 0x3e, 0x71, 0xa1, 0x38, - 0xe4, 0x6e, 0xa2, 0xa7, 0x50, 0x10, 0x2b, 0x93, 0xff, 0xe1, 0xca, 0x04, 0x1f, 0xdd, 0x87, 0xf2, - 0x66, 0x47, 0x39, 0x36, 0xf8, 0x06, 0x78, 0xf8, 0xbb, 0x0c, 0xf9, 0x81, 0xf8, 0x9e, 0xd4, 0x07, - 0xc3, 0xb3, 0xa1, 0x35, 0xba, 0xec, 0xda, 0x5d, 0x7b, 0x68, 0x9f, 0x5d, 0xd8, 0xcf, 0xac, 0xf6, - 0xe8, 0xb2, 0x3b, 0xe8, 0x5b, 0x2d, 0xfb, 0x1b, 0xdb, 0x6a, 0xd7, 0x24, 0xed, 0x68, 0xb5, 0x36, - 0xaa, 0x3b, 0x04, 0xa4, 0x02, 0xf0, 0xba, 0x14, 0xac, 0xc9, 0x5a, 0x69, 0xb5, 0x36, 0x94, 0xf4, - 0x8c, 0x74, 0xa8, 0xf2, 0xcc, 0xd0, 0xf9, 0xbe, 0xd7, 0xb7, 0xba, 0xb5, 0x9c, 0x56, 0x59, 0xad, - 0x8d, 0xa2, 0x08, 0x37, 0x95, 0x2c, 0xb9, 0xc7, 0x2b, 0x59, 0xe6, 0x3e, 0xec, 0xf3, 0x4c, 0xeb, - 0xa2, 0x37, 0xb0, 0xda, 0x35, 0x45, 0x83, 0xd5, 0xda, 0x28, 0xf0, 0x48, 0x53, 0x5e, 0xfd, 0xa6, - 0x4b, 0x0f, 0x5f, 0x40, 0x9e, 0x7d, 0xda, 0xd0, 0x47, 0x70, 0xdc, 0x73, 0xda, 0x96, 0x33, 0xea, - 0xf6, 0xba, 0xd6, 0x3b, 0xf3, 0x32, 0xc9, 0x14, 0x47, 0x27, 0x70, 0xc8, 0x59, 0x97, 0x5d, 0xf6, - 0x6b, 0xb5, 0x6b, 0xb2, 0x56, 0x5d, 0xad, 0x8d, 0xf2, 0x0d, 0x90, 0x0e, 0xcc, 0x39, 0x19, 0x43, - 0x0c, 0x2c, 0x42, 0xde, 0xf8, 0x7c, 0xf0, 0xfa, 0x4a, 0x97, 0xdf, 0x5c, 0xe9, 0xf2, 0x5f, 0x57, - 0xba, 0xfc, 0xcb, 0xb5, 0x2e, 0xbd, 0xb9, 0xd6, 0xa5, 0xb7, 0xd7, 0xba, 0xf4, 0xec, 0xab, 0x49, - 0x40, 0xa7, 0x8b, 0x71, 0xd3, 0x23, 0x73, 0xd3, 0x23, 0xc9, 0x9c, 0x24, 0x66, 0x30, 0xf6, 0x1e, - 0x4d, 0x88, 0xb9, 0x7c, 0x6a, 0xce, 0x89, 0xbf, 0x98, 0xe1, 0x84, 0xdf, 0x93, 0x8f, 0xbf, 0x78, - 0x94, 0x5d, 0xbc, 0xf4, 0x65, 0x84, 0x93, 0x71, 0x81, 0x5d, 0x94, 0x9f, 0xff, 0x1d, 0x00, 0x00, - 0xff, 0xff, 0x15, 0x20, 0x09, 0x7f, 0x99, 0x07, 0x00, 0x00, + // 937 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x56, 0x4f, 0x6f, 0xe2, 0xc6, + 0x1b, 0xc6, 0xc4, 0xfc, 0x7b, 0x93, 0x80, 0x33, 0xf9, 0xfd, 0x52, 0xcb, 0x4a, 0xc1, 0x8b, 0x5a, + 0x95, 0x4d, 0xb5, 0xb0, 0xd9, 0x56, 0xd5, 0xb6, 0xb7, 0x04, 0xbc, 0x8b, 0xb5, 0x14, 0x90, 0x81, + 0x43, 0xf7, 0x82, 0x8c, 0x3d, 0x05, 0x6b, 0xc1, 0x43, 0xed, 0x81, 0xd5, 0xaa, 0xe7, 0x4a, 0x2b, + 0x4e, 0xfd, 0x02, 0x48, 0x95, 0xfa, 0x15, 0xfa, 0x21, 0xf6, 0xb8, 0xc7, 0x3d, 0x55, 0x55, 0xf2, + 0x1d, 0x7a, 0xae, 0x3c, 0x33, 0x0e, 0x10, 0x45, 0x51, 0x55, 0xa9, 0xb7, 0x9e, 0x98, 0xf7, 0x79, + 0x9f, 0xf7, 0x7d, 0xde, 0x3f, 0xc3, 0xc8, 0xf0, 0xc0, 0x1b, 0x39, 0x35, 0x87, 0x04, 0xb8, 0xe6, + 0x4c, 0x6c, 0xdf, 0xc7, 0xd3, 0xda, 0xf2, 0x3c, 0x3e, 0x56, 0xe7, 0x01, 0xa1, 0x04, 0x1d, 0x7b, + 0x23, 0xa7, 0x1a, 0x51, 0xaa, 0x31, 0xbe, 0x3c, 0xd7, 0xfe, 0x37, 0x26, 0x63, 0xc2, 0xfc, 0xb5, + 0xe8, 0xc4, 0xa9, 0x5a, 0x69, 0x93, 0x6d, 0xea, 0x61, 0x9f, 0xb2, 0x64, 0xec, 0xc4, 0x09, 0xe5, + 0xdf, 0x92, 0x90, 0xa9, 0xf3, 0x2c, 0xe8, 0x31, 0xa4, 0x42, 0x6a, 0x53, 0xac, 0x4a, 0xba, 0x54, + 0xc9, 0x3f, 0xd1, 0xaa, 0x77, 0xe8, 0x54, 0x7b, 0x11, 0xc3, 0xe2, 0x44, 0xf4, 0x15, 0x64, 0x49, + 0xe0, 0xe2, 0xc0, 0xf3, 0xc7, 0x6a, 0xf2, 0x9e, 0xa0, 0x4e, 0x44, 0xb2, 0x6e, 0xb8, 0xe8, 0x05, + 0x1c, 0x38, 0x64, 0xe1, 0x53, 0x1c, 0xcc, 0xed, 0x80, 0xbe, 0x51, 0xf7, 0x74, 0xa9, 0xb2, 0xff, + 0xe4, 0xc1, 0x9d, 0xb1, 0xf5, 0x2d, 0xe2, 0xa5, 0xfc, 0xee, 0xf7, 0x52, 0xc2, 0xda, 0x09, 0x46, + 0x9f, 0x41, 0xc1, 0x21, 0xbe, 0x8f, 0x1d, 0xea, 0x11, 0x7f, 0x38, 0x21, 0xf3, 0x50, 0x95, 0xf5, + 0xbd, 0x4a, 0xce, 0xca, 0x6f, 0xe0, 0x26, 0x99, 0x87, 0x48, 0x85, 0xcc, 0x12, 0x07, 0xa1, 0x47, + 0x7c, 0x35, 0xa5, 0x4b, 0x95, 0x9c, 0x15, 0x9b, 0xe8, 0x21, 0x28, 0x8b, 0xf9, 0x38, 0xb0, 0x5d, + 0x3c, 0x0c, 0xf1, 0x0f, 0x0b, 0xec, 0x3b, 0x58, 0x4d, 0xeb, 0x52, 0x45, 0xb6, 0x0a, 0x02, 0xef, + 0x09, 0xf8, 0x1b, 0xf9, 0xed, 0x2f, 0xa5, 0x44, 0xf9, 0xcf, 0x24, 0x1c, 0x99, 0x2e, 0xf6, 0xa9, + 0xf7, 0xbd, 0x87, 0xdd, 0xff, 0x06, 0xf8, 0x11, 0x64, 0xe6, 0x24, 0xa0, 0x43, 0xcf, 0x65, 0x73, + 0xcb, 0x59, 0xe9, 0xc8, 0x34, 0x5d, 0xf4, 0x31, 0x80, 0x28, 0x25, 0xf2, 0x65, 0x98, 0x2f, 0x27, + 0x10, 0xd3, 0xbd, 0x73, 0xf0, 0xd9, 0xfb, 0x06, 0xdf, 0x82, 0x83, 0xed, 0x7e, 0xb6, 0x85, 0xa5, + 0x7b, 0x84, 0x93, 0xb7, 0x84, 0x45, 0xb6, 0x0f, 0x49, 0x48, 0x77, 0x6d, 0xe7, 0x15, 0xa6, 0x48, + 0x83, 0xec, 0x4d, 0x05, 0x12, 0xab, 0xe0, 0xc6, 0x46, 0x25, 0xd8, 0x0f, 0xc9, 0x22, 0x70, 0xf0, + 0x30, 0x4a, 0x2e, 0x92, 0x01, 0x87, 0xba, 0x24, 0xa0, 0xe8, 0x53, 0xc8, 0x0b, 0x82, 0x50, 0x60, + 0x0b, 0xc9, 0x59, 0x87, 0x1c, 0x8d, 0xef, 0xc7, 0x43, 0x50, 0x5c, 0x1c, 0x52, 0xcf, 0xb7, 0xd9, + 0xa4, 0x59, 0x32, 0x99, 0x11, 0x0b, 0x5b, 0x38, 0xcb, 0x58, 0x83, 0xe3, 0x6d, 0x6a, 0x9c, 0x96, + 0x8f, 0x1d, 0x6d, 0xb9, 0xe2, 0xdc, 0x08, 0x64, 0xd7, 0xa6, 0x36, 0x1b, 0xff, 0x81, 0xc5, 0xce, + 0xe8, 0x39, 0xe4, 0xa9, 0x37, 0xc3, 0x64, 0x41, 0x87, 0x13, 0xec, 0x8d, 0x27, 0x94, 0x2d, 0x60, + 0x7f, 0xe7, 0x8e, 0xf1, 0xc7, 0x60, 0x79, 0x5e, 0x6d, 0x32, 0x86, 0xb8, 0x20, 0x87, 0x22, 0x8e, + 0x83, 0xe8, 0x73, 0x38, 0x8a, 0x13, 0x45, 0xbf, 0x21, 0xb5, 0x67, 0x73, 0xb1, 0x27, 0x45, 0x38, + 0xfa, 0x31, 0x2e, 0x46, 0xfb, 0x23, 0xec, 0xf3, 0xc9, 0xb2, 0xfb, 0xfe, 0x4f, 0xf7, 0xb4, 0xb3, + 0x96, 0xbd, 0x5b, 0x6b, 0x89, 0x5b, 0x96, 0x37, 0x2d, 0x0b, 0x71, 0x17, 0xb2, 0x5c, 0xdc, 0x74, + 0xff, 0x0d, 0x65, 0xa1, 0xd2, 0x81, 0xc2, 0x85, 0xf3, 0xca, 0x27, 0xaf, 0xa7, 0xd8, 0x1d, 0xe3, + 0x19, 0xf6, 0x29, 0x52, 0x21, 0x1d, 0xe0, 0x70, 0x31, 0xa5, 0xea, 0xff, 0xa3, 0xa2, 0x9a, 0x09, + 0x4b, 0xd8, 0xe8, 0x04, 0x52, 0x38, 0x08, 0x48, 0xa0, 0x9e, 0x44, 0x42, 0xcd, 0x84, 0xc5, 0xcd, + 0x4b, 0x80, 0x6c, 0x80, 0xc3, 0x39, 0xf1, 0x43, 0x5c, 0xb6, 0x21, 0xd3, 0xe7, 0xd3, 0x44, 0x4f, + 0x21, 0x2d, 0x56, 0x26, 0xfd, 0xcd, 0x95, 0x09, 0x3e, 0x3a, 0x85, 0xdc, 0x66, 0x47, 0x49, 0x56, + 0xf8, 0x06, 0x28, 0x0f, 0xa2, 0x0b, 0x1f, 0xd8, 0xb3, 0x10, 0xbd, 0x80, 0xf8, 0x2f, 0x36, 0x14, + 0x2b, 0x14, 0x52, 0xa7, 0x77, 0xbe, 0x22, 0xa2, 0x30, 0x21, 0x96, 0x17, 0xa1, 0x02, 0x3d, 0xfb, + 0x29, 0x09, 0xa9, 0x9e, 0x78, 0xd1, 0x4a, 0xbd, 0xfe, 0x45, 0xdf, 0x18, 0x0e, 0xda, 0x66, 0xdb, + 0xec, 0x9b, 0x17, 0x2d, 0xf3, 0xa5, 0xd1, 0x18, 0x0e, 0xda, 0xbd, 0xae, 0x51, 0x37, 0x9f, 0x99, + 0x46, 0x43, 0x49, 0x68, 0x47, 0xab, 0xb5, 0x7e, 0xb8, 0x43, 0x40, 0x2a, 0x00, 0x8f, 0x8b, 0x40, + 0x45, 0xd2, 0xb2, 0xab, 0xb5, 0x2e, 0x47, 0x67, 0x54, 0x84, 0x43, 0xee, 0xe9, 0x5b, 0xdf, 0x75, + 0xba, 0x46, 0x5b, 0x49, 0x6a, 0xfb, 0xab, 0xb5, 0x9e, 0x11, 0xe6, 0x26, 0x92, 0x39, 0xf7, 0x78, + 0x24, 0xf3, 0x9c, 0xc2, 0x01, 0xf7, 0xd4, 0x5b, 0x9d, 0x9e, 0xd1, 0x50, 0x64, 0x0d, 0x56, 0x6b, + 0x3d, 0xcd, 0x2d, 0xa4, 0x43, 0x9e, 0x7b, 0x9f, 0xb5, 0x06, 0xbd, 0xa6, 0xd9, 0x7e, 0xae, 0xa4, + 0xb4, 0x83, 0xd5, 0x5a, 0xcf, 0xc6, 0x36, 0x3a, 0x83, 0xe3, 0x2d, 0x46, 0xbd, 0xf3, 0x6d, 0xb7, + 0x65, 0xf4, 0x0d, 0x25, 0xcd, 0xeb, 0xdf, 0x01, 0x35, 0xf9, 0xed, 0xaf, 0xc5, 0xc4, 0xd9, 0x6b, + 0x48, 0xb1, 0xa7, 0x1a, 0x7d, 0x02, 0x27, 0x1d, 0xab, 0x61, 0x58, 0xc3, 0x76, 0xa7, 0x6d, 0xdc, + 0xea, 0x9e, 0x15, 0x18, 0xe1, 0xa8, 0x0c, 0x05, 0xce, 0x1a, 0xb4, 0xd9, 0xaf, 0xd1, 0x50, 0x24, + 0xed, 0x70, 0xb5, 0xd6, 0x73, 0x37, 0x40, 0xd4, 0x3e, 0xe7, 0xc4, 0x0c, 0xd1, 0xbe, 0x30, 0xb9, + 0xf0, 0x65, 0xef, 0xdd, 0x55, 0x51, 0x7a, 0x7f, 0x55, 0x94, 0xfe, 0xb8, 0x2a, 0x4a, 0x3f, 0x5f, + 0x17, 0x13, 0xef, 0xaf, 0x8b, 0x89, 0x0f, 0xd7, 0xc5, 0xc4, 0xcb, 0xaf, 0xc7, 0x1e, 0x9d, 0x2c, + 0x46, 0x55, 0x87, 0xcc, 0x6a, 0x0e, 0x09, 0x67, 0x24, 0xac, 0x79, 0x23, 0xe7, 0xd1, 0x98, 0xd4, + 0x96, 0x4f, 0x6b, 0x33, 0xe2, 0x2e, 0xa6, 0x38, 0xe4, 0x9f, 0x08, 0x8f, 0xbf, 0x7c, 0x14, 0x7f, + 0x73, 0xd0, 0x37, 0x73, 0x1c, 0x8e, 0xd2, 0xec, 0x1b, 0xe1, 0x8b, 0xbf, 0x02, 0x00, 0x00, 0xff, + 0xff, 0x90, 0xd1, 0xb4, 0xca, 0x94, 0x08, 0x00, 0x00, } func (m *Channel) Marshal() (dAtA []byte, err error) { @@ -635,6 +702,11 @@ func (m *Channel) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.UpgradeSequence != 0 { + i = encodeVarintChannel(dAtA, i, uint64(m.UpgradeSequence)) + i-- + dAtA[i] = 0x30 + } if len(m.Version) > 0 { i -= len(m.Version) copy(dAtA[i:], m.Version) @@ -694,6 +766,11 @@ func (m *IdentifiedChannel) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.UpgradeSequence != 0 { + i = encodeVarintChannel(dAtA, i, uint64(m.UpgradeSequence)) + i-- + dAtA[i] = 0x40 + } if len(m.ChannelId) > 0 { i -= len(m.ChannelId) copy(dAtA[i:], m.ChannelId) @@ -1057,6 +1134,39 @@ func (m *Timeout) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +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 + { + size, err := m.UpgradeTimeout.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintChannel(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func encodeVarintChannel(dAtA []byte, offset int, v uint64) int { offset -= sovChannel(v) base := offset @@ -1092,6 +1202,9 @@ func (m *Channel) Size() (n int) { if l > 0 { n += 1 + l + sovChannel(uint64(l)) } + if m.UpgradeSequence != 0 { + n += 1 + sovChannel(uint64(m.UpgradeSequence)) + } return n } @@ -1127,6 +1240,9 @@ func (m *IdentifiedChannel) Size() (n int) { if l > 0 { n += 1 + l + sovChannel(uint64(l)) } + if m.UpgradeSequence != 0 { + n += 1 + sovChannel(uint64(m.UpgradeSequence)) + } return n } @@ -1276,6 +1392,17 @@ func (m *Timeout) Size() (n int) { return n } +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.UpgradeTimeout.Size() + n += 1 + l + sovChannel(uint64(l)) + return n +} + func sovChannel(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1446,6 +1573,25 @@ func (m *Channel) Unmarshal(dAtA []byte) error { } m.Version = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UpgradeSequence", wireType) + } + m.UpgradeSequence = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowChannel + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UpgradeSequence |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipChannel(dAtA[iNdEx:]) @@ -1695,6 +1841,25 @@ func (m *IdentifiedChannel) Unmarshal(dAtA []byte) error { } m.ChannelId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UpgradeSequence", wireType) + } + m.UpgradeSequence = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowChannel + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UpgradeSequence |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipChannel(dAtA[iNdEx:]) @@ -2630,6 +2795,89 @@ func (m *Timeout) Unmarshal(dAtA []byte) error { } return nil } +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 ErrIntOverflowChannel + } + 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 { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UpgradeTimeout", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowChannel + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthChannel + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthChannel + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.UpgradeTimeout.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipChannel(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthChannel + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipChannel(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/modules/core/04-channel/types/channel_test.go b/modules/core/04-channel/types/channel_test.go index d35ec13a519..211be035fe8 100644 --- a/modules/core/04-channel/types/channel_test.go +++ b/modules/core/04-channel/types/channel_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ) func TestChannelValidateBasic(t *testing.T) { @@ -57,3 +58,37 @@ func TestCounterpartyValidateBasic(t *testing.T) { } } } + +// TestIdentifiedChannelValidateBasic tests ValidateBasic for IdentifiedChannel. +func TestIdentifiedChannelValidateBasic(t *testing.T) { + channel := types.NewChannel(types.TRYOPEN, types.ORDERED, types.Counterparty{"portidone", "channelidone"}, connHops, version) + + testCases := []struct { + name string + identifiedChannel types.IdentifiedChannel + expErr error + }{ + { + "valid identified channel", + types.NewIdentifiedChannel("portidone", "channelidone", channel), + nil, + }, + { + "invalid portID", + types.NewIdentifiedChannel("(InvalidPort)", "channelidone", channel), + host.ErrInvalidID, + }, + { + "invalid channelID", + types.NewIdentifiedChannel("portidone", "(InvalidChannel)", channel), + host.ErrInvalidID, + }, + } + + for _, tc := range testCases { + tc := tc + + err := tc.identifiedChannel.ValidateBasic() + require.ErrorIs(t, err, tc.expErr) + } +} diff --git a/modules/core/04-channel/types/codec.go b/modules/core/04-channel/types/codec.go index 86f2f495d19..d55fffece0c 100644 --- a/modules/core/04-channel/types/codec.go +++ b/modules/core/04-channel/types/codec.go @@ -39,6 +39,15 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { &MsgAcknowledgement{}, &MsgTimeout{}, &MsgTimeoutOnClose{}, + &MsgChannelUpgradeInit{}, + &MsgChannelUpgradeTry{}, + &MsgChannelUpgradeAck{}, + &MsgChannelUpgradeConfirm{}, + &MsgChannelUpgradeOpen{}, + &MsgChannelUpgradeTimeout{}, + &MsgChannelUpgradeCancel{}, + &MsgPruneAcknowledgements{}, + &MsgUpdateParams{}, ) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) diff --git a/modules/core/04-channel/types/codec_test.go b/modules/core/04-channel/types/codec_test.go index 9122a95df0a..fab8d9e5bd0 100644 --- a/modules/core/04-channel/types/codec_test.go +++ b/modules/core/04-channel/types/codec_test.go @@ -83,6 +83,51 @@ func TestCodecTypeRegistration(t *testing.T) { sdk.MsgTypeURL(&types.MsgTimeoutOnClose{}), true, }, + { + "success: MsgChannelUpgradeInit", + sdk.MsgTypeURL(&types.MsgChannelUpgradeInit{}), + true, + }, + { + "success: MsgChannelUpgradeTry", + sdk.MsgTypeURL(&types.MsgChannelUpgradeTry{}), + true, + }, + { + "success: MsgChannelUpgradeAck", + sdk.MsgTypeURL(&types.MsgChannelUpgradeAck{}), + true, + }, + { + "success: MsgChannelUpgradeConfirm", + sdk.MsgTypeURL(&types.MsgChannelUpgradeConfirm{}), + true, + }, + { + "success: MsgChannelUpgradeOpen", + sdk.MsgTypeURL(&types.MsgChannelUpgradeOpen{}), + true, + }, + { + "success: MsgChannelUpgradeTimeout", + sdk.MsgTypeURL(&types.MsgChannelUpgradeTimeout{}), + true, + }, + { + "success: MsgChannelUpgradeCancel", + sdk.MsgTypeURL(&types.MsgChannelUpgradeCancel{}), + true, + }, + { + "success: MsgPruneAcknowledgements", + sdk.MsgTypeURL(&types.MsgPruneAcknowledgements{}), + true, + }, + { + "success: MsgUpdateParams", + sdk.MsgTypeURL(&types.MsgUpdateParams{}), + true, + }, { "type not registered on codec", "ibc.invalid.MsgTypeURL", diff --git a/modules/core/04-channel/types/errors.go b/modules/core/04-channel/types/errors.go index dfbbf30a1cb..b23dce37211 100644 --- a/modules/core/04-channel/types/errors.go +++ b/modules/core/04-channel/types/errors.go @@ -37,7 +37,23 @@ var ( // Perform a no-op on the current Msg ErrNoOpMsg = errorsmod.Register(SubModuleName, 23, "message is redundant, no-op will be performed") - ErrInvalidChannelVersion = errorsmod.Register(SubModuleName, 24, "invalid channel version") - ErrPacketNotSent = errorsmod.Register(SubModuleName, 25, "packet has not been sent") - ErrInvalidTimeout = errorsmod.Register(SubModuleName, 26, "invalid packet timeout") + ErrInvalidChannelVersion = errorsmod.Register(SubModuleName, 24, "invalid channel version") + ErrPacketNotSent = errorsmod.Register(SubModuleName, 25, "packet has not been sent") + ErrInvalidTimeout = errorsmod.Register(SubModuleName, 26, "invalid packet timeout") + ErrUpgradeErrorNotFound = errorsmod.Register(SubModuleName, 27, "upgrade error receipt not found") + ErrInvalidUpgrade = errorsmod.Register(SubModuleName, 28, "invalid upgrade") + ErrInvalidUpgradeSequence = errorsmod.Register(SubModuleName, 29, "invalid upgrade sequence") + ErrUpgradeNotFound = errorsmod.Register(SubModuleName, 30, "upgrade not found") + ErrIncompatibleCounterpartyUpgrade = errorsmod.Register(SubModuleName, 31, "incompatible counterparty upgrade") + ErrInvalidUpgradeError = errorsmod.Register(SubModuleName, 32, "invalid upgrade error") + ErrUpgradeRestoreFailed = errorsmod.Register(SubModuleName, 33, "restore failed") + ErrUpgradeTimeout = errorsmod.Register(SubModuleName, 34, "upgrade timed-out") + ErrInvalidUpgradeTimeout = errorsmod.Register(SubModuleName, 35, "upgrade timeout is invalid") + ErrPendingInflightPackets = errorsmod.Register(SubModuleName, 36, "pending inflight packets exist") + ErrUpgradeTimeoutFailed = errorsmod.Register(SubModuleName, 37, "upgrade timeout failed") + ErrInvalidPruningLimit = errorsmod.Register(SubModuleName, 38, "invalid pruning limit") + ErrTimeoutNotReached = errorsmod.Register(SubModuleName, 39, "timeout not reached") + ErrTimeoutElapsed = errorsmod.Register(SubModuleName, 40, "timeout elapsed") + ErrPruningSequenceStartNotFound = errorsmod.Register(SubModuleName, 41, "pruning sequence start not found") + ErrRecvStartSequenceNotFound = errorsmod.Register(SubModuleName, 42, "recv start sequence not found") ) diff --git a/modules/core/04-channel/types/events.go b/modules/core/04-channel/types/events.go index 3d4738626e2..dc08061f1fd 100644 --- a/modules/core/04-channel/types/events.go +++ b/modules/core/04-channel/types/events.go @@ -8,10 +8,20 @@ import ( // IBC channel events const ( - AttributeKeyConnectionID = "connection_id" - AttributeKeyPortID = "port_id" - AttributeKeyChannelID = "channel_id" - AttributeVersion = "version" + AttributeKeyConnectionID = "connection_id" + AttributeKeyPortID = "port_id" + AttributeKeyChannelID = "channel_id" + AttributeKeyChannelState = "channel_state" + AttributeVersion = "version" + AttributeKeyConnectionHops = "connection_hops" + AttributeKeyOrdering = "ordering" + + // upgrade specific keys + AttributeKeyUpgradeTimeoutHeight = "timeout_height" + AttributeKeyUpgradeTimeoutTimestamp = "timeout_timestamp" + AttributeKeyUpgradeSequence = "upgrade_sequence" + AttributeKeyErrorReceipt = "error_receipt" + AttributeCounterpartyPortID = "counterparty_port_id" AttributeCounterpartyChannelID = "counterparty_channel_id" @@ -41,13 +51,22 @@ const ( // IBC channel events vars var ( - EventTypeChannelOpenInit = "channel_open_init" - EventTypeChannelOpenTry = "channel_open_try" - EventTypeChannelOpenAck = "channel_open_ack" - EventTypeChannelOpenConfirm = "channel_open_confirm" - EventTypeChannelCloseInit = "channel_close_init" - EventTypeChannelCloseConfirm = "channel_close_confirm" - EventTypeChannelClosed = "channel_close" + EventTypeChannelOpenInit = "channel_open_init" + EventTypeChannelOpenTry = "channel_open_try" + EventTypeChannelOpenAck = "channel_open_ack" + EventTypeChannelOpenConfirm = "channel_open_confirm" + EventTypeChannelCloseInit = "channel_close_init" + EventTypeChannelCloseConfirm = "channel_close_confirm" + EventTypeChannelClosed = "channel_close" + EventTypeChannelUpgradeInit = "channel_upgrade_init" + EventTypeChannelUpgradeTry = "channel_upgrade_try" + EventTypeChannelUpgradeAck = "channel_upgrade_ack" + EventTypeChannelUpgradeConfirm = "channel_upgrade_confirm" + EventTypeChannelUpgradeOpen = "channel_upgrade_open" + EventTypeChannelUpgradeTimeout = "channel_upgrade_timeout" + EventTypeChannelUpgradeCancel = "channel_upgrade_cancelled" + EventTypeChannelUpgradeError = "channel_upgrade_error" + EventTypeChannelFlushComplete = "channel_flush_complete" AttributeValueCategory = fmt.Sprintf("%s_%s", ibcexported.ModuleName, SubModuleName) ) diff --git a/modules/core/04-channel/types/expected_keepers.go b/modules/core/04-channel/types/expected_keepers.go index b1e3aae98d3..820a25277ad 100644 --- a/modules/core/04-channel/types/expected_keepers.go +++ b/modules/core/04-channel/types/expected_keepers.go @@ -73,6 +73,24 @@ type ConnectionKeeper interface { channelID string, nextSequenceRecv uint64, ) error + VerifyChannelUpgrade( + ctx sdk.Context, + connection exported.ConnectionI, + height exported.Height, + proof []byte, + portID, + channelID string, + upgrade Upgrade, + ) error + VerifyChannelUpgradeError( + ctx sdk.Context, + connection exported.ConnectionI, + height exported.Height, + proof []byte, + portID, + channelID string, + errorReceipt ErrorReceipt, + ) error } // PortKeeper expected account IBC port keeper diff --git a/modules/core/04-channel/types/genesis.go b/modules/core/04-channel/types/genesis.go index fd85574d554..d95f24c35e6 100644 --- a/modules/core/04-channel/types/genesis.go +++ b/modules/core/04-channel/types/genesis.go @@ -41,7 +41,9 @@ func (ps PacketSequence) Validate() error { return validateGenFields(ps.PortId, ps.ChannelId, ps.Sequence) } -// NewGenesisState creates a GenesisState instance. +// NewGenesisState creates a GenesisState instance. It uses the default params. +// Breakage in v9.0.0 will allow the params to be provided. Please use +// NewGenesisStateWithParams in this version if you want to provide custom params. func NewGenesisState( channels []IdentifiedChannel, acks, receipts, commitments []PacketState, sendSeqs, recvSeqs, ackSeqs []PacketSequence, nextChannelSequence uint64, @@ -54,6 +56,25 @@ func NewGenesisState( RecvSequences: recvSeqs, AckSequences: ackSeqs, NextChannelSequence: nextChannelSequence, + Params: DefaultParams(), + } +} + +// NewGenesisStateWithParams creates a GenesisState instance. +func NewGenesisStateWithParams( + channels []IdentifiedChannel, acks, receipts, commitments []PacketState, + sendSeqs, recvSeqs, ackSeqs []PacketSequence, nextChannelSequence uint64, + params Params, +) GenesisState { + return GenesisState{ + Channels: channels, + Acknowledgements: acks, + Commitments: commitments, + SendSequences: sendSeqs, + RecvSequences: recvSeqs, + AckSequences: ackSeqs, + NextChannelSequence: nextChannelSequence, + Params: params, } } @@ -68,6 +89,7 @@ func DefaultGenesisState() GenesisState { RecvSequences: []PacketSequence{}, AckSequences: []PacketSequence{}, NextChannelSequence: 0, + Params: DefaultParams(), } } diff --git a/modules/core/04-channel/types/genesis.pb.go b/modules/core/04-channel/types/genesis.pb.go index 0ed3da2e528..bd8723eb637 100644 --- a/modules/core/04-channel/types/genesis.pb.go +++ b/modules/core/04-channel/types/genesis.pb.go @@ -34,6 +34,7 @@ type GenesisState struct { AckSequences []PacketSequence `protobuf:"bytes,7,rep,name=ack_sequences,json=ackSequences,proto3" json:"ack_sequences"` // the sequence for the next generated channel identifier NextChannelSequence uint64 `protobuf:"varint,8,opt,name=next_channel_sequence,json=nextChannelSequence,proto3" json:"next_channel_sequence,omitempty"` + Params Params `protobuf:"bytes,9,opt,name=params,proto3" json:"params"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -125,6 +126,13 @@ func (m *GenesisState) GetNextChannelSequence() uint64 { return 0 } +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + // PacketSequence defines the genesis type necessary to retrieve and store // next send and receive sequences. type PacketSequence struct { @@ -195,35 +203,37 @@ func init() { func init() { proto.RegisterFile("ibc/core/channel/v1/genesis.proto", fileDescriptor_cb06ec201f452595) } var fileDescriptor_cb06ec201f452595 = []byte{ - // 446 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0xd3, 0x4d, 0x6f, 0xd3, 0x30, - 0x18, 0x07, 0xf0, 0x66, 0x2d, 0x5d, 0xe7, 0xbd, 0x08, 0x3c, 0x10, 0xa1, 0x12, 0x59, 0x19, 0x12, - 0xea, 0x65, 0x31, 0x1b, 0x1c, 0xe0, 0x1a, 0x0e, 0xd0, 0x0b, 0x9a, 0xb2, 0x1b, 0x12, 0xaa, 0x12, - 0xfb, 0x21, 0xb3, 0xd2, 0xd8, 0x21, 0x76, 0x03, 0x7c, 0x0b, 0x3e, 0xd6, 0x8e, 0x3b, 0x72, 0x9a, - 0x50, 0xfb, 0x21, 0x90, 0x38, 0xa1, 0x38, 0x2f, 0x2b, 0x6a, 0x35, 0x29, 0xb7, 0xda, 0xcf, 0xf3, - 0xff, 0xfd, 0x7b, 0x88, 0xd1, 0x33, 0x1e, 0x52, 0x42, 0x65, 0x06, 0x84, 0x5e, 0x06, 0x42, 0xc0, - 0x8c, 0xe4, 0xa7, 0x24, 0x02, 0x01, 0x8a, 0x2b, 0x37, 0xcd, 0xa4, 0x96, 0xf8, 0x90, 0x87, 0xd4, - 0x2d, 0x56, 0xdc, 0x6a, 0xc5, 0xcd, 0x4f, 0x87, 0x0f, 0x23, 0x19, 0x49, 0x33, 0x27, 0xc5, 0xaf, - 0x72, 0x75, 0xb8, 0x51, 0xab, 0x53, 0x66, 0xe5, 0xf8, 0x4f, 0x0f, 0xed, 0xbd, 0x2f, 0xfd, 0x0b, - 0x1d, 0x68, 0xc0, 0x9f, 0xd1, 0xa0, 0xda, 0x50, 0xb6, 0x35, 0xea, 0x8e, 0x77, 0xcf, 0x5e, 0xb8, - 0x1b, 0x1a, 0xdd, 0x09, 0x03, 0xa1, 0xf9, 0x17, 0x0e, 0xec, 0x5d, 0x79, 0xe9, 0x3d, 0xb9, 0xba, - 0x39, 0xea, 0xfc, 0xbd, 0x39, 0x7a, 0xb0, 0x36, 0xf2, 0x1b, 0x12, 0xfb, 0xe8, 0x7e, 0x40, 0x63, - 0x21, 0xbf, 0xcd, 0x80, 0x45, 0x90, 0x80, 0xd0, 0xca, 0xde, 0x32, 0x35, 0xa3, 0x8d, 0x35, 0xe7, - 0x01, 0x8d, 0x41, 0x9b, 0xbf, 0xe6, 0xf5, 0x8a, 0x02, 0x7f, 0x2d, 0x8f, 0x3f, 0xa0, 0x5d, 0x2a, - 0x93, 0x84, 0xeb, 0x92, 0xeb, 0xb6, 0xe2, 0x56, 0xa3, 0xd8, 0x43, 0x83, 0x0c, 0x28, 0xf0, 0x54, - 0x2b, 0xbb, 0xd7, 0x8a, 0x69, 0x72, 0xf8, 0x1c, 0x1d, 0x28, 0x10, 0x6c, 0xaa, 0xe0, 0xeb, 0x1c, - 0x04, 0x05, 0x65, 0xdf, 0x33, 0xd2, 0xf3, 0xbb, 0xa4, 0x6a, 0xb7, 0xc2, 0xf6, 0x0b, 0xa0, 0xbe, - 0x33, 0x62, 0x06, 0x34, 0x5f, 0x11, 0xfb, 0xad, 0xc5, 0x02, 0xb8, 0x15, 0x3f, 0xa2, 0xfd, 0x80, - 0xc6, 0x2b, 0xe0, 0x76, 0x5b, 0x70, 0x2f, 0xa0, 0xf1, 0xad, 0x77, 0x86, 0x1e, 0x09, 0xf8, 0xae, - 0xa7, 0x55, 0xaa, 0x81, 0xed, 0xc1, 0xc8, 0x1a, 0xf7, 0xfc, 0xc3, 0x62, 0x58, 0x7d, 0x0b, 0x75, - 0xe8, 0x98, 0xa1, 0x83, 0xff, 0x65, 0xfc, 0x18, 0x6d, 0xa7, 0x32, 0xd3, 0x53, 0xce, 0x6c, 0x6b, - 0x64, 0x8d, 0x77, 0xfc, 0x7e, 0x71, 0x9c, 0x30, 0xfc, 0x14, 0xa1, 0x5a, 0xe6, 0xcc, 0xde, 0x32, - 0xb3, 0x9d, 0xea, 0x66, 0xc2, 0xf0, 0x10, 0x0d, 0x9a, 0xc2, 0xae, 0x29, 0x6c, 0xce, 0xde, 0xc5, - 0xd5, 0xc2, 0xb1, 0xae, 0x17, 0x8e, 0xf5, 0x7b, 0xe1, 0x58, 0x3f, 0x97, 0x4e, 0xe7, 0x7a, 0xe9, - 0x74, 0x7e, 0x2d, 0x9d, 0xce, 0xa7, 0xb7, 0x11, 0xd7, 0x97, 0xf3, 0xd0, 0xa5, 0x32, 0x21, 0x54, - 0xaa, 0x44, 0x2a, 0xc2, 0x43, 0x7a, 0x12, 0x49, 0x92, 0xbf, 0x21, 0x89, 0x64, 0xf3, 0x19, 0xa8, - 0xf2, 0xf1, 0xbc, 0x7c, 0x7d, 0x52, 0xbf, 0x1f, 0xfd, 0x23, 0x05, 0x15, 0xf6, 0xcd, 0xdb, 0x79, - 0xf5, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xce, 0x58, 0xd9, 0xe7, 0xae, 0x03, 0x00, 0x00, + // 471 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x93, 0x41, 0x6f, 0xd3, 0x30, + 0x18, 0x86, 0x9b, 0xb5, 0xeb, 0x5a, 0x77, 0x9b, 0xc0, 0x03, 0x11, 0x8a, 0xc8, 0xca, 0x90, 0x50, + 0x2f, 0x8b, 0x59, 0xe1, 0xc0, 0xae, 0xe5, 0x00, 0xbd, 0xa0, 0x29, 0xbb, 0x21, 0xa1, 0x2a, 0xb1, + 0x3f, 0x32, 0xab, 0x8d, 0x1d, 0x62, 0xb7, 0xc0, 0xbf, 0xe0, 0xb7, 0xf0, 0x2b, 0x76, 0xdc, 0x91, + 0xd3, 0x84, 0xda, 0x7f, 0xc1, 0x09, 0xc5, 0x71, 0xb2, 0xa2, 0x95, 0x49, 0xbd, 0xc5, 0xdf, 0xf7, + 0xbe, 0xcf, 0xfb, 0x1e, 0xf2, 0xa1, 0x67, 0x3c, 0xa2, 0x84, 0xca, 0x0c, 0x08, 0xbd, 0x08, 0x85, + 0x80, 0x29, 0x99, 0x9f, 0x90, 0x18, 0x04, 0x28, 0xae, 0xfc, 0x34, 0x93, 0x5a, 0xe2, 0x03, 0x1e, + 0x51, 0x3f, 0x97, 0xf8, 0x56, 0xe2, 0xcf, 0x4f, 0xba, 0x0f, 0x62, 0x19, 0x4b, 0xb3, 0x27, 0xf9, + 0x57, 0x21, 0xed, 0xae, 0xa5, 0x95, 0x2e, 0x23, 0x39, 0xfa, 0xb9, 0x8d, 0x76, 0xdf, 0x15, 0xfc, + 0x73, 0x1d, 0x6a, 0xc0, 0x9f, 0x50, 0xcb, 0x2a, 0x94, 0xeb, 0xf4, 0xea, 0xfd, 0xce, 0xe0, 0x85, + 0xbf, 0x26, 0xd1, 0x1f, 0x31, 0x10, 0x9a, 0x7f, 0xe6, 0xc0, 0xde, 0x16, 0xc3, 0xe1, 0xe3, 0xcb, + 0xeb, 0xc3, 0xda, 0x9f, 0xeb, 0xc3, 0xfb, 0xb7, 0x56, 0x41, 0x85, 0xc4, 0x01, 0xba, 0x17, 0xd2, + 0x89, 0x90, 0x5f, 0xa7, 0xc0, 0x62, 0x48, 0x40, 0x68, 0xe5, 0x6e, 0x99, 0x98, 0xde, 0xda, 0x98, + 0xb3, 0x90, 0x4e, 0x40, 0x9b, 0x6a, 0xc3, 0x46, 0x1e, 0x10, 0xdc, 0xf2, 0xe3, 0xf7, 0xa8, 0x43, + 0x65, 0x92, 0x70, 0x5d, 0xe0, 0xea, 0x1b, 0xe1, 0x56, 0xad, 0x78, 0x88, 0x5a, 0x19, 0x50, 0xe0, + 0xa9, 0x56, 0x6e, 0x63, 0x23, 0x4c, 0xe5, 0xc3, 0x67, 0x68, 0x5f, 0x81, 0x60, 0x63, 0x05, 0x5f, + 0x66, 0x20, 0x28, 0x28, 0x77, 0xdb, 0x90, 0x9e, 0xdf, 0x45, 0xb2, 0x5a, 0x0b, 0xdb, 0xcb, 0x01, + 0xe5, 0xcc, 0x10, 0x33, 0xa0, 0xf3, 0x15, 0x62, 0x73, 0x63, 0x62, 0x0e, 0xb8, 0x21, 0x7e, 0x40, + 0x7b, 0x21, 0x9d, 0xac, 0x00, 0x77, 0x36, 0x05, 0xee, 0x86, 0x74, 0x72, 0xc3, 0x1b, 0xa0, 0x87, + 0x02, 0xbe, 0xe9, 0xb1, 0x75, 0x55, 0x60, 0xb7, 0xd5, 0x73, 0xfa, 0x8d, 0xe0, 0x20, 0x5f, 0xda, + 0x7f, 0xa1, 0x34, 0xe1, 0x53, 0xd4, 0x4c, 0xc3, 0x2c, 0x4c, 0x94, 0xdb, 0xee, 0x39, 0xfd, 0xce, + 0xe0, 0xc9, 0x7f, 0xc2, 0x73, 0x89, 0x0d, 0xb5, 0x86, 0x23, 0x86, 0xf6, 0xff, 0x2d, 0x85, 0x1f, + 0xa1, 0x9d, 0x54, 0x66, 0x7a, 0xcc, 0x99, 0xeb, 0xf4, 0x9c, 0x7e, 0x3b, 0x68, 0xe6, 0xcf, 0x11, + 0xc3, 0x4f, 0x11, 0x2a, 0x4b, 0x71, 0xe6, 0x6e, 0x99, 0x5d, 0xdb, 0x4e, 0x46, 0x0c, 0x77, 0x51, + 0xab, 0xea, 0x5a, 0x37, 0x5d, 0xab, 0xf7, 0xf0, 0xfc, 0x72, 0xe1, 0x39, 0x57, 0x0b, 0xcf, 0xf9, + 0xbd, 0xf0, 0x9c, 0x1f, 0x4b, 0xaf, 0x76, 0xb5, 0xf4, 0x6a, 0xbf, 0x96, 0x5e, 0xed, 0xe3, 0x69, + 0xcc, 0xf5, 0xc5, 0x2c, 0xf2, 0xa9, 0x4c, 0x08, 0x95, 0x2a, 0x91, 0x8a, 0xf0, 0x88, 0x1e, 0xc7, + 0x92, 0xcc, 0xdf, 0x90, 0x44, 0xb2, 0xd9, 0x14, 0x54, 0x71, 0x77, 0x2f, 0x5f, 0x1f, 0x97, 0xa7, + 0xa7, 0xbf, 0xa7, 0xa0, 0xa2, 0xa6, 0x39, 0xbb, 0x57, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xaf, + 0xa9, 0x60, 0xe8, 0xe9, 0x03, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -246,6 +256,16 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a if m.NextChannelSequence != 0 { i = encodeVarintGenesis(dAtA, i, uint64(m.NextChannelSequence)) i-- @@ -456,6 +476,8 @@ func (m *GenesisState) Size() (n int) { if m.NextChannelSequence != 0 { n += 1 + sovGenesis(uint64(m.NextChannelSequence)) } + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) return n } @@ -771,6 +793,39 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { break } } + case 9: + 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 default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/modules/core/04-channel/types/keys.go b/modules/core/04-channel/types/keys.go index bc9e88afdea..a99e14d5b21 100644 --- a/modules/core/04-channel/types/keys.go +++ b/modules/core/04-channel/types/keys.go @@ -28,6 +28,9 @@ const ( // ChannelPrefix is the prefix used when creating a channel identifier ChannelPrefix = "channel-" + + // ParamsKey defines the key to store the params in the keeper. + ParamsKey = "channelParams" ) // FormatChannelIdentifier returns the channel identifier with the sequence appended. diff --git a/modules/core/04-channel/types/msgs.go b/modules/core/04-channel/types/msgs.go index 812829307c0..622b36ed6b6 100644 --- a/modules/core/04-channel/types/msgs.go +++ b/modules/core/04-channel/types/msgs.go @@ -2,6 +2,7 @@ package types import ( "encoding/base64" + "slices" errorsmod "cosmossdk.io/errors" @@ -24,6 +25,13 @@ var ( _ sdk.Msg = (*MsgAcknowledgement)(nil) _ sdk.Msg = (*MsgTimeout)(nil) _ sdk.Msg = (*MsgTimeoutOnClose)(nil) + _ sdk.Msg = (*MsgChannelUpgradeInit)(nil) + _ sdk.Msg = (*MsgChannelUpgradeTry)(nil) + _ sdk.Msg = (*MsgChannelUpgradeAck)(nil) + _ sdk.Msg = (*MsgChannelUpgradeConfirm)(nil) + _ sdk.Msg = (*MsgChannelUpgradeTimeout)(nil) + _ sdk.Msg = (*MsgChannelUpgradeCancel)(nil) + _ sdk.Msg = (*MsgPruneAcknowledgements)(nil) _ sdk.HasValidateBasic = (*MsgChannelOpenInit)(nil) _ sdk.HasValidateBasic = (*MsgChannelOpenTry)(nil) @@ -35,6 +43,13 @@ var ( _ sdk.HasValidateBasic = (*MsgAcknowledgement)(nil) _ sdk.HasValidateBasic = (*MsgTimeout)(nil) _ sdk.HasValidateBasic = (*MsgTimeoutOnClose)(nil) + _ sdk.HasValidateBasic = (*MsgChannelUpgradeInit)(nil) + _ sdk.HasValidateBasic = (*MsgChannelUpgradeTry)(nil) + _ sdk.HasValidateBasic = (*MsgChannelUpgradeAck)(nil) + _ sdk.HasValidateBasic = (*MsgChannelUpgradeConfirm)(nil) + _ sdk.HasValidateBasic = (*MsgChannelUpgradeTimeout)(nil) + _ sdk.HasValidateBasic = (*MsgChannelUpgradeCancel)(nil) + _ sdk.HasValidateBasic = (*MsgPruneAcknowledgements)(nil) ) // NewMsgChannelOpenInit creates a new MsgChannelOpenInit. It sets the counterparty channel @@ -88,7 +103,7 @@ func (msg MsgChannelOpenInit) GetSigners() []sdk.AccAddress { func NewMsgChannelOpenTry( portID, version string, channelOrder Order, connectionHops []string, counterpartyPortID, counterpartyChannelID, counterpartyVersion string, - proofInit []byte, proofHeight clienttypes.Height, signer string, + initProof []byte, proofHeight clienttypes.Height, signer string, ) *MsgChannelOpenTry { counterparty := NewCounterparty(counterpartyPortID, counterpartyChannelID) channel := NewChannel(TRYOPEN, channelOrder, counterparty, connectionHops, version) @@ -96,7 +111,7 @@ func NewMsgChannelOpenTry( PortId: portID, Channel: channel, CounterpartyVersion: counterpartyVersion, - ProofInit: proofInit, + ProofInit: initProof, ProofHeight: proofHeight, Signer: signer, } @@ -142,7 +157,7 @@ func (msg MsgChannelOpenTry) GetSigners() []sdk.AccAddress { // NewMsgChannelOpenAck creates a new MsgChannelOpenAck instance func NewMsgChannelOpenAck( - portID, channelID, counterpartyChannelID string, cpv string, proofTry []byte, proofHeight clienttypes.Height, + portID, channelID, counterpartyChannelID string, cpv string, tryProof []byte, proofHeight clienttypes.Height, signer string, ) *MsgChannelOpenAck { return &MsgChannelOpenAck{ @@ -150,7 +165,7 @@ func NewMsgChannelOpenAck( ChannelId: channelID, CounterpartyChannelId: counterpartyChannelID, CounterpartyVersion: cpv, - ProofTry: proofTry, + ProofTry: tryProof, ProofHeight: proofHeight, Signer: signer, } @@ -188,13 +203,13 @@ func (msg MsgChannelOpenAck) GetSigners() []sdk.AccAddress { // NewMsgChannelOpenConfirm creates a new MsgChannelOpenConfirm instance func NewMsgChannelOpenConfirm( - portID, channelID string, proofAck []byte, proofHeight clienttypes.Height, + portID, channelID string, ackProof []byte, proofHeight clienttypes.Height, signer string, ) *MsgChannelOpenConfirm { return &MsgChannelOpenConfirm{ PortId: portID, ChannelId: channelID, - ProofAck: proofAck, + ProofAck: ackProof, ProofHeight: proofHeight, Signer: signer, } @@ -263,16 +278,36 @@ func (msg MsgChannelCloseInit) GetSigners() []sdk.AccAddress { } // NewMsgChannelCloseConfirm creates a new MsgChannelCloseConfirm instance +// Breakage in v9.0.0 will allow for the counterparty upgrade sequence to be provided. +// Please use NewMsgChannelCloseConfirmWithCounterpartyUpgradeSequence to provide the +// counterparty upgrade sequence in this version. func NewMsgChannelCloseConfirm( - portID, channelID string, proofInit []byte, proofHeight clienttypes.Height, + portID, channelID string, initProof []byte, proofHeight clienttypes.Height, signer string, ) *MsgChannelCloseConfirm { return &MsgChannelCloseConfirm{ - PortId: portID, - ChannelId: channelID, - ProofInit: proofInit, - ProofHeight: proofHeight, - Signer: signer, + PortId: portID, + ChannelId: channelID, + ProofInit: initProof, + ProofHeight: proofHeight, + Signer: signer, + CounterpartyUpgradeSequence: 0, + } +} + +// NewMsgChannelCloseConfirmWithCounterpartyUpgradeSequence creates a new MsgChannelCloseConfirm instance +// with a non-zero counterparty upgrade sequence. +func NewMsgChannelCloseConfirmWithCounterpartyUpgradeSequence( + portID, channelID string, initProof []byte, proofHeight clienttypes.Height, + signer string, counterpartyUpgradeSequence uint64, +) *MsgChannelCloseConfirm { + return &MsgChannelCloseConfirm{ + PortId: portID, + ChannelId: channelID, + ProofInit: initProof, + ProofHeight: proofHeight, + Signer: signer, + CounterpartyUpgradeSequence: counterpartyUpgradeSequence, } } @@ -305,12 +340,12 @@ func (msg MsgChannelCloseConfirm) GetSigners() []sdk.AccAddress { // NewMsgRecvPacket constructs new MsgRecvPacket func NewMsgRecvPacket( - packet Packet, proofCommitment []byte, proofHeight clienttypes.Height, + packet Packet, commitmentProof []byte, proofHeight clienttypes.Height, signer string, ) *MsgRecvPacket { return &MsgRecvPacket{ Packet: packet, - ProofCommitment: proofCommitment, + ProofCommitment: commitmentProof, ProofHeight: proofHeight, Signer: signer, } @@ -346,13 +381,13 @@ func (msg MsgRecvPacket) GetSigners() []sdk.AccAddress { // NewMsgTimeout constructs new MsgTimeout func NewMsgTimeout( - packet Packet, nextSequenceRecv uint64, proofUnreceived []byte, + packet Packet, nextSequenceRecv uint64, unreceivedProof []byte, proofHeight clienttypes.Height, signer string, ) *MsgTimeout { return &MsgTimeout{ Packet: packet, NextSequenceRecv: nextSequenceRecv, - ProofUnreceived: proofUnreceived, + ProofUnreceived: unreceivedProof, ProofHeight: proofHeight, Signer: signer, } @@ -382,19 +417,43 @@ func (msg MsgTimeout) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{signer} } -// NewMsgTimeoutOnClose constructs new MsgTimeoutOnClose +// NewMsgTimeoutOnClose constructs a new MsgTimeoutOnClose. +// The counterparty upgrade sequence is set to 0. Breakage in +// v9.0.0 will allow the counterparty upgrade sequence to be provided. +// Please use NewMsgTimeoutOnCloseWithCounterpartyUpgradeSequence in this version +// to provide the counterparty upgrade sequence. func NewMsgTimeoutOnClose( packet Packet, nextSequenceRecv uint64, - proofUnreceived, proofClose []byte, + unreceivedProof, closeProof []byte, proofHeight clienttypes.Height, signer string, ) *MsgTimeoutOnClose { return &MsgTimeoutOnClose{ - Packet: packet, - NextSequenceRecv: nextSequenceRecv, - ProofUnreceived: proofUnreceived, - ProofClose: proofClose, - ProofHeight: proofHeight, - Signer: signer, + Packet: packet, + NextSequenceRecv: nextSequenceRecv, + ProofUnreceived: unreceivedProof, + ProofClose: closeProof, + ProofHeight: proofHeight, + Signer: signer, + CounterpartyUpgradeSequence: 0, + } +} + +// NewMsgTimeoutOnCloseWithCounterpartyUpgradeSequence constructs a new MsgTimeoutOnClose +// with the provided counterparty upgrade sequence. +func NewMsgTimeoutOnCloseWithCounterpartyUpgradeSequence( + packet Packet, nextSequenceRecv uint64, + unreceivedProof, closeProof []byte, + proofHeight clienttypes.Height, signer string, + counterpartyUpgradeSequence uint64, +) *MsgTimeoutOnClose { + return &MsgTimeoutOnClose{ + Packet: packet, + NextSequenceRecv: nextSequenceRecv, + ProofUnreceived: unreceivedProof, + ProofClose: closeProof, + ProofHeight: proofHeight, + Signer: signer, + CounterpartyUpgradeSequence: counterpartyUpgradeSequence, } } @@ -428,14 +487,14 @@ func (msg MsgTimeoutOnClose) GetSigners() []sdk.AccAddress { // NewMsgAcknowledgement constructs a new MsgAcknowledgement func NewMsgAcknowledgement( packet Packet, - ack, proofAcked []byte, + ack, ackedProof []byte, proofHeight clienttypes.Height, signer string, ) *MsgAcknowledgement { return &MsgAcknowledgement{ Packet: packet, Acknowledgement: ack, - ProofAcked: proofAcked, + ProofAcked: ackedProof, ProofHeight: proofHeight, Signer: signer, } @@ -464,3 +523,385 @@ func (msg MsgAcknowledgement) GetSigners() []sdk.AccAddress { } return []sdk.AccAddress{signer} } + +var _ sdk.Msg = &MsgChannelUpgradeInit{} + +// NewMsgChannelUpgradeInit constructs a new MsgChannelUpgradeInit +// nolint:interfacer +func NewMsgChannelUpgradeInit( + portID, channelID string, + upgradeFields UpgradeFields, + signer string, +) *MsgChannelUpgradeInit { + return &MsgChannelUpgradeInit{ + PortId: portID, + ChannelId: channelID, + Fields: upgradeFields, + Signer: signer, + } +} + +// ValidateBasic implements sdk.Msg +func (msg MsgChannelUpgradeInit) ValidateBasic() error { + if err := host.PortIdentifierValidator(msg.PortId); err != nil { + return errorsmod.Wrap(err, "invalid port ID") + } + if !IsValidChannelID(msg.ChannelId) { + return ErrInvalidChannelIdentifier + } + + _, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err) + } + + return msg.Fields.ValidateBasic() +} + +var _ sdk.Msg = &MsgChannelUpgradeTry{} + +// NewMsgChannelUpgradeTry constructs a new MsgChannelUpgradeTry +// nolint:interfacer +func NewMsgChannelUpgradeTry( + portID, + channelID string, + proposedConnectionHops []string, + counterpartyUpgradeFields UpgradeFields, + counterpartyUpgradeSequence uint64, + channelProof []byte, + upgradeProof []byte, + proofHeight clienttypes.Height, + signer string, +) *MsgChannelUpgradeTry { + return &MsgChannelUpgradeTry{ + PortId: portID, + ChannelId: channelID, + ProposedUpgradeConnectionHops: proposedConnectionHops, + CounterpartyUpgradeFields: counterpartyUpgradeFields, + CounterpartyUpgradeSequence: counterpartyUpgradeSequence, + ProofChannel: channelProof, + ProofUpgrade: upgradeProof, + ProofHeight: proofHeight, + Signer: signer, + } +} + +// ValidateBasic implements sdk.Msg +func (msg MsgChannelUpgradeTry) ValidateBasic() error { + if err := host.PortIdentifierValidator(msg.PortId); err != nil { + return errorsmod.Wrap(err, "invalid port ID") + } + + if !IsValidChannelID(msg.ChannelId) { + return ErrInvalidChannelIdentifier + } + + if len(msg.ProposedUpgradeConnectionHops) == 0 { + return errorsmod.Wrap(ErrInvalidUpgrade, "proposed connection hops cannot be empty") + } + + if err := msg.CounterpartyUpgradeFields.ValidateBasic(); err != nil { + return errorsmod.Wrap(err, "error validating counterparty upgrade fields") + } + + if msg.CounterpartyUpgradeSequence == 0 { + return errorsmod.Wrap(ErrInvalidUpgradeSequence, "counterparty sequence cannot be 0") + } + + if len(msg.ProofChannel) == 0 { + return errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty channel proof") + } + + if len(msg.ProofUpgrade) == 0 { + return errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty upgrade proof") + } + + _, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err) + } + + return nil +} + +var _ sdk.Msg = &MsgChannelUpgradeAck{} + +// NewMsgChannelUpgradeAck constructs a new MsgChannelUpgradeAck +// nolint:interfacer +func NewMsgChannelUpgradeAck(portID, channelID string, counterpartyUpgrade Upgrade, channelProof, upgradeProof []byte, proofHeight clienttypes.Height, signer string) *MsgChannelUpgradeAck { + return &MsgChannelUpgradeAck{ + PortId: portID, + ChannelId: channelID, + CounterpartyUpgrade: counterpartyUpgrade, + ProofChannel: channelProof, + ProofUpgrade: upgradeProof, + ProofHeight: proofHeight, + Signer: signer, + } +} + +// ValidateBasic implements sdk.Msg +func (msg MsgChannelUpgradeAck) ValidateBasic() error { + if err := host.PortIdentifierValidator(msg.PortId); err != nil { + return errorsmod.Wrap(err, "invalid port ID") + } + if !IsValidChannelID(msg.ChannelId) { + return ErrInvalidChannelIdentifier + } + if len(msg.ProofChannel) == 0 { + return errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty channel proof") + } + if len(msg.ProofUpgrade) == 0 { + return errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty upgrade sequence proof") + } + if _, err := sdk.AccAddressFromBech32(msg.Signer); err != nil { + return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err) + } + + return msg.CounterpartyUpgrade.ValidateBasic() +} + +var _ sdk.Msg = &MsgChannelUpgradeConfirm{} + +// NewMsgChannelUpgradeConfirm constructs a new MsgChannelUpgradeConfirm +func NewMsgChannelUpgradeConfirm( + portID, + channelID string, + counterpartyChannelState State, + counterpartyUpgrade Upgrade, + channelProof, + upgradeProof []byte, + proofHeight clienttypes.Height, + signer string, +) *MsgChannelUpgradeConfirm { + return &MsgChannelUpgradeConfirm{ + PortId: portID, + ChannelId: channelID, + CounterpartyChannelState: counterpartyChannelState, + CounterpartyUpgrade: counterpartyUpgrade, + ProofChannel: channelProof, + ProofUpgrade: upgradeProof, + ProofHeight: proofHeight, + Signer: signer, + } +} + +// ValidateBasic implements sdk.Msg +func (msg MsgChannelUpgradeConfirm) ValidateBasic() error { + if err := host.PortIdentifierValidator(msg.PortId); err != nil { + return errorsmod.Wrap(err, "invalid port ID") + } + + if !IsValidChannelID(msg.ChannelId) { + return ErrInvalidChannelIdentifier + } + + if !slices.Contains([]State{FLUSHING, FLUSHCOMPLETE}, msg.CounterpartyChannelState) { + return errorsmod.Wrapf(ErrInvalidChannelState, "expected channel state to be one of: %s or %s, got: %s", FLUSHING, FLUSHCOMPLETE, msg.CounterpartyChannelState) + } + + if len(msg.ProofChannel) == 0 { + return errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty channel proof") + } + + if len(msg.ProofUpgrade) == 0 { + return errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty upgrade proof") + } + + _, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err) + } + + return msg.CounterpartyUpgrade.ValidateBasic() +} + +var _ sdk.Msg = &MsgChannelUpgradeOpen{} + +// NewMsgChannelUpgradeOpen constructs a new MsgChannelUpgradeOpen +// nolint:interfacer +func NewMsgChannelUpgradeOpen( + portID, + channelID string, + counterpartyChannelState State, + counterpartyUpgradeSequence uint64, + channelProof []byte, + proofHeight clienttypes.Height, + signer string, +) *MsgChannelUpgradeOpen { + return &MsgChannelUpgradeOpen{ + PortId: portID, + ChannelId: channelID, + CounterpartyChannelState: counterpartyChannelState, + CounterpartyUpgradeSequence: counterpartyUpgradeSequence, + ProofChannel: channelProof, + ProofHeight: proofHeight, + Signer: signer, + } +} + +// ValidateBasic implements sdk.Msg +func (msg MsgChannelUpgradeOpen) ValidateBasic() error { + if err := host.PortIdentifierValidator(msg.PortId); err != nil { + return errorsmod.Wrap(err, "invalid port ID") + } + + if !IsValidChannelID(msg.ChannelId) { + return ErrInvalidChannelIdentifier + } + + if len(msg.ProofChannel) == 0 { + return errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty channel proof") + } + + if !slices.Contains([]State{FLUSHCOMPLETE, OPEN}, msg.CounterpartyChannelState) { + return errorsmod.Wrapf(ErrInvalidChannelState, "expected channel state to be one of: [%s, %s], got: %s", FLUSHCOMPLETE, OPEN, msg.CounterpartyChannelState) + } + + if msg.CounterpartyUpgradeSequence == 0 { + return errorsmod.Wrap(ErrInvalidUpgradeSequence, "counterparty upgrade sequence must be non-zero") + } + + _, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err) + } + + return nil +} + +var _ sdk.Msg = &MsgChannelUpgradeTimeout{} + +// NewMsgChannelUpgradeTimeout constructs a new MsgChannelUpgradeTimeout +// nolint:interfacer +func NewMsgChannelUpgradeTimeout( + portID, channelID string, + counterpartyChannel Channel, + channelProof []byte, + proofHeight clienttypes.Height, + signer string, +) *MsgChannelUpgradeTimeout { + return &MsgChannelUpgradeTimeout{ + PortId: portID, + ChannelId: channelID, + CounterpartyChannel: counterpartyChannel, + ProofChannel: channelProof, + ProofHeight: proofHeight, + Signer: signer, + } +} + +// ValidateBasic implements sdk.Msg +func (msg MsgChannelUpgradeTimeout) ValidateBasic() error { + if err := host.PortIdentifierValidator(msg.PortId); err != nil { + return errorsmod.Wrap(err, "invalid port ID") + } + + if !IsValidChannelID(msg.ChannelId) { + return ErrInvalidChannelIdentifier + } + + if len(msg.ProofChannel) == 0 { + return errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof") + } + + if !slices.Contains([]State{FLUSHING, OPEN}, msg.CounterpartyChannel.State) { + return errorsmod.Wrapf(ErrInvalidChannelState, "expected counterparty channel state to be one of: [%s, %s], got: %s", FLUSHING, OPEN, msg.CounterpartyChannel.State) + } + + _, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err) + } + + return nil +} + +var _ sdk.Msg = &MsgChannelUpgradeCancel{} + +// NewMsgChannelUpgradeCancel constructs a new MsgChannelUpgradeCancel +// nolint:interfacer +func NewMsgChannelUpgradeCancel( + portID, channelID string, + errorReceipt ErrorReceipt, + errorReceiptProof []byte, + proofHeight clienttypes.Height, + signer string, +) *MsgChannelUpgradeCancel { + return &MsgChannelUpgradeCancel{ + PortId: portID, + ChannelId: channelID, + ErrorReceipt: errorReceipt, + ProofErrorReceipt: errorReceiptProof, + ProofHeight: proofHeight, + Signer: signer, + } +} + +// ValidateBasic implements sdk.Msg. No checks are done for ErrorReceipt and ProofErrorReceipt +// since they are not required if the current channel state is not in FLUSHCOMPLETE and the signer +// is the designated authority (e.g. the governance module). +func (msg MsgChannelUpgradeCancel) ValidateBasic() error { + if err := host.PortIdentifierValidator(msg.PortId); err != nil { + return errorsmod.Wrap(err, "invalid port ID") + } + + if !IsValidChannelID(msg.ChannelId) { + return ErrInvalidChannelIdentifier + } + + _, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err) + } + + return nil +} + +// NewMsgUpdateChannelParams creates a new instance of MsgUpdateParams. +func NewMsgUpdateChannelParams(authority string, params Params) *MsgUpdateParams { + return &MsgUpdateParams{ + Authority: authority, + Params: params, + } +} + +// ValidateBasic performs basic checks on a MsgUpdateParams. +func (msg *MsgUpdateParams) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { + return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err) + } + return msg.Params.Validate() +} + +// NewMsgPruneAcknowledgements creates a new instance of MsgPruneAcknowledgements. +func NewMsgPruneAcknowledgements(portID, channelID string, limit uint64, signer string) *MsgPruneAcknowledgements { + return &MsgPruneAcknowledgements{ + PortId: portID, + ChannelId: channelID, + Limit: limit, + Signer: signer, + } +} + +// ValidateBasic performs basic checks on a MsgPruneAcknowledgements. +func (msg *MsgPruneAcknowledgements) ValidateBasic() error { + if err := host.PortIdentifierValidator(msg.PortId); err != nil { + return errorsmod.Wrap(err, "invalid port ID") + } + + if !IsValidChannelID(msg.ChannelId) { + return ErrInvalidChannelIdentifier + } + + _, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err) + } + + if msg.Limit == 0 { + return errorsmod.Wrap(ErrInvalidPruningLimit, "number of acknowledgements to prune must be greater than 0") + } + + return nil +} diff --git a/modules/core/04-channel/types/msgs_test.go b/modules/core/04-channel/types/msgs_test.go index 8570ad59065..40cf204b7e3 100644 --- a/modules/core/04-channel/types/msgs_test.go +++ b/modules/core/04-channel/types/msgs_test.go @@ -1,12 +1,14 @@ package types_test import ( + "errors" "fmt" "testing" dbm "github.com/cosmos/cosmos-db" testifysuite "github.com/stretchr/testify/suite" + errorsmod "cosmossdk.io/errors" log "cosmossdk.io/log" "cosmossdk.io/store/iavl" "cosmossdk.io/store/metrics" @@ -14,19 +16,28 @@ import ( storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + ibc "github.com/cosmos/ibc-go/v8/modules/core" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" + ibctesting "github.com/cosmos/ibc-go/v8/testing" + "github.com/cosmos/ibc-go/v8/testing/mock" "github.com/cosmos/ibc-go/v8/testing/simapp" ) const ( - // valid constatns used for testing - portid = "testportid" - chanid = "channel-0" - cpportid = "testcpport" - cpchanid = "testcpchannel" + // valid constants used for testing + portid = "testportid" + chanid = "channel-0" + cpportid = "testcpport" + cpchanid = "testcpchannel" + counterpartyUpgradeSequence = 0 version = "1.0" @@ -112,22 +123,122 @@ func (suite *TypesTestSuite) TestMsgChannelOpenInitValidateBasic() { tryOpenChannel := types.NewChannel(types.TRYOPEN, types.ORDERED, counterparty, connHops, version) testCases := []struct { - name string - msg *types.MsgChannelOpenInit - expPass bool + name string + msg *types.MsgChannelOpenInit + expErr error }{ - {"", types.NewMsgChannelOpenInit(portid, version, types.ORDERED, connHops, cpportid, addr), true}, - {"too short port id", types.NewMsgChannelOpenInit(invalidShortPort, version, types.ORDERED, connHops, cpportid, addr), false}, - {"too long port id", types.NewMsgChannelOpenInit(invalidLongPort, version, types.ORDERED, connHops, cpportid, addr), false}, - {"port id contains non-alpha", types.NewMsgChannelOpenInit(invalidPort, version, types.ORDERED, connHops, cpportid, addr), false}, - {"invalid channel order", types.NewMsgChannelOpenInit(portid, version, types.Order(3), connHops, cpportid, addr), false}, - {"connection hops more than 1 ", types.NewMsgChannelOpenInit(portid, version, types.ORDERED, invalidConnHops, cpportid, addr), false}, - {"too short connection id", types.NewMsgChannelOpenInit(portid, version, types.UNORDERED, invalidShortConnHops, cpportid, addr), false}, - {"too long connection id", types.NewMsgChannelOpenInit(portid, version, types.UNORDERED, invalidLongConnHops, cpportid, addr), false}, - {"connection id contains non-alpha", types.NewMsgChannelOpenInit(portid, version, types.UNORDERED, []string{invalidConnection}, cpportid, addr), false}, - {"", types.NewMsgChannelOpenInit(portid, "", types.UNORDERED, connHops, cpportid, addr), true}, - {"invalid counterparty port id", types.NewMsgChannelOpenInit(portid, version, types.UNORDERED, connHops, invalidPort, addr), false}, - {"channel not in INIT state", &types.MsgChannelOpenInit{portid, tryOpenChannel, addr}, false}, + { + "success", + types.NewMsgChannelOpenInit(portid, version, types.ORDERED, connHops, cpportid, addr), + nil, + }, + { + "success: empty version", + types.NewMsgChannelOpenInit(portid, "", types.UNORDERED, connHops, cpportid, addr), + nil, + }, + { + "too short port id", + types.NewMsgChannelOpenInit(invalidShortPort, version, types.ORDERED, connHops, cpportid, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s has invalid length: %d, must be between %d-%d characters", + invalidShortPort, + len(invalidShortPort), + 2, + host.DefaultMaxPortCharacterLength, + ), "invalid port ID"), + }, + { + "too long port id", + types.NewMsgChannelOpenInit(invalidLongPort, version, types.ORDERED, connHops, cpportid, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s has invalid length: %d, must be between %d-%d characters", + invalidLongPort, + len(invalidLongPort), + 2, + host.DefaultMaxPortCharacterLength, + ), "invalid port ID"), + }, + { + "port id contains non-alpha", + types.NewMsgChannelOpenInit(invalidPort, version, types.ORDERED, connHops, cpportid, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'", + invalidPort, + ), "invalid port ID"), + }, + { + "invalid channel order", + types.NewMsgChannelOpenInit(portid, version, types.Order(3), + connHops, cpportid, addr), + errorsmod.Wrap(types.ErrInvalidChannelOrdering, types.Order(3).String()), + }, + { + "connection hops more than 1 ", + types.NewMsgChannelOpenInit(portid, version, types.ORDERED, invalidConnHops, cpportid, addr), + errorsmod.Wrap( + types.ErrTooManyConnectionHops, + "current IBC version only supports one connection hop", + ), + }, + { + "too short connection id", + types.NewMsgChannelOpenInit(portid, version, types.UNORDERED, invalidShortConnHops, cpportid, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s has invalid length: %d, must be between %d-%d characters", + invalidShortConnection, len(invalidShortConnection), 10, host.DefaultMaxCharacterLength), + "invalid connection hop ID", + ), + }, + { + "too long connection id", + types.NewMsgChannelOpenInit(portid, version, types.UNORDERED, invalidLongConnHops, cpportid, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s has invalid length: %d, must be between %d-%d characters", + invalidLongConnection, len(invalidLongConnection), 10, host.DefaultMaxCharacterLength), + "invalid connection hop ID", + ), + }, + { + "connection id contains non-alpha", + types.NewMsgChannelOpenInit(portid, version, types.UNORDERED, []string{invalidConnection}, cpportid, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'", + invalidConnection, + ), "invalid connection hop ID", + ), + }, + { + "invalid counterparty port id", + types.NewMsgChannelOpenInit(portid, version, types.UNORDERED, connHops, invalidPort, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'", + invalidPort, + ), "invalid counterparty port ID", + ), + }, + { + "channel not in INIT state", + &types.MsgChannelOpenInit{portid, tryOpenChannel, addr}, + errorsmod.Wrapf(types.ErrInvalidChannelState, + "channel state must be INIT in MsgChannelOpenInit. expected: %s, got: %s", + types.INIT, tryOpenChannel.State, + ), + }, } for _, tc := range testCases { @@ -135,40 +246,171 @@ func (suite *TypesTestSuite) TestMsgChannelOpenInitValidateBasic() { suite.Run(tc.name, func() { err := tc.msg.ValidateBasic() - if tc.expPass { + + expPass := tc.expErr == nil + if expPass { suite.Require().NoError(err) } else { suite.Require().Error(err) + suite.Require().Equal(err.Error(), tc.expErr.Error()) } }) } } +func (suite *TypesTestSuite) TestMsgChannelOpenInitGetSigners() { + expSigner, err := sdk.AccAddressFromBech32(addr) + suite.Require().NoError(err) + msg := types.NewMsgChannelOpenInit(portid, version, types.ORDERED, connHops, cpportid, addr) + + encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) + + suite.Require().NoError(err) + suite.Require().Equal(expSigner.Bytes(), signers[0]) +} + func (suite *TypesTestSuite) TestMsgChannelOpenTryValidateBasic() { counterparty := types.NewCounterparty(cpportid, cpchanid) initChannel := types.NewChannel(types.INIT, types.ORDERED, counterparty, connHops, version) testCases := []struct { - name string - msg *types.MsgChannelOpenTry - expPass bool + name string + msg *types.MsgChannelOpenTry + expErr error }{ - {"", types.NewMsgChannelOpenTry(portid, version, types.ORDERED, connHops, cpportid, cpchanid, version, suite.proof, height, addr), true}, - {"too short port id", types.NewMsgChannelOpenTry(invalidShortPort, version, types.ORDERED, connHops, cpportid, cpchanid, version, suite.proof, height, addr), false}, - {"too long port id", types.NewMsgChannelOpenTry(invalidLongPort, version, types.ORDERED, connHops, cpportid, cpchanid, version, suite.proof, height, addr), false}, - {"port id contains non-alpha", types.NewMsgChannelOpenTry(invalidPort, version, types.ORDERED, connHops, cpportid, cpchanid, version, suite.proof, height, addr), false}, - {"", types.NewMsgChannelOpenTry(portid, version, types.ORDERED, connHops, cpportid, cpchanid, "", suite.proof, height, addr), true}, - {"invalid channel order", types.NewMsgChannelOpenTry(portid, version, types.Order(4), connHops, cpportid, cpchanid, version, suite.proof, height, addr), false}, - {"connection hops more than 1 ", types.NewMsgChannelOpenTry(portid, version, types.UNORDERED, invalidConnHops, cpportid, cpchanid, version, suite.proof, height, addr), false}, - {"too short connection id", types.NewMsgChannelOpenTry(portid, version, types.UNORDERED, invalidShortConnHops, cpportid, cpchanid, version, suite.proof, height, addr), false}, - {"too long connection id", types.NewMsgChannelOpenTry(portid, version, types.UNORDERED, invalidLongConnHops, cpportid, cpchanid, version, suite.proof, height, addr), false}, - {"connection id contains non-alpha", types.NewMsgChannelOpenTry(portid, version, types.UNORDERED, []string{invalidConnection}, cpportid, cpchanid, version, suite.proof, height, addr), false}, - {"", types.NewMsgChannelOpenTry(portid, "", types.UNORDERED, connHops, cpportid, cpchanid, version, suite.proof, height, addr), true}, - {"invalid counterparty port id", types.NewMsgChannelOpenTry(portid, version, types.UNORDERED, connHops, invalidPort, cpchanid, version, suite.proof, height, addr), false}, - {"invalid counterparty channel id", types.NewMsgChannelOpenTry(portid, version, types.UNORDERED, connHops, cpportid, invalidChannel, version, suite.proof, height, addr), false}, - {"empty proof", types.NewMsgChannelOpenTry(portid, version, types.UNORDERED, connHops, cpportid, cpchanid, version, emptyProof, height, addr), false}, - {"channel not in TRYOPEN state", &types.MsgChannelOpenTry{portid, "", initChannel, version, suite.proof, height, addr}, false}, - {"previous channel id is not empty", &types.MsgChannelOpenTry{portid, chanid, initChannel, version, suite.proof, height, addr}, false}, + { + "success", + types.NewMsgChannelOpenTry(portid, version, types.ORDERED, connHops, cpportid, cpchanid, version, suite.proof, height, addr), + nil, + }, + { + "success with empty channel version", + types.NewMsgChannelOpenTry(portid, "", types.UNORDERED, connHops, cpportid, cpchanid, version, suite.proof, height, addr), + nil, + }, + { + "success with empty counterparty version", + types.NewMsgChannelOpenTry(portid, version, types.ORDERED, connHops, cpportid, cpchanid, "", suite.proof, height, addr), + nil, + }, + { + "too short port id", + types.NewMsgChannelOpenTry(invalidShortPort, version, types.ORDERED, connHops, cpportid, cpchanid, version, suite.proof, height, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s has invalid length: %d, must be between %d-%d characters", + invalidShortPort, len(invalidShortPort), 2, host.DefaultMaxPortCharacterLength), + "invalid port ID", + ), + }, + { + "too long port id", + types.NewMsgChannelOpenTry(invalidLongPort, version, types.ORDERED, connHops, cpportid, cpchanid, version, suite.proof, height, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s has invalid length: %d, must be between %d-%d characters", + invalidLongPort, len(invalidLongPort), 2, host.DefaultMaxPortCharacterLength), + "invalid port ID", + ), + }, + { + "port id contains non-alpha", + types.NewMsgChannelOpenTry(invalidPort, version, types.ORDERED, connHops, cpportid, cpchanid, version, suite.proof, height, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'", + invalidPort, + ), "invalid port ID", + ), + }, + { + "invalid channel order", + types.NewMsgChannelOpenTry(portid, version, types.Order(4), connHops, cpportid, cpchanid, version, suite.proof, height, addr), + errorsmod.Wrap(types.ErrInvalidChannelOrdering, types.Order(4).String()), + }, + { + "connection hops more than 1 ", + types.NewMsgChannelOpenTry(portid, version, types.UNORDERED, invalidConnHops, cpportid, cpchanid, version, suite.proof, height, addr), + errorsmod.Wrap( + types.ErrTooManyConnectionHops, + "current IBC version only supports one connection hop", + ), + }, + { + "too short connection id", + types.NewMsgChannelOpenTry(portid, version, types.UNORDERED, invalidShortConnHops, cpportid, cpchanid, version, suite.proof, height, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s has invalid length: %d, must be between %d-%d characters", invalidShortConnection, len(invalidShortConnection), 10, host.DefaultMaxCharacterLength), + "invalid connection hop ID", + ), + }, + { + "too long connection id", + types.NewMsgChannelOpenTry(portid, version, types.UNORDERED, invalidLongConnHops, cpportid, cpchanid, version, suite.proof, height, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s has invalid length: %d, must be between %d-%d characters", invalidLongConnection, len(invalidLongConnection), 10, host.DefaultMaxCharacterLength), + "invalid connection hop ID", + ), + }, + { + "connection id contains non-alpha", + types.NewMsgChannelOpenTry(portid, version, types.UNORDERED, []string{invalidConnection}, cpportid, cpchanid, version, suite.proof, height, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'", + invalidConnection, + ), "invalid connection hop ID", + ), + }, + { + "invalid counterparty port id", + types.NewMsgChannelOpenTry(portid, version, types.UNORDERED, connHops, invalidPort, cpchanid, version, suite.proof, height, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'", + invalidPort, + ), "invalid counterparty port ID", + ), + }, + { + "invalid counterparty channel id", + types.NewMsgChannelOpenTry(portid, version, types.UNORDERED, connHops, cpportid, invalidChannel, version, suite.proof, height, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'", + invalidChannel, + ), "invalid counterparty channel ID", + ), + }, + { + "empty proof", + types.NewMsgChannelOpenTry(portid, version, types.UNORDERED, connHops, cpportid, cpchanid, version, emptyProof, height, addr), + errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty init proof"), + }, + { + "channel not in TRYOPEN state", + &types.MsgChannelOpenTry{portid, "", initChannel, version, suite.proof, height, addr}, + errorsmod.Wrapf(types.ErrInvalidChannelState, + "channel state must be TRYOPEN in MsgChannelOpenTry. expected: %s, got: %s", + types.TRYOPEN, initChannel.State, + ), + }, + { + "previous channel id is not empty", + &types.MsgChannelOpenTry{portid, chanid, initChannel, version, suite.proof, height, addr}, + errorsmod.Wrap(types.ErrInvalidChannelIdentifier, "previous channel identifier must be empty, this field has been deprecated as crossing hellos are no longer supported"), + }, } for _, tc := range testCases { @@ -177,31 +419,109 @@ func (suite *TypesTestSuite) TestMsgChannelOpenTryValidateBasic() { suite.Run(tc.name, func() { err := tc.msg.ValidateBasic() - if tc.expPass { + expPass := tc.expErr == nil + if expPass { suite.Require().NoError(err) } else { suite.Require().Error(err) + suite.Require().Equal(err.Error(), tc.expErr.Error()) } }) } } +func (suite *TypesTestSuite) TestMsgChannelOpenTryGetSigners() { + expSigner, err := sdk.AccAddressFromBech32(addr) + suite.Require().NoError(err) + msg := types.NewMsgChannelOpenTry(portid, version, types.ORDERED, connHops, cpportid, cpchanid, version, suite.proof, height, addr) + + encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) + + suite.Require().NoError(err) + suite.Require().Equal(expSigner.Bytes(), signers[0]) +} + func (suite *TypesTestSuite) TestMsgChannelOpenAckValidateBasic() { testCases := []struct { - name string - msg *types.MsgChannelOpenAck - expPass bool + name string + msg *types.MsgChannelOpenAck + expErr error }{ - {"", types.NewMsgChannelOpenAck(portid, chanid, chanid, version, suite.proof, height, addr), true}, - {"too short port id", types.NewMsgChannelOpenAck(invalidShortPort, chanid, chanid, version, suite.proof, height, addr), false}, - {"too long port id", types.NewMsgChannelOpenAck(invalidLongPort, chanid, chanid, version, suite.proof, height, addr), false}, - {"port id contains non-alpha", types.NewMsgChannelOpenAck(invalidPort, chanid, chanid, version, suite.proof, height, addr), false}, - {"too short channel id", types.NewMsgChannelOpenAck(portid, invalidShortChannel, chanid, version, suite.proof, height, addr), false}, - {"too long channel id", types.NewMsgChannelOpenAck(portid, invalidLongChannel, chanid, version, suite.proof, height, addr), false}, - {"channel id contains non-alpha", types.NewMsgChannelOpenAck(portid, invalidChannel, chanid, version, suite.proof, height, addr), false}, - {"", types.NewMsgChannelOpenAck(portid, chanid, chanid, "", suite.proof, height, addr), true}, - {"empty proof", types.NewMsgChannelOpenAck(portid, chanid, chanid, version, emptyProof, height, addr), false}, - {"invalid counterparty channel id", types.NewMsgChannelOpenAck(portid, chanid, invalidShortChannel, version, suite.proof, height, addr), false}, + { + "success", + types.NewMsgChannelOpenAck(portid, chanid, chanid, version, suite.proof, height, addr), + nil, + }, + { + "success empty cpv", + types.NewMsgChannelOpenAck(portid, chanid, chanid, "", suite.proof, height, addr), + nil, + }, + { + "too short port id", + types.NewMsgChannelOpenAck(invalidShortPort, chanid, chanid, version, suite.proof, height, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s has invalid length: %d, must be between %d-%d characters", + invalidShortPort, len(invalidShortPort), 2, host.DefaultMaxPortCharacterLength), + "invalid port ID", + ), + }, + { + "too long port id", + types.NewMsgChannelOpenAck(invalidLongPort, chanid, chanid, version, suite.proof, height, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s has invalid length: %d, must be between %d-%d characters", + invalidLongPort, len(invalidLongPort), 2, host.DefaultMaxPortCharacterLength), + "invalid port ID", + ), + }, + { + "port id contains non-alpha", + types.NewMsgChannelOpenAck(invalidPort, chanid, chanid, version, suite.proof, height, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'", + invalidPort, + ), "invalid port ID", + ), + }, + { + "too short channel id", + types.NewMsgChannelOpenAck(portid, invalidShortChannel, chanid, version, suite.proof, height, addr), + types.ErrInvalidChannelIdentifier, + }, + { + "too long channel id", + types.NewMsgChannelOpenAck(portid, invalidLongChannel, chanid, version, suite.proof, height, addr), + types.ErrInvalidChannelIdentifier, + }, + { + "channel id contains non-alpha", + types.NewMsgChannelOpenAck(portid, invalidChannel, chanid, version, suite.proof, height, addr), + types.ErrInvalidChannelIdentifier, + }, + { + "empty proof", + types.NewMsgChannelOpenAck(portid, chanid, chanid, version, emptyProof, height, addr), + errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty try proof"), + }, + { + "invalid counterparty channel id", + types.NewMsgChannelOpenAck(portid, chanid, invalidShortChannel, version, suite.proof, height, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s has invalid length: %d, must be between %d-%d characters", + invalidShortChannel, len(invalidShortChannel), 8, host.DefaultMaxCharacterLength), + "invalid counterparty channel ID", + ), + }, } for _, tc := range testCases { @@ -210,29 +530,93 @@ func (suite *TypesTestSuite) TestMsgChannelOpenAckValidateBasic() { suite.Run(tc.name, func() { err := tc.msg.ValidateBasic() - if tc.expPass { + expPass := tc.expErr == nil + if expPass { suite.Require().NoError(err) } else { suite.Require().Error(err) + suite.Require().Equal(err.Error(), tc.expErr.Error()) } }) } } +func (suite *TypesTestSuite) TestMsgChannelOpenAckGetSigners() { + expSigner, err := sdk.AccAddressFromBech32(addr) + suite.Require().NoError(err) + msg := types.NewMsgChannelOpenAck(portid, chanid, chanid, version, suite.proof, height, addr) + + encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) + + suite.Require().NoError(err) + suite.Require().Equal(expSigner.Bytes(), signers[0]) +} + func (suite *TypesTestSuite) TestMsgChannelOpenConfirmValidateBasic() { testCases := []struct { - name string - msg *types.MsgChannelOpenConfirm - expPass bool + name string + msg *types.MsgChannelOpenConfirm + expErr error }{ - {"", types.NewMsgChannelOpenConfirm(portid, chanid, suite.proof, height, addr), true}, - {"too short port id", types.NewMsgChannelOpenConfirm(invalidShortPort, chanid, suite.proof, height, addr), false}, - {"too long port id", types.NewMsgChannelOpenConfirm(invalidLongPort, chanid, suite.proof, height, addr), false}, - {"port id contains non-alpha", types.NewMsgChannelOpenConfirm(invalidPort, chanid, suite.proof, height, addr), false}, - {"too short channel id", types.NewMsgChannelOpenConfirm(portid, invalidShortChannel, suite.proof, height, addr), false}, - {"too long channel id", types.NewMsgChannelOpenConfirm(portid, invalidLongChannel, suite.proof, height, addr), false}, - {"channel id contains non-alpha", types.NewMsgChannelOpenConfirm(portid, invalidChannel, suite.proof, height, addr), false}, - {"empty proof", types.NewMsgChannelOpenConfirm(portid, chanid, emptyProof, height, addr), false}, + { + "success", + types.NewMsgChannelOpenConfirm(portid, chanid, suite.proof, height, addr), + nil, + }, + { + "too short port id", + types.NewMsgChannelOpenConfirm(invalidShortPort, chanid, suite.proof, height, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s has invalid length: %d, must be between %d-%d characters", + invalidShortPort, len(invalidShortPort), 2, host.DefaultMaxPortCharacterLength), + "invalid port ID", + ), + }, + { + "too long port id", + types.NewMsgChannelOpenConfirm(invalidLongPort, chanid, suite.proof, height, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s has invalid length: %d, must be between %d-%d characters", + invalidLongPort, len(invalidLongPort), 2, host.DefaultMaxPortCharacterLength), + "invalid port ID", + ), + }, + { + "port id contains non-alpha", + types.NewMsgChannelOpenConfirm(invalidPort, chanid, suite.proof, height, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'", + invalidPort, + ), "invalid port ID", + ), + }, + { + "too short channel id", + types.NewMsgChannelOpenConfirm(portid, invalidShortChannel, suite.proof, height, addr), + types.ErrInvalidChannelIdentifier, + }, + { + "too long channel id", + types.NewMsgChannelOpenConfirm(portid, invalidLongChannel, suite.proof, height, addr), + types.ErrInvalidChannelIdentifier, + }, + { + "channel id contains non-alpha", + types.NewMsgChannelOpenConfirm(portid, invalidChannel, suite.proof, height, addr), + types.ErrInvalidChannelIdentifier, + }, + { + "empty proof", + types.NewMsgChannelOpenConfirm(portid, chanid, emptyProof, height, addr), + errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty acknowledgement proof"), + }, } for _, tc := range testCases { @@ -241,28 +625,88 @@ func (suite *TypesTestSuite) TestMsgChannelOpenConfirmValidateBasic() { suite.Run(tc.name, func() { err := tc.msg.ValidateBasic() - if tc.expPass { + expPass := tc.expErr == nil + if expPass { suite.Require().NoError(err) } else { suite.Require().Error(err) + suite.Require().Equal(err.Error(), tc.expErr.Error()) } }) } } +func (suite *TypesTestSuite) TestMsgChannelOpenConfirmGetSigners() { + expSigner, err := sdk.AccAddressFromBech32(addr) + suite.Require().NoError(err) + msg := types.NewMsgChannelOpenConfirm(portid, chanid, suite.proof, height, addr) + + encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) + + suite.Require().NoError(err) + suite.Require().Equal(expSigner.Bytes(), signers[0]) +} + func (suite *TypesTestSuite) TestMsgChannelCloseInitValidateBasic() { testCases := []struct { - name string - msg *types.MsgChannelCloseInit - expPass bool + name string + msg *types.MsgChannelCloseInit + expErr error }{ - {"", types.NewMsgChannelCloseInit(portid, chanid, addr), true}, - {"too short port id", types.NewMsgChannelCloseInit(invalidShortPort, chanid, addr), false}, - {"too long port id", types.NewMsgChannelCloseInit(invalidLongPort, chanid, addr), false}, - {"port id contains non-alpha", types.NewMsgChannelCloseInit(invalidPort, chanid, addr), false}, - {"too short channel id", types.NewMsgChannelCloseInit(portid, invalidShortChannel, addr), false}, - {"too long channel id", types.NewMsgChannelCloseInit(portid, invalidLongChannel, addr), false}, - {"channel id contains non-alpha", types.NewMsgChannelCloseInit(portid, invalidChannel, addr), false}, + { + "success", + types.NewMsgChannelCloseInit(portid, chanid, addr), + nil, + }, + { + "too short port id", + types.NewMsgChannelCloseInit(invalidShortPort, chanid, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s has invalid length: %d, must be between %d-%d characters", + invalidShortPort, len(invalidShortPort), 2, host.DefaultMaxPortCharacterLength), + "invalid port ID", + ), + }, + { + "too long port id", + types.NewMsgChannelCloseInit(invalidLongPort, chanid, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s has invalid length: %d, must be between %d-%d characters", + invalidLongPort, len(invalidLongPort), 2, host.DefaultMaxPortCharacterLength), + "invalid port ID", + ), + }, + { + "port id contains non-alpha", + types.NewMsgChannelCloseInit(invalidPort, chanid, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'", + invalidPort, + ), "invalid port ID", + ), + }, + { + "too short channel id", + types.NewMsgChannelCloseInit(portid, invalidShortChannel, addr), + types.ErrInvalidChannelIdentifier, + }, + { + "too long channel id", + types.NewMsgChannelCloseInit(portid, invalidLongChannel, addr), + types.ErrInvalidChannelIdentifier, + }, + { + "channel id contains non-alpha", + types.NewMsgChannelCloseInit(portid, invalidChannel, addr), + types.ErrInvalidChannelIdentifier, + }, } for _, tc := range testCases { @@ -271,29 +715,98 @@ func (suite *TypesTestSuite) TestMsgChannelCloseInitValidateBasic() { suite.Run(tc.name, func() { err := tc.msg.ValidateBasic() - if tc.expPass { + expPass := tc.expErr == nil + if expPass { suite.Require().NoError(err) } else { suite.Require().Error(err) + suite.Require().Equal(err.Error(), tc.expErr.Error()) } }) } } +func (suite *TypesTestSuite) TestMsgChannelCloseInitGetSigners() { + expSigner, err := sdk.AccAddressFromBech32(addr) + suite.Require().NoError(err) + msg := types.NewMsgChannelCloseInit(portid, chanid, addr) + + encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) + + suite.Require().NoError(err) + suite.Require().Equal(expSigner.Bytes(), signers[0]) +} + func (suite *TypesTestSuite) TestMsgChannelCloseConfirmValidateBasic() { testCases := []struct { - name string - msg *types.MsgChannelCloseConfirm - expPass bool + name string + msg *types.MsgChannelCloseConfirm + expErr error }{ - {"", types.NewMsgChannelCloseConfirm(portid, chanid, suite.proof, height, addr), true}, - {"too short port id", types.NewMsgChannelCloseConfirm(invalidShortPort, chanid, suite.proof, height, addr), false}, - {"too long port id", types.NewMsgChannelCloseConfirm(invalidLongPort, chanid, suite.proof, height, addr), false}, - {"port id contains non-alpha", types.NewMsgChannelCloseConfirm(invalidPort, chanid, suite.proof, height, addr), false}, - {"too short channel id", types.NewMsgChannelCloseConfirm(portid, invalidShortChannel, suite.proof, height, addr), false}, - {"too long channel id", types.NewMsgChannelCloseConfirm(portid, invalidLongChannel, suite.proof, height, addr), false}, - {"channel id contains non-alpha", types.NewMsgChannelCloseConfirm(portid, invalidChannel, suite.proof, height, addr), false}, - {"empty proof", types.NewMsgChannelCloseConfirm(portid, chanid, emptyProof, height, addr), false}, + { + "success", + types.NewMsgChannelCloseConfirm(portid, chanid, suite.proof, height, addr), + nil, + }, + { + "success, positive counterparty upgrade sequence", + types.NewMsgChannelCloseConfirm(portid, chanid, suite.proof, height, addr), + nil, + }, + { + "too short port id", + types.NewMsgChannelCloseConfirm(invalidShortPort, chanid, suite.proof, height, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s has invalid length: %d, must be between %d-%d characters", + invalidShortPort, len(invalidShortPort), 2, host.DefaultMaxPortCharacterLength), + "invalid port ID", + ), + }, + { + "too long port id", + types.NewMsgChannelCloseConfirm(invalidLongPort, chanid, suite.proof, height, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s has invalid length: %d, must be between %d-%d characters", + invalidLongPort, len(invalidLongPort), 2, host.DefaultMaxPortCharacterLength), + "invalid port ID", + ), + }, + { + "port id contains non-alpha", + types.NewMsgChannelCloseConfirm(invalidPort, chanid, suite.proof, height, addr), + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'", + invalidPort, + ), "invalid port ID", + ), + }, + { + "too short channel id", + types.NewMsgChannelCloseConfirm(portid, invalidShortChannel, suite.proof, height, addr), + types.ErrInvalidChannelIdentifier, + }, + { + "too long channel id", + types.NewMsgChannelCloseConfirm(portid, invalidLongChannel, suite.proof, height, addr), + types.ErrInvalidChannelIdentifier, + }, + { + "channel id contains non-alpha", + types.NewMsgChannelCloseConfirm(portid, invalidChannel, suite.proof, height, addr), + types.ErrInvalidChannelIdentifier, + }, + { + "empty proof", + types.NewMsgChannelCloseConfirm(portid, chanid, emptyProof, height, addr), + errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty init proof"), + }, } for _, tc := range testCases { @@ -302,25 +815,55 @@ func (suite *TypesTestSuite) TestMsgChannelCloseConfirmValidateBasic() { suite.Run(tc.name, func() { err := tc.msg.ValidateBasic() - if tc.expPass { + expPass := tc.expErr == nil + if expPass { suite.Require().NoError(err) } else { suite.Require().Error(err) + suite.Require().Equal(err.Error(), tc.expErr.Error()) } }) } } +func (suite *TypesTestSuite) TestMsgChannelCloseConfirmGetSigners() { + expSigner, err := sdk.AccAddressFromBech32(addr) + suite.Require().NoError(err) + msg := types.NewMsgChannelCloseConfirm(portid, chanid, suite.proof, height, addr) + + encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) + + suite.Require().NoError(err) + suite.Require().Equal(expSigner.Bytes(), signers[0]) +} + func (suite *TypesTestSuite) TestMsgRecvPacketValidateBasic() { testCases := []struct { - name string - msg *types.MsgRecvPacket - expPass bool + name string + msg *types.MsgRecvPacket + expErr error }{ - {"success", types.NewMsgRecvPacket(packet, suite.proof, height, addr), true}, - {"missing signer address", types.NewMsgRecvPacket(packet, suite.proof, height, emptyAddr), false}, - {"proof contain empty proof", types.NewMsgRecvPacket(packet, emptyProof, height, addr), false}, - {"invalid packet", types.NewMsgRecvPacket(invalidPacket, suite.proof, height, addr), false}, + { + "success", + types.NewMsgRecvPacket(packet, suite.proof, height, addr), + nil, + }, + { + "missing signer address", + types.NewMsgRecvPacket(packet, suite.proof, height, emptyAddr), + errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", errors.New("empty address string is not allowed")), + }, + { + "proof contain empty proof", + types.NewMsgRecvPacket(packet, emptyProof, height, addr), + errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty commitment proof"), + }, + { + "invalid packet", + types.NewMsgRecvPacket(invalidPacket, suite.proof, height, addr), + errorsmod.Wrap(types.ErrInvalidPacket, "packet sequence cannot be 0"), + }, } for _, tc := range testCases { @@ -329,34 +872,60 @@ func (suite *TypesTestSuite) TestMsgRecvPacketValidateBasic() { suite.Run(tc.name, func() { err := tc.msg.ValidateBasic() - if tc.expPass { + expPass := tc.expErr == nil + if expPass { suite.NoError(err) } else { suite.Error(err) + suite.Require().Equal(err.Error(), tc.expErr.Error()) } }) } } func (suite *TypesTestSuite) TestMsgRecvPacketGetSigners() { + expSigner, err := sdk.AccAddressFromBech32(addr) + suite.Require().NoError(err) msg := types.NewMsgRecvPacket(packet, suite.proof, height, addr) - res := msg.GetSigners() - expected := "[7465737461646472313131313131313131313131]" - suite.Equal(expected, fmt.Sprintf("%v", res)) + encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) + + suite.Require().NoError(err) + suite.Require().Equal(expSigner.Bytes(), signers[0]) } func (suite *TypesTestSuite) TestMsgTimeoutValidateBasic() { testCases := []struct { - name string - msg *types.MsgTimeout - expPass bool + name string + msg *types.MsgTimeout + expErr error }{ - {"success", types.NewMsgTimeout(packet, 1, suite.proof, height, addr), true}, - {"seq 0", types.NewMsgTimeout(packet, 0, suite.proof, height, addr), false}, - {"missing signer address", types.NewMsgTimeout(packet, 1, suite.proof, height, emptyAddr), false}, - {"cannot submit an empty proof", types.NewMsgTimeout(packet, 1, emptyProof, height, addr), false}, - {"invalid packet", types.NewMsgTimeout(invalidPacket, 1, suite.proof, height, addr), false}, + { + "success", + types.NewMsgTimeout(packet, 1, suite.proof, height, addr), + nil, + }, + { + "seq 0", + types.NewMsgTimeout(packet, 0, suite.proof, height, addr), + errorsmod.Wrap(ibcerrors.ErrInvalidSequence, "next sequence receive cannot be 0"), + }, + { + "missing signer address", + types.NewMsgTimeout(packet, 1, suite.proof, height, emptyAddr), + errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", errors.New("empty address string is not allowed")), + }, + { + "cannot submit an empty proof", + types.NewMsgTimeout(packet, 1, emptyProof, height, addr), + errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty unreceived proof"), + }, + { + "invalid packet", + types.NewMsgTimeout(invalidPacket, 1, suite.proof, height, addr), + errorsmod.Wrap(types.ErrInvalidPacket, "packet sequence cannot be 0"), + }, } for _, tc := range testCases { @@ -365,27 +934,70 @@ func (suite *TypesTestSuite) TestMsgTimeoutValidateBasic() { suite.Run(tc.name, func() { err := tc.msg.ValidateBasic() - if tc.expPass { + expPass := tc.expErr == nil + if expPass { suite.Require().NoError(err) } else { suite.Require().Error(err) + suite.Require().Equal(err.Error(), tc.expErr.Error()) } }) } } +func (suite *TypesTestSuite) TestMsgTimeoutGetSigners() { + expSigner, err := sdk.AccAddressFromBech32(addr) + suite.Require().NoError(err) + msg := types.NewMsgTimeout(packet, 1, suite.proof, height, addr) + + encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) + + suite.Require().NoError(err) + suite.Require().Equal(expSigner.Bytes(), signers[0]) +} + func (suite *TypesTestSuite) TestMsgTimeoutOnCloseValidateBasic() { testCases := []struct { - name string - msg *types.MsgTimeoutOnClose - expPass bool + name string + msg *types.MsgTimeoutOnClose + expErr error }{ - {"success", types.NewMsgTimeoutOnClose(packet, 1, suite.proof, suite.proof, height, addr), true}, - {"seq 0", types.NewMsgTimeoutOnClose(packet, 0, suite.proof, suite.proof, height, addr), false}, - {"signer address is empty", types.NewMsgTimeoutOnClose(packet, 1, suite.proof, suite.proof, height, emptyAddr), false}, - {"empty proof", types.NewMsgTimeoutOnClose(packet, 1, emptyProof, suite.proof, height, addr), false}, - {"empty proof close", types.NewMsgTimeoutOnClose(packet, 1, suite.proof, emptyProof, height, addr), false}, - {"invalid packet", types.NewMsgTimeoutOnClose(invalidPacket, 1, suite.proof, suite.proof, height, addr), false}, + { + "success", + types.NewMsgTimeoutOnClose(packet, 1, suite.proof, suite.proof, height, addr), + nil, + }, + { + "success, positive counterparty upgrade sequence", + types.NewMsgTimeoutOnClose(packet, 1, suite.proof, suite.proof, height, addr), + nil, + }, + { + "seq 0", + types.NewMsgTimeoutOnClose(packet, 0, suite.proof, suite.proof, height, addr), + errorsmod.Wrap(ibcerrors.ErrInvalidSequence, "next sequence receive cannot be 0"), + }, + { + "signer address is empty", + types.NewMsgTimeoutOnClose(packet, 1, suite.proof, suite.proof, height, emptyAddr), + errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", errors.New("empty address string is not allowed")), + }, + { + "empty proof", + types.NewMsgTimeoutOnClose(packet, 1, emptyProof, suite.proof, height, addr), + errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty unreceived proof"), + }, + { + "empty proof close", + types.NewMsgTimeoutOnClose(packet, 1, suite.proof, emptyProof, height, addr), + errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof of closed counterparty channel end"), + }, + { + "invalid packet", + types.NewMsgTimeoutOnClose(invalidPacket, 1, suite.proof, suite.proof, height, addr), + errorsmod.Wrap(types.ErrInvalidPacket, "packet sequence cannot be 0"), + }, } for _, tc := range testCases { @@ -394,26 +1006,60 @@ func (suite *TypesTestSuite) TestMsgTimeoutOnCloseValidateBasic() { suite.Run(tc.name, func() { err := tc.msg.ValidateBasic() - if tc.expPass { + expPass := tc.expErr == nil + if expPass { suite.Require().NoError(err) } else { suite.Require().Error(err) + suite.Require().Equal(err.Error(), tc.expErr.Error()) } }) } } +func (suite *TypesTestSuite) TestMsgTimeoutOnCloseGetSigners() { + expSigner, err := sdk.AccAddressFromBech32(addr) + suite.Require().NoError(err) + msg := types.NewMsgTimeoutOnClose(packet, 1, suite.proof, suite.proof, height, addr) + + encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) + + suite.Require().NoError(err) + suite.Require().Equal(expSigner.Bytes(), signers[0]) +} + func (suite *TypesTestSuite) TestMsgAcknowledgementValidateBasic() { testCases := []struct { - name string - msg *types.MsgAcknowledgement - expPass bool + name string + msg *types.MsgAcknowledgement + expErr error }{ - {"success", types.NewMsgAcknowledgement(packet, packet.GetData(), suite.proof, height, addr), true}, - {"empty ack", types.NewMsgAcknowledgement(packet, nil, suite.proof, height, addr), false}, - {"missing signer address", types.NewMsgAcknowledgement(packet, packet.GetData(), suite.proof, height, emptyAddr), false}, - {"cannot submit an empty proof", types.NewMsgAcknowledgement(packet, packet.GetData(), emptyProof, height, addr), false}, - {"invalid packet", types.NewMsgAcknowledgement(invalidPacket, packet.GetData(), suite.proof, height, addr), false}, + { + "success", + types.NewMsgAcknowledgement(packet, packet.GetData(), suite.proof, height, addr), + nil, + }, + { + "empty ack", + types.NewMsgAcknowledgement(packet, nil, suite.proof, height, addr), + errorsmod.Wrap(types.ErrInvalidAcknowledgement, "ack bytes cannot be empty"), + }, + { + "missing signer address", + types.NewMsgAcknowledgement(packet, packet.GetData(), suite.proof, height, emptyAddr), + errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", errors.New("empty address string is not allowed")), + }, + { + "cannot submit an empty proof", + types.NewMsgAcknowledgement(packet, packet.GetData(), emptyProof, height, addr), + errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty acknowledgement proof"), + }, + { + "invalid packet", + types.NewMsgAcknowledgement(invalidPacket, packet.GetData(), suite.proof, height, addr), + errorsmod.Wrap(types.ErrInvalidPacket, "packet sequence cannot be 0"), + }, } for _, tc := range testCases { @@ -422,11 +1068,861 @@ func (suite *TypesTestSuite) TestMsgAcknowledgementValidateBasic() { suite.Run(tc.name, func() { err := tc.msg.ValidateBasic() - if tc.expPass { + expPass := tc.expErr == nil + if expPass { suite.Require().NoError(err) } else { suite.Require().Error(err) + suite.Require().Equal(err.Error(), tc.expErr.Error()) } }) } } + +func (suite *TypesTestSuite) TestMsgAcknowledgementGetSigners() { + expSigner, err := sdk.AccAddressFromBech32(addr) + suite.Require().NoError(err) + msg := types.NewMsgAcknowledgement(packet, packet.GetData(), suite.proof, height, addr) + + encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) + + suite.Require().NoError(err) + suite.Require().Equal(expSigner.Bytes(), signers[0]) +} + +func (suite *TypesTestSuite) TestMsgChannelUpgradeInitValidateBasic() { + var msg *types.MsgChannelUpgradeInit + + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success", + func() {}, + nil, + }, + { + "invalid port identifier", + func() { + msg.PortId = invalidPort + }, + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'", + invalidPort, + ), "invalid port ID", + ), + }, + { + "invalid channel identifier", + func() { + msg.ChannelId = invalidChannel + }, + types.ErrInvalidChannelIdentifier, + }, + { + "empty proposed upgrade channel version", + func() { + msg.Fields.Version = " " + }, + errorsmod.Wrap(types.ErrInvalidChannelVersion, "version cannot be empty"), + }, + { + "missing signer address", + func() { + msg.Signer = emptyAddr + }, + errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", errors.New("empty address string is not allowed")), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + msg = types.NewMsgChannelUpgradeInit( + ibctesting.MockPort, ibctesting.FirstChannelID, + types.NewUpgradeFields(types.UNORDERED, []string{ibctesting.FirstConnectionID}, mock.Version), + addr, + ) + + tc.malleate() + err := msg.ValidateBasic() + + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + suite.Require().Equal(err.Error(), tc.expErr.Error()) + } + }) + } +} + +func (suite *TypesTestSuite) TestMsgChannelUpgradeInitGetSigners() { + expSigner, err := sdk.AccAddressFromBech32(addr) + suite.Require().NoError(err) + msg := types.NewMsgChannelUpgradeInit( + ibctesting.MockPort, ibctesting.FirstChannelID, + types.NewUpgradeFields(types.UNORDERED, []string{ibctesting.FirstConnectionID}, mock.Version), + addr, + ) + + encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) + + suite.Require().NoError(err) + suite.Require().Equal(expSigner.Bytes(), signers[0]) +} + +func (suite *TypesTestSuite) TestMsgChannelUpgradeTryValidateBasic() { + var msg *types.MsgChannelUpgradeTry + + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success", + func() {}, + nil, + }, + { + "invalid port identifier", + func() { + msg.PortId = invalidPort + }, + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'", + invalidPort, + ), "invalid port ID", + ), + }, + { + "invalid channel identifier", + func() { + msg.ChannelId = invalidChannel + }, + types.ErrInvalidChannelIdentifier, + }, + { + "counterparty sequence cannot be zero", + func() { + msg.CounterpartyUpgradeSequence = 0 + }, + errorsmod.Wrap(types.ErrInvalidUpgradeSequence, "counterparty sequence cannot be 0"), + }, + { + "invalid connection hops", + func() { + msg.ProposedUpgradeConnectionHops = []string{} + }, + errorsmod.Wrap(types.ErrInvalidUpgrade, "proposed connection hops cannot be empty"), + }, + { + "invalid counterparty upgrade fields ordering", + func() { + msg.CounterpartyUpgradeFields.Ordering = types.NONE + }, + errorsmod.Wrap( + errorsmod.Wrap(types.ErrInvalidChannelOrdering, types.NONE.String()), "error validating counterparty upgrade fields", + ), + }, + { + "cannot submit an empty channel proof", + func() { + msg.ProofChannel = emptyProof + }, + errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty channel proof"), + }, + { + "cannot submit an empty upgrade proof", + func() { + msg.ProofUpgrade = emptyProof + }, + errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty upgrade proof"), + }, + { + "missing signer address", + func() { + msg.Signer = emptyAddr + }, + errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", errors.New("empty address string is not allowed")), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + msg = types.NewMsgChannelUpgradeTry( + ibctesting.MockPort, + ibctesting.FirstChannelID, + []string{ibctesting.FirstConnectionID}, + types.NewUpgradeFields(types.UNORDERED, []string{ibctesting.FirstConnectionID}, mock.Version), + 1, + suite.proof, + suite.proof, + height, + addr, + ) + + tc.malleate() + err := msg.ValidateBasic() + + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + suite.Require().Equal(err.Error(), tc.expErr.Error()) + } + }) + } +} + +func (suite *TypesTestSuite) TestMsgChannelUpgradeTryGetSigners() { + expSigner, err := sdk.AccAddressFromBech32(addr) + suite.Require().NoError(err) + msg := types.NewMsgChannelUpgradeTry( + ibctesting.MockPort, + ibctesting.FirstChannelID, + []string{ibctesting.FirstConnectionID}, + types.NewUpgradeFields(types.UNORDERED, []string{ibctesting.FirstConnectionID}, mock.Version), + 1, + suite.proof, + suite.proof, + height, + addr, + ) + + encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) + + suite.Require().NoError(err) + suite.Require().Equal(expSigner.Bytes(), signers[0]) +} + +func (suite *TypesTestSuite) TestMsgChannelUpgradeAckValidateBasic() { + var msg *types.MsgChannelUpgradeAck + + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success", + func() {}, + nil, + }, + { + "invalid port identifier", + func() { + msg.PortId = invalidPort + }, + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'", + invalidPort, + ), "invalid port ID", + ), + }, + { + "invalid channel identifier", + func() { + msg.ChannelId = invalidChannel + }, + types.ErrInvalidChannelIdentifier, + }, + { + "cannot submit an empty channel proof", + func() { + msg.ProofChannel = emptyProof + }, + errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty channel proof"), + }, + { + "cannot submit an empty upgrade proof", + func() { + msg.ProofUpgrade = emptyProof + }, + errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty upgrade sequence proof"), + }, + { + "missing signer address", + func() { + msg.Signer = emptyAddr + }, + errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", errors.New("empty address string is not allowed")), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + upgrade := types.NewUpgrade( + types.NewUpgradeFields(types.ORDERED, []string{ibctesting.FirstConnectionID}, mock.Version), + types.NewTimeout(clienttypes.NewHeight(1, 100), 0), + 0, + ) + + msg = types.NewMsgChannelUpgradeAck( + ibctesting.MockPort, ibctesting.FirstChannelID, + upgrade, suite.proof, suite.proof, + height, addr, + ) + + tc.malleate() + err := msg.ValidateBasic() + + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + suite.Require().Equal(err.Error(), tc.expErr.Error()) + } + }) + } +} + +func (suite *TypesTestSuite) TestMsgChannelUpgradeAckGetSigners() { + expSigner, err := sdk.AccAddressFromBech32(addr) + suite.Require().NoError(err) + upgrade := types.NewUpgrade( + types.NewUpgradeFields(types.ORDERED, []string{ibctesting.FirstConnectionID}, mock.Version), + types.NewTimeout(clienttypes.NewHeight(1, 100), 0), + 0, + ) + + msg := types.NewMsgChannelUpgradeAck( + ibctesting.MockPort, ibctesting.FirstChannelID, + upgrade, suite.proof, suite.proof, + height, addr, + ) + + encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) + + suite.Require().NoError(err) + suite.Require().Equal(expSigner.Bytes(), signers[0]) +} + +func (suite *TypesTestSuite) TestMsgChannelUpgradeConfirmValidateBasic() { + var msg *types.MsgChannelUpgradeConfirm + + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success", + func() {}, + nil, + }, + { + "success: counterparty state set to FLUSHCOMPLETE", + func() { + msg.CounterpartyChannelState = types.FLUSHCOMPLETE + }, + nil, + }, + { + "invalid port identifier", + func() { + msg.PortId = invalidPort + }, + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'", + invalidPort, + ), "invalid port ID", + ), + }, + { + "invalid channel identifier", + func() { + msg.ChannelId = invalidChannel + }, + types.ErrInvalidChannelIdentifier, + }, + { + "invalid counterparty channel state", + func() { + msg.CounterpartyChannelState = types.CLOSED + }, + errorsmod.Wrapf(types.ErrInvalidChannelState, "expected channel state to be one of: %s or %s, got: %s", types.FLUSHING, types.FLUSHCOMPLETE, types.CLOSED), + }, + { + "cannot submit an empty channel proof", + func() { + msg.ProofChannel = emptyProof + }, + errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty channel proof"), + }, + { + "cannot submit an empty upgrade proof", + func() { + msg.ProofUpgrade = emptyProof + }, + errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty upgrade proof"), + }, + { + "missing signer address", + func() { + msg.Signer = emptyAddr + }, + errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", errors.New("empty address string is not allowed")), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + counterpartyUpgrade := types.NewUpgrade( + types.NewUpgradeFields(types.UNORDERED, []string{ibctesting.FirstConnectionID}, mock.Version), + types.NewTimeout(clienttypes.NewHeight(0, 10000), timeoutTimestamp), + 0, + ) + + msg = types.NewMsgChannelUpgradeConfirm( + ibctesting.MockPort, ibctesting.FirstChannelID, + types.FLUSHING, counterpartyUpgrade, suite.proof, suite.proof, + height, addr, + ) + + tc.malleate() + err := msg.ValidateBasic() + + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + suite.Require().Equal(err.Error(), tc.expErr.Error()) + } + }) + } +} + +func (suite *TypesTestSuite) TestMsgChannelUpgradeConfirmGetSigners() { + expSigner, err := sdk.AccAddressFromBech32(addr) + suite.Require().NoError(err) + + msg := &types.MsgChannelUpgradeConfirm{Signer: addr} + + encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) + + suite.Require().NoError(err) + suite.Require().Equal(expSigner.Bytes(), signers[0]) +} + +func (suite *TypesTestSuite) TestMsgChannelUpgradeOpenValidateBasic() { + var msg *types.MsgChannelUpgradeOpen + + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success: flushcomplete state", + func() {}, + nil, + }, + { + "success: open state", + func() { + msg.CounterpartyChannelState = types.OPEN + }, + nil, + }, + { + "invalid port identifier", + func() { + msg.PortId = invalidPort + }, + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'", + invalidPort, + ), "invalid port ID", + ), + }, + { + "invalid channel identifier", + func() { + msg.ChannelId = invalidChannel + }, + types.ErrInvalidChannelIdentifier, + }, + { + "invalid counterparty channel state", + func() { + msg.CounterpartyChannelState = types.CLOSED + }, + errorsmod.Wrapf(types.ErrInvalidChannelState, "expected channel state to be one of: [%s, %s], got: %s", types.FLUSHCOMPLETE, types.OPEN, types.CLOSED), + }, + { + "invalid counterparty upgrade seqeuence", + func() { + msg.CounterpartyUpgradeSequence = 0 + }, + errorsmod.Wrapf(types.ErrInvalidUpgradeSequence, "counterparty upgrade sequence must be non-zero"), + }, + + { + "cannot submit an empty channel proof", + func() { + msg.ProofChannel = emptyProof + }, + errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty channel proof"), + }, + { + "missing signer address", + func() { + msg.Signer = emptyAddr + }, + errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", errors.New("empty address string is not allowed")), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + msg = types.NewMsgChannelUpgradeOpen( + ibctesting.MockPort, ibctesting.FirstChannelID, + types.FLUSHCOMPLETE, 1, suite.proof, + height, addr, + ) + + tc.malleate() + err := msg.ValidateBasic() + + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + suite.Require().Equal(err.Error(), tc.expErr.Error()) + } + }) + } +} + +func (suite *TypesTestSuite) TestMsgChannelUpgradeTimeoutValidateBasic() { + var msg *types.MsgChannelUpgradeTimeout + + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success", + func() {}, + nil, + }, + { + "invalid port identifier", + func() { + msg.PortId = invalidPort + }, + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'", + invalidPort, + ), "invalid port ID", + ), + }, + { + "invalid channel identifier", + func() { + msg.ChannelId = invalidChannel + }, + types.ErrInvalidChannelIdentifier, + }, + { + "cannot submit an empty proof", + func() { + msg.ProofChannel = emptyProof + }, + errorsmod.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof"), + }, + { + "invalid counterparty channel state", + func() { + msg.CounterpartyChannel.State = types.CLOSED + }, + errorsmod.Wrapf(types.ErrInvalidChannelState, "expected counterparty channel state to be one of: [%s, %s], got: %s", types.FLUSHING, types.OPEN, types.CLOSED), + }, + { + "missing signer address", + func() { + msg.Signer = emptyAddr + }, + errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", errors.New("empty address string is not allowed")), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + msg = types.NewMsgChannelUpgradeTimeout( + ibctesting.MockPort, ibctesting.FirstChannelID, + types.Channel{State: types.OPEN}, + suite.proof, + height, addr, + ) + + tc.malleate() + err := msg.ValidateBasic() + + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + suite.Require().Equal(err.Error(), tc.expErr.Error()) + } + }) + } +} + +func (suite *TypesTestSuite) TestMsgChannelUpgradeTimeoutGetSigners() { + expSigner, err := sdk.AccAddressFromBech32(addr) + suite.Require().NoError(err) + + msg := types.NewMsgChannelUpgradeTimeout( + ibctesting.MockPort, ibctesting.FirstChannelID, + types.Channel{}, + suite.proof, + height, addr, + ) + encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) + + suite.Require().NoError(err) + suite.Require().Equal(expSigner.Bytes(), signers[0]) +} + +func (suite *TypesTestSuite) TestMsgChannelUpgradeCancelValidateBasic() { + var msg *types.MsgChannelUpgradeCancel + + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success", + func() {}, + nil, + }, + { + "invalid port identifier", + func() { + msg.PortId = invalidPort + }, + errorsmod.Wrap( + errorsmod.Wrapf( + host.ErrInvalidID, + "identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'", + invalidPort, + ), "invalid port ID", + ), + }, + { + "invalid channel identifier", + func() { + msg.ChannelId = invalidChannel + }, + types.ErrInvalidChannelIdentifier, + }, + { + "can submit an empty proof", + func() { + msg.ProofErrorReceipt = emptyProof + }, + nil, + }, + { + "missing signer address", + func() { + msg.Signer = emptyAddr + }, + errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", errors.New("empty address string is not allowed")), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + msg = types.NewMsgChannelUpgradeCancel(ibctesting.MockPort, ibctesting.FirstChannelID, types.ErrorReceipt{Sequence: 1}, suite.proof, height, addr) + + tc.malleate() + err := msg.ValidateBasic() + + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + suite.Require().Equal(err.Error(), tc.expErr.Error()) + } + }) + } +} + +func (suite *TypesTestSuite) TestMsgChannelUpgradeCancelGetSigners() { + expSigner, err := sdk.AccAddressFromBech32(addr) + suite.Require().NoError(err) + + msg := types.NewMsgChannelUpgradeCancel(ibctesting.MockPort, ibctesting.FirstChannelID, types.ErrorReceipt{Sequence: 1}, suite.proof, height, addr) + encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) + + suite.Require().NoError(err) + suite.Require().Equal(expSigner.Bytes(), signers[0]) +} + +func (suite *TypesTestSuite) TestMsgPruneAcknowledgementsValidateBasic() { + var msg *types.MsgPruneAcknowledgements + + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success", + func() {}, + nil, + }, + { + "failure: zero pruning limit", + func() { + msg.Limit = 0 + }, + types.ErrInvalidPruningLimit, + }, + { + "invalid port identifier", + func() { + msg.PortId = invalidPort + }, + host.ErrInvalidID, + }, + { + "invalid channel identifier", + func() { + msg.ChannelId = invalidChannel + }, + types.ErrInvalidChannelIdentifier, + }, + { + "empty signer address", + func() { + msg.Signer = emptyAddr + }, + ibcerrors.ErrInvalidAddress, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + msg = types.NewMsgPruneAcknowledgements(ibctesting.MockPort, ibctesting.FirstChannelID, 1, addr) + + tc.malleate() + err := msg.ValidateBasic() + + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + } else { + suite.Require().ErrorIs(err, tc.expErr) + } + }) + } +} + +func (suite *TypesTestSuite) TestMsgUpdateParamsValidateBasic() { + var msg *types.MsgUpdateParams + + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success", + func() {}, + nil, + }, + { + "invalid authority", + func() { + msg.Authority = "invalid-address" + }, + ibcerrors.ErrInvalidAddress, + }, + { + "invalid params: non zero height", + func() { + newHeight := clienttypes.NewHeight(1, 1000) + msg = types.NewMsgUpdateChannelParams(authtypes.NewModuleAddress(govtypes.ModuleName).String(), types.NewParams(types.NewTimeout(newHeight, uint64(100000)))) + }, + types.ErrInvalidUpgradeTimeout, + }, + { + "invalid params: zero timestamp", + func() { + msg = types.NewMsgUpdateChannelParams(authtypes.NewModuleAddress(govtypes.ModuleName).String(), types.NewParams(types.NewTimeout(clienttypes.ZeroHeight(), uint64(0)))) + }, + types.ErrInvalidUpgradeTimeout, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + msg = types.NewMsgUpdateChannelParams(authtypes.NewModuleAddress(govtypes.ModuleName).String(), types.NewParams(types.NewTimeout(clienttypes.ZeroHeight(), uint64(100000)))) + + tc.malleate() + err := msg.ValidateBasic() + + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + } else { + suite.Require().ErrorIs(err, tc.expErr) + } + }) + } +} + +func (suite *TypesTestSuite) TestMsgPruneAcknowledgementsGetSigners() { + expSigner, err := sdk.AccAddressFromBech32(addr) + suite.Require().NoError(err) + + msg := types.NewMsgPruneAcknowledgements(ibctesting.MockPort, ibctesting.FirstChannelID, 0, addr) + encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) + + suite.Require().NoError(err) + suite.Require().Equal(expSigner.Bytes(), signers[0]) +} diff --git a/modules/core/04-channel/types/params.go b/modules/core/04-channel/types/params.go new file mode 100644 index 00000000000..688c55dc721 --- /dev/null +++ b/modules/core/04-channel/types/params.go @@ -0,0 +1,37 @@ +package types + +import ( + "time" + + errorsmod "cosmossdk.io/errors" + + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" +) + +// DefaultTimeout defines a default parameter for the channel upgrade protocol. +// It allows relayers a window in which they can flush all in-flight packets on a channel before completing the upgrade handshake. +// This parameter can be overridden by a valid authority using the UpdateChannelParams rpc. +var DefaultTimeout = NewTimeout(clienttypes.ZeroHeight(), uint64(10*time.Minute.Nanoseconds())) + +// NewParams creates a new parameter configuration for the channel submodule +func NewParams(upgradeTimeout Timeout) Params { + return Params{ + UpgradeTimeout: upgradeTimeout, + } +} + +// DefaultParams is the default parameter configuration for the channel submodule +func DefaultParams() Params { + return NewParams(DefaultTimeout) +} + +// Validate the params. +func (p Params) Validate() error { + if !p.UpgradeTimeout.Height.IsZero() { + return errorsmod.Wrapf(ErrInvalidUpgradeTimeout, "upgrade timeout height must be zero. got : %v", p.UpgradeTimeout.Height) + } + if p.UpgradeTimeout.Timestamp == 0 { + return errorsmod.Wrapf(ErrInvalidUpgradeTimeout, "upgrade timeout timestamp invalid: %v", p.UpgradeTimeout.Timestamp) + } + return nil +} diff --git a/modules/core/04-channel/types/query.go b/modules/core/04-channel/types/query.go index 81b0cb58307..baa307d827f 100644 --- a/modules/core/04-channel/types/query.go +++ b/modules/core/04-channel/types/query.go @@ -104,3 +104,21 @@ func NewQueryNextSequenceSendResponse( ProofHeight: height, } } + +// NewQueryUpgradeErrorResponse creates a new QueryUpgradeErrorResponse instance +func NewQueryUpgradeErrorResponse(errorReceipt ErrorReceipt, proof []byte, height clienttypes.Height) *QueryUpgradeErrorResponse { + return &QueryUpgradeErrorResponse{ + ErrorReceipt: errorReceipt, + Proof: proof, + ProofHeight: height, + } +} + +// NewQueryUpgradeResponse creates a new QueryUpgradeResponse instance +func NewQueryUpgradeResponse(upgrade Upgrade, proof []byte, height clienttypes.Height) *QueryUpgradeResponse { + return &QueryUpgradeResponse{ + Upgrade: upgrade, + Proof: proof, + ProofHeight: height, + } +} diff --git a/modules/core/04-channel/types/query.pb.go b/modules/core/04-channel/types/query.pb.go index 8ca3338c254..9d3c481b71b 100644 --- a/modules/core/04-channel/types/query.pb.go +++ b/modules/core/04-channel/types/query.pb.go @@ -1611,7 +1611,7 @@ func (m *QueryNextSequenceReceiveRequest) GetChannelId() string { return "" } -// QuerySequenceResponse is the request type for the +// QuerySequenceResponse is the response type for the // Query/QueryNextSequenceReceiveResponse RPC method type QueryNextSequenceReceiveResponse struct { // next sequence receive number @@ -1797,6 +1797,321 @@ func (m *QueryNextSequenceSendResponse) GetProofHeight() types.Height { return types.Height{} } +// QueryUpgradeErrorRequest is the request type for the Query/QueryUpgradeError RPC method +type QueryUpgradeErrorRequest struct { + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` +} + +func (m *QueryUpgradeErrorRequest) Reset() { *m = QueryUpgradeErrorRequest{} } +func (m *QueryUpgradeErrorRequest) String() string { return proto.CompactTextString(m) } +func (*QueryUpgradeErrorRequest) ProtoMessage() {} +func (*QueryUpgradeErrorRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_1034a1e9abc4cca1, []int{28} +} +func (m *QueryUpgradeErrorRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryUpgradeErrorRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryUpgradeErrorRequest.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 *QueryUpgradeErrorRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryUpgradeErrorRequest.Merge(m, src) +} +func (m *QueryUpgradeErrorRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryUpgradeErrorRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryUpgradeErrorRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryUpgradeErrorRequest proto.InternalMessageInfo + +func (m *QueryUpgradeErrorRequest) GetPortId() string { + if m != nil { + return m.PortId + } + return "" +} + +func (m *QueryUpgradeErrorRequest) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + +// QueryUpgradeErrorResponse is the response type for the Query/QueryUpgradeError RPC method +type QueryUpgradeErrorResponse struct { + ErrorReceipt ErrorReceipt `protobuf:"bytes,1,opt,name=error_receipt,json=errorReceipt,proto3" json:"error_receipt"` + // merkle proof of existence + Proof []byte `protobuf:"bytes,2,opt,name=proof,proto3" json:"proof,omitempty"` + // height at which the proof was retrieved + ProofHeight types.Height `protobuf:"bytes,3,opt,name=proof_height,json=proofHeight,proto3" json:"proof_height"` +} + +func (m *QueryUpgradeErrorResponse) Reset() { *m = QueryUpgradeErrorResponse{} } +func (m *QueryUpgradeErrorResponse) String() string { return proto.CompactTextString(m) } +func (*QueryUpgradeErrorResponse) ProtoMessage() {} +func (*QueryUpgradeErrorResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_1034a1e9abc4cca1, []int{29} +} +func (m *QueryUpgradeErrorResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryUpgradeErrorResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryUpgradeErrorResponse.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 *QueryUpgradeErrorResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryUpgradeErrorResponse.Merge(m, src) +} +func (m *QueryUpgradeErrorResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryUpgradeErrorResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryUpgradeErrorResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryUpgradeErrorResponse proto.InternalMessageInfo + +func (m *QueryUpgradeErrorResponse) GetErrorReceipt() ErrorReceipt { + if m != nil { + return m.ErrorReceipt + } + return ErrorReceipt{} +} + +func (m *QueryUpgradeErrorResponse) GetProof() []byte { + if m != nil { + return m.Proof + } + return nil +} + +func (m *QueryUpgradeErrorResponse) GetProofHeight() types.Height { + if m != nil { + return m.ProofHeight + } + return types.Height{} +} + +// QueryUpgradeRequest is the request type for the QueryUpgradeRequest RPC method +type QueryUpgradeRequest struct { + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` +} + +func (m *QueryUpgradeRequest) Reset() { *m = QueryUpgradeRequest{} } +func (m *QueryUpgradeRequest) String() string { return proto.CompactTextString(m) } +func (*QueryUpgradeRequest) ProtoMessage() {} +func (*QueryUpgradeRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_1034a1e9abc4cca1, []int{30} +} +func (m *QueryUpgradeRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryUpgradeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryUpgradeRequest.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 *QueryUpgradeRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryUpgradeRequest.Merge(m, src) +} +func (m *QueryUpgradeRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryUpgradeRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryUpgradeRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryUpgradeRequest proto.InternalMessageInfo + +func (m *QueryUpgradeRequest) GetPortId() string { + if m != nil { + return m.PortId + } + return "" +} + +func (m *QueryUpgradeRequest) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + +// QueryUpgradeResponse is the response type for the QueryUpgradeResponse RPC method +type QueryUpgradeResponse struct { + Upgrade Upgrade `protobuf:"bytes,1,opt,name=upgrade,proto3" json:"upgrade"` + // merkle proof of existence + Proof []byte `protobuf:"bytes,2,opt,name=proof,proto3" json:"proof,omitempty"` + // height at which the proof was retrieved + ProofHeight types.Height `protobuf:"bytes,3,opt,name=proof_height,json=proofHeight,proto3" json:"proof_height"` +} + +func (m *QueryUpgradeResponse) Reset() { *m = QueryUpgradeResponse{} } +func (m *QueryUpgradeResponse) String() string { return proto.CompactTextString(m) } +func (*QueryUpgradeResponse) ProtoMessage() {} +func (*QueryUpgradeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_1034a1e9abc4cca1, []int{31} +} +func (m *QueryUpgradeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryUpgradeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryUpgradeResponse.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 *QueryUpgradeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryUpgradeResponse.Merge(m, src) +} +func (m *QueryUpgradeResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryUpgradeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryUpgradeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryUpgradeResponse proto.InternalMessageInfo + +func (m *QueryUpgradeResponse) GetUpgrade() Upgrade { + if m != nil { + return m.Upgrade + } + return Upgrade{} +} + +func (m *QueryUpgradeResponse) GetProof() []byte { + if m != nil { + return m.Proof + } + return nil +} + +func (m *QueryUpgradeResponse) GetProofHeight() types.Height { + if m != nil { + return m.ProofHeight + } + return types.Height{} +} + +// QueryChannelParamsRequest is the request type for the Query/ChannelParams RPC method. +type QueryChannelParamsRequest struct { +} + +func (m *QueryChannelParamsRequest) Reset() { *m = QueryChannelParamsRequest{} } +func (m *QueryChannelParamsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryChannelParamsRequest) ProtoMessage() {} +func (*QueryChannelParamsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_1034a1e9abc4cca1, []int{32} +} +func (m *QueryChannelParamsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryChannelParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryChannelParamsRequest.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 *QueryChannelParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryChannelParamsRequest.Merge(m, src) +} +func (m *QueryChannelParamsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryChannelParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryChannelParamsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryChannelParamsRequest proto.InternalMessageInfo + +// QueryChannelParamsResponse is the response type for the Query/ChannelParams RPC method. +type QueryChannelParamsResponse struct { + // params defines the parameters of the module. + Params *Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params,omitempty"` +} + +func (m *QueryChannelParamsResponse) Reset() { *m = QueryChannelParamsResponse{} } +func (m *QueryChannelParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryChannelParamsResponse) ProtoMessage() {} +func (*QueryChannelParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_1034a1e9abc4cca1, []int{33} +} +func (m *QueryChannelParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryChannelParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryChannelParamsResponse.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 *QueryChannelParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryChannelParamsResponse.Merge(m, src) +} +func (m *QueryChannelParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryChannelParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryChannelParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryChannelParamsResponse proto.InternalMessageInfo + +func (m *QueryChannelParamsResponse) GetParams() *Params { + if m != nil { + return m.Params + } + return nil +} + func init() { proto.RegisterType((*QueryChannelRequest)(nil), "ibc.core.channel.v1.QueryChannelRequest") proto.RegisterType((*QueryChannelResponse)(nil), "ibc.core.channel.v1.QueryChannelResponse") @@ -1826,109 +2141,128 @@ func init() { proto.RegisterType((*QueryNextSequenceReceiveResponse)(nil), "ibc.core.channel.v1.QueryNextSequenceReceiveResponse") proto.RegisterType((*QueryNextSequenceSendRequest)(nil), "ibc.core.channel.v1.QueryNextSequenceSendRequest") proto.RegisterType((*QueryNextSequenceSendResponse)(nil), "ibc.core.channel.v1.QueryNextSequenceSendResponse") + proto.RegisterType((*QueryUpgradeErrorRequest)(nil), "ibc.core.channel.v1.QueryUpgradeErrorRequest") + proto.RegisterType((*QueryUpgradeErrorResponse)(nil), "ibc.core.channel.v1.QueryUpgradeErrorResponse") + proto.RegisterType((*QueryUpgradeRequest)(nil), "ibc.core.channel.v1.QueryUpgradeRequest") + proto.RegisterType((*QueryUpgradeResponse)(nil), "ibc.core.channel.v1.QueryUpgradeResponse") + proto.RegisterType((*QueryChannelParamsRequest)(nil), "ibc.core.channel.v1.QueryChannelParamsRequest") + proto.RegisterType((*QueryChannelParamsResponse)(nil), "ibc.core.channel.v1.QueryChannelParamsResponse") } func init() { proto.RegisterFile("ibc/core/channel/v1/query.proto", fileDescriptor_1034a1e9abc4cca1) } var fileDescriptor_1034a1e9abc4cca1 = []byte{ - // 1547 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x59, 0xcf, 0x6f, 0x13, 0x47, - 0x14, 0xce, 0x38, 0x06, 0x92, 0x07, 0x85, 0x30, 0x49, 0x4a, 0x58, 0x82, 0x13, 0x5c, 0xb5, 0x04, - 0x54, 0x76, 0x48, 0xa0, 0x34, 0xad, 0x5a, 0x24, 0x12, 0xa9, 0x90, 0xaa, 0xfc, 0xda, 0x94, 0x16, - 0x90, 0x5a, 0x77, 0xbd, 0x1e, 0x9c, 0x55, 0xe2, 0x5d, 0xe3, 0x5d, 0x1b, 0x50, 0xea, 0xaa, 0xea, - 0x81, 0x72, 0xac, 0xca, 0xa1, 0x52, 0x2f, 0x95, 0x7a, 0x2a, 0x87, 0x1e, 0xfa, 0x17, 0xf4, 0xca, - 0xad, 0x48, 0xf4, 0x50, 0x09, 0x89, 0x56, 0x04, 0x89, 0x5e, 0x7b, 0xe9, 0xb9, 0xda, 0xf9, 0xb1, - 0xde, 0xb5, 0x77, 0x37, 0x76, 0x1c, 0x4b, 0x51, 0x6f, 0xde, 0x99, 0x79, 0x6f, 0xbe, 0xef, 0x7b, - 0xf3, 0xde, 0xce, 0x5b, 0xc3, 0x84, 0x99, 0x37, 0x88, 0x61, 0x57, 0x28, 0x31, 0x96, 0x74, 0xcb, - 0xa2, 0x2b, 0xa4, 0x36, 0x4d, 0x6e, 0x56, 0x69, 0xe5, 0x8e, 0x5a, 0xae, 0xd8, 0xae, 0x8d, 0x87, - 0xcd, 0xbc, 0xa1, 0x7a, 0x0b, 0x54, 0xb1, 0x40, 0xad, 0x4d, 0x2b, 0x01, 0xab, 0x15, 0x93, 0x5a, - 0xae, 0x67, 0xc4, 0x7f, 0x71, 0x2b, 0xe5, 0xa8, 0x61, 0x3b, 0x25, 0xdb, 0x21, 0x79, 0xdd, 0xa1, - 0xdc, 0x1d, 0xa9, 0x4d, 0xe7, 0xa9, 0xab, 0x4f, 0x93, 0xb2, 0x5e, 0x34, 0x2d, 0xdd, 0x35, 0x6d, - 0x4b, 0xac, 0x3d, 0x14, 0x05, 0x41, 0x6e, 0xc6, 0x97, 0x8c, 0x17, 0x6d, 0xbb, 0xb8, 0x42, 0x89, - 0x5e, 0x36, 0x89, 0x6e, 0x59, 0xb6, 0xcb, 0xec, 0x1d, 0x31, 0xbb, 0x5f, 0xcc, 0xb2, 0xa7, 0x7c, - 0xf5, 0x06, 0xd1, 0x2d, 0x81, 0x5e, 0x19, 0x29, 0xda, 0x45, 0x9b, 0xfd, 0x24, 0xde, 0x2f, 0x3e, - 0x9a, 0x3d, 0x0f, 0xc3, 0x97, 0x3d, 0x4c, 0xf3, 0x7c, 0x13, 0x8d, 0xde, 0xac, 0x52, 0xc7, 0xc5, - 0xfb, 0x60, 0x47, 0xd9, 0xae, 0xb8, 0x39, 0xb3, 0x30, 0x86, 0x26, 0xd1, 0xd4, 0xa0, 0xb6, 0xdd, - 0x7b, 0x5c, 0x28, 0xe0, 0x83, 0x00, 0x02, 0x8f, 0x37, 0x97, 0x62, 0x73, 0x83, 0x62, 0x64, 0xa1, - 0x90, 0x7d, 0x80, 0x60, 0x24, 0xec, 0xcf, 0x29, 0xdb, 0x96, 0x43, 0xf1, 0x29, 0xd8, 0x21, 0x56, - 0x31, 0x87, 0x3b, 0x67, 0xc6, 0xd5, 0x08, 0x35, 0x55, 0x69, 0x26, 0x17, 0xe3, 0x11, 0xd8, 0x56, - 0xae, 0xd8, 0xf6, 0x0d, 0xb6, 0xd5, 0x2e, 0x8d, 0x3f, 0xe0, 0x79, 0xd8, 0xc5, 0x7e, 0xe4, 0x96, - 0xa8, 0x59, 0x5c, 0x72, 0xc7, 0xfa, 0x99, 0x4b, 0x25, 0xe0, 0x92, 0x47, 0xa0, 0x36, 0xad, 0x9e, - 0x63, 0x2b, 0xe6, 0xd2, 0x0f, 0x9f, 0x4e, 0xf4, 0x69, 0x3b, 0x99, 0x15, 0x1f, 0xca, 0x7e, 0x1a, - 0x86, 0xea, 0x48, 0xee, 0xef, 0x01, 0x34, 0x02, 0x23, 0xd0, 0xbe, 0xa6, 0xf2, 0x28, 0xaa, 0x5e, - 0x14, 0x55, 0x7e, 0x28, 0x44, 0x14, 0xd5, 0x4b, 0x7a, 0x91, 0x0a, 0x5b, 0x2d, 0x60, 0x99, 0x7d, - 0x8a, 0x60, 0xb4, 0x69, 0x03, 0x21, 0xc6, 0x1c, 0x0c, 0x08, 0x7e, 0xce, 0x18, 0x9a, 0xec, 0x67, - 0xfe, 0xa3, 0xd4, 0x58, 0x28, 0x50, 0xcb, 0x35, 0x6f, 0x98, 0xb4, 0x20, 0x75, 0xf1, 0xed, 0xf0, - 0xd9, 0x10, 0xca, 0x14, 0x43, 0x79, 0x78, 0x5d, 0x94, 0x1c, 0x40, 0x10, 0x26, 0x9e, 0x85, 0xed, - 0x1d, 0xaa, 0x28, 0xd6, 0x67, 0xef, 0x21, 0xc8, 0x70, 0x82, 0xb6, 0x65, 0x51, 0xc3, 0xf3, 0xd6, - 0xac, 0x65, 0x06, 0xc0, 0xf0, 0x27, 0xc5, 0x51, 0x0a, 0x8c, 0x34, 0x69, 0x9d, 0xda, 0xb0, 0xd6, - 0x7f, 0x23, 0x98, 0x88, 0x85, 0xf2, 0xff, 0x52, 0xfd, 0xaa, 0x14, 0x9d, 0x63, 0x9a, 0x67, 0xab, - 0x17, 0x5d, 0xdd, 0xa5, 0xdd, 0x26, 0xef, 0x9f, 0xbe, 0x88, 0x11, 0xae, 0x85, 0x88, 0x3a, 0xec, - 0x33, 0x7d, 0x7d, 0x72, 0x1c, 0x6a, 0xce, 0xf1, 0x96, 0x88, 0x4c, 0x39, 0x12, 0x45, 0x24, 0x20, - 0x69, 0xc0, 0xe7, 0xa8, 0x19, 0x35, 0xdc, 0xcb, 0x94, 0xff, 0x19, 0xc1, 0xa1, 0x10, 0x43, 0x8f, - 0x93, 0xe5, 0x54, 0x9d, 0xcd, 0xd0, 0x0f, 0x1f, 0x86, 0x3d, 0x15, 0x5a, 0x33, 0x1d, 0xd3, 0xb6, - 0x72, 0x56, 0xb5, 0x94, 0xa7, 0x15, 0x86, 0x32, 0xad, 0xed, 0x96, 0xc3, 0x17, 0xd8, 0x68, 0x68, - 0xa1, 0xa0, 0x93, 0x0e, 0x2f, 0x14, 0x78, 0x9f, 0x20, 0xc8, 0x26, 0xe1, 0x15, 0x41, 0x79, 0x17, - 0xf6, 0x18, 0x72, 0x26, 0x14, 0x8c, 0x11, 0x95, 0xbf, 0x0f, 0x54, 0xf9, 0x3e, 0x50, 0xcf, 0x58, - 0x77, 0xb4, 0xdd, 0x46, 0xc8, 0x0d, 0x3e, 0x00, 0x83, 0x22, 0x90, 0x3e, 0xab, 0x01, 0x3e, 0xb0, - 0x50, 0x68, 0x44, 0xa3, 0x3f, 0x29, 0x1a, 0xe9, 0x8d, 0x44, 0xa3, 0x02, 0xe3, 0x8c, 0xdc, 0x25, - 0xdd, 0x58, 0xa6, 0xee, 0xbc, 0x5d, 0x2a, 0x99, 0x6e, 0x89, 0x5a, 0x6e, 0xb7, 0x71, 0x50, 0x60, - 0xc0, 0xf1, 0x5c, 0x58, 0x06, 0x15, 0x01, 0xf0, 0x9f, 0xb3, 0xdf, 0x23, 0x38, 0x18, 0xb3, 0xa9, - 0x10, 0x93, 0x95, 0x2c, 0x39, 0xca, 0x36, 0xde, 0xa5, 0x05, 0x46, 0x7a, 0x79, 0x3c, 0x7f, 0x88, - 0x03, 0xe7, 0x74, 0x2b, 0x49, 0xb8, 0xce, 0xf6, 0x6f, 0xb8, 0xce, 0xbe, 0x90, 0x25, 0x3f, 0x02, - 0xa1, 0x5f, 0x66, 0x77, 0x36, 0xd4, 0x92, 0x95, 0x76, 0x32, 0xb2, 0xd2, 0x72, 0x27, 0xfc, 0x2c, - 0x07, 0x8d, 0xb6, 0x42, 0x99, 0xb5, 0x61, 0x7f, 0x80, 0xa8, 0x46, 0x0d, 0x6a, 0x96, 0x7b, 0x7a, - 0x32, 0xef, 0x23, 0x50, 0xa2, 0x76, 0x14, 0xb2, 0x2a, 0x30, 0x50, 0xf1, 0x86, 0x6a, 0x94, 0xfb, - 0x1d, 0xd0, 0xfc, 0xe7, 0x5e, 0xe6, 0xe8, 0x2d, 0x51, 0x30, 0x39, 0xa8, 0x33, 0xc6, 0xb2, 0x65, - 0xdf, 0x5a, 0xa1, 0x85, 0x22, 0xed, 0x75, 0xa2, 0x3e, 0x90, 0xa5, 0x2f, 0x66, 0x67, 0x21, 0xcb, - 0x14, 0xec, 0xd1, 0xc3, 0x53, 0x22, 0x65, 0x9b, 0x87, 0x7b, 0x99, 0xb7, 0xcf, 0x13, 0xb1, 0x6e, - 0x95, 0xe4, 0xc5, 0xa7, 0xe1, 0x40, 0x99, 0x01, 0xcc, 0x35, 0x72, 0x2d, 0x27, 0x05, 0x77, 0xc6, - 0xd2, 0x93, 0xfd, 0x53, 0x69, 0x6d, 0x7f, 0xb9, 0x29, 0xb3, 0x17, 0xe5, 0x82, 0xec, 0xbf, 0x08, - 0x5e, 0x49, 0xa4, 0x29, 0x62, 0xf2, 0x01, 0x0c, 0x35, 0x89, 0xdf, 0x7e, 0x19, 0x68, 0xb1, 0xdc, - 0x0a, 0xb5, 0xe0, 0x3b, 0x59, 0x97, 0xaf, 0x58, 0x32, 0xe7, 0x38, 0xe6, 0xae, 0x43, 0xbb, 0x4e, - 0x48, 0xfa, 0xd7, 0x0b, 0xc9, 0x6d, 0x51, 0x8e, 0x23, 0x80, 0x89, 0x60, 0x8c, 0xc3, 0x60, 0xc3, - 0x1f, 0x62, 0xfe, 0x1a, 0x03, 0x01, 0x4d, 0x52, 0x1d, 0x6a, 0x72, 0x57, 0x96, 0xab, 0xc6, 0xd6, - 0x67, 0x8c, 0xe5, 0xae, 0x05, 0x39, 0x0e, 0x23, 0x42, 0x10, 0xdd, 0x58, 0x6e, 0x51, 0x02, 0x97, - 0xe5, 0xc9, 0x6b, 0x48, 0x50, 0x85, 0x03, 0x91, 0x38, 0x7a, 0xcc, 0xff, 0x9a, 0xb8, 0x2b, 0x5f, - 0xa0, 0xb7, 0xfd, 0x78, 0x68, 0x1c, 0x40, 0xb7, 0xf7, 0xf0, 0x5f, 0x10, 0x4c, 0xc6, 0xfb, 0x16, - 0xbc, 0x66, 0x60, 0xd4, 0xa2, 0xb7, 0x1b, 0x87, 0x25, 0x27, 0xd8, 0xb3, 0xad, 0xd2, 0xda, 0xb0, - 0xd5, 0x6a, 0xdb, 0xcb, 0x12, 0xf8, 0x91, 0xb8, 0xcb, 0x05, 0x21, 0x2f, 0x52, 0xab, 0xd0, 0xad, - 0x16, 0x3f, 0xc9, 0xd4, 0x6b, 0x75, 0x2c, 0x84, 0x78, 0x1d, 0x70, 0x58, 0x08, 0x87, 0x5a, 0x05, - 0xa1, 0xc2, 0x90, 0xd5, 0x64, 0xd5, 0x43, 0x09, 0x66, 0x9e, 0xee, 0x83, 0x6d, 0x0c, 0x2a, 0xfe, - 0x11, 0xc1, 0x0e, 0x71, 0x63, 0xc7, 0x53, 0x91, 0x25, 0x2f, 0xe2, 0x9b, 0x8b, 0x72, 0xa4, 0x8d, - 0x95, 0x9c, 0x73, 0x76, 0xee, 0xab, 0xc7, 0xcf, 0xef, 0xa7, 0xde, 0xc1, 0x6f, 0x93, 0x84, 0x0f, - 0x46, 0x0e, 0x59, 0x6d, 0x28, 0x5b, 0x27, 0x9e, 0xde, 0x0e, 0x59, 0x15, 0x51, 0xa8, 0xe3, 0x7b, - 0x08, 0x06, 0x64, 0x8f, 0x8c, 0xd7, 0xdf, 0x5b, 0x66, 0xb6, 0x72, 0xb4, 0x9d, 0xa5, 0x02, 0xe7, - 0xab, 0x0c, 0xe7, 0x04, 0x3e, 0x98, 0x88, 0x13, 0xff, 0x8a, 0x00, 0xb7, 0x36, 0xee, 0xf8, 0x44, - 0xc2, 0x4e, 0x71, 0x5f, 0x1c, 0x94, 0x93, 0x9d, 0x19, 0x09, 0xa0, 0xa7, 0x19, 0xd0, 0x59, 0x7c, - 0x2a, 0x1a, 0xa8, 0x6f, 0xe8, 0x69, 0xea, 0x3f, 0xd4, 0x1b, 0x0c, 0x1e, 0x79, 0x0c, 0x5a, 0xba, - 0xe6, 0x44, 0x06, 0x71, 0xed, 0x7b, 0x22, 0x83, 0xd8, 0xc6, 0x3c, 0x7b, 0x91, 0x31, 0x58, 0xc0, - 0x67, 0x37, 0x7e, 0x24, 0x48, 0xb0, 0x9d, 0xc7, 0xdf, 0xa6, 0x60, 0x34, 0xb2, 0xed, 0xc4, 0xa7, - 0xd6, 0x07, 0x18, 0xd5, 0x57, 0x2b, 0x6f, 0x76, 0x6c, 0x27, 0xb8, 0x7d, 0x8d, 0x18, 0xb9, 0x2f, - 0x11, 0xfe, 0xa2, 0x1b, 0x76, 0xe1, 0x16, 0x99, 0xc8, 0x5e, 0x9b, 0xac, 0x36, 0x75, 0xed, 0x75, - 0xc2, 0xcb, 0x40, 0x60, 0x82, 0x0f, 0xd4, 0xf1, 0x13, 0x04, 0x43, 0xcd, 0xad, 0x0f, 0x9e, 0x8e, - 0xe7, 0x15, 0xd3, 0xda, 0x2a, 0x33, 0x9d, 0x98, 0x08, 0x15, 0x3e, 0x63, 0x22, 0x5c, 0xc7, 0x57, - 0xbb, 0xd0, 0xa0, 0xe5, 0xb2, 0xe1, 0x90, 0x55, 0x59, 0x38, 0xeb, 0xf8, 0x31, 0x82, 0xbd, 0x2d, - 0x8d, 0x1d, 0xee, 0x00, 0xab, 0x9f, 0x85, 0x27, 0x3a, 0xb2, 0x11, 0x04, 0xaf, 0x30, 0x82, 0x17, - 0xf1, 0xf9, 0x4d, 0x25, 0x88, 0x7f, 0x43, 0xf0, 0x52, 0xa8, 0xa7, 0xc2, 0xea, 0x7a, 0xe8, 0xc2, - 0xed, 0x9e, 0x42, 0xda, 0x5e, 0x2f, 0x98, 0x7c, 0xc2, 0x98, 0x7c, 0x8c, 0xaf, 0x74, 0xcf, 0xa4, - 0xc2, 0x5d, 0x87, 0xe2, 0xb4, 0x86, 0x60, 0x34, 0xf2, 0x0e, 0x9e, 0x94, 0x9a, 0x49, 0x1d, 0x5c, - 0x52, 0x6a, 0x26, 0xf6, 0x5f, 0xd9, 0x6b, 0x8c, 0xe9, 0x22, 0xbe, 0xdc, 0x3d, 0x53, 0xdd, 0x58, - 0x0e, 0xb1, 0x7c, 0x81, 0xe0, 0xe5, 0xe8, 0x4e, 0x03, 0x77, 0x0a, 0xd7, 0x3f, 0x97, 0xb3, 0x9d, - 0x1b, 0x0a, 0xa2, 0xd7, 0x19, 0xd1, 0x0f, 0xb1, 0xb6, 0x29, 0x44, 0xc3, 0x74, 0xee, 0xa6, 0x60, - 0x6f, 0xcb, 0x0d, 0x3e, 0x29, 0xef, 0xe2, 0xfa, 0x90, 0xa4, 0xbc, 0x8b, 0x6d, 0x11, 0x36, 0xa9, - 0xbc, 0x46, 0x95, 0x96, 0x84, 0xde, 0xa6, 0x4e, 0xaa, 0x3e, 0xa0, 0x5c, 0x59, 0x50, 0xfe, 0x07, - 0xc1, 0xee, 0xf0, 0x3d, 0x1e, 0x93, 0x76, 0x18, 0x05, 0x3a, 0x0f, 0xe5, 0x78, 0xfb, 0x06, 0x82, - 0xff, 0xe7, 0x8c, 0x7e, 0x0d, 0xbb, 0xbd, 0x61, 0x1f, 0x6a, 0x64, 0x42, 0xb4, 0xbd, 0x13, 0x8f, - 0x7f, 0x47, 0x30, 0x1c, 0x71, 0xd1, 0xc7, 0x09, 0xd7, 0x80, 0xf8, 0x9e, 0x43, 0x79, 0xa3, 0x43, - 0x2b, 0x21, 0xc1, 0x25, 0x26, 0xc1, 0xfb, 0xf8, 0x5c, 0x17, 0x12, 0x84, 0x6e, 0xe1, 0xde, 0x8d, - 0x68, 0xa8, 0xf9, 0xce, 0x9e, 0xf4, 0xa6, 0x8c, 0x69, 0x1c, 0x92, 0xde, 0x94, 0x71, 0x2d, 0xc1, - 0xa6, 0xbc, 0x48, 0x5a, 0x7b, 0x8a, 0xb9, 0xc5, 0x87, 0xcf, 0x32, 0xe8, 0xd1, 0xb3, 0x0c, 0xfa, - 0xeb, 0x59, 0x06, 0x7d, 0xb3, 0x96, 0xe9, 0x7b, 0xb4, 0x96, 0xe9, 0xfb, 0x63, 0x2d, 0xd3, 0x77, - 0xfd, 0xad, 0xa2, 0xe9, 0x2e, 0x55, 0xf3, 0xaa, 0x61, 0x97, 0x88, 0xf8, 0xbb, 0xd7, 0xcc, 0x1b, - 0xc7, 0x8a, 0x36, 0xa9, 0xcd, 0x92, 0x92, 0x5d, 0xa8, 0xae, 0x50, 0x87, 0xe3, 0x38, 0x7e, 0xf2, - 0x98, 0x84, 0xe2, 0xde, 0x29, 0x53, 0x27, 0xbf, 0x9d, 0x7d, 0x9a, 0x3f, 0xf1, 0x5f, 0x00, 0x00, - 0x00, 0xff, 0xff, 0xfa, 0x61, 0xcc, 0x20, 0x7e, 0x1e, 0x00, 0x00, + // 1757 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x5a, 0xcf, 0x6f, 0x14, 0x47, + 0x16, 0x76, 0xd9, 0xc6, 0x3f, 0x0a, 0x03, 0xa6, 0x6c, 0x2f, 0xa6, 0x6d, 0x8f, 0xcd, 0xa0, 0x5d, + 0x0c, 0x5a, 0xba, 0xb1, 0xcd, 0xb2, 0xde, 0x15, 0x8b, 0x84, 0xbd, 0xbb, 0x60, 0xb4, 0x80, 0x69, + 0x2f, 0x09, 0x20, 0x25, 0x93, 0x9e, 0x9e, 0x62, 0xdc, 0xb2, 0xa7, 0xbb, 0x99, 0xee, 0x19, 0x40, + 0x8e, 0xa3, 0x28, 0x07, 0xc2, 0x31, 0x0a, 0x8a, 0x22, 0xe5, 0x12, 0x29, 0xa7, 0x10, 0x29, 0x8a, + 0xf2, 0x17, 0xe4, 0x92, 0x03, 0xb7, 0x20, 0x91, 0x43, 0x24, 0x24, 0x12, 0x61, 0x22, 0x72, 0xcd, + 0x25, 0xe7, 0xa8, 0xab, 0x5e, 0xf5, 0x74, 0xcf, 0x74, 0xb7, 0x3d, 0x6e, 0x8f, 0x84, 0x72, 0x9b, + 0xae, 0xae, 0xf7, 0xea, 0xfb, 0xbe, 0x57, 0xf5, 0xba, 0xde, 0xb3, 0xf1, 0xb8, 0x91, 0xd7, 0x15, + 0xdd, 0x2a, 0x53, 0x45, 0x5f, 0xd6, 0x4c, 0x93, 0xae, 0x2a, 0xd5, 0x29, 0xe5, 0x56, 0x85, 0x96, + 0xef, 0xca, 0x76, 0xd9, 0x72, 0x2d, 0x32, 0x60, 0xe4, 0x75, 0xd9, 0x9b, 0x20, 0xc3, 0x04, 0xb9, + 0x3a, 0x25, 0x05, 0xac, 0x56, 0x0d, 0x6a, 0xba, 0x9e, 0x11, 0xff, 0xc5, 0xad, 0xa4, 0x63, 0xba, + 0xe5, 0x94, 0x2c, 0x47, 0xc9, 0x6b, 0x0e, 0xe5, 0xee, 0x94, 0xea, 0x54, 0x9e, 0xba, 0xda, 0x94, + 0x62, 0x6b, 0x45, 0xc3, 0xd4, 0x5c, 0xc3, 0x32, 0x61, 0xee, 0xa1, 0x28, 0x08, 0x62, 0x31, 0x3e, + 0x65, 0xb4, 0x68, 0x59, 0xc5, 0x55, 0xaa, 0x68, 0xb6, 0xa1, 0x68, 0xa6, 0x69, 0xb9, 0xcc, 0xde, + 0x81, 0xb7, 0x07, 0xe1, 0x2d, 0x7b, 0xca, 0x57, 0x6e, 0x2a, 0x9a, 0x09, 0xe8, 0xa5, 0xc1, 0xa2, + 0x55, 0xb4, 0xd8, 0x4f, 0xc5, 0xfb, 0x95, 0xb4, 0x62, 0xc5, 0x2e, 0x96, 0xb5, 0x02, 0xe5, 0x53, + 0xb2, 0x17, 0xf1, 0xc0, 0x15, 0x0f, 0xf6, 0x3c, 0x9f, 0xa0, 0xd2, 0x5b, 0x15, 0xea, 0xb8, 0xe4, + 0x00, 0xee, 0xb6, 0xad, 0xb2, 0x9b, 0x33, 0x0a, 0xc3, 0x68, 0x02, 0x4d, 0xf6, 0xaa, 0x5d, 0xde, + 0xe3, 0x42, 0x81, 0x8c, 0x61, 0x0c, 0xbe, 0xbc, 0x77, 0xed, 0xec, 0x5d, 0x2f, 0x8c, 0x2c, 0x14, + 0xb2, 0x0f, 0x11, 0x1e, 0x0c, 0xfb, 0x73, 0x6c, 0xcb, 0x74, 0x28, 0x39, 0x85, 0xbb, 0x61, 0x16, + 0x73, 0xb8, 0x7b, 0x7a, 0x54, 0x8e, 0x10, 0x5c, 0x16, 0x66, 0x62, 0x32, 0x19, 0xc4, 0xbb, 0xec, + 0xb2, 0x65, 0xdd, 0x64, 0x4b, 0xf5, 0xa9, 0xfc, 0x81, 0xcc, 0xe3, 0x3e, 0xf6, 0x23, 0xb7, 0x4c, + 0x8d, 0xe2, 0xb2, 0x3b, 0xdc, 0xc1, 0x5c, 0x4a, 0x01, 0x97, 0x3c, 0x48, 0xd5, 0x29, 0xf9, 0x3c, + 0x9b, 0x31, 0xd7, 0xf9, 0xe8, 0xd9, 0x78, 0x9b, 0xba, 0x9b, 0x59, 0xf1, 0xa1, 0xec, 0x9b, 0x61, + 0xa8, 0x8e, 0xe0, 0xfe, 0x5f, 0x8c, 0x6b, 0xb1, 0x03, 0xb4, 0x7f, 0x91, 0x79, 0xa0, 0x65, 0x2f, + 0xd0, 0x32, 0xdf, 0x37, 0x10, 0x68, 0x79, 0x51, 0x2b, 0x52, 0xb0, 0x55, 0x03, 0x96, 0xd9, 0x67, + 0x08, 0x0f, 0xd5, 0x2d, 0x00, 0x62, 0xcc, 0xe1, 0x1e, 0xe0, 0xe7, 0x0c, 0xa3, 0x89, 0x0e, 0xe6, + 0x3f, 0x4a, 0x8d, 0x85, 0x02, 0x35, 0x5d, 0xe3, 0xa6, 0x41, 0x0b, 0x42, 0x17, 0xdf, 0x8e, 0x9c, + 0x0b, 0xa1, 0x6c, 0x67, 0x28, 0x8f, 0x6c, 0x8a, 0x92, 0x03, 0x08, 0xc2, 0x24, 0xb3, 0xb8, 0xab, + 0x49, 0x15, 0x61, 0x7e, 0xf6, 0x3e, 0xc2, 0x19, 0x4e, 0xd0, 0x32, 0x4d, 0xaa, 0x7b, 0xde, 0xea, + 0xb5, 0xcc, 0x60, 0xac, 0xfb, 0x2f, 0x61, 0x2b, 0x05, 0x46, 0xea, 0xb4, 0x6e, 0xdf, 0xb6, 0xd6, + 0xbf, 0x20, 0x3c, 0x1e, 0x0b, 0xe5, 0x8f, 0xa5, 0xfa, 0x35, 0x21, 0x3a, 0xc7, 0x34, 0xcf, 0x66, + 0x2f, 0xb9, 0x9a, 0x4b, 0xd3, 0x1e, 0xde, 0x1f, 0x7d, 0x11, 0x23, 0x5c, 0x83, 0x88, 0x1a, 0x3e, + 0x60, 0xf8, 0xfa, 0xe4, 0x38, 0xd4, 0x9c, 0xe3, 0x4d, 0x81, 0x93, 0x72, 0x34, 0x8a, 0x48, 0x40, + 0xd2, 0x80, 0xcf, 0x21, 0x23, 0x6a, 0xb8, 0x95, 0x47, 0xfe, 0x4b, 0x84, 0x0f, 0x85, 0x18, 0x7a, + 0x9c, 0x4c, 0xa7, 0xe2, 0xec, 0x84, 0x7e, 0xe4, 0x08, 0xde, 0x57, 0xa6, 0x55, 0xc3, 0x31, 0x2c, + 0x33, 0x67, 0x56, 0x4a, 0x79, 0x5a, 0x66, 0x28, 0x3b, 0xd5, 0xbd, 0x62, 0xf8, 0x12, 0x1b, 0x0d, + 0x4d, 0x04, 0x3a, 0x9d, 0xe1, 0x89, 0x80, 0xf7, 0x29, 0xc2, 0xd9, 0x24, 0xbc, 0x10, 0x94, 0x7f, + 0xe1, 0x7d, 0xba, 0x78, 0x13, 0x0a, 0xc6, 0xa0, 0xcc, 0x3f, 0x19, 0xb2, 0xf8, 0x64, 0xc8, 0x67, + 0xcd, 0xbb, 0xea, 0x5e, 0x3d, 0xe4, 0x86, 0x8c, 0xe0, 0x5e, 0x08, 0xa4, 0xcf, 0xaa, 0x87, 0x0f, + 0x2c, 0x14, 0x6a, 0xd1, 0xe8, 0x48, 0x8a, 0x46, 0xe7, 0x76, 0xa2, 0x51, 0xc6, 0xa3, 0x8c, 0xdc, + 0xa2, 0xa6, 0xaf, 0x50, 0x77, 0xde, 0x2a, 0x95, 0x0c, 0xb7, 0x44, 0x4d, 0x37, 0x6d, 0x1c, 0x24, + 0xdc, 0xe3, 0x78, 0x2e, 0x4c, 0x9d, 0x42, 0x00, 0xfc, 0xe7, 0xec, 0x27, 0x08, 0x8f, 0xc5, 0x2c, + 0x0a, 0x62, 0xb2, 0x94, 0x25, 0x46, 0xd9, 0xc2, 0x7d, 0x6a, 0x60, 0xa4, 0x95, 0xdb, 0xf3, 0xd3, + 0x38, 0x70, 0x4e, 0x5a, 0x49, 0xc2, 0x79, 0xb6, 0x63, 0xdb, 0x79, 0xf6, 0xa5, 0x48, 0xf9, 0x11, + 0x08, 0xfd, 0x34, 0xbb, 0xbb, 0xa6, 0x96, 0xc8, 0xb4, 0x13, 0x91, 0x99, 0x96, 0x3b, 0xe1, 0x7b, + 0x39, 0x68, 0xf4, 0x2a, 0xa4, 0x59, 0x0b, 0x1f, 0x0c, 0x10, 0x55, 0xa9, 0x4e, 0x0d, 0xbb, 0xa5, + 0x3b, 0xf3, 0x01, 0xc2, 0x52, 0xd4, 0x8a, 0x20, 0xab, 0x84, 0x7b, 0xca, 0xde, 0x50, 0x95, 0x72, + 0xbf, 0x3d, 0xaa, 0xff, 0xdc, 0xca, 0x33, 0x7a, 0x1b, 0x12, 0x26, 0x07, 0x75, 0x56, 0x5f, 0x31, + 0xad, 0xdb, 0xab, 0xb4, 0x50, 0xa4, 0xad, 0x3e, 0xa8, 0x0f, 0x45, 0xea, 0x8b, 0x59, 0x19, 0x64, + 0x99, 0xc4, 0xfb, 0xb4, 0xf0, 0x2b, 0x38, 0xb2, 0xf5, 0xc3, 0xad, 0x3c, 0xb7, 0x2f, 0x12, 0xb1, + 0xbe, 0x2a, 0x87, 0x97, 0x9c, 0xc1, 0x23, 0x36, 0x03, 0x98, 0xab, 0x9d, 0xb5, 0x9c, 0x10, 0xdc, + 0x19, 0xee, 0x9c, 0xe8, 0x98, 0xec, 0x54, 0x0f, 0xda, 0x75, 0x27, 0x7b, 0x49, 0x4c, 0xc8, 0xfe, + 0x86, 0xf0, 0xe1, 0x44, 0x9a, 0x10, 0x93, 0xff, 0xe1, 0xfe, 0x3a, 0xf1, 0xb7, 0x9e, 0x06, 0x1a, + 0x2c, 0x5f, 0x85, 0x5c, 0xf0, 0xb1, 0xc8, 0xcb, 0x57, 0x4d, 0x71, 0xe6, 0x38, 0xe6, 0xd4, 0xa1, + 0xdd, 0x24, 0x24, 0x1d, 0x9b, 0x85, 0xe4, 0x0e, 0xa4, 0xe3, 0x08, 0x60, 0x10, 0x8c, 0x51, 0xdc, + 0x5b, 0xf3, 0x87, 0x98, 0xbf, 0xda, 0x40, 0x40, 0x93, 0xf6, 0x26, 0x35, 0xb9, 0x27, 0xd2, 0x55, + 0x6d, 0xe9, 0xb3, 0xfa, 0x4a, 0x6a, 0x41, 0x4e, 0xe0, 0x41, 0x10, 0x44, 0xd3, 0x57, 0x1a, 0x94, + 0x20, 0xb6, 0xd8, 0x79, 0x35, 0x09, 0x2a, 0x78, 0x24, 0x12, 0x47, 0x8b, 0xf9, 0x5f, 0x87, 0xbb, + 0xf2, 0x25, 0x7a, 0xc7, 0x8f, 0x87, 0xca, 0x01, 0xa4, 0xbd, 0x87, 0x7f, 0x8d, 0xf0, 0x44, 0xbc, + 0x6f, 0xe0, 0x35, 0x8d, 0x87, 0x4c, 0x7a, 0xa7, 0xb6, 0x59, 0x72, 0xc0, 0x9e, 0x2d, 0xd5, 0xa9, + 0x0e, 0x98, 0x8d, 0xb6, 0xad, 0x4c, 0x81, 0xaf, 0xc1, 0x5d, 0x2e, 0x08, 0x79, 0x89, 0x9a, 0x85, + 0xb4, 0x5a, 0x7c, 0x2e, 0x8e, 0x5e, 0xa3, 0x63, 0x10, 0xe2, 0xaf, 0x98, 0x84, 0x85, 0x70, 0xa8, + 0x59, 0x00, 0x15, 0xfa, 0xcd, 0x3a, 0xab, 0x56, 0x4a, 0xa0, 0xe2, 0x61, 0xbe, 0x11, 0x79, 0x83, + 0xe5, 0x3f, 0xe5, 0xb2, 0x55, 0x4e, 0x4b, 0xff, 0x5b, 0x04, 0xd7, 0x90, 0xb0, 0x53, 0x3f, 0xd1, + 0xee, 0xa1, 0xde, 0x00, 0x8f, 0xbd, 0xed, 0xc2, 0xad, 0xff, 0x50, 0x64, 0x96, 0x05, 0x53, 0x36, + 0x11, 0xe0, 0xf7, 0xd1, 0xc0, 0x58, 0x2b, 0xa5, 0x11, 0x5d, 0x26, 0x60, 0x91, 0x56, 0x95, 0xaf, + 0x44, 0x97, 0xc9, 0xf7, 0x07, 0x82, 0x9c, 0xc6, 0xdd, 0xd0, 0xde, 0x4a, 0xec, 0x32, 0x81, 0x19, + 0x20, 0x15, 0x26, 0xad, 0x14, 0x60, 0x04, 0xc2, 0x08, 0x75, 0xdc, 0xa2, 0x56, 0xd6, 0x4a, 0x22, + 0x57, 0x66, 0xaf, 0x40, 0x26, 0xad, 0x7b, 0x09, 0x9c, 0x66, 0x70, 0x97, 0xcd, 0x46, 0x80, 0xd2, + 0x48, 0xcc, 0x37, 0x94, 0x19, 0xc1, 0xd4, 0xe9, 0x9f, 0x47, 0xf0, 0x2e, 0xe6, 0x93, 0x7c, 0x86, + 0x70, 0x37, 0x38, 0x26, 0x93, 0x91, 0xa6, 0x11, 0xfd, 0x3f, 0xe9, 0xe8, 0x16, 0x66, 0x72, 0x7c, + 0xd9, 0xb9, 0xf7, 0x9e, 0xbc, 0x78, 0xd0, 0x7e, 0x9a, 0xfc, 0x53, 0x49, 0xe8, 0x6f, 0x3a, 0xca, + 0x5a, 0x2d, 0xa0, 0xeb, 0x8a, 0x17, 0x66, 0x47, 0x59, 0x83, 0xe0, 0xaf, 0x93, 0xfb, 0x08, 0xf7, + 0x88, 0x7e, 0x0d, 0xd9, 0x7c, 0x6d, 0xa1, 0x9c, 0x74, 0x6c, 0x2b, 0x53, 0x01, 0xe7, 0x9f, 0x19, + 0xce, 0x71, 0x32, 0x96, 0x88, 0x93, 0x7c, 0x83, 0x30, 0x69, 0x6c, 0x22, 0x91, 0x99, 0x84, 0x95, + 0xe2, 0xba, 0x5f, 0xd2, 0xc9, 0xe6, 0x8c, 0x00, 0xe8, 0x19, 0x06, 0x74, 0x96, 0x9c, 0x8a, 0x06, + 0xea, 0x1b, 0x7a, 0x9a, 0xfa, 0x0f, 0xeb, 0x35, 0x06, 0x8f, 0x3d, 0x06, 0x0d, 0x1d, 0x9c, 0x44, + 0x06, 0x71, 0xad, 0xa4, 0x44, 0x06, 0xb1, 0x4d, 0xa2, 0xec, 0x65, 0xc6, 0x60, 0x81, 0x9c, 0xdb, + 0xfe, 0x96, 0x50, 0x82, 0xad, 0x25, 0xf2, 0x61, 0x3b, 0x1e, 0x8a, 0x6c, 0x81, 0x90, 0x53, 0x9b, + 0x03, 0x8c, 0xea, 0xf1, 0x48, 0x7f, 0x6f, 0xda, 0x0e, 0xb8, 0xbd, 0x8f, 0x18, 0xb9, 0x77, 0x11, + 0x79, 0x27, 0x0d, 0xbb, 0x70, 0xbb, 0x46, 0x11, 0x7d, 0x1f, 0x65, 0xad, 0xae, 0x83, 0xb4, 0xae, + 0xf0, 0xb4, 0x13, 0x78, 0xc1, 0x07, 0xd6, 0xc9, 0x53, 0x84, 0xfb, 0xeb, 0xcb, 0x70, 0x32, 0x15, + 0xcf, 0x2b, 0xa6, 0xcd, 0x22, 0x4d, 0x37, 0x63, 0x02, 0x2a, 0xbc, 0xc5, 0x44, 0xb8, 0x41, 0xae, + 0xa5, 0xd0, 0xa0, 0xe1, 0xe2, 0xeb, 0x28, 0x6b, 0xe2, 0x23, 0xbe, 0x4e, 0x9e, 0x20, 0xbc, 0xbf, + 0xa1, 0xc9, 0x40, 0x9a, 0xc0, 0xea, 0x9f, 0xc2, 0x99, 0xa6, 0x6c, 0x80, 0xe0, 0x55, 0x46, 0xf0, + 0x32, 0xb9, 0xb8, 0xa3, 0x04, 0xc9, 0x77, 0x08, 0xef, 0x09, 0xd5, 0xf7, 0x44, 0xde, 0x0c, 0x5d, + 0xb8, 0xf5, 0x20, 0x29, 0x5b, 0x9e, 0x0f, 0x4c, 0xde, 0x60, 0x4c, 0x5e, 0x27, 0x57, 0xd3, 0x33, + 0x81, 0x6b, 0x46, 0x28, 0x4e, 0x1b, 0x08, 0x0f, 0x45, 0xd6, 0x83, 0x49, 0x47, 0x33, 0xa9, 0x9b, + 0x90, 0x74, 0x34, 0x13, 0x7b, 0x01, 0xd9, 0xeb, 0x8c, 0xe9, 0x12, 0xb9, 0x92, 0x9e, 0xa9, 0xa6, + 0xaf, 0x84, 0x58, 0xbe, 0x44, 0xf8, 0x4f, 0xd1, 0x55, 0x2f, 0x69, 0x16, 0xae, 0xbf, 0x2f, 0x67, + 0x9b, 0x37, 0x04, 0xa2, 0x37, 0x18, 0xd1, 0xff, 0x13, 0x75, 0x47, 0x88, 0x86, 0xe9, 0xdc, 0x6b, + 0xc7, 0xfb, 0x1b, 0xaa, 0xc9, 0xa4, 0x73, 0x17, 0x57, 0x13, 0x27, 0x9d, 0xbb, 0xd8, 0x72, 0x75, + 0x87, 0xd2, 0x6b, 0x54, 0x6a, 0x49, 0xa8, 0xb3, 0xd7, 0x95, 0x8a, 0x0f, 0x28, 0x67, 0x03, 0xe5, + 0x5f, 0x11, 0xde, 0x1b, 0xae, 0x29, 0x89, 0xb2, 0x15, 0x46, 0x81, 0x2a, 0x58, 0x3a, 0xb1, 0x75, + 0x03, 0xe0, 0xff, 0x36, 0xa3, 0x5f, 0x25, 0x6e, 0x6b, 0xd8, 0x87, 0x8a, 0xea, 0x10, 0x6d, 0x6f, + 0xc7, 0x93, 0xef, 0x11, 0x1e, 0x88, 0x28, 0x3a, 0x49, 0xc2, 0x35, 0x20, 0xbe, 0xfe, 0x95, 0xfe, + 0xd6, 0xa4, 0x15, 0x48, 0xb0, 0xc8, 0x24, 0xb8, 0x40, 0xce, 0xa7, 0x90, 0x20, 0x54, 0x11, 0x7a, + 0x37, 0xa2, 0xfe, 0xfa, 0xfa, 0x31, 0xe9, 0x4b, 0x19, 0x53, 0xc4, 0x26, 0x7d, 0x29, 0xe3, 0xca, + 0xd3, 0x1d, 0xf9, 0x90, 0x34, 0xd6, 0xb7, 0xde, 0x35, 0xb5, 0x2f, 0x58, 0x13, 0x92, 0xe3, 0x09, + 0x5b, 0xad, 0xb1, 0x20, 0x95, 0xe4, 0xad, 0x4e, 0xdf, 0xc1, 0xa0, 0x40, 0x9d, 0x95, 0x63, 0x55, + 0x27, 0xf9, 0x02, 0xe1, 0x6e, 0x58, 0x2a, 0xa9, 0x30, 0x09, 0x97, 0x8c, 0x49, 0x85, 0x49, 0x5d, + 0x31, 0x98, 0xbd, 0xc0, 0x20, 0xff, 0x9b, 0xcc, 0xa5, 0x87, 0x4c, 0x3e, 0x42, 0x78, 0x4f, 0xa8, + 0x3c, 0x4b, 0xfa, 0x6e, 0x47, 0x15, 0x79, 0x49, 0xdf, 0xed, 0xc8, 0xba, 0x2f, 0x7b, 0x98, 0xc1, + 0x1f, 0x23, 0x23, 0x91, 0xf0, 0x79, 0x9d, 0x37, 0xb7, 0xf4, 0xe8, 0x79, 0x06, 0x3d, 0x7e, 0x9e, + 0x41, 0x3f, 0x3d, 0xcf, 0xa0, 0x0f, 0x36, 0x32, 0x6d, 0x8f, 0x37, 0x32, 0x6d, 0x3f, 0x6c, 0x64, + 0xda, 0x6e, 0xfc, 0xa3, 0x68, 0xb8, 0xcb, 0x95, 0xbc, 0xac, 0x5b, 0x25, 0x05, 0xfe, 0x49, 0xc5, + 0xc8, 0xeb, 0xc7, 0x8b, 0x96, 0x52, 0x9d, 0x55, 0x4a, 0x56, 0xa1, 0xb2, 0x4a, 0x1d, 0xee, 0xf5, + 0xc4, 0xc9, 0xe3, 0xc2, 0xb1, 0x7b, 0xd7, 0xa6, 0x4e, 0xbe, 0x8b, 0xfd, 0xb5, 0x70, 0xe6, 0xf7, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x50, 0xcd, 0xd6, 0x34, 0x23, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1979,6 +2313,12 @@ type QueryClient interface { NextSequenceReceive(ctx context.Context, in *QueryNextSequenceReceiveRequest, opts ...grpc.CallOption) (*QueryNextSequenceReceiveResponse, error) // NextSequenceSend returns the next send sequence for a given channel. NextSequenceSend(ctx context.Context, in *QueryNextSequenceSendRequest, opts ...grpc.CallOption) (*QueryNextSequenceSendResponse, error) + // UpgradeError returns the error receipt if the upgrade handshake failed. + UpgradeError(ctx context.Context, in *QueryUpgradeErrorRequest, opts ...grpc.CallOption) (*QueryUpgradeErrorResponse, error) + // Upgrade returns the upgrade for a given port and channel id. + Upgrade(ctx context.Context, in *QueryUpgradeRequest, opts ...grpc.CallOption) (*QueryUpgradeResponse, error) + // ChannelParams queries all parameters of the ibc channel submodule. + ChannelParams(ctx context.Context, in *QueryChannelParamsRequest, opts ...grpc.CallOption) (*QueryChannelParamsResponse, error) } type queryClient struct { @@ -2115,6 +2455,33 @@ func (c *queryClient) NextSequenceSend(ctx context.Context, in *QueryNextSequenc return out, nil } +func (c *queryClient) UpgradeError(ctx context.Context, in *QueryUpgradeErrorRequest, opts ...grpc.CallOption) (*QueryUpgradeErrorResponse, error) { + out := new(QueryUpgradeErrorResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Query/UpgradeError", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) Upgrade(ctx context.Context, in *QueryUpgradeRequest, opts ...grpc.CallOption) (*QueryUpgradeResponse, error) { + out := new(QueryUpgradeResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Query/Upgrade", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) ChannelParams(ctx context.Context, in *QueryChannelParamsRequest, opts ...grpc.CallOption) (*QueryChannelParamsResponse, error) { + out := new(QueryChannelParamsResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Query/ChannelParams", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // Channel queries an IBC Channel. @@ -2153,6 +2520,12 @@ type QueryServer interface { NextSequenceReceive(context.Context, *QueryNextSequenceReceiveRequest) (*QueryNextSequenceReceiveResponse, error) // NextSequenceSend returns the next send sequence for a given channel. NextSequenceSend(context.Context, *QueryNextSequenceSendRequest) (*QueryNextSequenceSendResponse, error) + // UpgradeError returns the error receipt if the upgrade handshake failed. + UpgradeError(context.Context, *QueryUpgradeErrorRequest) (*QueryUpgradeErrorResponse, error) + // Upgrade returns the upgrade for a given port and channel id. + Upgrade(context.Context, *QueryUpgradeRequest) (*QueryUpgradeResponse, error) + // ChannelParams queries all parameters of the ibc channel submodule. + ChannelParams(context.Context, *QueryChannelParamsRequest) (*QueryChannelParamsResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -2201,6 +2574,15 @@ func (*UnimplementedQueryServer) NextSequenceReceive(ctx context.Context, req *Q func (*UnimplementedQueryServer) NextSequenceSend(ctx context.Context, req *QueryNextSequenceSendRequest) (*QueryNextSequenceSendResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method NextSequenceSend not implemented") } +func (*UnimplementedQueryServer) UpgradeError(ctx context.Context, req *QueryUpgradeErrorRequest) (*QueryUpgradeErrorResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpgradeError not implemented") +} +func (*UnimplementedQueryServer) Upgrade(ctx context.Context, req *QueryUpgradeRequest) (*QueryUpgradeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Upgrade not implemented") +} +func (*UnimplementedQueryServer) ChannelParams(ctx context.Context, req *QueryChannelParamsRequest) (*QueryChannelParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChannelParams not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -2458,44 +2840,98 @@ func _Query_NextSequenceSend_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } -var _Query_serviceDesc = grpc.ServiceDesc{ - ServiceName: "ibc.core.channel.v1.Query", - HandlerType: (*QueryServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Channel", - Handler: _Query_Channel_Handler, - }, - { - MethodName: "Channels", - Handler: _Query_Channels_Handler, - }, - { - MethodName: "ConnectionChannels", - Handler: _Query_ConnectionChannels_Handler, - }, - { - MethodName: "ChannelClientState", - Handler: _Query_ChannelClientState_Handler, - }, - { - MethodName: "ChannelConsensusState", - Handler: _Query_ChannelConsensusState_Handler, - }, - { - MethodName: "PacketCommitment", - Handler: _Query_PacketCommitment_Handler, - }, - { - MethodName: "PacketCommitments", - Handler: _Query_PacketCommitments_Handler, - }, - { - MethodName: "PacketReceipt", - Handler: _Query_PacketReceipt_Handler, - }, - { - MethodName: "PacketAcknowledgement", +func _Query_UpgradeError_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryUpgradeErrorRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).UpgradeError(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Query/UpgradeError", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).UpgradeError(ctx, req.(*QueryUpgradeErrorRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_Upgrade_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryUpgradeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Upgrade(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Query/Upgrade", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Upgrade(ctx, req.(*QueryUpgradeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_ChannelParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryChannelParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).ChannelParams(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Query/ChannelParams", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).ChannelParams(ctx, req.(*QueryChannelParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "ibc.core.channel.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Channel", + Handler: _Query_Channel_Handler, + }, + { + MethodName: "Channels", + Handler: _Query_Channels_Handler, + }, + { + MethodName: "ConnectionChannels", + Handler: _Query_ConnectionChannels_Handler, + }, + { + MethodName: "ChannelClientState", + Handler: _Query_ChannelClientState_Handler, + }, + { + MethodName: "ChannelConsensusState", + Handler: _Query_ChannelConsensusState_Handler, + }, + { + MethodName: "PacketCommitment", + Handler: _Query_PacketCommitment_Handler, + }, + { + MethodName: "PacketCommitments", + Handler: _Query_PacketCommitments_Handler, + }, + { + MethodName: "PacketReceipt", + Handler: _Query_PacketReceipt_Handler, + }, + { + MethodName: "PacketAcknowledgement", Handler: _Query_PacketAcknowledgement_Handler, }, { @@ -2518,6 +2954,18 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "NextSequenceSend", Handler: _Query_NextSequenceSend_Handler, }, + { + MethodName: "UpgradeError", + Handler: _Query_UpgradeError_Handler, + }, + { + MethodName: "Upgrade", + Handler: _Query_Upgrade_Handler, + }, + { + MethodName: "ChannelParams", + Handler: _Query_ChannelParams_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "ibc/core/channel/v1/query.proto", @@ -3882,115 +4330,347 @@ func (m *QueryNextSequenceSendResponse) MarshalToSizedBuffer(dAtA []byte) (int, 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++ +func (m *QueryUpgradeErrorRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - dAtA[offset] = uint8(v) - return base + return dAtA[:n], nil } -func (m *QueryChannelRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.PortId) - 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 *QueryUpgradeErrorRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryChannelResponse) Size() (n int) { - if m == nil { - return 0 - } +func (m *QueryUpgradeErrorRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if m.Channel != nil { - l = m.Channel.Size() - n += 1 + l + sovQuery(uint64(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 } - l = len(m.Proof) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa } - l = m.ProofHeight.Size() - n += 1 + l + sovQuery(uint64(l)) - return n + return len(dAtA) - i, nil } -func (m *QueryChannelsRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Pagination != nil { - l = m.Pagination.Size() - n += 1 + l + sovQuery(uint64(l)) +func (m *QueryUpgradeErrorResponse) 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 n + return dAtA[:n], nil } -func (m *QueryChannelsResponse) Size() (n int) { - if m == nil { - return 0 - } +func (m *QueryUpgradeErrorResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryUpgradeErrorResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if len(m.Channels) > 0 { - for _, e := range m.Channels { - l = e.Size() - n += 1 + l + sovQuery(uint64(l)) + { + size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) } - if m.Pagination != nil { - l = m.Pagination.Size() - n += 1 + l + sovQuery(uint64(l)) + i-- + dAtA[i] = 0x1a + if len(m.Proof) > 0 { + i -= len(m.Proof) + copy(dAtA[i:], m.Proof) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Proof))) + i-- + dAtA[i] = 0x12 } - l = m.Height.Size() - n += 1 + l + sovQuery(uint64(l)) - return n + { + size, err := m.ErrorReceipt.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 *QueryConnectionChannelsRequest) Size() (n int) { - if m == nil { - return 0 +func (m *QueryUpgradeRequest) 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 *QueryUpgradeRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryUpgradeRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - l = len(m.Connection) - if l > 0 { - n += 1 + l + sovQuery(uint64(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 m.Pagination != nil { - l = m.Pagination.Size() - n += 1 + l + sovQuery(uint64(l)) + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa } - return n + return len(dAtA) - i, nil } -func (m *QueryConnectionChannelsResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.Channels) > 0 { - for _, e := range m.Channels { - l = e.Size() - n += 1 + l + sovQuery(uint64(l)) - } +func (m *QueryUpgradeResponse) 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 *QueryUpgradeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryUpgradeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.Proof) > 0 { + i -= len(m.Proof) + copy(dAtA[i:], m.Proof) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Proof))) + i-- + dAtA[i] = 0x12 + } + { + size, err := m.Upgrade.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 *QueryChannelParamsRequest) 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 *QueryChannelParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryChannelParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryChannelParamsResponse) 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 *QueryChannelParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryChannelParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Params != nil { + { + size, err := m.Params.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 *QueryChannelRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + 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 *QueryChannelResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Channel != nil { + l = m.Channel.Size() + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.Proof) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = m.ProofHeight.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryChannelsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryChannelsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Channels) > 0 { + for _, e := range m.Channels { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + l = m.Height.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryConnectionChannelsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Connection) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryConnectionChannelsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Channels) > 0 { + for _, e := range m.Channels { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } } if m.Pagination != nil { l = m.Pagination.Size() @@ -4444,37 +5124,127 @@ func (m *QueryNextSequenceSendResponse) Size() (n int) { return n } -func sovQuery(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 +func (m *QueryUpgradeErrorRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + 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 sozQuery(x uint64) (n int) { - return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) + +func (m *QueryUpgradeErrorResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.ErrorReceipt.Size() + n += 1 + l + sovQuery(uint64(l)) + l = len(m.Proof) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = m.ProofHeight.Size() + n += 1 + l + sovQuery(uint64(l)) + return n } -func (m *QueryChannelRequest) 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: QueryChannelRequest: wiretype end group for non-group") - } + +func (m *QueryUpgradeRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + 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 *QueryUpgradeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Upgrade.Size() + n += 1 + l + sovQuery(uint64(l)) + l = len(m.Proof) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = m.ProofHeight.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryChannelParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryChannelParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Params != nil { + l = m.Params.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 *QueryChannelRequest) 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: QueryChannelRequest: wiretype end group for non-group") + } if fieldNum <= 0 { return fmt.Errorf("proto: QueryChannelRequest: illegal tag %d (wire type %d)", fieldNum, wire) } @@ -7960,44 +8730,544 @@ func (m *QueryUnreceivedAcksResponse) Unmarshal(dAtA []byte) error { if postIndex < 0 { return ErrInvalidLengthQuery } - if postIndex > l { + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.Sequences) == 0 { + m.Sequences = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Sequences = append(m.Sequences, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field Sequences", wireType) + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", 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 err := m.Height.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 *QueryNextSequenceReceiveRequest) 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: QueryNextSequenceReceiveRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryNextSequenceReceiveRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", 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.PortId = 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 *QueryNextSequenceReceiveResponse) 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: QueryNextSequenceReceiveResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryNextSequenceReceiveResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NextSequenceReceive", wireType) + } + m.NextSequenceReceive = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NextSequenceReceive |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proof", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Proof = append(m.Proof[:0], dAtA[iNdEx:postIndex]...) + if m.Proof == nil { + m.Proof = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", 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 err := m.ProofHeight.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 *QueryNextSequenceSendRequest) 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: QueryNextSequenceSendRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryNextSequenceSendRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", 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.PortId = 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 *QueryNextSequenceSendResponse) 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: QueryNextSequenceSendResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryNextSequenceSendResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NextSequenceSend", wireType) + } + m.NextSequenceSend = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { return io.ErrUnexpectedEOF } - var elementCount int - var count int - for _, integer := range dAtA[iNdEx:postIndex] { - if integer < 128 { - count++ - } + b := dAtA[iNdEx] + iNdEx++ + m.NextSequenceSend |= uint64(b&0x7F) << shift + if b < 0x80 { + break } - elementCount = count - if elementCount != 0 && len(m.Sequences) == 0 { - m.Sequences = make([]uint64, 0, elementCount) + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proof", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery } - for iNdEx < postIndex { - var v uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Sequences = append(m.Sequences, v) + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break } - } else { - return fmt.Errorf("proto: wrong wireType = %d for field Sequences", wireType) } - case 2: + if byteLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Proof = append(m.Proof[:0], dAtA[iNdEx:postIndex]...) + if m.Proof == nil { + m.Proof = []byte{} + } + iNdEx = postIndex + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -8024,7 +9294,7 @@ func (m *QueryUnreceivedAcksResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Height.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.ProofHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -8049,7 +9319,7 @@ func (m *QueryUnreceivedAcksResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryNextSequenceReceiveRequest) Unmarshal(dAtA []byte) error { +func (m *QueryUpgradeErrorRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -8072,10 +9342,10 @@ func (m *QueryNextSequenceReceiveRequest) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryNextSequenceReceiveRequest: wiretype end group for non-group") + return fmt.Errorf("proto: QueryUpgradeErrorRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryNextSequenceReceiveRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryUpgradeErrorRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -8163,7 +9433,7 @@ func (m *QueryNextSequenceReceiveRequest) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryNextSequenceReceiveResponse) Unmarshal(dAtA []byte) error { +func (m *QueryUpgradeErrorResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -8186,17 +9456,17 @@ func (m *QueryNextSequenceReceiveResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryNextSequenceReceiveResponse: wiretype end group for non-group") + return fmt.Errorf("proto: QueryUpgradeErrorResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryNextSequenceReceiveResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryUpgradeErrorResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NextSequenceReceive", wireType) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ErrorReceipt", wireType) } - m.NextSequenceReceive = 0 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowQuery @@ -8206,11 +9476,25 @@ func (m *QueryNextSequenceReceiveResponse) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.NextSequenceReceive |= uint64(b&0x7F) << shift + 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 err := m.ErrorReceipt.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Proof", wireType) @@ -8299,7 +9583,7 @@ func (m *QueryNextSequenceReceiveResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryNextSequenceSendRequest) Unmarshal(dAtA []byte) error { +func (m *QueryUpgradeRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -8322,10 +9606,10 @@ func (m *QueryNextSequenceSendRequest) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryNextSequenceSendRequest: wiretype end group for non-group") + return fmt.Errorf("proto: QueryUpgradeRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryNextSequenceSendRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryUpgradeRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -8413,7 +9697,7 @@ func (m *QueryNextSequenceSendRequest) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryNextSequenceSendResponse) Unmarshal(dAtA []byte) error { +func (m *QueryUpgradeResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -8436,17 +9720,17 @@ func (m *QueryNextSequenceSendResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryNextSequenceSendResponse: wiretype end group for non-group") + return fmt.Errorf("proto: QueryUpgradeResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryNextSequenceSendResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryUpgradeResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NextSequenceSend", wireType) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Upgrade", wireType) } - m.NextSequenceSend = 0 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowQuery @@ -8456,11 +9740,25 @@ func (m *QueryNextSequenceSendResponse) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.NextSequenceSend |= uint64(b&0x7F) << shift + 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 err := m.Upgrade.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Proof", wireType) @@ -8549,6 +9847,142 @@ func (m *QueryNextSequenceSendResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryChannelParamsRequest) 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: QueryChannelParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryChannelParamsRequest: 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 *QueryChannelParamsResponse) 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: QueryChannelParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryChannelParamsResponse: 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 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.Params == nil { + m.Params = &Params{} + } + if err := m.Params.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 diff --git a/modules/core/04-channel/types/query.pb.gw.go b/modules/core/04-channel/types/query.pb.gw.go index 2f9c58f146d..bce31252f8b 100644 --- a/modules/core/04-channel/types/query.pb.gw.go +++ b/modules/core/04-channel/types/query.pb.gw.go @@ -1243,6 +1243,176 @@ func local_request_Query_NextSequenceSend_0(ctx context.Context, marshaler runti } +func request_Query_UpgradeError_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryUpgradeErrorRequest + 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) + } + + val, ok = pathParams["port_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "port_id") + } + + protoReq.PortId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "port_id", err) + } + + msg, err := client.UpgradeError(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_UpgradeError_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryUpgradeErrorRequest + 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) + } + + val, ok = pathParams["port_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "port_id") + } + + protoReq.PortId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "port_id", err) + } + + msg, err := server.UpgradeError(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_Upgrade_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryUpgradeRequest + 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) + } + + val, ok = pathParams["port_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "port_id") + } + + protoReq.PortId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "port_id", err) + } + + msg, err := client.Upgrade(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Upgrade_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryUpgradeRequest + 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) + } + + val, ok = pathParams["port_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "port_id") + } + + protoReq.PortId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "port_id", err) + } + + msg, err := server.Upgrade(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_ChannelParams_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryChannelParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.ChannelParams(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_ChannelParams_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryChannelParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.ChannelParams(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. @@ -1571,6 +1741,75 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_UpgradeError_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_UpgradeError_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_UpgradeError_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_Upgrade_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_Upgrade_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_Upgrade_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ChannelParams_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_ChannelParams_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_ChannelParams_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1892,6 +2131,66 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_UpgradeError_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_UpgradeError_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_UpgradeError_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_Upgrade_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_Upgrade_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_Upgrade_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ChannelParams_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_ChannelParams_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_ChannelParams_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1923,6 +2222,12 @@ var ( pattern_Query_NextSequenceReceive_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "next_sequence"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_NextSequenceSend_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "next_sequence_send"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_UpgradeError_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "upgrade_error"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_Upgrade_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "upgrade"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_ChannelParams_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"ibc", "core", "channel", "v1", "params"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -1953,4 +2258,10 @@ var ( forward_Query_NextSequenceReceive_0 = runtime.ForwardResponseMessage forward_Query_NextSequenceSend_0 = runtime.ForwardResponseMessage + + forward_Query_UpgradeError_0 = runtime.ForwardResponseMessage + + forward_Query_Upgrade_0 = runtime.ForwardResponseMessage + + forward_Query_ChannelParams_0 = runtime.ForwardResponseMessage ) diff --git a/modules/core/04-channel/types/timeout.go b/modules/core/04-channel/types/timeout.go new file mode 100644 index 00000000000..dc51c31a78a --- /dev/null +++ b/modules/core/04-channel/types/timeout.go @@ -0,0 +1,60 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" + + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" +) + +// NewTimeout returns a new Timeout instance. +func NewTimeout(height clienttypes.Height, timestamp uint64) Timeout { + return Timeout{ + Height: height, + Timestamp: timestamp, + } +} + +// IsValid returns true if either the height or timestamp is non-zero. +func (t Timeout) IsValid() bool { + return !t.Height.IsZero() || t.Timestamp != 0 +} + +// Elapsed returns true if either the provided height or timestamp is past the +// respective absolute timeout values. +func (t Timeout) Elapsed(height clienttypes.Height, timestamp uint64) bool { + return t.heightElapsed(height) || t.timestampElapsed(timestamp) +} + +// ErrTimeoutElapsed returns a timeout elapsed error indicating which timeout value +// has elapsed. +func (t Timeout) ErrTimeoutElapsed(height clienttypes.Height, timestamp uint64) error { + if t.heightElapsed(height) { + return errorsmod.Wrapf(ErrTimeoutElapsed, "current height: %s, timeout height %s", height, t.Height) + } + + return errorsmod.Wrapf(ErrTimeoutElapsed, "current timestamp: %d, timeout timestamp %d", timestamp, t.Timestamp) +} + +// ErrTimeoutNotReached returns a timeout not reached error indicating which timeout value +// has not been reached. +func (t Timeout) ErrTimeoutNotReached(height clienttypes.Height, timestamp uint64) error { + // only return height information if the height is set + // t.heightElapsed() will return false when it is empty + if !t.Height.IsZero() && !t.heightElapsed(height) { + return errorsmod.Wrapf(ErrTimeoutNotReached, "current height: %s, timeout height %s", height, t.Height) + } + + return errorsmod.Wrapf(ErrTimeoutNotReached, "current timestamp: %d, timeout timestamp %d", timestamp, t.Timestamp) +} + +// heightElapsed returns true if the timeout height is non empty +// and the timeout height is greater than or equal to the relative height. +func (t Timeout) heightElapsed(height clienttypes.Height) bool { + return !t.Height.IsZero() && height.GTE(t.Height) +} + +// timestampElapsed returns true if the timeout timestamp is non empty +// and the timeout timestamp is greater than or equal to the relative timestamp. +func (t Timeout) timestampElapsed(timestamp uint64) bool { + return t.Timestamp != 0 && timestamp >= t.Timestamp +} diff --git a/modules/core/04-channel/types/timeout_test.go b/modules/core/04-channel/types/timeout_test.go new file mode 100644 index 00000000000..add2c3c876c --- /dev/null +++ b/modules/core/04-channel/types/timeout_test.go @@ -0,0 +1,238 @@ +package types_test + +import ( + errorsmod "cosmossdk.io/errors" + + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" +) + +func (suite *TypesTestSuite) TestIsValid() { + var timeout types.Timeout + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success: valid timeout with height and timestamp", + func() { + timeout = types.NewTimeout(clienttypes.NewHeight(1, 100), 100) + }, + true, + }, + { + "success: valid timeout with height and zero timestamp", + func() { + timeout = types.NewTimeout(clienttypes.NewHeight(1, 100), 0) + }, + true, + }, + { + "success: valid timeout with timestamp and zero height", + func() { + timeout = types.NewTimeout(clienttypes.ZeroHeight(), 100) + }, + true, + }, + { + "invalid timeout with zero height and zero timestamp", + func() { + timeout = types.NewTimeout(clienttypes.ZeroHeight(), 0) + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + tc.malleate() + + isValid := timeout.IsValid() + if tc.expPass { + suite.Require().True(isValid) + } else { + suite.Require().False(isValid) + } + }) + } +} + +func (suite *TypesTestSuite) TestElapsed() { + // elapsed is expected to be true when either timeout height or timestamp + // is greater than or equal to 2 + var ( + height = clienttypes.NewHeight(0, 2) + timestamp = uint64(2) + ) + + testCases := []struct { + name string + timeout types.Timeout + expElapsed bool + }{ + { + "elapsed: both timeout with height and timestamp", + types.NewTimeout(height, timestamp), + true, + }, + { + "elapsed: timeout with height and zero timestamp", + types.NewTimeout(height, 0), + true, + }, + { + "elapsed: timeout with timestamp and zero height", + types.NewTimeout(clienttypes.ZeroHeight(), timestamp), + true, + }, + { + "elapsed: height elapsed, timestamp did not", + types.NewTimeout(height, timestamp+1), + true, + }, + { + "elapsed: timestamp elapsed, height did not", + types.NewTimeout(height.Increment().(clienttypes.Height), timestamp), + true, + }, + { + "elapsed: timestamp elapsed when less than current timestamp", + types.NewTimeout(clienttypes.ZeroHeight(), timestamp-1), + true, + }, + { + "elapsed: height elapsed when less than current height", + types.NewTimeout(clienttypes.NewHeight(0, 1), 0), + true, + }, + { + "not elapsed: invalid timeout", + types.NewTimeout(clienttypes.ZeroHeight(), 0), + false, + }, + { + "not elapsed: neither height nor timeout elapsed", + types.NewTimeout(height.Increment().(clienttypes.Height), timestamp+1), + false, + }, + { + "not elapsed: timeout not reached with height and zero timestamp", + types.NewTimeout(height.Increment().(clienttypes.Height), 0), + false, + }, + { + "elapsed: timeout not reached with timestamp and zero height", + types.NewTimeout(clienttypes.ZeroHeight(), timestamp+1), + false, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + elapsed := tc.timeout.Elapsed(height, timestamp) + suite.Require().Equal(tc.expElapsed, elapsed) + }) + } +} + +func (suite *TypesTestSuite) TestErrTimeoutElapsed() { + // elapsed is expected to be true when either timeout height or timestamp + // is greater than or equal to 2 + var ( + height = clienttypes.NewHeight(0, 2) + timestamp = uint64(2) + ) + + testCases := []struct { + name string + timeout types.Timeout + expError error + }{ + { + "both timeout with height and timestamp", + types.NewTimeout(height, timestamp), + errorsmod.Wrapf(types.ErrTimeoutElapsed, "current height: %s, timeout height %s", height, height), + }, + { + "timeout with height and zero timestamp", + types.NewTimeout(height, 0), + errorsmod.Wrapf(types.ErrTimeoutElapsed, "current height: %s, timeout height %s", height, height), + }, + { + "timeout with timestamp and zero height", + types.NewTimeout(clienttypes.ZeroHeight(), timestamp), + errorsmod.Wrapf(types.ErrTimeoutElapsed, "current timestamp: %d, timeout timestamp %d", timestamp, timestamp), + }, + { + "height elapsed, timestamp did not", + types.NewTimeout(height, timestamp+1), + errorsmod.Wrapf(types.ErrTimeoutElapsed, "current height: %s, timeout height %s", height, height), + }, + { + "timestamp elapsed, height did not", + types.NewTimeout(height.Increment().(clienttypes.Height), timestamp), + errorsmod.Wrapf(types.ErrTimeoutElapsed, "current timestamp: %d, timeout timestamp %d", timestamp, timestamp), + }, + { + "height elapsed when less than current height", + types.NewTimeout(clienttypes.NewHeight(0, 1), 0), + errorsmod.Wrapf(types.ErrTimeoutElapsed, "current height: %s, timeout height %s", height, clienttypes.NewHeight(0, 1)), + }, + { + "timestamp elapsed when less than current timestamp", + types.NewTimeout(clienttypes.ZeroHeight(), timestamp-1), + errorsmod.Wrapf(types.ErrTimeoutElapsed, "current timestamp: %d, timeout timestamp %d", timestamp, timestamp-1), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + err := tc.timeout.ErrTimeoutElapsed(height, timestamp) + suite.Require().Equal(tc.expError.Error(), err.Error()) + }) + } +} + +func (suite *TypesTestSuite) TestErrTimeoutNotReached() { + // elapsed is expected to be true when either timeout height or timestamp + // is greater than or equal to 2 + var ( + height = clienttypes.NewHeight(0, 2) + timestamp = uint64(2) + ) + + testCases := []struct { + name string + timeout types.Timeout + expError error + }{ + { + "neither timeout reached with height and timestamp", + types.NewTimeout(height.Increment().(clienttypes.Height), timestamp+1), + errorsmod.Wrapf(types.ErrTimeoutNotReached, "current height: %s, timeout height %s", height, height.Increment().(clienttypes.Height)), + }, + { + "timeout not reached with height and zero timestamp", + types.NewTimeout(height.Increment().(clienttypes.Height), 0), + errorsmod.Wrapf(types.ErrTimeoutNotReached, "current height: %s, timeout height %s", height, height.Increment().(clienttypes.Height)), + }, + { + "timeout not reached with timestamp and zero height", + types.NewTimeout(clienttypes.ZeroHeight(), timestamp+1), + errorsmod.Wrapf(types.ErrTimeoutNotReached, "current timestamp: %d, timeout timestamp %d", timestamp, timestamp+1), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + err := tc.timeout.ErrTimeoutNotReached(height, timestamp) + suite.Require().Equal(tc.expError.Error(), err.Error()) + }) + } +} diff --git a/modules/core/04-channel/types/tx.pb.go b/modules/core/04-channel/types/tx.pb.go index bd9cd757eb6..398a9f15b64 100644 --- a/modules/core/04-channel/types/tx.pb.go +++ b/modules/core/04-channel/types/tx.pb.go @@ -40,18 +40,22 @@ const ( NOOP ResponseResultType = 1 // The message was executed successfully SUCCESS ResponseResultType = 2 + // The message was executed unsuccessfully + FAILURE ResponseResultType = 3 ) var ResponseResultType_name = map[int32]string{ 0: "RESPONSE_RESULT_TYPE_UNSPECIFIED", 1: "RESPONSE_RESULT_TYPE_NOOP", 2: "RESPONSE_RESULT_TYPE_SUCCESS", + 3: "RESPONSE_RESULT_TYPE_FAILURE", } var ResponseResultType_value = map[string]int32{ "RESPONSE_RESULT_TYPE_UNSPECIFIED": 0, "RESPONSE_RESULT_TYPE_NOOP": 1, "RESPONSE_RESULT_TYPE_SUCCESS": 2, + "RESPONSE_RESULT_TYPE_FAILURE": 3, } func (x ResponseResultType) String() string { @@ -231,6 +235,9 @@ var xxx_messageInfo_MsgChannelOpenTryResponse proto.InternalMessageInfo // MsgChannelOpenAck defines a msg sent by a Relayer to Chain A to acknowledge // the change of channel state to TRYOPEN on Chain B. +// WARNING: a channel upgrade MUST NOT initialize an upgrade for this channel +// in the same block as executing this message otherwise the counterparty will +// be incapable of opening. type MsgChannelOpenAck struct { PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` @@ -473,11 +480,12 @@ var xxx_messageInfo_MsgChannelCloseInitResponse proto.InternalMessageInfo // MsgChannelCloseConfirm defines a msg sent by a Relayer to Chain B // to acknowledge the change of channel state to CLOSED on Chain A. type MsgChannelCloseConfirm struct { - PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` - ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` - ProofInit []byte `protobuf:"bytes,3,opt,name=proof_init,json=proofInit,proto3" json:"proof_init,omitempty"` - ProofHeight types.Height `protobuf:"bytes,4,opt,name=proof_height,json=proofHeight,proto3" json:"proof_height"` - Signer string `protobuf:"bytes,5,opt,name=signer,proto3" json:"signer,omitempty"` + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + ProofInit []byte `protobuf:"bytes,3,opt,name=proof_init,json=proofInit,proto3" json:"proof_init,omitempty"` + ProofHeight types.Height `protobuf:"bytes,4,opt,name=proof_height,json=proofHeight,proto3" json:"proof_height"` + Signer string `protobuf:"bytes,5,opt,name=signer,proto3" json:"signer,omitempty"` + CounterpartyUpgradeSequence uint64 `protobuf:"varint,6,opt,name=counterparty_upgrade_sequence,json=counterpartyUpgradeSequence,proto3" json:"counterparty_upgrade_sequence,omitempty"` } func (m *MsgChannelCloseConfirm) Reset() { *m = MsgChannelCloseConfirm{} } @@ -712,12 +720,13 @@ var xxx_messageInfo_MsgTimeoutResponse proto.InternalMessageInfo // MsgTimeoutOnClose timed-out packet upon counterparty channel closure. type MsgTimeoutOnClose struct { - Packet Packet `protobuf:"bytes,1,opt,name=packet,proto3" json:"packet"` - ProofUnreceived []byte `protobuf:"bytes,2,opt,name=proof_unreceived,json=proofUnreceived,proto3" json:"proof_unreceived,omitempty"` - ProofClose []byte `protobuf:"bytes,3,opt,name=proof_close,json=proofClose,proto3" json:"proof_close,omitempty"` - ProofHeight types.Height `protobuf:"bytes,4,opt,name=proof_height,json=proofHeight,proto3" json:"proof_height"` - NextSequenceRecv uint64 `protobuf:"varint,5,opt,name=next_sequence_recv,json=nextSequenceRecv,proto3" json:"next_sequence_recv,omitempty"` - Signer string `protobuf:"bytes,6,opt,name=signer,proto3" json:"signer,omitempty"` + Packet Packet `protobuf:"bytes,1,opt,name=packet,proto3" json:"packet"` + ProofUnreceived []byte `protobuf:"bytes,2,opt,name=proof_unreceived,json=proofUnreceived,proto3" json:"proof_unreceived,omitempty"` + ProofClose []byte `protobuf:"bytes,3,opt,name=proof_close,json=proofClose,proto3" json:"proof_close,omitempty"` + ProofHeight types.Height `protobuf:"bytes,4,opt,name=proof_height,json=proofHeight,proto3" json:"proof_height"` + NextSequenceRecv uint64 `protobuf:"varint,5,opt,name=next_sequence_recv,json=nextSequenceRecv,proto3" json:"next_sequence_recv,omitempty"` + Signer string `protobuf:"bytes,6,opt,name=signer,proto3" json:"signer,omitempty"` + CounterpartyUpgradeSequence uint64 `protobuf:"varint,7,opt,name=counterparty_upgrade_sequence,json=counterpartyUpgradeSequence,proto3" json:"counterparty_upgrade_sequence,omitempty"` } func (m *MsgTimeoutOnClose) Reset() { *m = MsgTimeoutOnClose{} } @@ -871,1829 +880,6810 @@ func (m *MsgAcknowledgementResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgAcknowledgementResponse proto.InternalMessageInfo -func init() { - proto.RegisterEnum("ibc.core.channel.v1.ResponseResultType", ResponseResultType_name, ResponseResultType_value) - proto.RegisterType((*MsgChannelOpenInit)(nil), "ibc.core.channel.v1.MsgChannelOpenInit") - proto.RegisterType((*MsgChannelOpenInitResponse)(nil), "ibc.core.channel.v1.MsgChannelOpenInitResponse") - proto.RegisterType((*MsgChannelOpenTry)(nil), "ibc.core.channel.v1.MsgChannelOpenTry") - proto.RegisterType((*MsgChannelOpenTryResponse)(nil), "ibc.core.channel.v1.MsgChannelOpenTryResponse") - proto.RegisterType((*MsgChannelOpenAck)(nil), "ibc.core.channel.v1.MsgChannelOpenAck") - proto.RegisterType((*MsgChannelOpenAckResponse)(nil), "ibc.core.channel.v1.MsgChannelOpenAckResponse") - proto.RegisterType((*MsgChannelOpenConfirm)(nil), "ibc.core.channel.v1.MsgChannelOpenConfirm") - proto.RegisterType((*MsgChannelOpenConfirmResponse)(nil), "ibc.core.channel.v1.MsgChannelOpenConfirmResponse") - proto.RegisterType((*MsgChannelCloseInit)(nil), "ibc.core.channel.v1.MsgChannelCloseInit") - proto.RegisterType((*MsgChannelCloseInitResponse)(nil), "ibc.core.channel.v1.MsgChannelCloseInitResponse") - proto.RegisterType((*MsgChannelCloseConfirm)(nil), "ibc.core.channel.v1.MsgChannelCloseConfirm") - proto.RegisterType((*MsgChannelCloseConfirmResponse)(nil), "ibc.core.channel.v1.MsgChannelCloseConfirmResponse") - proto.RegisterType((*MsgRecvPacket)(nil), "ibc.core.channel.v1.MsgRecvPacket") - proto.RegisterType((*MsgRecvPacketResponse)(nil), "ibc.core.channel.v1.MsgRecvPacketResponse") - proto.RegisterType((*MsgTimeout)(nil), "ibc.core.channel.v1.MsgTimeout") - proto.RegisterType((*MsgTimeoutResponse)(nil), "ibc.core.channel.v1.MsgTimeoutResponse") - proto.RegisterType((*MsgTimeoutOnClose)(nil), "ibc.core.channel.v1.MsgTimeoutOnClose") - proto.RegisterType((*MsgTimeoutOnCloseResponse)(nil), "ibc.core.channel.v1.MsgTimeoutOnCloseResponse") - proto.RegisterType((*MsgAcknowledgement)(nil), "ibc.core.channel.v1.MsgAcknowledgement") - proto.RegisterType((*MsgAcknowledgementResponse)(nil), "ibc.core.channel.v1.MsgAcknowledgementResponse") +// MsgChannelUpgradeInit defines the request type for the ChannelUpgradeInit rpc +// WARNING: Initializing a channel upgrade in the same block as opening the channel +// may result in the counterparty being incapable of opening. +type MsgChannelUpgradeInit struct { + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + Fields UpgradeFields `protobuf:"bytes,3,opt,name=fields,proto3" json:"fields"` + Signer string `protobuf:"bytes,4,opt,name=signer,proto3" json:"signer,omitempty"` } -func init() { proto.RegisterFile("ibc/core/channel/v1/tx.proto", fileDescriptor_bc4637e0ac3fc7b7) } - -var fileDescriptor_bc4637e0ac3fc7b7 = []byte{ - // 1191 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xbf, 0x6f, 0xdb, 0x46, - 0x14, 0x16, 0x65, 0x59, 0xb2, 0x9f, 0xdc, 0x48, 0xa1, 0x93, 0x58, 0xa1, 0x6d, 0x49, 0xf5, 0x10, - 0xbb, 0x6e, 0x2d, 0xc5, 0x4a, 0x5b, 0x34, 0x41, 0x81, 0xc2, 0x56, 0x55, 0xd4, 0x40, 0xfd, 0x03, - 0x94, 0x5c, 0xa0, 0x49, 0x51, 0xc1, 0xa2, 0x2e, 0x34, 0x21, 0x89, 0xa7, 0x92, 0x94, 0x12, 0x6d, - 0x45, 0x27, 0xc3, 0x43, 0xd1, 0xa1, 0xab, 0x81, 0x02, 0x9d, 0xba, 0x65, 0xca, 0xde, 0x2d, 0x63, - 0xc6, 0xa2, 0x40, 0x83, 0xc2, 0x1e, 0xf2, 0x6f, 0x14, 0xbc, 0x3b, 0x52, 0x14, 0x45, 0x4a, 0x4c, - 0xac, 0x78, 0x23, 0xdf, 0xfb, 0xee, 0xfd, 0xf8, 0xbe, 0xe3, 0xe3, 0x91, 0xb0, 0xa4, 0xd4, 0xa4, - 0xbc, 0x84, 0x35, 0x94, 0x97, 0x8e, 0x8f, 0x54, 0x15, 0x35, 0xf3, 0xdd, 0xcd, 0xbc, 0xf1, 0x34, - 0xd7, 0xd6, 0xb0, 0x81, 0xf9, 0x79, 0xa5, 0x26, 0xe5, 0x4c, 0x6f, 0x8e, 0x79, 0x73, 0xdd, 0x4d, - 0xe1, 0x86, 0x8c, 0x65, 0x4c, 0xfc, 0x79, 0xf3, 0x8a, 0x42, 0x85, 0x4c, 0x3f, 0x50, 0x53, 0x41, - 0xaa, 0x61, 0xc6, 0xa1, 0x57, 0x0c, 0xf0, 0xbe, 0x57, 0x26, 0x2b, 0x2c, 0x85, 0x2c, 0x48, 0x58, - 0x6f, 0x61, 0x3d, 0xdf, 0xd2, 0x65, 0xd3, 0xd9, 0xd2, 0x65, 0xea, 0x58, 0xf9, 0x8d, 0x03, 0x7e, - 0x57, 0x97, 0x8b, 0x14, 0xbd, 0xdf, 0x46, 0xea, 0x8e, 0xaa, 0x18, 0xfc, 0x02, 0xc4, 0xda, 0x58, - 0x33, 0xaa, 0x4a, 0x3d, 0xc5, 0x65, 0xb9, 0xb5, 0x59, 0x31, 0x6a, 0xde, 0xee, 0xd4, 0xf9, 0xcf, - 0x21, 0xc6, 0x22, 0xa7, 0xc2, 0x59, 0x6e, 0x2d, 0x5e, 0x58, 0xca, 0x79, 0x74, 0x92, 0x63, 0xf1, - 0xb6, 0x23, 0x2f, 0x5e, 0x65, 0x42, 0xa2, 0xb5, 0x84, 0xbf, 0x05, 0x51, 0x5d, 0x91, 0x55, 0xa4, - 0xa5, 0xa6, 0x68, 0x54, 0x7a, 0xf7, 0x20, 0x71, 0xf2, 0x7b, 0x26, 0xf4, 0xf3, 0xeb, 0x67, 0xeb, - 0xcc, 0xb0, 0xf2, 0x08, 0x84, 0xe1, 0xaa, 0x44, 0xa4, 0xb7, 0xb1, 0xaa, 0x23, 0x7e, 0x19, 0x80, - 0x45, 0xec, 0x17, 0x38, 0xcb, 0x2c, 0x3b, 0x75, 0x3e, 0x05, 0xb1, 0x2e, 0xd2, 0x74, 0x05, 0xab, - 0xa4, 0xc6, 0x59, 0xd1, 0xba, 0x7d, 0x10, 0x31, 0xf3, 0xac, 0xbc, 0x0a, 0xc3, 0xf5, 0xc1, 0xe8, - 0x15, 0xad, 0xe7, 0xdf, 0x72, 0x01, 0xe6, 0xdb, 0x1a, 0xea, 0x2a, 0xb8, 0xa3, 0x57, 0x1d, 0x69, - 0x49, 0xe8, 0xed, 0x70, 0x8a, 0x13, 0xaf, 0x5b, 0xee, 0xa2, 0x5d, 0x82, 0x83, 0xa6, 0xa9, 0x37, - 0xa7, 0x69, 0x13, 0x6e, 0x48, 0xb8, 0xa3, 0x1a, 0x48, 0x6b, 0x1f, 0x69, 0x46, 0xaf, 0x6a, 0x75, - 0x13, 0x21, 0x75, 0xcd, 0x3b, 0x7d, 0xdf, 0x52, 0x97, 0x49, 0x49, 0x5b, 0xc3, 0xf8, 0x71, 0x55, - 0x51, 0x15, 0x23, 0x35, 0x9d, 0xe5, 0xd6, 0xe6, 0xc4, 0x59, 0x62, 0x21, 0x7a, 0x16, 0x61, 0x8e, - 0xba, 0x8f, 0x91, 0x22, 0x1f, 0x1b, 0xa9, 0x28, 0x29, 0x4a, 0x70, 0x14, 0x45, 0x37, 0x54, 0x77, - 0x33, 0xf7, 0x35, 0x41, 0xb0, 0x92, 0xe2, 0x64, 0x15, 0x35, 0x39, 0xd4, 0x8b, 0x8d, 0x56, 0xef, - 0x21, 0xdc, 0x1e, 0xe2, 0xd7, 0x16, 0xcf, 0xa1, 0x0e, 0x37, 0xa0, 0x8e, 0x4b, 0xd6, 0xb0, 0x4b, - 0x56, 0x26, 0xde, 0x5f, 0x43, 0xe2, 0x6d, 0x49, 0x0d, 0x7f, 0xf1, 0x46, 0xc7, 0xe4, 0x3f, 0x85, - 0x85, 0x01, 0xa6, 0x1d, 0x58, 0xba, 0x43, 0x6f, 0x3a, 0xdd, 0x7d, 0x7d, 0xdf, 0x42, 0xa1, 0x45, - 0xa0, 0x7a, 0x54, 0x0d, 0xad, 0xc7, 0x04, 0x9a, 0x21, 0x06, 0x73, 0xf3, 0x5d, 0xad, 0x3e, 0x8b, - 0x6e, 0x7d, 0xb6, 0xa4, 0x86, 0xa5, 0xcf, 0xca, 0x3f, 0x1c, 0xdc, 0x1c, 0xf4, 0x16, 0xb1, 0xfa, - 0x58, 0xd1, 0x5a, 0x6f, 0x4d, 0xb2, 0xdd, 0xf9, 0x91, 0xd4, 0x20, 0xb4, 0x5a, 0x9d, 0x9b, 0xca, - 0xb9, 0x3b, 0x8f, 0x5c, 0xae, 0xf3, 0xe9, 0xd1, 0x9d, 0x67, 0x60, 0xd9, 0xb3, 0x37, 0xbb, 0xfb, - 0x2e, 0xcc, 0xf7, 0x01, 0xc5, 0x26, 0xd6, 0xd1, 0xe8, 0x79, 0x38, 0xa6, 0xf5, 0xc0, 0x03, 0x6f, - 0x19, 0x16, 0x3d, 0xf2, 0xda, 0x65, 0xfd, 0xcb, 0xc1, 0x2d, 0x97, 0xff, 0xb2, 0xaa, 0x0c, 0x4e, - 0x8c, 0xa9, 0x71, 0x13, 0xe3, 0xdd, 0xea, 0x92, 0x85, 0xb4, 0x77, 0x7b, 0x36, 0x03, 0x17, 0x1c, - 0xbc, 0xb7, 0xab, 0xcb, 0x22, 0x92, 0xba, 0x07, 0x47, 0x52, 0x03, 0x19, 0xfc, 0x7d, 0x88, 0xb6, - 0xc9, 0x15, 0xe9, 0x3b, 0x5e, 0x58, 0xf4, 0x1c, 0xb1, 0x14, 0xcc, 0x8a, 0x63, 0x0b, 0xf8, 0x0f, - 0x20, 0x49, 0x9b, 0x93, 0x70, 0xab, 0xa5, 0x18, 0x2d, 0xa4, 0x1a, 0x84, 0xa0, 0x39, 0x31, 0x41, - 0xec, 0x45, 0xdb, 0x3c, 0xc4, 0xc3, 0xd4, 0xe5, 0x78, 0x88, 0x8c, 0xe6, 0xe1, 0x07, 0xf2, 0xec, - 0xf5, 0x9b, 0xb4, 0xa7, 0xe6, 0x17, 0x10, 0xd5, 0x90, 0xde, 0x69, 0xd2, 0x66, 0xaf, 0x15, 0x56, - 0x3d, 0x9b, 0xb5, 0xe0, 0x22, 0x81, 0x56, 0x7a, 0x6d, 0x24, 0xb2, 0x65, 0x6c, 0x7a, 0xfe, 0x12, - 0x06, 0xd8, 0xd5, 0xe5, 0x8a, 0xd2, 0x42, 0xb8, 0x33, 0x19, 0x0a, 0x3b, 0xaa, 0x86, 0x24, 0xa4, - 0x74, 0x51, 0x7d, 0x80, 0xc2, 0x43, 0xdb, 0x3c, 0x19, 0x0a, 0x3f, 0x02, 0x5e, 0x45, 0x4f, 0x8d, - 0xaa, 0x8e, 0x7e, 0xec, 0x20, 0x55, 0x42, 0x55, 0x0d, 0x49, 0x5d, 0x42, 0x67, 0x44, 0x4c, 0x9a, - 0x9e, 0x32, 0x73, 0x98, 0xe4, 0x05, 0xdf, 0x78, 0x8f, 0xc8, 0xf1, 0x87, 0xf1, 0x31, 0x69, 0xb6, - 0x9f, 0xd3, 0x77, 0x15, 0x8b, 0xbe, 0xaf, 0x92, 0x8d, 0x7d, 0x45, 0xa4, 0x67, 0x20, 0xce, 0xb6, - 0xb8, 0x99, 0x94, 0x3d, 0xdf, 0xf4, 0x89, 0xa7, 0x65, 0x4c, 0xe4, 0x01, 0xf7, 0x56, 0x65, 0x7a, - 0xac, 0x2a, 0xd1, 0xd1, 0xaa, 0xd4, 0xc8, 0x0b, 0x6a, 0x90, 0xb7, 0x49, 0x8b, 0x73, 0x12, 0x26, - 0xd2, 0x6f, 0x49, 0x0d, 0x15, 0x3f, 0x69, 0xa2, 0xba, 0x8c, 0xc8, 0xf3, 0x7e, 0x09, 0x75, 0xd6, - 0x20, 0x71, 0x34, 0x18, 0xcd, 0x12, 0xc7, 0x65, 0xee, 0x8b, 0x63, 0x2e, 0xac, 0x0f, 0x88, 0xb3, - 0x65, 0x5a, 0xae, 0x78, 0xfa, 0x4a, 0xe4, 0xb4, 0xed, 0x62, 0x62, 0xc2, 0x7c, 0xaf, 0xff, 0xc9, - 0x01, 0x3f, 0x0c, 0xe2, 0x3f, 0x81, 0xac, 0x58, 0x2a, 0x1f, 0xec, 0xef, 0x95, 0x4b, 0x55, 0xb1, - 0x54, 0x3e, 0xfc, 0xa6, 0x52, 0xad, 0x7c, 0x77, 0x50, 0xaa, 0x1e, 0xee, 0x95, 0x0f, 0x4a, 0xc5, - 0x9d, 0xaf, 0x76, 0x4a, 0x5f, 0x26, 0x43, 0x42, 0xe2, 0xf4, 0x2c, 0x1b, 0x77, 0x98, 0xf8, 0x55, - 0xb8, 0xed, 0xb9, 0x6c, 0x6f, 0x7f, 0xff, 0x20, 0xc9, 0x09, 0x33, 0xa7, 0x67, 0xd9, 0x88, 0x79, - 0xcd, 0x6f, 0xc0, 0x92, 0x27, 0xb0, 0x7c, 0x58, 0x2c, 0x96, 0xca, 0xe5, 0x64, 0x58, 0x88, 0x9f, - 0x9e, 0x65, 0x63, 0xec, 0x56, 0x88, 0x9c, 0xfc, 0x91, 0x0e, 0x15, 0x9e, 0xcf, 0xc0, 0xd4, 0xae, - 0x2e, 0xf3, 0x0d, 0x48, 0xb8, 0xbf, 0x8c, 0xbc, 0xbb, 0x1f, 0xfe, 0x58, 0x11, 0xf2, 0x01, 0x81, - 0x36, 0xcf, 0xc7, 0x70, 0xcd, 0xf5, 0x49, 0x72, 0x27, 0x40, 0x88, 0x8a, 0xd6, 0x13, 0x72, 0xc1, - 0x70, 0x3e, 0x99, 0xcc, 0x53, 0x58, 0x90, 0x4c, 0x5b, 0x52, 0x23, 0x50, 0x26, 0xc7, 0x61, 0x92, - 0x37, 0x80, 0xf7, 0x38, 0x48, 0xae, 0x07, 0x88, 0xc2, 0xb0, 0x42, 0x21, 0x38, 0xd6, 0xce, 0xaa, - 0x42, 0x72, 0xe8, 0x04, 0xb7, 0x36, 0x26, 0x8e, 0x8d, 0x14, 0xee, 0x06, 0x45, 0xda, 0xf9, 0x9e, - 0xc0, 0xbc, 0xd7, 0xc9, 0xec, 0xc3, 0x20, 0x81, 0xac, 0x3e, 0xef, 0xbd, 0x01, 0xd8, 0x4e, 0xfc, - 0x3d, 0x80, 0xe3, 0x40, 0xb4, 0xe2, 0x17, 0xa2, 0x8f, 0x11, 0xd6, 0xc7, 0x63, 0xec, 0xe8, 0x65, - 0x88, 0x59, 0x07, 0x85, 0x8c, 0xdf, 0x32, 0x06, 0x10, 0x56, 0xc7, 0x00, 0x9c, 0x7b, 0xcf, 0xf5, - 0x3e, 0xbc, 0x33, 0x66, 0x29, 0xc3, 0xf9, 0xef, 0x3d, 0x9f, 0xf7, 0x44, 0x03, 0x12, 0xee, 0xe1, - 0xee, 0x5b, 0xa5, 0x0b, 0xe8, 0xff, 0xf0, 0xfa, 0x0c, 0x49, 0x61, 0xfa, 0xa7, 0xd7, 0xcf, 0xd6, - 0xb9, 0xed, 0xf2, 0x8b, 0xf3, 0x34, 0xf7, 0xf2, 0x3c, 0xcd, 0xfd, 0x77, 0x9e, 0xe6, 0x7e, 0xbd, - 0x48, 0x87, 0x5e, 0x5e, 0xa4, 0x43, 0x7f, 0x5f, 0xa4, 0x43, 0x0f, 0xef, 0xcb, 0x8a, 0x71, 0xdc, - 0xa9, 0xe5, 0x24, 0xdc, 0xca, 0xb3, 0x9f, 0x31, 0x4a, 0x4d, 0xda, 0x90, 0x71, 0xbe, 0xfb, 0x59, - 0xbe, 0x85, 0xeb, 0x9d, 0x26, 0xd2, 0xe9, 0x4f, 0x9c, 0xbb, 0x1f, 0x6f, 0x58, 0xff, 0x71, 0x8c, - 0x5e, 0x1b, 0xe9, 0xb5, 0x28, 0xf9, 0x55, 0x73, 0xef, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8d, - 0xa0, 0x17, 0x65, 0x52, 0x12, 0x00, 0x00, +func (m *MsgChannelUpgradeInit) Reset() { *m = MsgChannelUpgradeInit{} } +func (m *MsgChannelUpgradeInit) String() string { return proto.CompactTextString(m) } +func (*MsgChannelUpgradeInit) ProtoMessage() {} +func (*MsgChannelUpgradeInit) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{20} +} +func (m *MsgChannelUpgradeInit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgChannelUpgradeInit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgChannelUpgradeInit.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 *MsgChannelUpgradeInit) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgChannelUpgradeInit.Merge(m, src) +} +func (m *MsgChannelUpgradeInit) XXX_Size() int { + return m.Size() +} +func (m *MsgChannelUpgradeInit) XXX_DiscardUnknown() { + xxx_messageInfo_MsgChannelUpgradeInit.DiscardUnknown(m) } -// 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 +var xxx_messageInfo_MsgChannelUpgradeInit proto.InternalMessageInfo -// 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 { - // ChannelOpenInit defines a rpc handler method for MsgChannelOpenInit. - ChannelOpenInit(ctx context.Context, in *MsgChannelOpenInit, opts ...grpc.CallOption) (*MsgChannelOpenInitResponse, error) - // ChannelOpenTry defines a rpc handler method for MsgChannelOpenTry. - ChannelOpenTry(ctx context.Context, in *MsgChannelOpenTry, opts ...grpc.CallOption) (*MsgChannelOpenTryResponse, error) - // ChannelOpenAck defines a rpc handler method for MsgChannelOpenAck. - ChannelOpenAck(ctx context.Context, in *MsgChannelOpenAck, opts ...grpc.CallOption) (*MsgChannelOpenAckResponse, error) - // ChannelOpenConfirm defines a rpc handler method for MsgChannelOpenConfirm. - ChannelOpenConfirm(ctx context.Context, in *MsgChannelOpenConfirm, opts ...grpc.CallOption) (*MsgChannelOpenConfirmResponse, error) - // ChannelCloseInit defines a rpc handler method for MsgChannelCloseInit. - ChannelCloseInit(ctx context.Context, in *MsgChannelCloseInit, opts ...grpc.CallOption) (*MsgChannelCloseInitResponse, error) - // ChannelCloseConfirm defines a rpc handler method for - // MsgChannelCloseConfirm. - ChannelCloseConfirm(ctx context.Context, in *MsgChannelCloseConfirm, opts ...grpc.CallOption) (*MsgChannelCloseConfirmResponse, error) - // RecvPacket defines a rpc handler method for MsgRecvPacket. - RecvPacket(ctx context.Context, in *MsgRecvPacket, opts ...grpc.CallOption) (*MsgRecvPacketResponse, error) - // Timeout defines a rpc handler method for MsgTimeout. - Timeout(ctx context.Context, in *MsgTimeout, opts ...grpc.CallOption) (*MsgTimeoutResponse, error) - // TimeoutOnClose defines a rpc handler method for MsgTimeoutOnClose. - TimeoutOnClose(ctx context.Context, in *MsgTimeoutOnClose, opts ...grpc.CallOption) (*MsgTimeoutOnCloseResponse, error) - // Acknowledgement defines a rpc handler method for MsgAcknowledgement. - Acknowledgement(ctx context.Context, in *MsgAcknowledgement, opts ...grpc.CallOption) (*MsgAcknowledgementResponse, error) +// MsgChannelUpgradeInitResponse defines the MsgChannelUpgradeInit response type +type MsgChannelUpgradeInitResponse struct { + Upgrade Upgrade `protobuf:"bytes,1,opt,name=upgrade,proto3" json:"upgrade"` + UpgradeSequence uint64 `protobuf:"varint,2,opt,name=upgrade_sequence,json=upgradeSequence,proto3" json:"upgrade_sequence,omitempty"` } -type msgClient struct { - cc grpc1.ClientConn +func (m *MsgChannelUpgradeInitResponse) Reset() { *m = MsgChannelUpgradeInitResponse{} } +func (m *MsgChannelUpgradeInitResponse) String() string { return proto.CompactTextString(m) } +func (*MsgChannelUpgradeInitResponse) ProtoMessage() {} +func (*MsgChannelUpgradeInitResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{21} } - -func NewMsgClient(cc grpc1.ClientConn) MsgClient { - return &msgClient{cc} +func (m *MsgChannelUpgradeInitResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) } - -func (c *msgClient) ChannelOpenInit(ctx context.Context, in *MsgChannelOpenInit, opts ...grpc.CallOption) (*MsgChannelOpenInitResponse, error) { - out := new(MsgChannelOpenInitResponse) - err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelOpenInit", in, out, opts...) - if err != nil { - return nil, err +func (m *MsgChannelUpgradeInitResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgChannelUpgradeInitResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil } - return out, nil } - -func (c *msgClient) ChannelOpenTry(ctx context.Context, in *MsgChannelOpenTry, opts ...grpc.CallOption) (*MsgChannelOpenTryResponse, error) { - out := new(MsgChannelOpenTryResponse) - err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelOpenTry", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil +func (m *MsgChannelUpgradeInitResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgChannelUpgradeInitResponse.Merge(m, src) } - -func (c *msgClient) ChannelOpenAck(ctx context.Context, in *MsgChannelOpenAck, opts ...grpc.CallOption) (*MsgChannelOpenAckResponse, error) { - out := new(MsgChannelOpenAckResponse) - err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelOpenAck", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil +func (m *MsgChannelUpgradeInitResponse) XXX_Size() int { + return m.Size() } - -func (c *msgClient) ChannelOpenConfirm(ctx context.Context, in *MsgChannelOpenConfirm, opts ...grpc.CallOption) (*MsgChannelOpenConfirmResponse, error) { - out := new(MsgChannelOpenConfirmResponse) - err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelOpenConfirm", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil +func (m *MsgChannelUpgradeInitResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgChannelUpgradeInitResponse.DiscardUnknown(m) } -func (c *msgClient) ChannelCloseInit(ctx context.Context, in *MsgChannelCloseInit, opts ...grpc.CallOption) (*MsgChannelCloseInitResponse, error) { - out := new(MsgChannelCloseInitResponse) - err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelCloseInit", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} +var xxx_messageInfo_MsgChannelUpgradeInitResponse proto.InternalMessageInfo -func (c *msgClient) ChannelCloseConfirm(ctx context.Context, in *MsgChannelCloseConfirm, opts ...grpc.CallOption) (*MsgChannelCloseConfirmResponse, error) { - out := new(MsgChannelCloseConfirmResponse) - err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelCloseConfirm", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil +// MsgChannelUpgradeTry defines the request type for the ChannelUpgradeTry rpc +type MsgChannelUpgradeTry struct { + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + ProposedUpgradeConnectionHops []string `protobuf:"bytes,3,rep,name=proposed_upgrade_connection_hops,json=proposedUpgradeConnectionHops,proto3" json:"proposed_upgrade_connection_hops,omitempty"` + CounterpartyUpgradeFields UpgradeFields `protobuf:"bytes,4,opt,name=counterparty_upgrade_fields,json=counterpartyUpgradeFields,proto3" json:"counterparty_upgrade_fields"` + CounterpartyUpgradeSequence uint64 `protobuf:"varint,5,opt,name=counterparty_upgrade_sequence,json=counterpartyUpgradeSequence,proto3" json:"counterparty_upgrade_sequence,omitempty"` + ProofChannel []byte `protobuf:"bytes,6,opt,name=proof_channel,json=proofChannel,proto3" json:"proof_channel,omitempty"` + ProofUpgrade []byte `protobuf:"bytes,7,opt,name=proof_upgrade,json=proofUpgrade,proto3" json:"proof_upgrade,omitempty"` + ProofHeight types.Height `protobuf:"bytes,8,opt,name=proof_height,json=proofHeight,proto3" json:"proof_height"` + Signer string `protobuf:"bytes,9,opt,name=signer,proto3" json:"signer,omitempty"` } -func (c *msgClient) RecvPacket(ctx context.Context, in *MsgRecvPacket, opts ...grpc.CallOption) (*MsgRecvPacketResponse, error) { - out := new(MsgRecvPacketResponse) - err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/RecvPacket", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil +func (m *MsgChannelUpgradeTry) Reset() { *m = MsgChannelUpgradeTry{} } +func (m *MsgChannelUpgradeTry) String() string { return proto.CompactTextString(m) } +func (*MsgChannelUpgradeTry) ProtoMessage() {} +func (*MsgChannelUpgradeTry) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{22} } - -func (c *msgClient) Timeout(ctx context.Context, in *MsgTimeout, opts ...grpc.CallOption) (*MsgTimeoutResponse, error) { - out := new(MsgTimeoutResponse) - err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/Timeout", in, out, opts...) - if err != nil { - return nil, err +func (m *MsgChannelUpgradeTry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgChannelUpgradeTry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgChannelUpgradeTry.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil } - return out, nil +} +func (m *MsgChannelUpgradeTry) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgChannelUpgradeTry.Merge(m, src) +} +func (m *MsgChannelUpgradeTry) XXX_Size() int { + return m.Size() +} +func (m *MsgChannelUpgradeTry) XXX_DiscardUnknown() { + xxx_messageInfo_MsgChannelUpgradeTry.DiscardUnknown(m) } -func (c *msgClient) TimeoutOnClose(ctx context.Context, in *MsgTimeoutOnClose, opts ...grpc.CallOption) (*MsgTimeoutOnCloseResponse, error) { - out := new(MsgTimeoutOnCloseResponse) - err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/TimeoutOnClose", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil +var xxx_messageInfo_MsgChannelUpgradeTry proto.InternalMessageInfo + +// MsgChannelUpgradeTryResponse defines the MsgChannelUpgradeTry response type +type MsgChannelUpgradeTryResponse struct { + Upgrade Upgrade `protobuf:"bytes,1,opt,name=upgrade,proto3" json:"upgrade"` + UpgradeSequence uint64 `protobuf:"varint,2,opt,name=upgrade_sequence,json=upgradeSequence,proto3" json:"upgrade_sequence,omitempty"` + Result ResponseResultType `protobuf:"varint,3,opt,name=result,proto3,enum=ibc.core.channel.v1.ResponseResultType" json:"result,omitempty"` } -func (c *msgClient) Acknowledgement(ctx context.Context, in *MsgAcknowledgement, opts ...grpc.CallOption) (*MsgAcknowledgementResponse, error) { - out := new(MsgAcknowledgementResponse) - err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/Acknowledgement", in, out, opts...) - if err != nil { - return nil, err +func (m *MsgChannelUpgradeTryResponse) Reset() { *m = MsgChannelUpgradeTryResponse{} } +func (m *MsgChannelUpgradeTryResponse) String() string { return proto.CompactTextString(m) } +func (*MsgChannelUpgradeTryResponse) ProtoMessage() {} +func (*MsgChannelUpgradeTryResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{23} +} +func (m *MsgChannelUpgradeTryResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgChannelUpgradeTryResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgChannelUpgradeTryResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil } - return out, nil } - -// MsgServer is the server API for Msg service. -type MsgServer interface { - // ChannelOpenInit defines a rpc handler method for MsgChannelOpenInit. - ChannelOpenInit(context.Context, *MsgChannelOpenInit) (*MsgChannelOpenInitResponse, error) - // ChannelOpenTry defines a rpc handler method for MsgChannelOpenTry. - ChannelOpenTry(context.Context, *MsgChannelOpenTry) (*MsgChannelOpenTryResponse, error) - // ChannelOpenAck defines a rpc handler method for MsgChannelOpenAck. - ChannelOpenAck(context.Context, *MsgChannelOpenAck) (*MsgChannelOpenAckResponse, error) - // ChannelOpenConfirm defines a rpc handler method for MsgChannelOpenConfirm. - ChannelOpenConfirm(context.Context, *MsgChannelOpenConfirm) (*MsgChannelOpenConfirmResponse, error) - // ChannelCloseInit defines a rpc handler method for MsgChannelCloseInit. - ChannelCloseInit(context.Context, *MsgChannelCloseInit) (*MsgChannelCloseInitResponse, error) - // ChannelCloseConfirm defines a rpc handler method for - // MsgChannelCloseConfirm. - ChannelCloseConfirm(context.Context, *MsgChannelCloseConfirm) (*MsgChannelCloseConfirmResponse, error) - // RecvPacket defines a rpc handler method for MsgRecvPacket. - RecvPacket(context.Context, *MsgRecvPacket) (*MsgRecvPacketResponse, error) - // Timeout defines a rpc handler method for MsgTimeout. - Timeout(context.Context, *MsgTimeout) (*MsgTimeoutResponse, error) - // TimeoutOnClose defines a rpc handler method for MsgTimeoutOnClose. - TimeoutOnClose(context.Context, *MsgTimeoutOnClose) (*MsgTimeoutOnCloseResponse, error) - // Acknowledgement defines a rpc handler method for MsgAcknowledgement. - Acknowledgement(context.Context, *MsgAcknowledgement) (*MsgAcknowledgementResponse, error) +func (m *MsgChannelUpgradeTryResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgChannelUpgradeTryResponse.Merge(m, src) +} +func (m *MsgChannelUpgradeTryResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgChannelUpgradeTryResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgChannelUpgradeTryResponse.DiscardUnknown(m) } -// UnimplementedMsgServer can be embedded to have forward compatible implementations. -type UnimplementedMsgServer struct { +var xxx_messageInfo_MsgChannelUpgradeTryResponse proto.InternalMessageInfo + +// MsgChannelUpgradeAck defines the request type for the ChannelUpgradeAck rpc +type MsgChannelUpgradeAck struct { + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + CounterpartyUpgrade Upgrade `protobuf:"bytes,3,opt,name=counterparty_upgrade,json=counterpartyUpgrade,proto3" json:"counterparty_upgrade"` + ProofChannel []byte `protobuf:"bytes,4,opt,name=proof_channel,json=proofChannel,proto3" json:"proof_channel,omitempty"` + ProofUpgrade []byte `protobuf:"bytes,5,opt,name=proof_upgrade,json=proofUpgrade,proto3" json:"proof_upgrade,omitempty"` + ProofHeight types.Height `protobuf:"bytes,6,opt,name=proof_height,json=proofHeight,proto3" json:"proof_height"` + Signer string `protobuf:"bytes,7,opt,name=signer,proto3" json:"signer,omitempty"` } -func (*UnimplementedMsgServer) ChannelOpenInit(ctx context.Context, req *MsgChannelOpenInit) (*MsgChannelOpenInitResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ChannelOpenInit not implemented") +func (m *MsgChannelUpgradeAck) Reset() { *m = MsgChannelUpgradeAck{} } +func (m *MsgChannelUpgradeAck) String() string { return proto.CompactTextString(m) } +func (*MsgChannelUpgradeAck) ProtoMessage() {} +func (*MsgChannelUpgradeAck) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{24} } -func (*UnimplementedMsgServer) ChannelOpenTry(ctx context.Context, req *MsgChannelOpenTry) (*MsgChannelOpenTryResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ChannelOpenTry not implemented") +func (m *MsgChannelUpgradeAck) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) } -func (*UnimplementedMsgServer) ChannelOpenAck(ctx context.Context, req *MsgChannelOpenAck) (*MsgChannelOpenAckResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ChannelOpenAck not implemented") +func (m *MsgChannelUpgradeAck) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgChannelUpgradeAck.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 (*UnimplementedMsgServer) ChannelOpenConfirm(ctx context.Context, req *MsgChannelOpenConfirm) (*MsgChannelOpenConfirmResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ChannelOpenConfirm not implemented") +func (m *MsgChannelUpgradeAck) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgChannelUpgradeAck.Merge(m, src) } -func (*UnimplementedMsgServer) ChannelCloseInit(ctx context.Context, req *MsgChannelCloseInit) (*MsgChannelCloseInitResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ChannelCloseInit not implemented") +func (m *MsgChannelUpgradeAck) XXX_Size() int { + return m.Size() } -func (*UnimplementedMsgServer) ChannelCloseConfirm(ctx context.Context, req *MsgChannelCloseConfirm) (*MsgChannelCloseConfirmResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ChannelCloseConfirm not implemented") +func (m *MsgChannelUpgradeAck) XXX_DiscardUnknown() { + xxx_messageInfo_MsgChannelUpgradeAck.DiscardUnknown(m) } -func (*UnimplementedMsgServer) RecvPacket(ctx context.Context, req *MsgRecvPacket) (*MsgRecvPacketResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method RecvPacket not implemented") + +var xxx_messageInfo_MsgChannelUpgradeAck proto.InternalMessageInfo + +// MsgChannelUpgradeAckResponse defines MsgChannelUpgradeAck response type +type MsgChannelUpgradeAckResponse struct { + Result ResponseResultType `protobuf:"varint,1,opt,name=result,proto3,enum=ibc.core.channel.v1.ResponseResultType" json:"result,omitempty"` } -func (*UnimplementedMsgServer) Timeout(ctx context.Context, req *MsgTimeout) (*MsgTimeoutResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Timeout not implemented") + +func (m *MsgChannelUpgradeAckResponse) Reset() { *m = MsgChannelUpgradeAckResponse{} } +func (m *MsgChannelUpgradeAckResponse) String() string { return proto.CompactTextString(m) } +func (*MsgChannelUpgradeAckResponse) ProtoMessage() {} +func (*MsgChannelUpgradeAckResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{25} } -func (*UnimplementedMsgServer) TimeoutOnClose(ctx context.Context, req *MsgTimeoutOnClose) (*MsgTimeoutOnCloseResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method TimeoutOnClose not implemented") +func (m *MsgChannelUpgradeAckResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) } -func (*UnimplementedMsgServer) Acknowledgement(ctx context.Context, req *MsgAcknowledgement) (*MsgAcknowledgementResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Acknowledgement not implemented") +func (m *MsgChannelUpgradeAckResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgChannelUpgradeAckResponse.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 RegisterMsgServer(s grpc1.Server, srv MsgServer) { - s.RegisterService(&_Msg_serviceDesc, srv) +func (m *MsgChannelUpgradeAckResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgChannelUpgradeAckResponse.Merge(m, src) +} +func (m *MsgChannelUpgradeAckResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgChannelUpgradeAckResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgChannelUpgradeAckResponse.DiscardUnknown(m) } -func _Msg_ChannelOpenInit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgChannelOpenInit) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).ChannelOpenInit(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/ibc.core.channel.v1.Msg/ChannelOpenInit", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).ChannelOpenInit(ctx, req.(*MsgChannelOpenInit)) - } - return interceptor(ctx, in, info, handler) +var xxx_messageInfo_MsgChannelUpgradeAckResponse proto.InternalMessageInfo + +// MsgChannelUpgradeConfirm defines the request type for the ChannelUpgradeConfirm rpc +type MsgChannelUpgradeConfirm struct { + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + CounterpartyChannelState State `protobuf:"varint,3,opt,name=counterparty_channel_state,json=counterpartyChannelState,proto3,enum=ibc.core.channel.v1.State" json:"counterparty_channel_state,omitempty"` + CounterpartyUpgrade Upgrade `protobuf:"bytes,4,opt,name=counterparty_upgrade,json=counterpartyUpgrade,proto3" json:"counterparty_upgrade"` + ProofChannel []byte `protobuf:"bytes,5,opt,name=proof_channel,json=proofChannel,proto3" json:"proof_channel,omitempty"` + ProofUpgrade []byte `protobuf:"bytes,6,opt,name=proof_upgrade,json=proofUpgrade,proto3" json:"proof_upgrade,omitempty"` + ProofHeight types.Height `protobuf:"bytes,7,opt,name=proof_height,json=proofHeight,proto3" json:"proof_height"` + Signer string `protobuf:"bytes,8,opt,name=signer,proto3" json:"signer,omitempty"` } -func _Msg_ChannelOpenTry_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgChannelOpenTry) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).ChannelOpenTry(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/ibc.core.channel.v1.Msg/ChannelOpenTry", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).ChannelOpenTry(ctx, req.(*MsgChannelOpenTry)) +func (m *MsgChannelUpgradeConfirm) Reset() { *m = MsgChannelUpgradeConfirm{} } +func (m *MsgChannelUpgradeConfirm) String() string { return proto.CompactTextString(m) } +func (*MsgChannelUpgradeConfirm) ProtoMessage() {} +func (*MsgChannelUpgradeConfirm) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{26} +} +func (m *MsgChannelUpgradeConfirm) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgChannelUpgradeConfirm) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgChannelUpgradeConfirm.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil } - return interceptor(ctx, in, info, handler) +} +func (m *MsgChannelUpgradeConfirm) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgChannelUpgradeConfirm.Merge(m, src) +} +func (m *MsgChannelUpgradeConfirm) XXX_Size() int { + return m.Size() +} +func (m *MsgChannelUpgradeConfirm) XXX_DiscardUnknown() { + xxx_messageInfo_MsgChannelUpgradeConfirm.DiscardUnknown(m) } -func _Msg_ChannelOpenAck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgChannelOpenAck) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).ChannelOpenAck(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/ibc.core.channel.v1.Msg/ChannelOpenAck", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).ChannelOpenAck(ctx, req.(*MsgChannelOpenAck)) - } - return interceptor(ctx, in, info, handler) +var xxx_messageInfo_MsgChannelUpgradeConfirm proto.InternalMessageInfo + +// MsgChannelUpgradeConfirmResponse defines MsgChannelUpgradeConfirm response type +type MsgChannelUpgradeConfirmResponse struct { + Result ResponseResultType `protobuf:"varint,1,opt,name=result,proto3,enum=ibc.core.channel.v1.ResponseResultType" json:"result,omitempty"` } -func _Msg_ChannelOpenConfirm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgChannelOpenConfirm) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).ChannelOpenConfirm(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/ibc.core.channel.v1.Msg/ChannelOpenConfirm", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).ChannelOpenConfirm(ctx, req.(*MsgChannelOpenConfirm)) +func (m *MsgChannelUpgradeConfirmResponse) Reset() { *m = MsgChannelUpgradeConfirmResponse{} } +func (m *MsgChannelUpgradeConfirmResponse) String() string { return proto.CompactTextString(m) } +func (*MsgChannelUpgradeConfirmResponse) ProtoMessage() {} +func (*MsgChannelUpgradeConfirmResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{27} +} +func (m *MsgChannelUpgradeConfirmResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgChannelUpgradeConfirmResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgChannelUpgradeConfirmResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil } - return interceptor(ctx, in, info, handler) +} +func (m *MsgChannelUpgradeConfirmResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgChannelUpgradeConfirmResponse.Merge(m, src) +} +func (m *MsgChannelUpgradeConfirmResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgChannelUpgradeConfirmResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgChannelUpgradeConfirmResponse.DiscardUnknown(m) } -func _Msg_ChannelCloseInit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgChannelCloseInit) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).ChannelCloseInit(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/ibc.core.channel.v1.Msg/ChannelCloseInit", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).ChannelCloseInit(ctx, req.(*MsgChannelCloseInit)) - } - return interceptor(ctx, in, info, handler) +var xxx_messageInfo_MsgChannelUpgradeConfirmResponse proto.InternalMessageInfo + +// MsgChannelUpgradeOpen defines the request type for the ChannelUpgradeOpen rpc +type MsgChannelUpgradeOpen struct { + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + CounterpartyChannelState State `protobuf:"varint,3,opt,name=counterparty_channel_state,json=counterpartyChannelState,proto3,enum=ibc.core.channel.v1.State" json:"counterparty_channel_state,omitempty"` + CounterpartyUpgradeSequence uint64 `protobuf:"varint,4,opt,name=counterparty_upgrade_sequence,json=counterpartyUpgradeSequence,proto3" json:"counterparty_upgrade_sequence,omitempty"` + ProofChannel []byte `protobuf:"bytes,5,opt,name=proof_channel,json=proofChannel,proto3" json:"proof_channel,omitempty"` + ProofHeight types.Height `protobuf:"bytes,6,opt,name=proof_height,json=proofHeight,proto3" json:"proof_height"` + Signer string `protobuf:"bytes,7,opt,name=signer,proto3" json:"signer,omitempty"` } -func _Msg_ChannelCloseConfirm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgChannelCloseConfirm) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).ChannelCloseConfirm(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/ibc.core.channel.v1.Msg/ChannelCloseConfirm", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).ChannelCloseConfirm(ctx, req.(*MsgChannelCloseConfirm)) +func (m *MsgChannelUpgradeOpen) Reset() { *m = MsgChannelUpgradeOpen{} } +func (m *MsgChannelUpgradeOpen) String() string { return proto.CompactTextString(m) } +func (*MsgChannelUpgradeOpen) ProtoMessage() {} +func (*MsgChannelUpgradeOpen) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{28} +} +func (m *MsgChannelUpgradeOpen) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgChannelUpgradeOpen) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgChannelUpgradeOpen.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil } - return interceptor(ctx, in, info, handler) +} +func (m *MsgChannelUpgradeOpen) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgChannelUpgradeOpen.Merge(m, src) +} +func (m *MsgChannelUpgradeOpen) XXX_Size() int { + return m.Size() +} +func (m *MsgChannelUpgradeOpen) XXX_DiscardUnknown() { + xxx_messageInfo_MsgChannelUpgradeOpen.DiscardUnknown(m) } -func _Msg_RecvPacket_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgRecvPacket) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).RecvPacket(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/ibc.core.channel.v1.Msg/RecvPacket", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).RecvPacket(ctx, req.(*MsgRecvPacket)) - } - return interceptor(ctx, in, info, handler) +var xxx_messageInfo_MsgChannelUpgradeOpen proto.InternalMessageInfo + +// MsgChannelUpgradeOpenResponse defines the MsgChannelUpgradeOpen response type +type MsgChannelUpgradeOpenResponse struct { } -func _Msg_Timeout_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgTimeout) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).Timeout(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/ibc.core.channel.v1.Msg/Timeout", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).Timeout(ctx, req.(*MsgTimeout)) +func (m *MsgChannelUpgradeOpenResponse) Reset() { *m = MsgChannelUpgradeOpenResponse{} } +func (m *MsgChannelUpgradeOpenResponse) String() string { return proto.CompactTextString(m) } +func (*MsgChannelUpgradeOpenResponse) ProtoMessage() {} +func (*MsgChannelUpgradeOpenResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{29} +} +func (m *MsgChannelUpgradeOpenResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgChannelUpgradeOpenResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgChannelUpgradeOpenResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil } - return interceptor(ctx, in, info, handler) +} +func (m *MsgChannelUpgradeOpenResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgChannelUpgradeOpenResponse.Merge(m, src) +} +func (m *MsgChannelUpgradeOpenResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgChannelUpgradeOpenResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgChannelUpgradeOpenResponse.DiscardUnknown(m) } -func _Msg_TimeoutOnClose_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgTimeoutOnClose) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).TimeoutOnClose(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/ibc.core.channel.v1.Msg/TimeoutOnClose", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).TimeoutOnClose(ctx, req.(*MsgTimeoutOnClose)) - } - return interceptor(ctx, in, info, handler) +var xxx_messageInfo_MsgChannelUpgradeOpenResponse proto.InternalMessageInfo + +// MsgChannelUpgradeTimeout defines the request type for the ChannelUpgradeTimeout rpc +type MsgChannelUpgradeTimeout struct { + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + CounterpartyChannel Channel `protobuf:"bytes,3,opt,name=counterparty_channel,json=counterpartyChannel,proto3" json:"counterparty_channel"` + ProofChannel []byte `protobuf:"bytes,4,opt,name=proof_channel,json=proofChannel,proto3" json:"proof_channel,omitempty"` + ProofHeight types.Height `protobuf:"bytes,5,opt,name=proof_height,json=proofHeight,proto3" json:"proof_height"` + Signer string `protobuf:"bytes,6,opt,name=signer,proto3" json:"signer,omitempty"` } -func _Msg_Acknowledgement_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgAcknowledgement) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).Acknowledgement(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/ibc.core.channel.v1.Msg/Acknowledgement", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).Acknowledgement(ctx, req.(*MsgAcknowledgement)) +func (m *MsgChannelUpgradeTimeout) Reset() { *m = MsgChannelUpgradeTimeout{} } +func (m *MsgChannelUpgradeTimeout) String() string { return proto.CompactTextString(m) } +func (*MsgChannelUpgradeTimeout) ProtoMessage() {} +func (*MsgChannelUpgradeTimeout) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{30} +} +func (m *MsgChannelUpgradeTimeout) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgChannelUpgradeTimeout) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgChannelUpgradeTimeout.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil } - return interceptor(ctx, in, info, handler) +} +func (m *MsgChannelUpgradeTimeout) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgChannelUpgradeTimeout.Merge(m, src) +} +func (m *MsgChannelUpgradeTimeout) XXX_Size() int { + return m.Size() +} +func (m *MsgChannelUpgradeTimeout) XXX_DiscardUnknown() { + xxx_messageInfo_MsgChannelUpgradeTimeout.DiscardUnknown(m) } -var _Msg_serviceDesc = grpc.ServiceDesc{ - ServiceName: "ibc.core.channel.v1.Msg", - HandlerType: (*MsgServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "ChannelOpenInit", - Handler: _Msg_ChannelOpenInit_Handler, - }, - { - MethodName: "ChannelOpenTry", - Handler: _Msg_ChannelOpenTry_Handler, - }, - { - MethodName: "ChannelOpenAck", - Handler: _Msg_ChannelOpenAck_Handler, - }, - { - MethodName: "ChannelOpenConfirm", - Handler: _Msg_ChannelOpenConfirm_Handler, - }, - { - MethodName: "ChannelCloseInit", - Handler: _Msg_ChannelCloseInit_Handler, - }, - { - MethodName: "ChannelCloseConfirm", - Handler: _Msg_ChannelCloseConfirm_Handler, - }, - { - MethodName: "RecvPacket", - Handler: _Msg_RecvPacket_Handler, - }, - { - MethodName: "Timeout", - Handler: _Msg_Timeout_Handler, - }, - { - MethodName: "TimeoutOnClose", - Handler: _Msg_TimeoutOnClose_Handler, - }, - { - MethodName: "Acknowledgement", - Handler: _Msg_Acknowledgement_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "ibc/core/channel/v1/tx.proto", -} +var xxx_messageInfo_MsgChannelUpgradeTimeout proto.InternalMessageInfo -func (m *MsgChannelOpenInit) 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 +// MsgChannelUpgradeTimeoutRepsonse defines the MsgChannelUpgradeTimeout response type +type MsgChannelUpgradeTimeoutResponse struct { } -func (m *MsgChannelOpenInit) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +func (m *MsgChannelUpgradeTimeoutResponse) Reset() { *m = MsgChannelUpgradeTimeoutResponse{} } +func (m *MsgChannelUpgradeTimeoutResponse) String() string { return proto.CompactTextString(m) } +func (*MsgChannelUpgradeTimeoutResponse) ProtoMessage() {} +func (*MsgChannelUpgradeTimeoutResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{31} } - -func (m *MsgChannelOpenInit) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Signer) > 0 { - i -= len(m.Signer) - copy(dAtA[i:], m.Signer) - i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) - i-- - dAtA[i] = 0x1a - } - { - size, err := m.Channel.MarshalToSizedBuffer(dAtA[:i]) +func (m *MsgChannelUpgradeTimeoutResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgChannelUpgradeTimeoutResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgChannelUpgradeTimeoutResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) if err != nil { - return 0, err + return nil, err } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - if len(m.PortId) > 0 { - i -= len(m.PortId) - copy(dAtA[i:], m.PortId) - i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) - i-- - dAtA[i] = 0xa + return b[:n], nil } - return len(dAtA) - i, nil } - -func (m *MsgChannelOpenInitResponse) 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 *MsgChannelUpgradeTimeoutResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgChannelUpgradeTimeoutResponse.Merge(m, src) } - -func (m *MsgChannelOpenInitResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +func (m *MsgChannelUpgradeTimeoutResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgChannelUpgradeTimeoutResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgChannelUpgradeTimeoutResponse.DiscardUnknown(m) } -func (m *MsgChannelOpenInitResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Version) > 0 { - i -= len(m.Version) - copy(dAtA[i:], m.Version) - i = encodeVarintTx(dAtA, i, uint64(len(m.Version))) - i-- - dAtA[i] = 0x12 - } - 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] = 0xa - } - return len(dAtA) - i, nil +var xxx_messageInfo_MsgChannelUpgradeTimeoutResponse proto.InternalMessageInfo + +// MsgChannelUpgradeCancel defines the request type for the ChannelUpgradeCancel rpc +type MsgChannelUpgradeCancel struct { + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + ErrorReceipt ErrorReceipt `protobuf:"bytes,3,opt,name=error_receipt,json=errorReceipt,proto3" json:"error_receipt"` + ProofErrorReceipt []byte `protobuf:"bytes,4,opt,name=proof_error_receipt,json=proofErrorReceipt,proto3" json:"proof_error_receipt,omitempty"` + ProofHeight types.Height `protobuf:"bytes,5,opt,name=proof_height,json=proofHeight,proto3" json:"proof_height"` + Signer string `protobuf:"bytes,6,opt,name=signer,proto3" json:"signer,omitempty"` } -func (m *MsgChannelOpenTry) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err +func (m *MsgChannelUpgradeCancel) Reset() { *m = MsgChannelUpgradeCancel{} } +func (m *MsgChannelUpgradeCancel) String() string { return proto.CompactTextString(m) } +func (*MsgChannelUpgradeCancel) ProtoMessage() {} +func (*MsgChannelUpgradeCancel) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{32} +} +func (m *MsgChannelUpgradeCancel) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgChannelUpgradeCancel) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgChannelUpgradeCancel.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil } - return dAtA[:n], nil +} +func (m *MsgChannelUpgradeCancel) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgChannelUpgradeCancel.Merge(m, src) +} +func (m *MsgChannelUpgradeCancel) XXX_Size() int { + return m.Size() +} +func (m *MsgChannelUpgradeCancel) XXX_DiscardUnknown() { + xxx_messageInfo_MsgChannelUpgradeCancel.DiscardUnknown(m) } -func (m *MsgChannelOpenTry) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +var xxx_messageInfo_MsgChannelUpgradeCancel proto.InternalMessageInfo + +// MsgChannelUpgradeCancelResponse defines the MsgChannelUpgradeCancel response type +type MsgChannelUpgradeCancelResponse struct { } -func (m *MsgChannelOpenTry) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Signer) > 0 { - i -= len(m.Signer) - copy(dAtA[i:], m.Signer) - i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) - i-- - dAtA[i] = 0x3a - } - { - size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) +func (m *MsgChannelUpgradeCancelResponse) Reset() { *m = MsgChannelUpgradeCancelResponse{} } +func (m *MsgChannelUpgradeCancelResponse) String() string { return proto.CompactTextString(m) } +func (*MsgChannelUpgradeCancelResponse) ProtoMessage() {} +func (*MsgChannelUpgradeCancelResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{33} +} +func (m *MsgChannelUpgradeCancelResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgChannelUpgradeCancelResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgChannelUpgradeCancelResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) if err != nil { - return 0, err + return nil, err } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x32 - if len(m.ProofInit) > 0 { - i -= len(m.ProofInit) - copy(dAtA[i:], m.ProofInit) - i = encodeVarintTx(dAtA, i, uint64(len(m.ProofInit))) - i-- - dAtA[i] = 0x2a - } - if len(m.CounterpartyVersion) > 0 { - i -= len(m.CounterpartyVersion) - copy(dAtA[i:], m.CounterpartyVersion) - i = encodeVarintTx(dAtA, i, uint64(len(m.CounterpartyVersion))) - i-- - dAtA[i] = 0x22 + return b[:n], nil } - { - size, err := m.Channel.MarshalToSizedBuffer(dAtA[:i]) +} +func (m *MsgChannelUpgradeCancelResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgChannelUpgradeCancelResponse.Merge(m, src) +} +func (m *MsgChannelUpgradeCancelResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgChannelUpgradeCancelResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgChannelUpgradeCancelResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgChannelUpgradeCancelResponse proto.InternalMessageInfo + +// MsgUpdateParams is the MsgUpdateParams request type. +type MsgUpdateParams struct { + // authority is the address that controls the module (defaults to x/gov unless overwritten). + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // params defines the channel parameters to update. + // + // NOTE: All parameters must be supplied. + Params Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params"` +} + +func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } +func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParams) ProtoMessage() {} +func (*MsgUpdateParams) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{34} +} +func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParams.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) if err != nil { - return 0, err + return nil, err } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - if len(m.PreviousChannelId) > 0 { - i -= len(m.PreviousChannelId) - copy(dAtA[i:], m.PreviousChannelId) - i = encodeVarintTx(dAtA, i, uint64(len(m.PreviousChannelId))) - i-- - dAtA[i] = 0x12 - } - if len(m.PortId) > 0 { - i -= len(m.PortId) - copy(dAtA[i:], m.PortId) - i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) - i-- - dAtA[i] = 0xa + return b[:n], nil } - return len(dAtA) - i, nil } - -func (m *MsgChannelOpenTryResponse) 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 *MsgUpdateParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParams.Merge(m, src) +} +func (m *MsgUpdateParams) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParams) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParams.DiscardUnknown(m) } -func (m *MsgChannelOpenTryResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +var xxx_messageInfo_MsgUpdateParams proto.InternalMessageInfo + +// MsgUpdateParamsResponse defines the MsgUpdateParams response type. +type MsgUpdateParamsResponse struct { } -func (m *MsgChannelOpenTryResponse) 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] = 0x12 - } - if len(m.Version) > 0 { - i -= len(m.Version) - copy(dAtA[i:], m.Version) - i = encodeVarintTx(dAtA, i, uint64(len(m.Version))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil +func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse{} } +func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParamsResponse) ProtoMessage() {} +func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{35} } - -func (m *MsgChannelOpenAck) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err +func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParamsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil } - return dAtA[:n], nil +} +func (m *MsgUpdateParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParamsResponse.Merge(m, src) +} +func (m *MsgUpdateParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParamsResponse.DiscardUnknown(m) } -func (m *MsgChannelOpenAck) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo + +// MsgPruneAcknowledgements defines the request type for the PruneAcknowledgements rpc. +type MsgPruneAcknowledgements struct { + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + Limit uint64 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` + Signer string `protobuf:"bytes,4,opt,name=signer,proto3" json:"signer,omitempty"` } -func (m *MsgChannelOpenAck) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Signer) > 0 { - i -= len(m.Signer) - copy(dAtA[i:], m.Signer) - i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) - i-- - dAtA[i] = 0x3a - } - { - size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) +func (m *MsgPruneAcknowledgements) Reset() { *m = MsgPruneAcknowledgements{} } +func (m *MsgPruneAcknowledgements) String() string { return proto.CompactTextString(m) } +func (*MsgPruneAcknowledgements) ProtoMessage() {} +func (*MsgPruneAcknowledgements) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{36} +} +func (m *MsgPruneAcknowledgements) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgPruneAcknowledgements) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgPruneAcknowledgements.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) if err != nil { - return 0, err + return nil, err } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x32 - if len(m.ProofTry) > 0 { - i -= len(m.ProofTry) - copy(dAtA[i:], m.ProofTry) - i = encodeVarintTx(dAtA, i, uint64(len(m.ProofTry))) - i-- - dAtA[i] = 0x2a - } - if len(m.CounterpartyVersion) > 0 { - i -= len(m.CounterpartyVersion) - copy(dAtA[i:], m.CounterpartyVersion) - i = encodeVarintTx(dAtA, i, uint64(len(m.CounterpartyVersion))) - i-- - dAtA[i] = 0x22 - } - if len(m.CounterpartyChannelId) > 0 { - i -= len(m.CounterpartyChannelId) - copy(dAtA[i:], m.CounterpartyChannelId) - i = encodeVarintTx(dAtA, i, uint64(len(m.CounterpartyChannelId))) - i-- - dAtA[i] = 0x1a - } - 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] = 0x12 - } - if len(m.PortId) > 0 { - i -= len(m.PortId) - copy(dAtA[i:], m.PortId) - i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) - i-- - dAtA[i] = 0xa + return b[:n], nil } - return len(dAtA) - i, nil } - -func (m *MsgChannelOpenAckResponse) 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 *MsgPruneAcknowledgements) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgPruneAcknowledgements.Merge(m, src) } - -func (m *MsgChannelOpenAckResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +func (m *MsgPruneAcknowledgements) XXX_Size() int { + return m.Size() } - -func (m *MsgChannelOpenAckResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil +func (m *MsgPruneAcknowledgements) XXX_DiscardUnknown() { + xxx_messageInfo_MsgPruneAcknowledgements.DiscardUnknown(m) } -func (m *MsgChannelOpenConfirm) 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 -} +var xxx_messageInfo_MsgPruneAcknowledgements proto.InternalMessageInfo -func (m *MsgChannelOpenConfirm) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +// MsgPruneAcknowledgementsResponse defines the response type for the PruneAcknowledgements rpc. +type MsgPruneAcknowledgementsResponse struct { + // Number of sequences pruned (includes both packet acknowledgements and packet receipts where appropriate). + TotalPrunedSequences uint64 `protobuf:"varint,1,opt,name=total_pruned_sequences,json=totalPrunedSequences,proto3" json:"total_pruned_sequences,omitempty"` + // Number of sequences left after pruning. + TotalRemainingSequences uint64 `protobuf:"varint,2,opt,name=total_remaining_sequences,json=totalRemainingSequences,proto3" json:"total_remaining_sequences,omitempty"` } -func (m *MsgChannelOpenConfirm) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Signer) > 0 { - i -= len(m.Signer) - copy(dAtA[i:], m.Signer) - i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) - i-- - dAtA[i] = 0x2a - } - { - size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) +func (m *MsgPruneAcknowledgementsResponse) Reset() { *m = MsgPruneAcknowledgementsResponse{} } +func (m *MsgPruneAcknowledgementsResponse) String() string { return proto.CompactTextString(m) } +func (*MsgPruneAcknowledgementsResponse) ProtoMessage() {} +func (*MsgPruneAcknowledgementsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{37} +} +func (m *MsgPruneAcknowledgementsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgPruneAcknowledgementsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgPruneAcknowledgementsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) if err != nil { - return 0, err + return nil, err } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x22 - if len(m.ProofAck) > 0 { - i -= len(m.ProofAck) - copy(dAtA[i:], m.ProofAck) - i = encodeVarintTx(dAtA, i, uint64(len(m.ProofAck))) - i-- - dAtA[i] = 0x1a - } - 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] = 0x12 - } - if len(m.PortId) > 0 { - i -= len(m.PortId) - copy(dAtA[i:], m.PortId) - i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) - i-- - dAtA[i] = 0xa + return b[:n], nil } - return len(dAtA) - i, nil +} +func (m *MsgPruneAcknowledgementsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgPruneAcknowledgementsResponse.Merge(m, src) +} +func (m *MsgPruneAcknowledgementsResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgPruneAcknowledgementsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgPruneAcknowledgementsResponse.DiscardUnknown(m) } -func (m *MsgChannelOpenConfirmResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err +var xxx_messageInfo_MsgPruneAcknowledgementsResponse proto.InternalMessageInfo + +func (m *MsgPruneAcknowledgementsResponse) GetTotalPrunedSequences() uint64 { + if m != nil { + return m.TotalPrunedSequences } - return dAtA[:n], nil + return 0 } -func (m *MsgChannelOpenConfirmResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +func (m *MsgPruneAcknowledgementsResponse) GetTotalRemainingSequences() uint64 { + if m != nil { + return m.TotalRemainingSequences + } + return 0 } -func (m *MsgChannelOpenConfirmResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil +func init() { + proto.RegisterEnum("ibc.core.channel.v1.ResponseResultType", ResponseResultType_name, ResponseResultType_value) + proto.RegisterType((*MsgChannelOpenInit)(nil), "ibc.core.channel.v1.MsgChannelOpenInit") + proto.RegisterType((*MsgChannelOpenInitResponse)(nil), "ibc.core.channel.v1.MsgChannelOpenInitResponse") + proto.RegisterType((*MsgChannelOpenTry)(nil), "ibc.core.channel.v1.MsgChannelOpenTry") + proto.RegisterType((*MsgChannelOpenTryResponse)(nil), "ibc.core.channel.v1.MsgChannelOpenTryResponse") + proto.RegisterType((*MsgChannelOpenAck)(nil), "ibc.core.channel.v1.MsgChannelOpenAck") + proto.RegisterType((*MsgChannelOpenAckResponse)(nil), "ibc.core.channel.v1.MsgChannelOpenAckResponse") + proto.RegisterType((*MsgChannelOpenConfirm)(nil), "ibc.core.channel.v1.MsgChannelOpenConfirm") + proto.RegisterType((*MsgChannelOpenConfirmResponse)(nil), "ibc.core.channel.v1.MsgChannelOpenConfirmResponse") + proto.RegisterType((*MsgChannelCloseInit)(nil), "ibc.core.channel.v1.MsgChannelCloseInit") + proto.RegisterType((*MsgChannelCloseInitResponse)(nil), "ibc.core.channel.v1.MsgChannelCloseInitResponse") + proto.RegisterType((*MsgChannelCloseConfirm)(nil), "ibc.core.channel.v1.MsgChannelCloseConfirm") + proto.RegisterType((*MsgChannelCloseConfirmResponse)(nil), "ibc.core.channel.v1.MsgChannelCloseConfirmResponse") + proto.RegisterType((*MsgRecvPacket)(nil), "ibc.core.channel.v1.MsgRecvPacket") + proto.RegisterType((*MsgRecvPacketResponse)(nil), "ibc.core.channel.v1.MsgRecvPacketResponse") + proto.RegisterType((*MsgTimeout)(nil), "ibc.core.channel.v1.MsgTimeout") + proto.RegisterType((*MsgTimeoutResponse)(nil), "ibc.core.channel.v1.MsgTimeoutResponse") + proto.RegisterType((*MsgTimeoutOnClose)(nil), "ibc.core.channel.v1.MsgTimeoutOnClose") + proto.RegisterType((*MsgTimeoutOnCloseResponse)(nil), "ibc.core.channel.v1.MsgTimeoutOnCloseResponse") + proto.RegisterType((*MsgAcknowledgement)(nil), "ibc.core.channel.v1.MsgAcknowledgement") + proto.RegisterType((*MsgAcknowledgementResponse)(nil), "ibc.core.channel.v1.MsgAcknowledgementResponse") + proto.RegisterType((*MsgChannelUpgradeInit)(nil), "ibc.core.channel.v1.MsgChannelUpgradeInit") + proto.RegisterType((*MsgChannelUpgradeInitResponse)(nil), "ibc.core.channel.v1.MsgChannelUpgradeInitResponse") + proto.RegisterType((*MsgChannelUpgradeTry)(nil), "ibc.core.channel.v1.MsgChannelUpgradeTry") + proto.RegisterType((*MsgChannelUpgradeTryResponse)(nil), "ibc.core.channel.v1.MsgChannelUpgradeTryResponse") + proto.RegisterType((*MsgChannelUpgradeAck)(nil), "ibc.core.channel.v1.MsgChannelUpgradeAck") + proto.RegisterType((*MsgChannelUpgradeAckResponse)(nil), "ibc.core.channel.v1.MsgChannelUpgradeAckResponse") + proto.RegisterType((*MsgChannelUpgradeConfirm)(nil), "ibc.core.channel.v1.MsgChannelUpgradeConfirm") + proto.RegisterType((*MsgChannelUpgradeConfirmResponse)(nil), "ibc.core.channel.v1.MsgChannelUpgradeConfirmResponse") + proto.RegisterType((*MsgChannelUpgradeOpen)(nil), "ibc.core.channel.v1.MsgChannelUpgradeOpen") + proto.RegisterType((*MsgChannelUpgradeOpenResponse)(nil), "ibc.core.channel.v1.MsgChannelUpgradeOpenResponse") + proto.RegisterType((*MsgChannelUpgradeTimeout)(nil), "ibc.core.channel.v1.MsgChannelUpgradeTimeout") + proto.RegisterType((*MsgChannelUpgradeTimeoutResponse)(nil), "ibc.core.channel.v1.MsgChannelUpgradeTimeoutResponse") + proto.RegisterType((*MsgChannelUpgradeCancel)(nil), "ibc.core.channel.v1.MsgChannelUpgradeCancel") + proto.RegisterType((*MsgChannelUpgradeCancelResponse)(nil), "ibc.core.channel.v1.MsgChannelUpgradeCancelResponse") + proto.RegisterType((*MsgUpdateParams)(nil), "ibc.core.channel.v1.MsgUpdateParams") + proto.RegisterType((*MsgUpdateParamsResponse)(nil), "ibc.core.channel.v1.MsgUpdateParamsResponse") + proto.RegisterType((*MsgPruneAcknowledgements)(nil), "ibc.core.channel.v1.MsgPruneAcknowledgements") + proto.RegisterType((*MsgPruneAcknowledgementsResponse)(nil), "ibc.core.channel.v1.MsgPruneAcknowledgementsResponse") } -func (m *MsgChannelCloseInit) 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 init() { proto.RegisterFile("ibc/core/channel/v1/tx.proto", fileDescriptor_bc4637e0ac3fc7b7) } -func (m *MsgChannelCloseInit) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +var fileDescriptor_bc4637e0ac3fc7b7 = []byte{ + // 1975 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x5a, 0xcf, 0x6f, 0xdb, 0xc8, + 0x15, 0x36, 0xf5, 0x33, 0x7e, 0x4e, 0xd6, 0x0a, 0xe5, 0xc4, 0x32, 0x6d, 0x4b, 0x8a, 0x5a, 0x6c, + 0xbc, 0x6e, 0x22, 0xad, 0xbd, 0x49, 0xd1, 0x0d, 0x16, 0x68, 0x1d, 0x55, 0xe9, 0x1a, 0x88, 0x63, + 0x83, 0xb2, 0x8a, 0x76, 0xb7, 0xa8, 0x20, 0x53, 0x13, 0x8a, 0x90, 0x44, 0x72, 0x49, 0x4a, 0xbb, + 0x2e, 0xd0, 0x62, 0xd1, 0x53, 0x90, 0xc3, 0xa2, 0x05, 0xf6, 0x1a, 0xa0, 0x45, 0xff, 0x81, 0x3d, + 0xf7, 0xc7, 0xa1, 0xb7, 0x3d, 0x15, 0x7b, 0x5c, 0x14, 0xe8, 0xa2, 0x48, 0x0e, 0xb9, 0xf4, 0x2f, + 0x28, 0x50, 0xa0, 0xe0, 0xcc, 0x90, 0xa2, 0xc8, 0xa1, 0x44, 0x59, 0xaa, 0xd1, 0x9b, 0x38, 0xf3, + 0xcd, 0x7b, 0x6f, 0xbe, 0xef, 0xcd, 0xe3, 0xcc, 0x50, 0xb0, 0xa5, 0x9c, 0x49, 0x15, 0x49, 0x33, + 0x50, 0x45, 0xea, 0xb4, 0x54, 0x15, 0xf5, 0x2a, 0xc3, 0xbd, 0x8a, 0xf5, 0x49, 0x59, 0x37, 0x34, + 0x4b, 0xe3, 0xb3, 0xca, 0x99, 0x54, 0xb6, 0x7b, 0xcb, 0xb4, 0xb7, 0x3c, 0xdc, 0x13, 0xd6, 0x64, + 0x4d, 0xd6, 0x70, 0x7f, 0xc5, 0xfe, 0x45, 0xa0, 0xc2, 0xba, 0xa4, 0x99, 0x7d, 0xcd, 0xac, 0xf4, + 0x4d, 0xd9, 0x36, 0xd1, 0x37, 0x65, 0xda, 0x51, 0x18, 0x79, 0xe8, 0x29, 0x48, 0xb5, 0xec, 0x5e, + 0xf2, 0x8b, 0x02, 0x6e, 0xb1, 0x42, 0x70, 0xfc, 0x4d, 0x80, 0x0c, 0x74, 0xd9, 0x68, 0xb5, 0x11, + 0x81, 0x94, 0x3e, 0xe7, 0x80, 0x3f, 0x32, 0xe5, 0x2a, 0xe9, 0x3f, 0xd6, 0x91, 0x7a, 0xa8, 0x2a, + 0x16, 0xbf, 0x0e, 0x69, 0x5d, 0x33, 0xac, 0xa6, 0xd2, 0xce, 0x71, 0x45, 0x6e, 0x67, 0x59, 0x4c, + 0xd9, 0x8f, 0x87, 0x6d, 0xfe, 0x3d, 0x48, 0x53, 0x5b, 0xb9, 0x58, 0x91, 0xdb, 0x59, 0xd9, 0xdf, + 0x2a, 0x33, 0x26, 0x5b, 0xa6, 0xf6, 0x1e, 0x26, 0xbe, 0xfc, 0xa6, 0xb0, 0x24, 0x3a, 0x43, 0xf8, + 0x9b, 0x90, 0x32, 0x15, 0x59, 0x45, 0x46, 0x2e, 0x4e, 0xac, 0x92, 0xa7, 0x07, 0xab, 0xcf, 0x7e, + 0x57, 0x58, 0xfa, 0xf5, 0xeb, 0x2f, 0x76, 0x69, 0x43, 0xe9, 0x43, 0x10, 0x82, 0x51, 0x89, 0xc8, + 0xd4, 0x35, 0xd5, 0x44, 0xfc, 0x36, 0x00, 0xb5, 0x38, 0x0a, 0x70, 0x99, 0xb6, 0x1c, 0xb6, 0xf9, + 0x1c, 0xa4, 0x87, 0xc8, 0x30, 0x15, 0x4d, 0xc5, 0x31, 0x2e, 0x8b, 0xce, 0xe3, 0x83, 0x84, 0xed, + 0xa7, 0xf4, 0x4d, 0x0c, 0xae, 0x8f, 0x5b, 0x3f, 0x35, 0xce, 0xc3, 0xa7, 0xbc, 0x0f, 0x59, 0xdd, + 0x40, 0x43, 0x45, 0x1b, 0x98, 0x4d, 0x8f, 0x5b, 0x6c, 0xfa, 0x61, 0x2c, 0xc7, 0x89, 0xd7, 0x9d, + 0xee, 0xaa, 0x1b, 0x82, 0x87, 0xa6, 0xf8, 0xec, 0x34, 0xed, 0xc1, 0x9a, 0xa4, 0x0d, 0x54, 0x0b, + 0x19, 0x7a, 0xcb, 0xb0, 0xce, 0x9b, 0xce, 0x6c, 0x12, 0x38, 0xae, 0xac, 0xb7, 0xef, 0xc7, 0xa4, + 0xcb, 0xa6, 0x44, 0x37, 0x34, 0xed, 0x69, 0x53, 0x51, 0x15, 0x2b, 0x97, 0x2c, 0x72, 0x3b, 0x57, + 0xc5, 0x65, 0xdc, 0x82, 0xf5, 0xac, 0xc2, 0x55, 0xd2, 0xdd, 0x41, 0x8a, 0xdc, 0xb1, 0x72, 0x29, + 0x1c, 0x94, 0xe0, 0x09, 0x8a, 0xa4, 0xd6, 0x70, 0xaf, 0xfc, 0x3e, 0x46, 0xd0, 0x90, 0x56, 0xf0, + 0x28, 0xd2, 0xe4, 0x51, 0x2f, 0x3d, 0x59, 0xbd, 0x0f, 0x60, 0x23, 0xc0, 0xaf, 0x2b, 0x9e, 0x47, + 0x1d, 0x6e, 0x4c, 0x1d, 0x9f, 0xac, 0x31, 0x9f, 0xac, 0x54, 0xbc, 0xbf, 0x06, 0xc4, 0x3b, 0x90, + 0xba, 0xe1, 0xe2, 0x4d, 0xb6, 0xc9, 0x7f, 0x17, 0xd6, 0xc7, 0x98, 0xf6, 0x60, 0x49, 0x86, 0xde, + 0xf0, 0x76, 0x8f, 0xf4, 0xbd, 0x80, 0x42, 0x9b, 0x40, 0xf4, 0x68, 0x5a, 0xc6, 0x39, 0x15, 0xe8, + 0x0a, 0x6e, 0xb0, 0x93, 0xef, 0x72, 0xf5, 0xd9, 0xf4, 0xeb, 0x73, 0x20, 0x75, 0x1d, 0x7d, 0x4a, + 0x7f, 0xe7, 0xe0, 0xc6, 0x78, 0x6f, 0x55, 0x53, 0x9f, 0x2a, 0x46, 0xff, 0xc2, 0x24, 0xbb, 0x33, + 0x6f, 0x49, 0x5d, 0x4c, 0xab, 0x33, 0x73, 0x5b, 0x39, 0xff, 0xcc, 0x13, 0xf3, 0xcd, 0x3c, 0x39, + 0x79, 0xe6, 0x05, 0xd8, 0x66, 0xce, 0xcd, 0x9d, 0xfd, 0x10, 0xb2, 0x23, 0x40, 0xb5, 0xa7, 0x99, + 0x68, 0x72, 0x3d, 0x9c, 0x32, 0xf5, 0xc8, 0x05, 0x6f, 0x1b, 0x36, 0x19, 0x7e, 0xdd, 0xb0, 0x7e, + 0x1f, 0x83, 0x9b, 0xbe, 0xfe, 0x79, 0x55, 0x19, 0xaf, 0x18, 0xf1, 0x69, 0x15, 0x63, 0x91, 0xba, + 0xf0, 0x0f, 0x61, 0x7b, 0x6c, 0xf9, 0xd0, 0x77, 0x52, 0xd3, 0x44, 0x1f, 0x0d, 0x90, 0x2a, 0x21, + 0x9c, 0xff, 0x09, 0x71, 0xd3, 0x0b, 0x6a, 0x10, 0x4c, 0x9d, 0x42, 0x82, 0x14, 0x16, 0x21, 0xcf, + 0xa6, 0xc8, 0x65, 0xf1, 0x15, 0x07, 0xd7, 0x8e, 0x4c, 0x59, 0x44, 0xd2, 0xf0, 0xa4, 0x25, 0x75, + 0x91, 0xc5, 0xbf, 0x0b, 0x29, 0x1d, 0xff, 0xc2, 0xdc, 0xad, 0xec, 0x6f, 0x32, 0xcb, 0x34, 0x01, + 0xd3, 0x09, 0xd2, 0x01, 0xfc, 0x5b, 0x90, 0x21, 0x04, 0x49, 0x5a, 0xbf, 0xaf, 0x58, 0x7d, 0xa4, + 0x5a, 0x98, 0xe4, 0xab, 0xe2, 0x2a, 0x6e, 0xaf, 0xba, 0xcd, 0x01, 0x2e, 0xe3, 0xf3, 0x71, 0x99, + 0x98, 0x9c, 0x4a, 0x3f, 0xc7, 0xeb, 0x77, 0x34, 0x49, 0xb7, 0xf2, 0x7e, 0x1f, 0x52, 0x06, 0x32, + 0x07, 0x3d, 0x32, 0xd9, 0x37, 0xf6, 0x6f, 0x33, 0x27, 0xeb, 0xc0, 0x45, 0x0c, 0x3d, 0x3d, 0xd7, + 0x91, 0x48, 0x87, 0xd1, 0x0a, 0xfc, 0x59, 0x0c, 0xe0, 0xc8, 0x94, 0x4f, 0x95, 0x3e, 0xd2, 0x06, + 0x8b, 0xa1, 0x70, 0xa0, 0x1a, 0x48, 0x42, 0xca, 0x10, 0xb5, 0xc7, 0x28, 0x6c, 0xb8, 0xcd, 0x8b, + 0xa1, 0xf0, 0x0e, 0xf0, 0x2a, 0xfa, 0xc4, 0x72, 0xd3, 0xac, 0x69, 0x20, 0x69, 0x88, 0xe9, 0x4c, + 0x88, 0x19, 0xbb, 0xc7, 0x49, 0x2e, 0x9b, 0xbc, 0xe8, 0x45, 0xe5, 0x43, 0xbc, 0x85, 0xa2, 0x7c, + 0x2c, 0x9a, 0xed, 0x7f, 0x93, 0xf7, 0x1d, 0xb5, 0x7e, 0xac, 0xe2, 0xc4, 0xbe, 0x24, 0xd2, 0x0b, + 0xb0, 0x42, 0x53, 0xdc, 0x76, 0x4a, 0x6b, 0x04, 0xa9, 0x1a, 0x24, 0x8c, 0x85, 0x14, 0x09, 0xb6, + 0x2a, 0xc9, 0xa9, 0xaa, 0xa4, 0x66, 0x2b, 0x29, 0xe9, 0x0b, 0x94, 0x94, 0x33, 0xfc, 0xa2, 0x1c, + 0xe7, 0x7e, 0xd1, 0x02, 0x3f, 0x8b, 0xe1, 0xf4, 0x39, 0x90, 0xba, 0xaa, 0xf6, 0x71, 0x0f, 0xb5, + 0x65, 0x84, 0x6b, 0xc6, 0x1c, 0x0a, 0xef, 0xc0, 0x6a, 0x6b, 0xdc, 0x9a, 0x23, 0xb0, 0xaf, 0x79, + 0x24, 0xb0, 0x3d, 0xb0, 0x3d, 0x26, 0xf0, 0x81, 0xdd, 0x72, 0xc9, 0x6f, 0x67, 0x09, 0xef, 0xfa, + 0x7d, 0x4c, 0x2c, 0x9a, 0xef, 0x3f, 0x8e, 0xed, 0x6f, 0x68, 0x0a, 0xcc, 0xf5, 0x92, 0xff, 0x01, + 0xa4, 0x9e, 0x2a, 0xa8, 0xd7, 0x36, 0x69, 0x55, 0x2a, 0x31, 0x03, 0xa3, 0x9e, 0x1e, 0x61, 0xa4, + 0xa3, 0x18, 0x19, 0x17, 0xbd, 0xb6, 0x7f, 0xc6, 0x79, 0x37, 0x30, 0x9e, 0xe0, 0x5d, 0x96, 0xde, + 0x83, 0x34, 0x4d, 0x7d, 0x9a, 0x38, 0x5b, 0x93, 0xa2, 0x71, 0x4e, 0x1e, 0x74, 0x88, 0x5d, 0x1c, + 0x02, 0x0b, 0x27, 0x86, 0x17, 0xce, 0xea, 0xc0, 0xb7, 0x58, 0x08, 0x9b, 0xff, 0x89, 0xc3, 0x5a, + 0x20, 0xa0, 0x89, 0xc7, 0xa9, 0x29, 0x64, 0xfe, 0x08, 0x8a, 0xba, 0xa1, 0xe9, 0x9a, 0x89, 0xda, + 0xee, 0x1a, 0x96, 0x34, 0x55, 0x45, 0x92, 0xa5, 0x68, 0x6a, 0xb3, 0xa3, 0xe9, 0x36, 0xcd, 0xf1, + 0x9d, 0x65, 0x71, 0xdb, 0xc1, 0x51, 0xaf, 0x55, 0x17, 0xf5, 0xbe, 0xa6, 0x9b, 0x7c, 0x07, 0x36, + 0x99, 0x05, 0x81, 0x4a, 0x95, 0x98, 0x51, 0xaa, 0x0d, 0x46, 0xe1, 0x20, 0x80, 0xe9, 0xa5, 0x27, + 0x39, 0xb5, 0xf4, 0xf0, 0xdf, 0x82, 0x6b, 0xb4, 0xd4, 0xd2, 0x63, 0x63, 0x0a, 0xaf, 0x45, 0xb2, + 0xfa, 0x28, 0xbb, 0x23, 0x90, 0xa3, 0x70, 0xda, 0x03, 0xa2, 0x16, 0x03, 0x4b, 0xf6, 0xca, 0x7c, + 0x4b, 0x76, 0x79, 0x72, 0x42, 0xfe, 0x8d, 0x83, 0x2d, 0x96, 0xfe, 0x97, 0x9e, 0x8f, 0x9e, 0xf2, + 0x10, 0x9f, 0xa7, 0x3c, 0xfc, 0x23, 0xc6, 0x48, 0xe8, 0x79, 0x8e, 0x98, 0x0d, 0xdf, 0x51, 0xd1, + 0x61, 0x23, 0x1e, 0x99, 0x8d, 0x2c, 0x23, 0x71, 0x82, 0x09, 0x93, 0x88, 0x92, 0x30, 0xc9, 0x08, + 0x09, 0xf3, 0xbf, 0x3d, 0x7b, 0x22, 0x46, 0xbe, 0x78, 0x8e, 0x9f, 0x8b, 0xaa, 0xf2, 0x7f, 0x8a, + 0x43, 0x2e, 0xe0, 0x67, 0xde, 0x23, 0xd3, 0x4f, 0x40, 0x60, 0xde, 0x16, 0x98, 0x56, 0xcb, 0x42, + 0x34, 0xed, 0x04, 0x66, 0xbc, 0x75, 0x1b, 0x21, 0xe6, 0x18, 0x97, 0x09, 0xb8, 0x27, 0x34, 0x49, + 0x12, 0x0b, 0x4e, 0x92, 0x64, 0x94, 0x24, 0x49, 0x45, 0x48, 0x92, 0xf4, 0x7c, 0x49, 0x72, 0x65, + 0x72, 0x92, 0x28, 0x50, 0x0c, 0x13, 0x6f, 0xd1, 0x89, 0xf2, 0x69, 0x9c, 0xb1, 0x1d, 0x38, 0xd6, + 0x91, 0xfa, 0x7f, 0x98, 0x25, 0x53, 0x5f, 0x34, 0x89, 0x0b, 0xbc, 0x68, 0x58, 0x29, 0x71, 0xb9, + 0x25, 0xa1, 0xc0, 0xd8, 0xd3, 0xd8, 0x0a, 0xb8, 0xe7, 0xf6, 0x3f, 0xc7, 0x18, 0x8b, 0xd9, 0x39, + 0x7f, 0x2e, 0xaa, 0x2e, 0xcf, 0x7e, 0x5f, 0x9b, 0x65, 0x08, 0x15, 0xad, 0x2e, 0xfb, 0xf9, 0x4d, + 0xce, 0xc7, 0x6f, 0x6a, 0x32, 0xbf, 0x25, 0xc6, 0x6a, 0xf2, 0x9d, 0x56, 0x4b, 0x7f, 0x89, 0xc1, + 0x7a, 0x70, 0xc9, 0xb5, 0x54, 0x09, 0xf5, 0x2e, 0xcc, 0xf0, 0x63, 0xb8, 0x86, 0x0c, 0x43, 0x33, + 0x9a, 0xf8, 0x40, 0xa9, 0x3b, 0x87, 0xf6, 0x5b, 0x4c, 0x6a, 0x6b, 0x36, 0x52, 0x24, 0x40, 0x3a, + 0xdb, 0xab, 0xc8, 0xd3, 0xc6, 0x97, 0x21, 0x4b, 0x38, 0x1b, 0xb7, 0x49, 0xe8, 0xbd, 0x8e, 0xbb, + 0xbc, 0x36, 0x2e, 0x99, 0xe3, 0x5b, 0x50, 0x08, 0xa1, 0xcf, 0xa5, 0xf8, 0x57, 0xb0, 0x7a, 0x64, + 0xca, 0x0d, 0xbd, 0xdd, 0xb2, 0xd0, 0x49, 0xcb, 0x68, 0xf5, 0x4d, 0x7e, 0x0b, 0x96, 0x5b, 0x03, + 0xab, 0xa3, 0x19, 0x8a, 0x75, 0xee, 0x7c, 0xc7, 0x70, 0x1b, 0xc8, 0x11, 0xd0, 0xc6, 0xd1, 0x4f, + 0x2d, 0x61, 0x47, 0x40, 0x1b, 0x32, 0x3a, 0x02, 0xda, 0x4f, 0x0f, 0x78, 0x27, 0xbe, 0x91, 0xb9, + 0xd2, 0x06, 0x56, 0xd8, 0xeb, 0xdf, 0x0d, 0xed, 0xb7, 0x1c, 0x5e, 0x60, 0x27, 0xc6, 0x40, 0x45, + 0xbe, 0xe3, 0x97, 0x79, 0x61, 0xf9, 0xd7, 0x20, 0xd9, 0x53, 0xfa, 0xf4, 0x6e, 0x31, 0x21, 0x92, + 0x87, 0xe8, 0x47, 0x9d, 0xcf, 0x39, 0x9c, 0xb6, 0xcc, 0x98, 0xdc, 0x97, 0xc0, 0x3d, 0xb8, 0x69, + 0x69, 0x56, 0xab, 0xd7, 0xd4, 0x6d, 0x58, 0xdb, 0xad, 0x84, 0x26, 0x0e, 0x35, 0x21, 0xae, 0xe1, + 0x5e, 0x6c, 0xa3, 0xed, 0x94, 0x40, 0x93, 0x7f, 0x00, 0x1b, 0x64, 0x94, 0x81, 0xfa, 0x2d, 0x45, + 0x55, 0x54, 0xd9, 0x33, 0x90, 0x6c, 0x2f, 0xd7, 0x31, 0x40, 0x74, 0xfa, 0xdd, 0xb1, 0xbb, 0x5f, + 0x73, 0xc0, 0x07, 0x5f, 0x2a, 0xfc, 0x7d, 0x28, 0x8a, 0xb5, 0xfa, 0xc9, 0xf1, 0x93, 0x7a, 0xad, + 0x29, 0xd6, 0xea, 0x8d, 0xc7, 0xa7, 0xcd, 0xd3, 0x9f, 0x9e, 0xd4, 0x9a, 0x8d, 0x27, 0xf5, 0x93, + 0x5a, 0xf5, 0xf0, 0xd1, 0x61, 0xed, 0x87, 0x99, 0x25, 0x61, 0xf5, 0xf9, 0x8b, 0xe2, 0x8a, 0xa7, + 0x89, 0xbf, 0x0d, 0x1b, 0xcc, 0x61, 0x4f, 0x8e, 0x8f, 0x4f, 0x32, 0x9c, 0x70, 0xe5, 0xf9, 0x8b, + 0x62, 0xc2, 0xfe, 0xcd, 0xdf, 0x85, 0x2d, 0x26, 0xb0, 0xde, 0xa8, 0x56, 0x6b, 0xf5, 0x7a, 0x26, + 0x26, 0xac, 0x3c, 0x7f, 0x51, 0x4c, 0xd3, 0xc7, 0x50, 0xf8, 0xa3, 0x83, 0xc3, 0xc7, 0x0d, 0xb1, + 0x96, 0x89, 0x13, 0x38, 0x7d, 0x14, 0x12, 0xcf, 0xfe, 0x90, 0x5f, 0xda, 0xff, 0x57, 0x06, 0xe2, + 0x47, 0xa6, 0xcc, 0x77, 0x61, 0xd5, 0xff, 0x3d, 0x90, 0xfd, 0x72, 0x0d, 0x7e, 0xa2, 0x13, 0x2a, + 0x11, 0x81, 0xae, 0x82, 0x1d, 0x78, 0xc3, 0xf7, 0x21, 0xee, 0xcd, 0x08, 0x26, 0x4e, 0x8d, 0x73, + 0xa1, 0x1c, 0x0d, 0x17, 0xe2, 0xc9, 0xde, 0xd2, 0x47, 0xf1, 0x74, 0x20, 0x75, 0x23, 0x79, 0xf2, + 0xee, 0x61, 0x2d, 0xe0, 0x19, 0x9f, 0x4f, 0x76, 0x23, 0x58, 0xa1, 0x58, 0x61, 0x3f, 0x3a, 0xd6, + 0xf5, 0xaa, 0x42, 0x26, 0xf0, 0xdd, 0x62, 0x67, 0x8a, 0x1d, 0x17, 0x29, 0xbc, 0x1d, 0x15, 0xe9, + 0xfa, 0xfb, 0x18, 0xb2, 0xac, 0xef, 0x11, 0xdf, 0x89, 0x62, 0xc8, 0x99, 0xe7, 0x3b, 0x33, 0x80, + 0x5d, 0xc7, 0x3f, 0x03, 0xf0, 0x5c, 0xe1, 0x97, 0xc2, 0x4c, 0x8c, 0x30, 0xc2, 0xee, 0x74, 0x8c, + 0x6b, 0xbd, 0x0e, 0x69, 0x67, 0x6b, 0x51, 0x08, 0x1b, 0x46, 0x01, 0xc2, 0xed, 0x29, 0x00, 0x6f, + 0xee, 0xf9, 0x6e, 0x70, 0xdf, 0x9c, 0x32, 0x94, 0xe2, 0xc2, 0x73, 0x2f, 0xe4, 0x56, 0xb2, 0x0b, + 0xab, 0xfe, 0xab, 0xc4, 0xd0, 0x28, 0x7d, 0xc0, 0xf0, 0xc5, 0x1b, 0x76, 0x25, 0x37, 0x4a, 0x74, + 0xef, 0x3d, 0xda, 0xb4, 0x44, 0xf7, 0x60, 0xa7, 0x26, 0x3a, 0xeb, 0x8a, 0xeb, 0x23, 0xb8, 0x1e, + 0xbc, 0x6f, 0x7a, 0x2b, 0x9a, 0x21, 0xbb, 0x70, 0xec, 0x45, 0x86, 0x86, 0xbb, 0xb4, 0xcb, 0x47, + 0x44, 0x97, 0x76, 0x05, 0xd9, 0x8b, 0x0c, 0x75, 0x5d, 0xfe, 0x12, 0x6e, 0xb0, 0x4f, 0xaf, 0x77, + 0xa3, 0xd9, 0x72, 0x96, 0xd8, 0xfd, 0x99, 0xe0, 0xe1, 0xd2, 0xe2, 0x33, 0x51, 0x44, 0x69, 0x6d, + 0x6c, 0x54, 0x69, 0xbd, 0x3b, 0xfd, 0xe0, 0xa4, 0x9d, 0xa5, 0x18, 0x71, 0xd2, 0xce, 0xc2, 0xbc, + 0x3f, 0x13, 0xdc, 0x75, 0xff, 0x0b, 0x58, 0x63, 0xee, 0x80, 0xef, 0x44, 0xe4, 0x10, 0xa3, 0x85, + 0x7b, 0xb3, 0xa0, 0x5d, 0xdf, 0x0a, 0x64, 0xc9, 0xde, 0x8c, 0xa2, 0xe8, 0x16, 0xf1, 0xdb, 0x61, + 0xc6, 0xbc, 0x1b, 0x39, 0xe1, 0x4e, 0x14, 0x94, 0x97, 0x65, 0xf6, 0x56, 0x2f, 0x94, 0x65, 0x26, + 0x3c, 0x9c, 0xe5, 0x89, 0x9b, 0x36, 0x21, 0xf9, 0xe9, 0xeb, 0x2f, 0x76, 0xb9, 0x87, 0xf5, 0x2f, + 0x5f, 0xe6, 0xb9, 0xaf, 0x5e, 0xe6, 0xb9, 0x7f, 0xbe, 0xcc, 0x73, 0xbf, 0x79, 0x95, 0x5f, 0xfa, + 0xea, 0x55, 0x7e, 0xe9, 0xeb, 0x57, 0xf9, 0xa5, 0x0f, 0xde, 0x95, 0x15, 0xab, 0x33, 0x38, 0x2b, + 0x4b, 0x5a, 0xbf, 0x42, 0xff, 0x1f, 0xa5, 0x9c, 0x49, 0x77, 0x65, 0xad, 0x32, 0xfc, 0x5e, 0xa5, + 0xaf, 0xb5, 0x07, 0x3d, 0x64, 0x92, 0xff, 0x35, 0xbd, 0x7d, 0xef, 0xae, 0xf3, 0xd7, 0x26, 0xeb, + 0x5c, 0x47, 0xe6, 0x59, 0x0a, 0xff, 0xad, 0xe9, 0x9d, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xf2, + 0x6f, 0x97, 0x8a, 0xa1, 0x25, 0x00, 0x00, } -func (m *MsgChannelCloseInit) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Signer) > 0 { - i -= len(m.Signer) - copy(dAtA[i:], m.Signer) - i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) - i-- - dAtA[i] = 0x1a +// 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 { + // ChannelOpenInit defines a rpc handler method for MsgChannelOpenInit. + ChannelOpenInit(ctx context.Context, in *MsgChannelOpenInit, opts ...grpc.CallOption) (*MsgChannelOpenInitResponse, error) + // ChannelOpenTry defines a rpc handler method for MsgChannelOpenTry. + ChannelOpenTry(ctx context.Context, in *MsgChannelOpenTry, opts ...grpc.CallOption) (*MsgChannelOpenTryResponse, error) + // ChannelOpenAck defines a rpc handler method for MsgChannelOpenAck. + ChannelOpenAck(ctx context.Context, in *MsgChannelOpenAck, opts ...grpc.CallOption) (*MsgChannelOpenAckResponse, error) + // ChannelOpenConfirm defines a rpc handler method for MsgChannelOpenConfirm. + ChannelOpenConfirm(ctx context.Context, in *MsgChannelOpenConfirm, opts ...grpc.CallOption) (*MsgChannelOpenConfirmResponse, error) + // ChannelCloseInit defines a rpc handler method for MsgChannelCloseInit. + ChannelCloseInit(ctx context.Context, in *MsgChannelCloseInit, opts ...grpc.CallOption) (*MsgChannelCloseInitResponse, error) + // ChannelCloseConfirm defines a rpc handler method for + // MsgChannelCloseConfirm. + ChannelCloseConfirm(ctx context.Context, in *MsgChannelCloseConfirm, opts ...grpc.CallOption) (*MsgChannelCloseConfirmResponse, error) + // RecvPacket defines a rpc handler method for MsgRecvPacket. + RecvPacket(ctx context.Context, in *MsgRecvPacket, opts ...grpc.CallOption) (*MsgRecvPacketResponse, error) + // Timeout defines a rpc handler method for MsgTimeout. + Timeout(ctx context.Context, in *MsgTimeout, opts ...grpc.CallOption) (*MsgTimeoutResponse, error) + // TimeoutOnClose defines a rpc handler method for MsgTimeoutOnClose. + TimeoutOnClose(ctx context.Context, in *MsgTimeoutOnClose, opts ...grpc.CallOption) (*MsgTimeoutOnCloseResponse, error) + // Acknowledgement defines a rpc handler method for MsgAcknowledgement. + Acknowledgement(ctx context.Context, in *MsgAcknowledgement, opts ...grpc.CallOption) (*MsgAcknowledgementResponse, error) + // ChannelUpgradeInit defines a rpc handler method for MsgChannelUpgradeInit. + ChannelUpgradeInit(ctx context.Context, in *MsgChannelUpgradeInit, opts ...grpc.CallOption) (*MsgChannelUpgradeInitResponse, error) + // ChannelUpgradeTry defines a rpc handler method for MsgChannelUpgradeTry. + ChannelUpgradeTry(ctx context.Context, in *MsgChannelUpgradeTry, opts ...grpc.CallOption) (*MsgChannelUpgradeTryResponse, error) + // ChannelUpgradeAck defines a rpc handler method for MsgChannelUpgradeAck. + ChannelUpgradeAck(ctx context.Context, in *MsgChannelUpgradeAck, opts ...grpc.CallOption) (*MsgChannelUpgradeAckResponse, error) + // ChannelUpgradeConfirm defines a rpc handler method for MsgChannelUpgradeConfirm. + ChannelUpgradeConfirm(ctx context.Context, in *MsgChannelUpgradeConfirm, opts ...grpc.CallOption) (*MsgChannelUpgradeConfirmResponse, error) + // ChannelUpgradeOpen defines a rpc handler method for MsgChannelUpgradeOpen. + ChannelUpgradeOpen(ctx context.Context, in *MsgChannelUpgradeOpen, opts ...grpc.CallOption) (*MsgChannelUpgradeOpenResponse, error) + // ChannelUpgradeTimeout defines a rpc handler method for MsgChannelUpgradeTimeout. + ChannelUpgradeTimeout(ctx context.Context, in *MsgChannelUpgradeTimeout, opts ...grpc.CallOption) (*MsgChannelUpgradeTimeoutResponse, error) + // ChannelUpgradeCancel defines a rpc handler method for MsgChannelUpgradeCancel. + ChannelUpgradeCancel(ctx context.Context, in *MsgChannelUpgradeCancel, opts ...grpc.CallOption) (*MsgChannelUpgradeCancelResponse, error) + // UpdateChannelParams defines a rpc handler method for MsgUpdateParams. + UpdateChannelParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) + // PruneAcknowledgements defines a rpc handler method for MsgPruneAcknowledgements. + PruneAcknowledgements(ctx context.Context, in *MsgPruneAcknowledgements, opts ...grpc.CallOption) (*MsgPruneAcknowledgementsResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) ChannelOpenInit(ctx context.Context, in *MsgChannelOpenInit, opts ...grpc.CallOption) (*MsgChannelOpenInitResponse, error) { + out := new(MsgChannelOpenInitResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelOpenInit", in, out, opts...) + if err != nil { + return nil, err } - 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] = 0x12 + return out, nil +} + +func (c *msgClient) ChannelOpenTry(ctx context.Context, in *MsgChannelOpenTry, opts ...grpc.CallOption) (*MsgChannelOpenTryResponse, error) { + out := new(MsgChannelOpenTryResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelOpenTry", in, out, opts...) + if err != nil { + return nil, err } - if len(m.PortId) > 0 { - i -= len(m.PortId) - copy(dAtA[i:], m.PortId) - i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) - i-- - dAtA[i] = 0xa + return out, nil +} + +func (c *msgClient) ChannelOpenAck(ctx context.Context, in *MsgChannelOpenAck, opts ...grpc.CallOption) (*MsgChannelOpenAckResponse, error) { + out := new(MsgChannelOpenAckResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelOpenAck", in, out, opts...) + if err != nil { + return nil, err } - return len(dAtA) - i, nil + return out, nil } -func (m *MsgChannelCloseInitResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) +func (c *msgClient) ChannelOpenConfirm(ctx context.Context, in *MsgChannelOpenConfirm, opts ...grpc.CallOption) (*MsgChannelOpenConfirmResponse, error) { + out := new(MsgChannelOpenConfirmResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelOpenConfirm", in, out, opts...) if err != nil { return nil, err } - return dAtA[:n], nil + return out, nil } -func (m *MsgChannelCloseInitResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +func (c *msgClient) ChannelCloseInit(ctx context.Context, in *MsgChannelCloseInit, opts ...grpc.CallOption) (*MsgChannelCloseInitResponse, error) { + out := new(MsgChannelCloseInitResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelCloseInit", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil } -func (m *MsgChannelCloseInitResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil +func (c *msgClient) ChannelCloseConfirm(ctx context.Context, in *MsgChannelCloseConfirm, opts ...grpc.CallOption) (*MsgChannelCloseConfirmResponse, error) { + out := new(MsgChannelCloseConfirmResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelCloseConfirm", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil } -func (m *MsgChannelCloseConfirm) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) +func (c *msgClient) RecvPacket(ctx context.Context, in *MsgRecvPacket, opts ...grpc.CallOption) (*MsgRecvPacketResponse, error) { + out := new(MsgRecvPacketResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/RecvPacket", in, out, opts...) if err != nil { return nil, err } - return dAtA[:n], nil + return out, nil } -func (m *MsgChannelCloseConfirm) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +func (c *msgClient) Timeout(ctx context.Context, in *MsgTimeout, opts ...grpc.CallOption) (*MsgTimeoutResponse, error) { + out := new(MsgTimeoutResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/Timeout", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil } -func (m *MsgChannelCloseConfirm) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Signer) > 0 { - i -= len(m.Signer) - copy(dAtA[i:], m.Signer) - i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) - i-- - dAtA[i] = 0x2a +func (c *msgClient) TimeoutOnClose(ctx context.Context, in *MsgTimeoutOnClose, opts ...grpc.CallOption) (*MsgTimeoutOnCloseResponse, error) { + out := new(MsgTimeoutOnCloseResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/TimeoutOnClose", in, out, opts...) + if err != nil { + return nil, err } - { - size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) + return out, nil +} + +func (c *msgClient) Acknowledgement(ctx context.Context, in *MsgAcknowledgement, opts ...grpc.CallOption) (*MsgAcknowledgementResponse, error) { + out := new(MsgAcknowledgementResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/Acknowledgement", in, out, opts...) + if err != nil { + return nil, err } - i-- - dAtA[i] = 0x22 - if len(m.ProofInit) > 0 { - i -= len(m.ProofInit) - copy(dAtA[i:], m.ProofInit) - i = encodeVarintTx(dAtA, i, uint64(len(m.ProofInit))) - i-- - dAtA[i] = 0x1a + return out, nil +} + +func (c *msgClient) ChannelUpgradeInit(ctx context.Context, in *MsgChannelUpgradeInit, opts ...grpc.CallOption) (*MsgChannelUpgradeInitResponse, error) { + out := new(MsgChannelUpgradeInitResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelUpgradeInit", in, out, opts...) + if err != nil { + return nil, err } - 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] = 0x12 + return out, nil +} + +func (c *msgClient) ChannelUpgradeTry(ctx context.Context, in *MsgChannelUpgradeTry, opts ...grpc.CallOption) (*MsgChannelUpgradeTryResponse, error) { + out := new(MsgChannelUpgradeTryResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelUpgradeTry", in, out, opts...) + if err != nil { + return nil, err } - if len(m.PortId) > 0 { - i -= len(m.PortId) - copy(dAtA[i:], m.PortId) - i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) - i-- - dAtA[i] = 0xa + return out, nil +} + +func (c *msgClient) ChannelUpgradeAck(ctx context.Context, in *MsgChannelUpgradeAck, opts ...grpc.CallOption) (*MsgChannelUpgradeAckResponse, error) { + out := new(MsgChannelUpgradeAckResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelUpgradeAck", in, out, opts...) + if err != nil { + return nil, err } - return len(dAtA) - i, nil + return out, nil } -func (m *MsgChannelCloseConfirmResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) +func (c *msgClient) ChannelUpgradeConfirm(ctx context.Context, in *MsgChannelUpgradeConfirm, opts ...grpc.CallOption) (*MsgChannelUpgradeConfirmResponse, error) { + out := new(MsgChannelUpgradeConfirmResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelUpgradeConfirm", in, out, opts...) if err != nil { return nil, err } - return dAtA[:n], nil + return out, nil } -func (m *MsgChannelCloseConfirmResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +func (c *msgClient) ChannelUpgradeOpen(ctx context.Context, in *MsgChannelUpgradeOpen, opts ...grpc.CallOption) (*MsgChannelUpgradeOpenResponse, error) { + out := new(MsgChannelUpgradeOpenResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelUpgradeOpen", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil } -func (m *MsgChannelCloseConfirmResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil +func (c *msgClient) ChannelUpgradeTimeout(ctx context.Context, in *MsgChannelUpgradeTimeout, opts ...grpc.CallOption) (*MsgChannelUpgradeTimeoutResponse, error) { + out := new(MsgChannelUpgradeTimeoutResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelUpgradeTimeout", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil } -func (m *MsgRecvPacket) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) +func (c *msgClient) ChannelUpgradeCancel(ctx context.Context, in *MsgChannelUpgradeCancel, opts ...grpc.CallOption) (*MsgChannelUpgradeCancelResponse, error) { + out := new(MsgChannelUpgradeCancelResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/ChannelUpgradeCancel", in, out, opts...) if err != nil { return nil, err } - return dAtA[:n], nil + return out, nil } -func (m *MsgRecvPacket) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +func (c *msgClient) UpdateChannelParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) { + out := new(MsgUpdateParamsResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/UpdateChannelParams", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil } -func (m *MsgRecvPacket) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Signer) > 0 { - i -= len(m.Signer) - copy(dAtA[i:], m.Signer) - i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) - i-- - dAtA[i] = 0x22 +func (c *msgClient) PruneAcknowledgements(ctx context.Context, in *MsgPruneAcknowledgements, opts ...grpc.CallOption) (*MsgPruneAcknowledgementsResponse, error) { + out := new(MsgPruneAcknowledgementsResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/PruneAcknowledgements", in, out, opts...) + if err != nil { + return nil, err } - { - size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - if len(m.ProofCommitment) > 0 { - i -= len(m.ProofCommitment) - copy(dAtA[i:], m.ProofCommitment) - i = encodeVarintTx(dAtA, i, uint64(len(m.ProofCommitment))) - i-- - dAtA[i] = 0x12 - } - { - size, err := m.Packet.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + return out, nil } -func (m *MsgRecvPacketResponse) 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 +// MsgServer is the server API for Msg service. +type MsgServer interface { + // ChannelOpenInit defines a rpc handler method for MsgChannelOpenInit. + ChannelOpenInit(context.Context, *MsgChannelOpenInit) (*MsgChannelOpenInitResponse, error) + // ChannelOpenTry defines a rpc handler method for MsgChannelOpenTry. + ChannelOpenTry(context.Context, *MsgChannelOpenTry) (*MsgChannelOpenTryResponse, error) + // ChannelOpenAck defines a rpc handler method for MsgChannelOpenAck. + ChannelOpenAck(context.Context, *MsgChannelOpenAck) (*MsgChannelOpenAckResponse, error) + // ChannelOpenConfirm defines a rpc handler method for MsgChannelOpenConfirm. + ChannelOpenConfirm(context.Context, *MsgChannelOpenConfirm) (*MsgChannelOpenConfirmResponse, error) + // ChannelCloseInit defines a rpc handler method for MsgChannelCloseInit. + ChannelCloseInit(context.Context, *MsgChannelCloseInit) (*MsgChannelCloseInitResponse, error) + // ChannelCloseConfirm defines a rpc handler method for + // MsgChannelCloseConfirm. + ChannelCloseConfirm(context.Context, *MsgChannelCloseConfirm) (*MsgChannelCloseConfirmResponse, error) + // RecvPacket defines a rpc handler method for MsgRecvPacket. + RecvPacket(context.Context, *MsgRecvPacket) (*MsgRecvPacketResponse, error) + // Timeout defines a rpc handler method for MsgTimeout. + Timeout(context.Context, *MsgTimeout) (*MsgTimeoutResponse, error) + // TimeoutOnClose defines a rpc handler method for MsgTimeoutOnClose. + TimeoutOnClose(context.Context, *MsgTimeoutOnClose) (*MsgTimeoutOnCloseResponse, error) + // Acknowledgement defines a rpc handler method for MsgAcknowledgement. + Acknowledgement(context.Context, *MsgAcknowledgement) (*MsgAcknowledgementResponse, error) + // ChannelUpgradeInit defines a rpc handler method for MsgChannelUpgradeInit. + ChannelUpgradeInit(context.Context, *MsgChannelUpgradeInit) (*MsgChannelUpgradeInitResponse, error) + // ChannelUpgradeTry defines a rpc handler method for MsgChannelUpgradeTry. + ChannelUpgradeTry(context.Context, *MsgChannelUpgradeTry) (*MsgChannelUpgradeTryResponse, error) + // ChannelUpgradeAck defines a rpc handler method for MsgChannelUpgradeAck. + ChannelUpgradeAck(context.Context, *MsgChannelUpgradeAck) (*MsgChannelUpgradeAckResponse, error) + // ChannelUpgradeConfirm defines a rpc handler method for MsgChannelUpgradeConfirm. + ChannelUpgradeConfirm(context.Context, *MsgChannelUpgradeConfirm) (*MsgChannelUpgradeConfirmResponse, error) + // ChannelUpgradeOpen defines a rpc handler method for MsgChannelUpgradeOpen. + ChannelUpgradeOpen(context.Context, *MsgChannelUpgradeOpen) (*MsgChannelUpgradeOpenResponse, error) + // ChannelUpgradeTimeout defines a rpc handler method for MsgChannelUpgradeTimeout. + ChannelUpgradeTimeout(context.Context, *MsgChannelUpgradeTimeout) (*MsgChannelUpgradeTimeoutResponse, error) + // ChannelUpgradeCancel defines a rpc handler method for MsgChannelUpgradeCancel. + ChannelUpgradeCancel(context.Context, *MsgChannelUpgradeCancel) (*MsgChannelUpgradeCancelResponse, error) + // UpdateChannelParams defines a rpc handler method for MsgUpdateParams. + UpdateChannelParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) + // PruneAcknowledgements defines a rpc handler method for MsgPruneAcknowledgements. + PruneAcknowledgements(context.Context, *MsgPruneAcknowledgements) (*MsgPruneAcknowledgementsResponse, error) } -func (m *MsgRecvPacketResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { } -func (m *MsgRecvPacketResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Result != 0 { - i = encodeVarintTx(dAtA, i, uint64(m.Result)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil +func (*UnimplementedMsgServer) ChannelOpenInit(ctx context.Context, req *MsgChannelOpenInit) (*MsgChannelOpenInitResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChannelOpenInit not implemented") } - -func (m *MsgTimeout) 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 (*UnimplementedMsgServer) ChannelOpenTry(ctx context.Context, req *MsgChannelOpenTry) (*MsgChannelOpenTryResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChannelOpenTry not implemented") +} +func (*UnimplementedMsgServer) ChannelOpenAck(ctx context.Context, req *MsgChannelOpenAck) (*MsgChannelOpenAckResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChannelOpenAck not implemented") +} +func (*UnimplementedMsgServer) ChannelOpenConfirm(ctx context.Context, req *MsgChannelOpenConfirm) (*MsgChannelOpenConfirmResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChannelOpenConfirm not implemented") +} +func (*UnimplementedMsgServer) ChannelCloseInit(ctx context.Context, req *MsgChannelCloseInit) (*MsgChannelCloseInitResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChannelCloseInit not implemented") +} +func (*UnimplementedMsgServer) ChannelCloseConfirm(ctx context.Context, req *MsgChannelCloseConfirm) (*MsgChannelCloseConfirmResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChannelCloseConfirm not implemented") +} +func (*UnimplementedMsgServer) RecvPacket(ctx context.Context, req *MsgRecvPacket) (*MsgRecvPacketResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RecvPacket not implemented") +} +func (*UnimplementedMsgServer) Timeout(ctx context.Context, req *MsgTimeout) (*MsgTimeoutResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Timeout not implemented") +} +func (*UnimplementedMsgServer) TimeoutOnClose(ctx context.Context, req *MsgTimeoutOnClose) (*MsgTimeoutOnCloseResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method TimeoutOnClose not implemented") +} +func (*UnimplementedMsgServer) Acknowledgement(ctx context.Context, req *MsgAcknowledgement) (*MsgAcknowledgementResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Acknowledgement not implemented") +} +func (*UnimplementedMsgServer) ChannelUpgradeInit(ctx context.Context, req *MsgChannelUpgradeInit) (*MsgChannelUpgradeInitResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChannelUpgradeInit not implemented") +} +func (*UnimplementedMsgServer) ChannelUpgradeTry(ctx context.Context, req *MsgChannelUpgradeTry) (*MsgChannelUpgradeTryResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChannelUpgradeTry not implemented") +} +func (*UnimplementedMsgServer) ChannelUpgradeAck(ctx context.Context, req *MsgChannelUpgradeAck) (*MsgChannelUpgradeAckResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChannelUpgradeAck not implemented") +} +func (*UnimplementedMsgServer) ChannelUpgradeConfirm(ctx context.Context, req *MsgChannelUpgradeConfirm) (*MsgChannelUpgradeConfirmResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChannelUpgradeConfirm not implemented") +} +func (*UnimplementedMsgServer) ChannelUpgradeOpen(ctx context.Context, req *MsgChannelUpgradeOpen) (*MsgChannelUpgradeOpenResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChannelUpgradeOpen not implemented") +} +func (*UnimplementedMsgServer) ChannelUpgradeTimeout(ctx context.Context, req *MsgChannelUpgradeTimeout) (*MsgChannelUpgradeTimeoutResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChannelUpgradeTimeout not implemented") +} +func (*UnimplementedMsgServer) ChannelUpgradeCancel(ctx context.Context, req *MsgChannelUpgradeCancel) (*MsgChannelUpgradeCancelResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChannelUpgradeCancel not implemented") +} +func (*UnimplementedMsgServer) UpdateChannelParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateChannelParams not implemented") +} +func (*UnimplementedMsgServer) PruneAcknowledgements(ctx context.Context, req *MsgPruneAcknowledgements) (*MsgPruneAcknowledgementsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PruneAcknowledgements not implemented") } -func (m *MsgTimeout) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) } -func (m *MsgTimeout) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Signer) > 0 { - i -= len(m.Signer) - copy(dAtA[i:], m.Signer) - i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) - i-- - dAtA[i] = 0x2a - } - if m.NextSequenceRecv != 0 { - i = encodeVarintTx(dAtA, i, uint64(m.NextSequenceRecv)) - i-- - dAtA[i] = 0x20 +func _Msg_ChannelOpenInit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgChannelOpenInit) + if err := dec(in); err != nil { + return nil, err } - { - size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) + if interceptor == nil { + return srv.(MsgServer).ChannelOpenInit(ctx, in) } - i-- - dAtA[i] = 0x1a - if len(m.ProofUnreceived) > 0 { - i -= len(m.ProofUnreceived) - copy(dAtA[i:], m.ProofUnreceived) - i = encodeVarintTx(dAtA, i, uint64(len(m.ProofUnreceived))) - i-- - dAtA[i] = 0x12 + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/ChannelOpenInit", } - { - size, err := m.Packet.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ChannelOpenInit(ctx, req.(*MsgChannelOpenInit)) } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + return interceptor(ctx, in, info, handler) } -func (m *MsgTimeoutResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { +func _Msg_ChannelOpenTry_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgChannelOpenTry) + if err := dec(in); err != nil { return nil, err } - return dAtA[:n], nil -} - -func (m *MsgTimeoutResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgTimeoutResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Result != 0 { - i = encodeVarintTx(dAtA, i, uint64(m.Result)) - i-- - dAtA[i] = 0x8 + if interceptor == nil { + return srv.(MsgServer).ChannelOpenTry(ctx, in) } - return len(dAtA) - i, nil + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/ChannelOpenTry", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ChannelOpenTry(ctx, req.(*MsgChannelOpenTry)) + } + return interceptor(ctx, in, info, handler) } -func (m *MsgTimeoutOnClose) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { +func _Msg_ChannelOpenAck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgChannelOpenAck) + if err := dec(in); err != nil { return nil, err } - return dAtA[:n], nil + if interceptor == nil { + return srv.(MsgServer).ChannelOpenAck(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/ChannelOpenAck", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ChannelOpenAck(ctx, req.(*MsgChannelOpenAck)) + } + return interceptor(ctx, in, info, handler) } -func (m *MsgTimeoutOnClose) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +func _Msg_ChannelOpenConfirm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgChannelOpenConfirm) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ChannelOpenConfirm(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/ChannelOpenConfirm", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ChannelOpenConfirm(ctx, req.(*MsgChannelOpenConfirm)) + } + return interceptor(ctx, in, info, handler) } -func (m *MsgTimeoutOnClose) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Signer) > 0 { - i -= len(m.Signer) - copy(dAtA[i:], m.Signer) - i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) - i-- - dAtA[i] = 0x32 +func _Msg_ChannelCloseInit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgChannelCloseInit) + if err := dec(in); err != nil { + return nil, err } - if m.NextSequenceRecv != 0 { - i = encodeVarintTx(dAtA, i, uint64(m.NextSequenceRecv)) - i-- - dAtA[i] = 0x28 + if interceptor == nil { + return srv.(MsgServer).ChannelCloseInit(ctx, in) } - { - size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/ChannelCloseInit", } - i-- - dAtA[i] = 0x22 - if len(m.ProofClose) > 0 { - i -= len(m.ProofClose) - copy(dAtA[i:], m.ProofClose) - i = encodeVarintTx(dAtA, i, uint64(len(m.ProofClose))) - i-- - dAtA[i] = 0x1a + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ChannelCloseInit(ctx, req.(*MsgChannelCloseInit)) } - if len(m.ProofUnreceived) > 0 { - i -= len(m.ProofUnreceived) - copy(dAtA[i:], m.ProofUnreceived) - i = encodeVarintTx(dAtA, i, uint64(len(m.ProofUnreceived))) - i-- - dAtA[i] = 0x12 + return interceptor(ctx, in, info, handler) +} + +func _Msg_ChannelCloseConfirm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgChannelCloseConfirm) + if err := dec(in); err != nil { + return nil, err } - { - size, err := m.Packet.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) + if interceptor == nil { + return srv.(MsgServer).ChannelCloseConfirm(ctx, in) } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/ChannelCloseConfirm", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ChannelCloseConfirm(ctx, req.(*MsgChannelCloseConfirm)) + } + return interceptor(ctx, in, info, handler) } -func (m *MsgTimeoutOnCloseResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { +func _Msg_RecvPacket_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRecvPacket) + if err := dec(in); err != nil { return nil, err } - return dAtA[:n], nil + if interceptor == nil { + return srv.(MsgServer).RecvPacket(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/RecvPacket", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).RecvPacket(ctx, req.(*MsgRecvPacket)) + } + return interceptor(ctx, in, info, handler) } -func (m *MsgTimeoutOnCloseResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +func _Msg_Timeout_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgTimeout) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Timeout(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/Timeout", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Timeout(ctx, req.(*MsgTimeout)) + } + return interceptor(ctx, in, info, handler) } -func (m *MsgTimeoutOnCloseResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Result != 0 { - i = encodeVarintTx(dAtA, i, uint64(m.Result)) - i-- - dAtA[i] = 0x8 +func _Msg_TimeoutOnClose_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgTimeoutOnClose) + if err := dec(in); err != nil { + return nil, err } - return len(dAtA) - i, nil + if interceptor == nil { + return srv.(MsgServer).TimeoutOnClose(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/TimeoutOnClose", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).TimeoutOnClose(ctx, req.(*MsgTimeoutOnClose)) + } + return interceptor(ctx, in, info, handler) } -func (m *MsgAcknowledgement) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { +func _Msg_Acknowledgement_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgAcknowledgement) + if err := dec(in); err != nil { return nil, err } - return dAtA[:n], nil + if interceptor == nil { + return srv.(MsgServer).Acknowledgement(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/Acknowledgement", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Acknowledgement(ctx, req.(*MsgAcknowledgement)) + } + return interceptor(ctx, in, info, handler) } -func (m *MsgAcknowledgement) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +func _Msg_ChannelUpgradeInit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgChannelUpgradeInit) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ChannelUpgradeInit(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/ChannelUpgradeInit", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ChannelUpgradeInit(ctx, req.(*MsgChannelUpgradeInit)) + } + return interceptor(ctx, in, info, handler) } -func (m *MsgAcknowledgement) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Signer) > 0 { - i -= len(m.Signer) - copy(dAtA[i:], m.Signer) - i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) - i-- - dAtA[i] = 0x2a - } - { - size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) +func _Msg_ChannelUpgradeTry_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgChannelUpgradeTry) + if err := dec(in); err != nil { + return nil, err } - i-- - dAtA[i] = 0x22 - if len(m.ProofAcked) > 0 { - i -= len(m.ProofAcked) - copy(dAtA[i:], m.ProofAcked) - i = encodeVarintTx(dAtA, i, uint64(len(m.ProofAcked))) - i-- - dAtA[i] = 0x1a + if interceptor == nil { + return srv.(MsgServer).ChannelUpgradeTry(ctx, in) } - if len(m.Acknowledgement) > 0 { - i -= len(m.Acknowledgement) - copy(dAtA[i:], m.Acknowledgement) - i = encodeVarintTx(dAtA, i, uint64(len(m.Acknowledgement))) - i-- - dAtA[i] = 0x12 + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/ChannelUpgradeTry", } - { - size, err := m.Packet.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ChannelUpgradeTry(ctx, req.(*MsgChannelUpgradeTry)) } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + return interceptor(ctx, in, info, handler) } -func (m *MsgAcknowledgementResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { +func _Msg_ChannelUpgradeAck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgChannelUpgradeAck) + if err := dec(in); err != nil { return nil, err } - return dAtA[:n], nil + if interceptor == nil { + return srv.(MsgServer).ChannelUpgradeAck(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/ChannelUpgradeAck", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ChannelUpgradeAck(ctx, req.(*MsgChannelUpgradeAck)) + } + return interceptor(ctx, in, info, handler) } -func (m *MsgAcknowledgementResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +func _Msg_ChannelUpgradeConfirm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgChannelUpgradeConfirm) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ChannelUpgradeConfirm(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/ChannelUpgradeConfirm", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ChannelUpgradeConfirm(ctx, req.(*MsgChannelUpgradeConfirm)) + } + return interceptor(ctx, in, info, handler) } -func (m *MsgAcknowledgementResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Result != 0 { - i = encodeVarintTx(dAtA, i, uint64(m.Result)) - i-- - dAtA[i] = 0x8 - } - 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++ +func _Msg_ChannelUpgradeOpen_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgChannelUpgradeOpen) + if err := dec(in); err != nil { + return nil, err } - dAtA[offset] = uint8(v) - return base -} -func (m *MsgChannelOpenInit) Size() (n int) { - if m == nil { - return 0 + if interceptor == nil { + return srv.(MsgServer).ChannelUpgradeOpen(ctx, in) } - var l int - _ = l - l = len(m.PortId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/ChannelUpgradeOpen", } - l = m.Channel.Size() - n += 1 + l + sovTx(uint64(l)) - l = len(m.Signer) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ChannelUpgradeOpen(ctx, req.(*MsgChannelUpgradeOpen)) } - return n + return interceptor(ctx, in, info, handler) } -func (m *MsgChannelOpenInitResponse) Size() (n int) { - if m == nil { - return 0 +func _Msg_ChannelUpgradeTimeout_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgChannelUpgradeTimeout) + if err := dec(in); err != nil { + return nil, err } - var l int - _ = l - l = len(m.ChannelId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if interceptor == nil { + return srv.(MsgServer).ChannelUpgradeTimeout(ctx, in) } - l = len(m.Version) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/ChannelUpgradeTimeout", } - return n + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ChannelUpgradeTimeout(ctx, req.(*MsgChannelUpgradeTimeout)) + } + return interceptor(ctx, in, info, handler) } -func (m *MsgChannelOpenTry) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.PortId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.PreviousChannelId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) +func _Msg_ChannelUpgradeCancel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgChannelUpgradeCancel) + if err := dec(in); err != nil { + return nil, err } - l = m.Channel.Size() - n += 1 + l + sovTx(uint64(l)) - l = len(m.CounterpartyVersion) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if interceptor == nil { + return srv.(MsgServer).ChannelUpgradeCancel(ctx, in) } - l = len(m.ProofInit) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/ChannelUpgradeCancel", } - l = m.ProofHeight.Size() - n += 1 + l + sovTx(uint64(l)) - l = len(m.Signer) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ChannelUpgradeCancel(ctx, req.(*MsgChannelUpgradeCancel)) } - return n + return interceptor(ctx, in, info, handler) } -func (m *MsgChannelOpenTryResponse) Size() (n int) { - if m == nil { - return 0 +func _Msg_UpdateChannelParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateParams) + if err := dec(in); err != nil { + return nil, err } - var l int - _ = l - l = len(m.Version) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if interceptor == nil { + return srv.(MsgServer).UpdateChannelParams(ctx, in) } - l = len(m.ChannelId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/UpdateChannelParams", } - return n + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateChannelParams(ctx, req.(*MsgUpdateParams)) + } + return interceptor(ctx, in, info, handler) } -func (m *MsgChannelOpenAck) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.PortId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.ChannelId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.CounterpartyChannelId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) +func _Msg_PruneAcknowledgements_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgPruneAcknowledgements) + if err := dec(in); err != nil { + return nil, err } - l = len(m.CounterpartyVersion) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if interceptor == nil { + return srv.(MsgServer).PruneAcknowledgements(ctx, in) } - l = len(m.ProofTry) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/PruneAcknowledgements", } - l = m.ProofHeight.Size() - n += 1 + l + sovTx(uint64(l)) - l = len(m.Signer) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).PruneAcknowledgements(ctx, req.(*MsgPruneAcknowledgements)) } - return n + return interceptor(ctx, in, info, handler) } -func (m *MsgChannelOpenAckResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "ibc.core.channel.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ChannelOpenInit", + Handler: _Msg_ChannelOpenInit_Handler, + }, + { + MethodName: "ChannelOpenTry", + Handler: _Msg_ChannelOpenTry_Handler, + }, + { + MethodName: "ChannelOpenAck", + Handler: _Msg_ChannelOpenAck_Handler, + }, + { + MethodName: "ChannelOpenConfirm", + Handler: _Msg_ChannelOpenConfirm_Handler, + }, + { + MethodName: "ChannelCloseInit", + Handler: _Msg_ChannelCloseInit_Handler, + }, + { + MethodName: "ChannelCloseConfirm", + Handler: _Msg_ChannelCloseConfirm_Handler, + }, + { + MethodName: "RecvPacket", + Handler: _Msg_RecvPacket_Handler, + }, + { + MethodName: "Timeout", + Handler: _Msg_Timeout_Handler, + }, + { + MethodName: "TimeoutOnClose", + Handler: _Msg_TimeoutOnClose_Handler, + }, + { + MethodName: "Acknowledgement", + Handler: _Msg_Acknowledgement_Handler, + }, + { + MethodName: "ChannelUpgradeInit", + Handler: _Msg_ChannelUpgradeInit_Handler, + }, + { + MethodName: "ChannelUpgradeTry", + Handler: _Msg_ChannelUpgradeTry_Handler, + }, + { + MethodName: "ChannelUpgradeAck", + Handler: _Msg_ChannelUpgradeAck_Handler, + }, + { + MethodName: "ChannelUpgradeConfirm", + Handler: _Msg_ChannelUpgradeConfirm_Handler, + }, + { + MethodName: "ChannelUpgradeOpen", + Handler: _Msg_ChannelUpgradeOpen_Handler, + }, + { + MethodName: "ChannelUpgradeTimeout", + Handler: _Msg_ChannelUpgradeTimeout_Handler, + }, + { + MethodName: "ChannelUpgradeCancel", + Handler: _Msg_ChannelUpgradeCancel_Handler, + }, + { + MethodName: "UpdateChannelParams", + Handler: _Msg_UpdateChannelParams_Handler, + }, + { + MethodName: "PruneAcknowledgements", + Handler: _Msg_PruneAcknowledgements_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "ibc/core/channel/v1/tx.proto", } -func (m *MsgChannelOpenConfirm) Size() (n int) { - if m == nil { - return 0 +func (m *MsgChannelOpenInit) 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 *MsgChannelOpenInit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelOpenInit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - l = len(m.PortId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x1a } - l = len(m.ChannelId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + { + size, err := m.Channel.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) } - l = len(m.ProofAck) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = m.ProofHeight.Size() - n += 1 + l + sovTx(uint64(l)) - l = len(m.Signer) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + i-- + dAtA[i] = 0x12 + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa } - return n + return len(dAtA) - i, nil } -func (m *MsgChannelOpenConfirmResponse) Size() (n int) { - if m == nil { - return 0 +func (m *MsgChannelOpenInitResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - var l int - _ = l - return n + return dAtA[:n], nil } -func (m *MsgChannelCloseInit) Size() (n int) { - if m == nil { - return 0 - } +func (m *MsgChannelOpenInitResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelOpenInitResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - l = len(m.PortId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.ChannelId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.Version) > 0 { + i -= len(m.Version) + copy(dAtA[i:], m.Version) + i = encodeVarintTx(dAtA, i, uint64(len(m.Version))) + i-- + dAtA[i] = 0x12 } - l = len(m.Signer) - if l > 0 { - n += 1 + l + sovTx(uint64(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] = 0xa } - return n + return len(dAtA) - i, nil } -func (m *MsgChannelCloseInitResponse) Size() (n int) { - if m == nil { - return 0 +func (m *MsgChannelOpenTry) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - var l int - _ = l - return n + return dAtA[:n], nil } -func (m *MsgChannelCloseConfirm) Size() (n int) { - if m == nil { - return 0 - } +func (m *MsgChannelOpenTry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelOpenTry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - l = len(m.PortId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.ChannelId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x3a } - l = len(m.ProofInit) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + { + size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) } - l = m.ProofHeight.Size() - n += 1 + l + sovTx(uint64(l)) - l = len(m.Signer) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + i-- + dAtA[i] = 0x32 + if len(m.ProofInit) > 0 { + i -= len(m.ProofInit) + copy(dAtA[i:], m.ProofInit) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProofInit))) + i-- + dAtA[i] = 0x2a } - return n -} - -func (m *MsgChannelCloseConfirmResponse) Size() (n int) { - if m == nil { - return 0 + if len(m.CounterpartyVersion) > 0 { + i -= len(m.CounterpartyVersion) + copy(dAtA[i:], m.CounterpartyVersion) + i = encodeVarintTx(dAtA, i, uint64(len(m.CounterpartyVersion))) + i-- + dAtA[i] = 0x22 } - var l int - _ = l - return n -} - -func (m *MsgRecvPacket) Size() (n int) { - if m == nil { - return 0 + { + size, err := m.Channel.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) } - var l int - _ = l - l = m.Packet.Size() - n += 1 + l + sovTx(uint64(l)) - l = len(m.ProofCommitment) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + i-- + dAtA[i] = 0x1a + if len(m.PreviousChannelId) > 0 { + i -= len(m.PreviousChannelId) + copy(dAtA[i:], m.PreviousChannelId) + i = encodeVarintTx(dAtA, i, uint64(len(m.PreviousChannelId))) + i-- + dAtA[i] = 0x12 } - l = m.ProofHeight.Size() - n += 1 + l + sovTx(uint64(l)) - l = len(m.Signer) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa } - return n + return len(dAtA) - i, nil } -func (m *MsgRecvPacketResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Result != 0 { - n += 1 + sovTx(uint64(m.Result)) +func (m *MsgChannelOpenTryResponse) 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 n + return dAtA[:n], nil } -func (m *MsgTimeout) Size() (n int) { - if m == nil { - return 0 - } +func (m *MsgChannelOpenTryResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelOpenTryResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - l = m.Packet.Size() - n += 1 + l + sovTx(uint64(l)) - l = len(m.ProofUnreceived) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = m.ProofHeight.Size() - n += 1 + l + sovTx(uint64(l)) - if m.NextSequenceRecv != 0 { - n += 1 + sovTx(uint64(m.NextSequenceRecv)) + 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] = 0x12 } - l = len(m.Signer) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.Version) > 0 { + i -= len(m.Version) + copy(dAtA[i:], m.Version) + i = encodeVarintTx(dAtA, i, uint64(len(m.Version))) + i-- + dAtA[i] = 0xa } - return n + return len(dAtA) - i, nil } -func (m *MsgTimeoutResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Result != 0 { - n += 1 + sovTx(uint64(m.Result)) +func (m *MsgChannelOpenAck) 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 n + return dAtA[:n], nil } -func (m *MsgTimeoutOnClose) Size() (n int) { - if m == nil { - return 0 - } +func (m *MsgChannelOpenAck) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelOpenAck) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - l = m.Packet.Size() - n += 1 + l + sovTx(uint64(l)) - l = len(m.ProofUnreceived) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x3a } - l = len(m.ProofClose) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + { + size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) } - l = m.ProofHeight.Size() - n += 1 + l + sovTx(uint64(l)) - if m.NextSequenceRecv != 0 { - n += 1 + sovTx(uint64(m.NextSequenceRecv)) + i-- + dAtA[i] = 0x32 + if len(m.ProofTry) > 0 { + i -= len(m.ProofTry) + copy(dAtA[i:], m.ProofTry) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProofTry))) + i-- + dAtA[i] = 0x2a } - l = len(m.Signer) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.CounterpartyVersion) > 0 { + i -= len(m.CounterpartyVersion) + copy(dAtA[i:], m.CounterpartyVersion) + i = encodeVarintTx(dAtA, i, uint64(len(m.CounterpartyVersion))) + i-- + dAtA[i] = 0x22 } - return n + if len(m.CounterpartyChannelId) > 0 { + i -= len(m.CounterpartyChannelId) + copy(dAtA[i:], m.CounterpartyChannelId) + i = encodeVarintTx(dAtA, i, uint64(len(m.CounterpartyChannelId))) + i-- + dAtA[i] = 0x1a + } + 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] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } -func (m *MsgTimeoutOnCloseResponse) Size() (n int) { - if m == nil { - return 0 +func (m *MsgChannelOpenAckResponse) 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 *MsgChannelOpenAckResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelOpenAckResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if m.Result != 0 { - n += 1 + sovTx(uint64(m.Result)) - } - return n + return len(dAtA) - i, nil } -func (m *MsgAcknowledgement) Size() (n int) { - if m == nil { - return 0 +func (m *MsgChannelOpenConfirm) 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 *MsgChannelOpenConfirm) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelOpenConfirm) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - l = m.Packet.Size() - n += 1 + l + sovTx(uint64(l)) - l = len(m.Acknowledgement) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x2a } - l = len(m.ProofAcked) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + { + size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) } - l = m.ProofHeight.Size() - n += 1 + l + sovTx(uint64(l)) - l = len(m.Signer) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + i-- + dAtA[i] = 0x22 + if len(m.ProofAck) > 0 { + i -= len(m.ProofAck) + copy(dAtA[i:], m.ProofAck) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProofAck))) + i-- + dAtA[i] = 0x1a } - return n + 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] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } -func (m *MsgAcknowledgementResponse) Size() (n int) { - if m == nil { - return 0 +func (m *MsgChannelOpenConfirmResponse) 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 *MsgChannelOpenConfirmResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelOpenConfirmResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if m.Result != 0 { - n += 1 + sovTx(uint64(m.Result)) + return len(dAtA) - i, nil +} + +func (m *MsgChannelCloseInit) 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 n + return dAtA[:n], nil } -func sovTx(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 +func (m *MsgChannelCloseInit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } -func sozTx(x uint64) (n int) { - return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) + +func (m *MsgChannelCloseInit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x1a + } + 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] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgChannelCloseInitResponse) 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 *MsgChannelCloseInitResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelCloseInitResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgChannelCloseConfirm) 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 *MsgChannelCloseConfirm) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelCloseConfirm) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.CounterpartyUpgradeSequence != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.CounterpartyUpgradeSequence)) + i-- + dAtA[i] = 0x30 + } + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x2a + } + { + size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if len(m.ProofInit) > 0 { + i -= len(m.ProofInit) + copy(dAtA[i:], m.ProofInit) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProofInit))) + i-- + dAtA[i] = 0x1a + } + 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] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgChannelCloseConfirmResponse) 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 *MsgChannelCloseConfirmResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelCloseConfirmResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgRecvPacket) 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 *MsgRecvPacket) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRecvPacket) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x22 + } + { + size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.ProofCommitment) > 0 { + i -= len(m.ProofCommitment) + copy(dAtA[i:], m.ProofCommitment) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProofCommitment))) + i-- + dAtA[i] = 0x12 + } + { + size, err := m.Packet.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *MsgRecvPacketResponse) 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 *MsgRecvPacketResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRecvPacketResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Result != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Result)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MsgTimeout) 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 *MsgTimeout) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgTimeout) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x2a + } + if m.NextSequenceRecv != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.NextSequenceRecv)) + i-- + dAtA[i] = 0x20 + } + { + size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.ProofUnreceived) > 0 { + i -= len(m.ProofUnreceived) + copy(dAtA[i:], m.ProofUnreceived) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProofUnreceived))) + i-- + dAtA[i] = 0x12 + } + { + size, err := m.Packet.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *MsgTimeoutResponse) 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 *MsgTimeoutResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgTimeoutResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Result != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Result)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MsgTimeoutOnClose) 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 *MsgTimeoutOnClose) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgTimeoutOnClose) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.CounterpartyUpgradeSequence != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.CounterpartyUpgradeSequence)) + i-- + dAtA[i] = 0x38 + } + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x32 + } + if m.NextSequenceRecv != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.NextSequenceRecv)) + i-- + dAtA[i] = 0x28 + } + { + size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if len(m.ProofClose) > 0 { + i -= len(m.ProofClose) + copy(dAtA[i:], m.ProofClose) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProofClose))) + i-- + dAtA[i] = 0x1a + } + if len(m.ProofUnreceived) > 0 { + i -= len(m.ProofUnreceived) + copy(dAtA[i:], m.ProofUnreceived) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProofUnreceived))) + i-- + dAtA[i] = 0x12 + } + { + size, err := m.Packet.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *MsgTimeoutOnCloseResponse) 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 *MsgTimeoutOnCloseResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgTimeoutOnCloseResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Result != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Result)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MsgAcknowledgement) 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 *MsgAcknowledgement) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgAcknowledgement) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x2a + } + { + size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if len(m.ProofAcked) > 0 { + i -= len(m.ProofAcked) + copy(dAtA[i:], m.ProofAcked) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProofAcked))) + i-- + dAtA[i] = 0x1a + } + if len(m.Acknowledgement) > 0 { + i -= len(m.Acknowledgement) + copy(dAtA[i:], m.Acknowledgement) + i = encodeVarintTx(dAtA, i, uint64(len(m.Acknowledgement))) + i-- + dAtA[i] = 0x12 + } + { + size, err := m.Packet.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *MsgAcknowledgementResponse) 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 *MsgAcknowledgementResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgAcknowledgementResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Result != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Result)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MsgChannelUpgradeInit) 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 *MsgChannelUpgradeInit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelUpgradeInit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x22 + } + { + size, err := m.Fields.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + 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] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgChannelUpgradeInitResponse) 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 *MsgChannelUpgradeInitResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelUpgradeInitResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.UpgradeSequence != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.UpgradeSequence)) + i-- + dAtA[i] = 0x10 + } + { + size, err := m.Upgrade.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *MsgChannelUpgradeTry) 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 *MsgChannelUpgradeTry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelUpgradeTry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x4a + } + { + size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + if len(m.ProofUpgrade) > 0 { + i -= len(m.ProofUpgrade) + copy(dAtA[i:], m.ProofUpgrade) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProofUpgrade))) + i-- + dAtA[i] = 0x3a + } + if len(m.ProofChannel) > 0 { + i -= len(m.ProofChannel) + copy(dAtA[i:], m.ProofChannel) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProofChannel))) + i-- + dAtA[i] = 0x32 + } + if m.CounterpartyUpgradeSequence != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.CounterpartyUpgradeSequence)) + i-- + dAtA[i] = 0x28 + } + { + size, err := m.CounterpartyUpgradeFields.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if len(m.ProposedUpgradeConnectionHops) > 0 { + for iNdEx := len(m.ProposedUpgradeConnectionHops) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ProposedUpgradeConnectionHops[iNdEx]) + copy(dAtA[i:], m.ProposedUpgradeConnectionHops[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProposedUpgradeConnectionHops[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + 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] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgChannelUpgradeTryResponse) 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 *MsgChannelUpgradeTryResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelUpgradeTryResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Result != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Result)) + i-- + dAtA[i] = 0x18 + } + if m.UpgradeSequence != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.UpgradeSequence)) + i-- + dAtA[i] = 0x10 + } + { + size, err := m.Upgrade.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *MsgChannelUpgradeAck) 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 *MsgChannelUpgradeAck) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelUpgradeAck) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x3a + } + { + size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + if len(m.ProofUpgrade) > 0 { + i -= len(m.ProofUpgrade) + copy(dAtA[i:], m.ProofUpgrade) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProofUpgrade))) + i-- + dAtA[i] = 0x2a + } + if len(m.ProofChannel) > 0 { + i -= len(m.ProofChannel) + copy(dAtA[i:], m.ProofChannel) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProofChannel))) + i-- + dAtA[i] = 0x22 + } + { + size, err := m.CounterpartyUpgrade.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + 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] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgChannelUpgradeAckResponse) 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 *MsgChannelUpgradeAckResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelUpgradeAckResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Result != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Result)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MsgChannelUpgradeConfirm) 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 *MsgChannelUpgradeConfirm) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelUpgradeConfirm) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x42 + } + { + size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + if len(m.ProofUpgrade) > 0 { + i -= len(m.ProofUpgrade) + copy(dAtA[i:], m.ProofUpgrade) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProofUpgrade))) + i-- + dAtA[i] = 0x32 + } + if len(m.ProofChannel) > 0 { + i -= len(m.ProofChannel) + copy(dAtA[i:], m.ProofChannel) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProofChannel))) + i-- + dAtA[i] = 0x2a + } + { + size, err := m.CounterpartyUpgrade.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if m.CounterpartyChannelState != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.CounterpartyChannelState)) + i-- + dAtA[i] = 0x18 + } + 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] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgChannelUpgradeConfirmResponse) 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 *MsgChannelUpgradeConfirmResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelUpgradeConfirmResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Result != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Result)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MsgChannelUpgradeOpen) 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 *MsgChannelUpgradeOpen) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelUpgradeOpen) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x3a + } + { + size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + if len(m.ProofChannel) > 0 { + i -= len(m.ProofChannel) + copy(dAtA[i:], m.ProofChannel) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProofChannel))) + i-- + dAtA[i] = 0x2a + } + if m.CounterpartyUpgradeSequence != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.CounterpartyUpgradeSequence)) + i-- + dAtA[i] = 0x20 + } + if m.CounterpartyChannelState != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.CounterpartyChannelState)) + i-- + dAtA[i] = 0x18 + } + 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] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgChannelUpgradeOpenResponse) 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 *MsgChannelUpgradeOpenResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelUpgradeOpenResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgChannelUpgradeTimeout) 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 *MsgChannelUpgradeTimeout) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelUpgradeTimeout) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x32 + } + { + size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + if len(m.ProofChannel) > 0 { + i -= len(m.ProofChannel) + copy(dAtA[i:], m.ProofChannel) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProofChannel))) + i-- + dAtA[i] = 0x22 + } + { + size, err := m.CounterpartyChannel.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + 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] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgChannelUpgradeTimeoutResponse) 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 *MsgChannelUpgradeTimeoutResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelUpgradeTimeoutResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgChannelUpgradeCancel) 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 *MsgChannelUpgradeCancel) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelUpgradeCancel) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x32 + } + { + size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + if len(m.ProofErrorReceipt) > 0 { + i -= len(m.ProofErrorReceipt) + copy(dAtA[i:], m.ProofErrorReceipt) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProofErrorReceipt))) + i-- + dAtA[i] = 0x22 + } + { + size, err := m.ErrorReceipt.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + 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] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgChannelUpgradeCancelResponse) 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 *MsgChannelUpgradeCancelResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChannelUpgradeCancelResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgUpdateParams) 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 *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + 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 *MsgUpdateParamsResponse) 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 *MsgUpdateParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgPruneAcknowledgements) 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 *MsgPruneAcknowledgements) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgPruneAcknowledgements) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x22 + } + if m.Limit != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Limit)) + i-- + dAtA[i] = 0x18 + } + 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] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgPruneAcknowledgementsResponse) 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 *MsgPruneAcknowledgementsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgPruneAcknowledgementsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.TotalRemainingSequences != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.TotalRemainingSequences)) + i-- + dAtA[i] = 0x10 + } + if m.TotalPrunedSequences != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.TotalPrunedSequences)) + i-- + dAtA[i] = 0x8 + } + 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 *MsgChannelOpenInit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Channel.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgChannelOpenInitResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Version) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgChannelOpenTry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.PreviousChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Channel.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.CounterpartyVersion) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ProofInit) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.ProofHeight.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgChannelOpenTryResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Version) + 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 *MsgChannelOpenAck) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.CounterpartyChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.CounterpartyVersion) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ProofTry) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.ProofHeight.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgChannelOpenAckResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgChannelOpenConfirm) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ProofAck) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.ProofHeight.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgChannelOpenConfirmResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgChannelCloseInit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgChannelCloseInitResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgChannelCloseConfirm) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ProofInit) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.ProofHeight.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.CounterpartyUpgradeSequence != 0 { + n += 1 + sovTx(uint64(m.CounterpartyUpgradeSequence)) + } + return n +} + +func (m *MsgChannelCloseConfirmResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgRecvPacket) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Packet.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.ProofCommitment) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.ProofHeight.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgRecvPacketResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Result != 0 { + n += 1 + sovTx(uint64(m.Result)) + } + return n +} + +func (m *MsgTimeout) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Packet.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.ProofUnreceived) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.ProofHeight.Size() + n += 1 + l + sovTx(uint64(l)) + if m.NextSequenceRecv != 0 { + n += 1 + sovTx(uint64(m.NextSequenceRecv)) + } + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgTimeoutResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Result != 0 { + n += 1 + sovTx(uint64(m.Result)) + } + return n +} + +func (m *MsgTimeoutOnClose) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Packet.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.ProofUnreceived) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ProofClose) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.ProofHeight.Size() + n += 1 + l + sovTx(uint64(l)) + if m.NextSequenceRecv != 0 { + n += 1 + sovTx(uint64(m.NextSequenceRecv)) + } + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.CounterpartyUpgradeSequence != 0 { + n += 1 + sovTx(uint64(m.CounterpartyUpgradeSequence)) + } + return n +} + +func (m *MsgTimeoutOnCloseResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Result != 0 { + n += 1 + sovTx(uint64(m.Result)) + } + return n +} + +func (m *MsgAcknowledgement) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Packet.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Acknowledgement) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ProofAcked) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.ProofHeight.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgAcknowledgementResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Result != 0 { + n += 1 + sovTx(uint64(m.Result)) + } + return n +} + +func (m *MsgChannelUpgradeInit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Fields.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgChannelUpgradeInitResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Upgrade.Size() + n += 1 + l + sovTx(uint64(l)) + if m.UpgradeSequence != 0 { + n += 1 + sovTx(uint64(m.UpgradeSequence)) + } + return n +} + +func (m *MsgChannelUpgradeTry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.ProposedUpgradeConnectionHops) > 0 { + for _, s := range m.ProposedUpgradeConnectionHops { + l = len(s) + n += 1 + l + sovTx(uint64(l)) + } + } + l = m.CounterpartyUpgradeFields.Size() + n += 1 + l + sovTx(uint64(l)) + if m.CounterpartyUpgradeSequence != 0 { + n += 1 + sovTx(uint64(m.CounterpartyUpgradeSequence)) + } + l = len(m.ProofChannel) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ProofUpgrade) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.ProofHeight.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgChannelUpgradeTryResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Upgrade.Size() + n += 1 + l + sovTx(uint64(l)) + if m.UpgradeSequence != 0 { + n += 1 + sovTx(uint64(m.UpgradeSequence)) + } + if m.Result != 0 { + n += 1 + sovTx(uint64(m.Result)) + } + return n +} + +func (m *MsgChannelUpgradeAck) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.CounterpartyUpgrade.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.ProofChannel) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ProofUpgrade) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.ProofHeight.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgChannelUpgradeAckResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Result != 0 { + n += 1 + sovTx(uint64(m.Result)) + } + return n +} + +func (m *MsgChannelUpgradeConfirm) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.CounterpartyChannelState != 0 { + n += 1 + sovTx(uint64(m.CounterpartyChannelState)) + } + l = m.CounterpartyUpgrade.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.ProofChannel) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ProofUpgrade) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.ProofHeight.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgChannelUpgradeConfirmResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Result != 0 { + n += 1 + sovTx(uint64(m.Result)) + } + return n +} + +func (m *MsgChannelUpgradeOpen) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.CounterpartyChannelState != 0 { + n += 1 + sovTx(uint64(m.CounterpartyChannelState)) + } + if m.CounterpartyUpgradeSequence != 0 { + n += 1 + sovTx(uint64(m.CounterpartyUpgradeSequence)) + } + l = len(m.ProofChannel) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.ProofHeight.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgChannelUpgradeOpenResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgChannelUpgradeTimeout) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.CounterpartyChannel.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.ProofChannel) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.ProofHeight.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgChannelUpgradeTimeoutResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgChannelUpgradeCancel) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.ErrorReceipt.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.ProofErrorReceipt) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.ProofHeight.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgChannelUpgradeCancelResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgUpdateParams) 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 = m.Params.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgUpdateParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgPruneAcknowledgements) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.Limit != 0 { + n += 1 + sovTx(uint64(m.Limit)) + } + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgPruneAcknowledgementsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.TotalPrunedSequences != 0 { + n += 1 + sovTx(uint64(m.TotalPrunedSequences)) + } + if m.TotalRemainingSequences != 0 { + n += 1 + sovTx(uint64(m.TotalRemainingSequences)) + } + 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 *MsgChannelOpenInit) 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: MsgChannelOpenInit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgChannelOpenInit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", 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.PortId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Channel", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Channel.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", 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.Signer = 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 *MsgChannelOpenInitResponse) 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: MsgChannelOpenInitResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgChannelOpenInitResponse: 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 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 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", 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.Version = 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 *MsgChannelOpenTry) 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: MsgChannelOpenTry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgChannelOpenTry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", 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.PortId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PreviousChannelId", 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.PreviousChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Channel", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Channel.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyVersion", 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.CounterpartyVersion = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofInit", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProofInit = append(m.ProofInit[:0], dAtA[iNdEx:postIndex]...) + if m.ProofInit == nil { + m.ProofInit = []byte{} + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ProofHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", 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.Signer = 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 *MsgChannelOpenTryResponse) 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: MsgChannelOpenTryResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgChannelOpenTryResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", 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.Version = 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 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 *MsgChannelOpenAck) 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: MsgChannelOpenAck: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgChannelOpenAck: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", 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.PortId = 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 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 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyChannelId", 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.CounterpartyChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyVersion", 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.CounterpartyVersion = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofTry", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProofTry = append(m.ProofTry[:0], dAtA[iNdEx:postIndex]...) + if m.ProofTry == nil { + m.ProofTry = []byte{} + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ProofHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", 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.Signer = 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 *MsgChannelOpenAckResponse) 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: MsgChannelOpenAckResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgChannelOpenAckResponse: 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 *MsgChannelOpenConfirm) 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: MsgChannelOpenConfirm: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgChannelOpenConfirm: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", 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.PortId = 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 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 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofAck", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProofAck = append(m.ProofAck[:0], dAtA[iNdEx:postIndex]...) + if m.ProofAck == nil { + m.ProofAck = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ProofHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", 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.Signer = 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 *MsgChannelOpenConfirmResponse) 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: MsgChannelOpenConfirmResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgChannelOpenConfirmResponse: 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 *MsgChannelCloseInit) 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: MsgChannelCloseInit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgChannelCloseInit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", 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.PortId = 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 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 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", 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.Signer = 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 *MsgChannelCloseInitResponse) 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: MsgChannelCloseInitResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgChannelCloseInitResponse: 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 *MsgChannelCloseConfirm) 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: MsgChannelCloseConfirm: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgChannelCloseConfirm: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", 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.PortId = 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 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 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofInit", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProofInit = append(m.ProofInit[:0], dAtA[iNdEx:postIndex]...) + if m.ProofInit == nil { + m.ProofInit = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ProofHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", 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.Signer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyUpgradeSequence", wireType) + } + m.CounterpartyUpgradeSequence = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CounterpartyUpgradeSequence |= 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 *MsgChannelCloseConfirmResponse) 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: MsgChannelCloseConfirmResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgChannelCloseConfirmResponse: 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 *MsgRecvPacket) 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: MsgRecvPacket: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRecvPacket: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Packet", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Packet.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofCommitment", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProofCommitment = append(m.ProofCommitment[:0], dAtA[iNdEx:postIndex]...) + if m.ProofCommitment == nil { + m.ProofCommitment = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ProofHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", 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.Signer = 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 *MsgRecvPacketResponse) 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: MsgRecvPacketResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRecvPacketResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + m.Result = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Result |= ResponseResultType(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 *MsgTimeout) 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: MsgTimeout: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgTimeout: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Packet", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Packet.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofUnreceived", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProofUnreceived = append(m.ProofUnreceived[:0], dAtA[iNdEx:postIndex]...) + if m.ProofUnreceived == nil { + m.ProofUnreceived = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ProofHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NextSequenceRecv", wireType) + } + m.NextSequenceRecv = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NextSequenceRecv |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", 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.Signer = 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 *MsgTimeoutResponse) 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: MsgTimeoutResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgTimeoutResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + m.Result = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Result |= ResponseResultType(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 *MsgTimeoutOnClose) 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: MsgTimeoutOnClose: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgTimeoutOnClose: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Packet", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Packet.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofUnreceived", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProofUnreceived = append(m.ProofUnreceived[:0], dAtA[iNdEx:postIndex]...) + if m.ProofUnreceived == nil { + m.ProofUnreceived = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofClose", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProofClose = append(m.ProofClose[:0], dAtA[iNdEx:postIndex]...) + if m.ProofClose == nil { + m.ProofClose = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ProofHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NextSequenceRecv", wireType) + } + m.NextSequenceRecv = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NextSequenceRecv |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", 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.Signer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyUpgradeSequence", wireType) + } + m.CounterpartyUpgradeSequence = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CounterpartyUpgradeSequence |= 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 *MsgTimeoutOnCloseResponse) 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: MsgTimeoutOnCloseResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgTimeoutOnCloseResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + m.Result = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Result |= ResponseResultType(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 *MsgChannelOpenInit) Unmarshal(dAtA []byte) error { +func (m *MsgAcknowledgement) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2716,17 +7706,17 @@ func (m *MsgChannelOpenInit) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgChannelOpenInit: wiretype end group for non-group") + return fmt.Errorf("proto: MsgAcknowledgement: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgChannelOpenInit: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgAcknowledgement: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Packet", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -2736,29 +7726,30 @@ func (m *MsgChannelOpenInit) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.PortId = string(dAtA[iNdEx:postIndex]) + if err := m.Packet.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Channel", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Acknowledgement", wireType) } - var msglen int + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -2768,30 +7759,31 @@ func (m *MsgChannelOpenInit) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + if byteLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + msglen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Channel.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + m.Acknowledgement = append(m.Acknowledgement[:0], dAtA[iNdEx:postIndex]...) + if m.Acknowledgement == nil { + m.Acknowledgement = []byte{} } iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProofAcked", wireType) } - var stringLen uint64 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -2801,79 +7793,31 @@ func (m *MsgChannelOpenInit) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if byteLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.Signer = 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 *MsgChannelOpenInitResponse) 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 + m.ProofAcked = append(m.ProofAcked[:0], dAtA[iNdEx:postIndex]...) + if m.ProofAcked == nil { + m.ProofAcked = []byte{} } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgChannelOpenInitResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgChannelOpenInitResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + iNdEx = postIndex + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -2883,27 +7827,28 @@ func (m *MsgChannelOpenInitResponse) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.ChannelId = string(dAtA[iNdEx:postIndex]) + if err := m.ProofHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 2: + case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2931,7 +7876,7 @@ func (m *MsgChannelOpenInitResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Version = string(dAtA[iNdEx:postIndex]) + m.Signer = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -2954,7 +7899,7 @@ func (m *MsgChannelOpenInitResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgChannelOpenTry) Unmarshal(dAtA []byte) error { +func (m *MsgAcknowledgementResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2977,49 +7922,17 @@ func (m *MsgChannelOpenTry) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgChannelOpenTry: wiretype end group for non-group") + return fmt.Errorf("proto: MsgAcknowledgementResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgChannelOpenTry: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgAcknowledgementResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PortId", 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.PortId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PreviousChannelId", wireType) + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) } - var stringLen uint64 + m.Result = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -3029,60 +7942,64 @@ func (m *MsgChannelOpenTry) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + m.Result |= ResponseResultType(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err } - postIndex := iNdEx + intStringLen - if postIndex < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTx } - if postIndex > l { + if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } - m.PreviousChannelId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Channel", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTx + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgChannelUpgradeInit) 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 postIndex > l { + if iNdEx >= l { return io.ErrUnexpectedEOF } - if err := m.Channel.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break } - iNdEx = postIndex - case 4: + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgChannelUpgradeInit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgChannelUpgradeInit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyVersion", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -3110,13 +8027,13 @@ func (m *MsgChannelOpenTry) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.CounterpartyVersion = string(dAtA[iNdEx:postIndex]) + m.PortId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 5: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProofInit", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) } - var byteLen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -3126,29 +8043,27 @@ func (m *MsgChannelOpenTry) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + byteLen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.ProofInit = append(m.ProofInit[:0], dAtA[iNdEx:postIndex]...) - if m.ProofInit == nil { - m.ProofInit = []byte{} - } + m.ChannelId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 6: + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Fields", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -3175,11 +8090,11 @@ func (m *MsgChannelOpenTry) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.ProofHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Fields.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 7: + case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) } @@ -3232,7 +8147,7 @@ func (m *MsgChannelOpenTry) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgChannelOpenTryResponse) Unmarshal(dAtA []byte) error { +func (m *MsgChannelUpgradeInitResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -3255,17 +8170,17 @@ func (m *MsgChannelOpenTryResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgChannelOpenTryResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgChannelUpgradeInitResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgChannelOpenTryResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgChannelUpgradeInitResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Upgrade", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -3275,29 +8190,30 @@ func (m *MsgChannelOpenTryResponse) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.Version = string(dAtA[iNdEx:postIndex]) + if err := m.Upgrade.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UpgradeSequence", wireType) } - var stringLen uint64 + m.UpgradeSequence = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -3307,24 +8223,11 @@ func (m *MsgChannelOpenTryResponse) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + m.UpgradeSequence |= 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:]) @@ -3346,7 +8249,7 @@ func (m *MsgChannelOpenTryResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgChannelOpenAck) Unmarshal(dAtA []byte) error { +func (m *MsgChannelUpgradeTry) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -3369,10 +8272,10 @@ func (m *MsgChannelOpenAck) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgChannelOpenAck: wiretype end group for non-group") + return fmt.Errorf("proto: MsgChannelUpgradeTry: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgChannelOpenAck: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgChannelUpgradeTry: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -3441,7 +8344,7 @@ func (m *MsgChannelOpenAck) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyChannelId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProposedUpgradeConnectionHops", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -3469,13 +8372,13 @@ func (m *MsgChannelOpenAck) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.CounterpartyChannelId = string(dAtA[iNdEx:postIndex]) + m.ProposedUpgradeConnectionHops = append(m.ProposedUpgradeConnectionHops, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyVersion", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyUpgradeFields", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -3485,27 +8388,47 @@ func (m *MsgChannelOpenAck) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.CounterpartyVersion = string(dAtA[iNdEx:postIndex]) + if err := m.CounterpartyUpgradeFields.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyUpgradeSequence", wireType) + } + m.CounterpartyUpgradeSequence = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CounterpartyUpgradeSequence |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProofTry", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProofChannel", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -3532,12 +8455,46 @@ func (m *MsgChannelOpenAck) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ProofTry = append(m.ProofTry[:0], dAtA[iNdEx:postIndex]...) - if m.ProofTry == nil { - m.ProofTry = []byte{} + m.ProofChannel = append(m.ProofChannel[:0], dAtA[iNdEx:postIndex]...) + if m.ProofChannel == nil { + m.ProofChannel = []byte{} } iNdEx = postIndex - case 6: + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofUpgrade", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProofUpgrade = append(m.ProofUpgrade[:0], dAtA[iNdEx:postIndex]...) + if m.ProofUpgrade == nil { + m.ProofUpgrade = []byte{} + } + iNdEx = postIndex + case 8: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) } @@ -3570,7 +8527,7 @@ func (m *MsgChannelOpenAck) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 7: + case 9: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) } @@ -3623,7 +8580,7 @@ func (m *MsgChannelOpenAck) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgChannelOpenAckResponse) Unmarshal(dAtA []byte) error { +func (m *MsgChannelUpgradeTryResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -3646,12 +8603,83 @@ func (m *MsgChannelOpenAckResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgChannelOpenAckResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgChannelUpgradeTryResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgChannelOpenAckResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgChannelUpgradeTryResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Upgrade", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Upgrade.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UpgradeSequence", wireType) + } + m.UpgradeSequence = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UpgradeSequence |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + m.Result = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Result |= ResponseResultType(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -3673,7 +8701,7 @@ func (m *MsgChannelOpenAckResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgChannelOpenConfirm) Unmarshal(dAtA []byte) error { +func (m *MsgChannelUpgradeAck) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -3696,10 +8724,10 @@ func (m *MsgChannelOpenConfirm) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgChannelOpenConfirm: wiretype end group for non-group") + return fmt.Errorf("proto: MsgChannelUpgradeAck: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgChannelOpenConfirm: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgChannelUpgradeAck: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -3725,20 +8753,85 @@ func (m *MsgChannelOpenConfirm) Unmarshal(dAtA []byte) error { if intStringLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PortId = 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 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 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyUpgrade", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.PortId = string(dAtA[iNdEx:postIndex]) + if err := m.CounterpartyUpgrade.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 2: + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProofChannel", wireType) } - var stringLen uint64 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -3748,27 +8841,29 @@ func (m *MsgChannelOpenConfirm) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if byteLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.ChannelId = string(dAtA[iNdEx:postIndex]) + m.ProofChannel = append(m.ProofChannel[:0], dAtA[iNdEx:postIndex]...) + if m.ProofChannel == nil { + m.ProofChannel = []byte{} + } iNdEx = postIndex - case 3: + case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProofAck", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProofUpgrade", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -3795,12 +8890,12 @@ func (m *MsgChannelOpenConfirm) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ProofAck = append(m.ProofAck[:0], dAtA[iNdEx:postIndex]...) - if m.ProofAck == nil { - m.ProofAck = []byte{} + m.ProofUpgrade = append(m.ProofUpgrade[:0], dAtA[iNdEx:postIndex]...) + if m.ProofUpgrade == nil { + m.ProofUpgrade = []byte{} } iNdEx = postIndex - case 4: + case 6: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) } @@ -3833,7 +8928,7 @@ func (m *MsgChannelOpenConfirm) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 5: + case 7: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) } @@ -3886,7 +8981,7 @@ func (m *MsgChannelOpenConfirm) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgChannelOpenConfirmResponse) Unmarshal(dAtA []byte) error { +func (m *MsgChannelUpgradeAckResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -3909,12 +9004,31 @@ func (m *MsgChannelOpenConfirmResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgChannelOpenConfirmResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgChannelUpgradeAckResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgChannelOpenConfirmResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgChannelUpgradeAckResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + m.Result = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Result |= ResponseResultType(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -3936,7 +9050,7 @@ func (m *MsgChannelOpenConfirmResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgChannelCloseInit) Unmarshal(dAtA []byte) error { +func (m *MsgChannelUpgradeConfirm) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -3959,10 +9073,10 @@ func (m *MsgChannelCloseInit) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgChannelCloseInit: wiretype end group for non-group") + return fmt.Errorf("proto: MsgChannelUpgradeConfirm: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgChannelCloseInit: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgChannelUpgradeConfirm: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -4030,10 +9144,10 @@ func (m *MsgChannelCloseInit) Unmarshal(dAtA []byte) error { m.ChannelId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyChannelState", wireType) } - var stringLen uint64 + m.CounterpartyChannelState = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -4043,129 +9157,16 @@ func (m *MsgChannelCloseInit) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + m.CounterpartyChannelState |= State(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.Signer = 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 *MsgChannelCloseInitResponse) 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: MsgChannelCloseInitResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgChannelCloseInitResponse: 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 *MsgChannelCloseConfirm) 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: MsgChannelCloseConfirm: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgChannelCloseConfirm: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyUpgrade", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -4175,29 +9176,30 @@ func (m *MsgChannelCloseConfirm) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.PortId = string(dAtA[iNdEx:postIndex]) + if err := m.CounterpartyUpgrade.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 2: + case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProofChannel", wireType) } - var stringLen uint64 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -4207,27 +9209,29 @@ func (m *MsgChannelCloseConfirm) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if byteLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.ChannelId = string(dAtA[iNdEx:postIndex]) + m.ProofChannel = append(m.ProofChannel[:0], dAtA[iNdEx:postIndex]...) + if m.ProofChannel == nil { + m.ProofChannel = []byte{} + } iNdEx = postIndex - case 3: + case 6: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProofInit", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProofUpgrade", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -4254,12 +9258,12 @@ func (m *MsgChannelCloseConfirm) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ProofInit = append(m.ProofInit[:0], dAtA[iNdEx:postIndex]...) - if m.ProofInit == nil { - m.ProofInit = []byte{} + m.ProofUpgrade = append(m.ProofUpgrade[:0], dAtA[iNdEx:postIndex]...) + if m.ProofUpgrade == nil { + m.ProofUpgrade = []byte{} } iNdEx = postIndex - case 4: + case 7: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) } @@ -4292,7 +9296,7 @@ func (m *MsgChannelCloseConfirm) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 5: + case 8: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) } @@ -4345,7 +9349,7 @@ func (m *MsgChannelCloseConfirm) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgChannelCloseConfirmResponse) Unmarshal(dAtA []byte) error { +func (m *MsgChannelUpgradeConfirmResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4368,12 +9372,31 @@ func (m *MsgChannelCloseConfirmResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgChannelCloseConfirmResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgChannelUpgradeConfirmResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgChannelCloseConfirmResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgChannelUpgradeConfirmResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + m.Result = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Result |= ResponseResultType(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -4395,7 +9418,7 @@ func (m *MsgChannelCloseConfirmResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgRecvPacket) Unmarshal(dAtA []byte) error { +func (m *MsgChannelUpgradeOpen) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4418,17 +9441,49 @@ func (m *MsgRecvPacket) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgRecvPacket: wiretype end group for non-group") + return fmt.Errorf("proto: MsgChannelUpgradeOpen: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRecvPacket: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgChannelUpgradeOpen: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Packet", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field PortId", 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.PortId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -4438,28 +9493,65 @@ func (m *MsgRecvPacket) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Packet.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.ChannelId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 2: + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyChannelState", wireType) + } + m.CounterpartyChannelState = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CounterpartyChannelState |= State(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyUpgradeSequence", wireType) + } + m.CounterpartyUpgradeSequence = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CounterpartyUpgradeSequence |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProofCommitment", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProofChannel", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -4486,12 +9578,12 @@ func (m *MsgRecvPacket) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ProofCommitment = append(m.ProofCommitment[:0], dAtA[iNdEx:postIndex]...) - if m.ProofCommitment == nil { - m.ProofCommitment = []byte{} + m.ProofChannel = append(m.ProofChannel[:0], dAtA[iNdEx:postIndex]...) + if m.ProofChannel == nil { + m.ProofChannel = []byte{} } iNdEx = postIndex - case 3: + case 6: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) } @@ -4524,7 +9616,7 @@ func (m *MsgRecvPacket) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 4: + case 7: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) } @@ -4577,7 +9669,7 @@ func (m *MsgRecvPacket) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgRecvPacketResponse) Unmarshal(dAtA []byte) error { +func (m *MsgChannelUpgradeOpenResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4600,31 +9692,12 @@ func (m *MsgRecvPacketResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgRecvPacketResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgChannelUpgradeOpenResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRecvPacketResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgChannelUpgradeOpenResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) - } - m.Result = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Result |= ResponseResultType(b&0x7F) << shift - if b < 0x80 { - break - } - } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -4646,7 +9719,7 @@ func (m *MsgRecvPacketResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgTimeout) Unmarshal(dAtA []byte) error { +func (m *MsgChannelUpgradeTimeout) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4669,17 +9742,17 @@ func (m *MsgTimeout) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgTimeout: wiretype end group for non-group") + return fmt.Errorf("proto: MsgChannelUpgradeTimeout: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgTimeout: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgChannelUpgradeTimeout: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Packet", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -4689,30 +9762,29 @@ func (m *MsgTimeout) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Packet.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.PortId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProofUnreceived", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) } - var byteLen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -4722,29 +9794,27 @@ func (m *MsgTimeout) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + byteLen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.ProofUnreceived = append(m.ProofUnreceived[:0], dAtA[iNdEx:postIndex]...) - if m.ProofUnreceived == nil { - m.ProofUnreceived = []byte{} - } + m.ChannelId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyChannel", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -4771,15 +9841,15 @@ func (m *MsgTimeout) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.ProofHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.CounterpartyChannel.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NextSequenceRecv", wireType) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofChannel", wireType) } - m.NextSequenceRecv = 0 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -4789,12 +9859,60 @@ func (m *MsgTimeout) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.NextSequenceRecv |= uint64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProofChannel = append(m.ProofChannel[:0], dAtA[iNdEx:postIndex]...) + if m.ProofChannel == nil { + m.ProofChannel = []byte{} + } + iNdEx = postIndex case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ProofHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) } @@ -4847,7 +9965,7 @@ func (m *MsgTimeout) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgTimeoutResponse) Unmarshal(dAtA []byte) error { +func (m *MsgChannelUpgradeTimeoutResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4870,31 +9988,12 @@ func (m *MsgTimeoutResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgTimeoutResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgChannelUpgradeTimeoutResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgTimeoutResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgChannelUpgradeTimeoutResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) - } - m.Result = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Result |= ResponseResultType(b&0x7F) << shift - if b < 0x80 { - break - } - } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -4916,7 +10015,7 @@ func (m *MsgTimeoutResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgTimeoutOnClose) Unmarshal(dAtA []byte) error { +func (m *MsgChannelUpgradeCancel) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4939,17 +10038,17 @@ func (m *MsgTimeoutOnClose) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgTimeoutOnClose: wiretype end group for non-group") + return fmt.Errorf("proto: MsgChannelUpgradeCancel: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgTimeoutOnClose: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgChannelUpgradeCancel: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Packet", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -4959,30 +10058,29 @@ func (m *MsgTimeoutOnClose) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Packet.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.PortId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProofUnreceived", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) } - var byteLen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -4992,29 +10090,60 @@ func (m *MsgTimeoutOnClose) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + 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 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ErrorReceipt", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + if msglen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + byteLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.ProofUnreceived = append(m.ProofUnreceived[:0], dAtA[iNdEx:postIndex]...) - if m.ProofUnreceived == nil { - m.ProofUnreceived = []byte{} + if err := m.ErrorReceipt.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } iNdEx = postIndex - case 3: + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProofClose", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProofErrorReceipt", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -5041,12 +10170,12 @@ func (m *MsgTimeoutOnClose) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ProofClose = append(m.ProofClose[:0], dAtA[iNdEx:postIndex]...) - if m.ProofClose == nil { - m.ProofClose = []byte{} + m.ProofErrorReceipt = append(m.ProofErrorReceipt[:0], dAtA[iNdEx:postIndex]...) + if m.ProofErrorReceipt == nil { + m.ProofErrorReceipt = []byte{} } iNdEx = postIndex - case 4: + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) } @@ -5079,25 +10208,6 @@ func (m *MsgTimeoutOnClose) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NextSequenceRecv", wireType) - } - m.NextSequenceRecv = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.NextSequenceRecv |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } case 6: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) @@ -5151,7 +10261,7 @@ func (m *MsgTimeoutOnClose) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgTimeoutOnCloseResponse) Unmarshal(dAtA []byte) error { +func (m *MsgChannelUpgradeCancelResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -5174,31 +10284,12 @@ func (m *MsgTimeoutOnCloseResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgTimeoutOnCloseResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgChannelUpgradeCancelResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgTimeoutOnCloseResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgChannelUpgradeCancelResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) - } - m.Result = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Result |= ResponseResultType(b&0x7F) << shift - if b < 0x80 { - break - } - } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -5220,7 +10311,7 @@ func (m *MsgTimeoutOnCloseResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgAcknowledgement) Unmarshal(dAtA []byte) error { +func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -5243,17 +10334,17 @@ func (m *MsgAcknowledgement) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgAcknowledgement: wiretype end group for non-group") + return fmt.Errorf("proto: MsgUpdateParams: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgAcknowledgement: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgUpdateParams: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Packet", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -5263,30 +10354,29 @@ func (m *MsgAcknowledgement) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Packet.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.Authority = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Acknowledgement", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) } - var byteLen int + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -5296,31 +10386,130 @@ func (m *MsgAcknowledgement) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + if msglen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + byteLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.Acknowledgement = append(m.Acknowledgement[:0], dAtA[iNdEx:postIndex]...) - if m.Acknowledgement == nil { - m.Acknowledgement = []byte{} + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } iNdEx = postIndex - case 3: + 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 *MsgUpdateParamsResponse) 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: MsgUpdateParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParamsResponse: 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 *MsgPruneAcknowledgements) 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: MsgPruneAcknowledgements: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgPruneAcknowledgements: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProofAcked", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) } - var byteLen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -5330,31 +10519,29 @@ func (m *MsgAcknowledgement) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + byteLen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.ProofAcked = append(m.ProofAcked[:0], dAtA[iNdEx:postIndex]...) - if m.ProofAcked == nil { - m.ProofAcked = []byte{} - } + m.PortId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 4: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -5364,26 +10551,44 @@ func (m *MsgAcknowledgement) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.ProofHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.ChannelId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 5: + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + m.Limit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Limit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) } @@ -5436,7 +10641,7 @@ func (m *MsgAcknowledgement) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgAcknowledgementResponse) Unmarshal(dAtA []byte) error { +func (m *MsgPruneAcknowledgementsResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -5459,17 +10664,17 @@ func (m *MsgAcknowledgementResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgAcknowledgementResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgPruneAcknowledgementsResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgAcknowledgementResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgPruneAcknowledgementsResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field TotalPrunedSequences", wireType) } - m.Result = 0 + m.TotalPrunedSequences = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -5479,7 +10684,26 @@ func (m *MsgAcknowledgementResponse) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Result |= ResponseResultType(b&0x7F) << shift + m.TotalPrunedSequences |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalRemainingSequences", wireType) + } + m.TotalRemainingSequences = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalRemainingSequences |= uint64(b&0x7F) << shift if b < 0x80 { break } diff --git a/modules/core/04-channel/types/upgrade.go b/modules/core/04-channel/types/upgrade.go new file mode 100644 index 00000000000..ea3e8508389 --- /dev/null +++ b/modules/core/04-channel/types/upgrade.go @@ -0,0 +1,128 @@ +package types + +import ( + "errors" + "fmt" + "slices" + "strings" + + errorsmod "cosmossdk.io/errors" + + connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" +) + +// NewUpgrade creates a new Upgrade instance. +func NewUpgrade(upgradeFields UpgradeFields, timeout Timeout, nextSequenceSend uint64) Upgrade { + return Upgrade{ + Fields: upgradeFields, + Timeout: timeout, + NextSequenceSend: nextSequenceSend, + } +} + +// NewUpgradeFields returns a new ModifiableUpgradeFields instance. +func NewUpgradeFields(ordering Order, connectionHops []string, version string) UpgradeFields { + return UpgradeFields{ + Ordering: ordering, + ConnectionHops: connectionHops, + Version: version, + } +} + +// ValidateBasic performs a basic validation of the upgrade fields +func (u Upgrade) ValidateBasic() error { + if err := u.Fields.ValidateBasic(); err != nil { + return errorsmod.Wrap(err, "proposed upgrade fields are invalid") + } + + if !u.Timeout.IsValid() { + return errorsmod.Wrap(ErrInvalidUpgrade, "upgrade timeout height and upgrade timeout timestamp cannot both be 0") + } + + return nil +} + +// ValidateBasic performs a basic validation of the proposed upgrade fields +func (uf UpgradeFields) ValidateBasic() error { + if !slices.Contains(connectiontypes.SupportedOrderings, uf.Ordering.String()) { + return errorsmod.Wrap(ErrInvalidChannelOrdering, uf.Ordering.String()) + } + + if len(uf.ConnectionHops) != 1 { + return errorsmod.Wrap(ErrTooManyConnectionHops, "current IBC version only supports one connection hop") + } + + if strings.TrimSpace(uf.Version) == "" { + return errorsmod.Wrap(ErrInvalidChannelVersion, "version cannot be empty") + } + + return nil +} + +// UpgradeError defines an error that occurs during an upgrade. +type UpgradeError struct { + // err is the underlying error that caused the upgrade to fail. + // this error should not be written to state. + err error + // sequence is the upgrade sequence number of the upgrade that failed. + sequence uint64 +} + +var _ error = &UpgradeError{} + +// NewUpgradeError returns a new UpgradeError instance. +func NewUpgradeError(upgradeSequence uint64, err error) *UpgradeError { + return &UpgradeError{ + err: err, + sequence: upgradeSequence, + } +} + +// Error implements the error interface, returning the underlying error which caused the upgrade to fail. +func (u *UpgradeError) Error() string { + return u.err.Error() +} + +// Is returns true if the of the provided error is an upgrade error. +func (*UpgradeError) Is(err error) bool { + _, ok := err.(*UpgradeError) + return ok +} + +// Unwrap returns the next error in the error chain. +// If there is no next error, Unwrap returns nil. +func (u *UpgradeError) Unwrap() error { + return u.err +} + +// Cause implements the sdk error interface which uses this function to unwrap the error in various functions such as `wrappedError.Is()`. +// Cause returns the underlying error which caused the upgrade to fail. +func (u *UpgradeError) Cause() error { + baseError := u.err + for { + if err := errors.Unwrap(baseError); err != nil { + baseError = err + } else { + return baseError + } + } +} + +// GetErrorReceipt returns an error receipt with the code from the underlying error type stripped. +func (u *UpgradeError) GetErrorReceipt() ErrorReceipt { + // restoreErrorString defines a string constant included in error receipts. + // NOTE: Changing this const is state machine breaking as it is written into state. + const restoreErrorString = "restored channel to pre-upgrade state" + + _, code, _ := errorsmod.ABCIInfo(u, false) // discard non-determinstic codespace and log values + return ErrorReceipt{ + Sequence: u.sequence, + Message: fmt.Sprintf("ABCI code: %d: %s", code, restoreErrorString), + } +} + +// IsUpgradeError returns true if err is of type UpgradeError or contained +// in the error chain of err and false otherwise. +func IsUpgradeError(err error) bool { + return errors.Is(err, &UpgradeError{}) +} diff --git a/modules/core/04-channel/types/upgrade.pb.go b/modules/core/04-channel/types/upgrade.pb.go new file mode 100644 index 00000000000..e7931817125 --- /dev/null +++ b/modules/core/04-channel/types/upgrade.pb.go @@ -0,0 +1,842 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/core/channel/v1/upgrade.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 + +// Upgrade is a verifiable type which contains the relevant information +// for an attempted upgrade. It provides the proposed changes to the channel +// end, the timeout for this upgrade attempt and the next packet sequence +// which allows the counterparty to efficiently know the highest sequence it has received. +// The next sequence send is used for pruning and upgrading from unordered to ordered channels. +type Upgrade struct { + Fields UpgradeFields `protobuf:"bytes,1,opt,name=fields,proto3" json:"fields"` + Timeout Timeout `protobuf:"bytes,2,opt,name=timeout,proto3" json:"timeout"` + NextSequenceSend uint64 `protobuf:"varint,3,opt,name=next_sequence_send,json=nextSequenceSend,proto3" json:"next_sequence_send,omitempty"` +} + +func (m *Upgrade) Reset() { *m = Upgrade{} } +func (m *Upgrade) String() string { return proto.CompactTextString(m) } +func (*Upgrade) ProtoMessage() {} +func (*Upgrade) Descriptor() ([]byte, []int) { + return fileDescriptor_fb1cef68588848b2, []int{0} +} +func (m *Upgrade) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Upgrade) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Upgrade.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 *Upgrade) XXX_Merge(src proto.Message) { + xxx_messageInfo_Upgrade.Merge(m, src) +} +func (m *Upgrade) XXX_Size() int { + return m.Size() +} +func (m *Upgrade) XXX_DiscardUnknown() { + xxx_messageInfo_Upgrade.DiscardUnknown(m) +} + +var xxx_messageInfo_Upgrade proto.InternalMessageInfo + +// UpgradeFields are the fields in a channel end which may be changed +// during a channel upgrade. +type UpgradeFields struct { + Ordering Order `protobuf:"varint,1,opt,name=ordering,proto3,enum=ibc.core.channel.v1.Order" json:"ordering,omitempty"` + ConnectionHops []string `protobuf:"bytes,2,rep,name=connection_hops,json=connectionHops,proto3" json:"connection_hops,omitempty"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` +} + +func (m *UpgradeFields) Reset() { *m = UpgradeFields{} } +func (m *UpgradeFields) String() string { return proto.CompactTextString(m) } +func (*UpgradeFields) ProtoMessage() {} +func (*UpgradeFields) Descriptor() ([]byte, []int) { + return fileDescriptor_fb1cef68588848b2, []int{1} +} +func (m *UpgradeFields) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UpgradeFields) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UpgradeFields.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 *UpgradeFields) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpgradeFields.Merge(m, src) +} +func (m *UpgradeFields) XXX_Size() int { + return m.Size() +} +func (m *UpgradeFields) XXX_DiscardUnknown() { + xxx_messageInfo_UpgradeFields.DiscardUnknown(m) +} + +var xxx_messageInfo_UpgradeFields proto.InternalMessageInfo + +// ErrorReceipt defines a type which encapsulates the upgrade sequence and error associated with the +// upgrade handshake failure. When a channel upgrade handshake is aborted both chains are expected to increment to the +// next sequence. +type ErrorReceipt struct { + // the channel upgrade sequence + Sequence uint64 `protobuf:"varint,1,opt,name=sequence,proto3" json:"sequence,omitempty"` + // the error message detailing the cause of failure + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` +} + +func (m *ErrorReceipt) Reset() { *m = ErrorReceipt{} } +func (m *ErrorReceipt) String() string { return proto.CompactTextString(m) } +func (*ErrorReceipt) ProtoMessage() {} +func (*ErrorReceipt) Descriptor() ([]byte, []int) { + return fileDescriptor_fb1cef68588848b2, []int{2} +} +func (m *ErrorReceipt) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ErrorReceipt) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ErrorReceipt.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 *ErrorReceipt) XXX_Merge(src proto.Message) { + xxx_messageInfo_ErrorReceipt.Merge(m, src) +} +func (m *ErrorReceipt) XXX_Size() int { + return m.Size() +} +func (m *ErrorReceipt) XXX_DiscardUnknown() { + xxx_messageInfo_ErrorReceipt.DiscardUnknown(m) +} + +var xxx_messageInfo_ErrorReceipt proto.InternalMessageInfo + +func init() { + proto.RegisterType((*Upgrade)(nil), "ibc.core.channel.v1.Upgrade") + proto.RegisterType((*UpgradeFields)(nil), "ibc.core.channel.v1.UpgradeFields") + proto.RegisterType((*ErrorReceipt)(nil), "ibc.core.channel.v1.ErrorReceipt") +} + +func init() { proto.RegisterFile("ibc/core/channel/v1/upgrade.proto", fileDescriptor_fb1cef68588848b2) } + +var fileDescriptor_fb1cef68588848b2 = []byte{ + // 406 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0x41, 0x6f, 0xd3, 0x30, + 0x14, 0xc7, 0xe3, 0xad, 0x5a, 0x57, 0x03, 0x03, 0x19, 0x0e, 0x51, 0x85, 0xb2, 0xd2, 0x0b, 0x3d, + 0xb0, 0x98, 0x0d, 0x84, 0x00, 0x71, 0x40, 0x93, 0x40, 0x88, 0x0b, 0x92, 0x0b, 0x17, 0x2e, 0x55, + 0xe3, 0x3c, 0x52, 0x4b, 0x8d, 0x5f, 0xb0, 0x9d, 0x08, 0xbe, 0x01, 0xc7, 0x7d, 0x04, 0xbe, 0x08, + 0xf7, 0x1d, 0x77, 0xe4, 0x84, 0x50, 0xfb, 0x45, 0x50, 0x9c, 0xa4, 0x68, 0x52, 0x6e, 0x7e, 0x7e, + 0xbf, 0xff, 0xdf, 0xff, 0xe7, 0x47, 0x1f, 0xa8, 0x44, 0x72, 0x89, 0x06, 0xb8, 0x5c, 0x2d, 0xb5, + 0x86, 0x35, 0xaf, 0x4e, 0x79, 0x59, 0x64, 0x66, 0x99, 0x42, 0x5c, 0x18, 0x74, 0xc8, 0xee, 0xaa, + 0x44, 0xc6, 0x35, 0x12, 0xb7, 0x48, 0x5c, 0x9d, 0x8e, 0xef, 0x65, 0x98, 0xa1, 0xef, 0xf3, 0xfa, + 0xd4, 0xa0, 0xe3, 0x5e, 0xb7, 0x4e, 0xe5, 0x91, 0xe9, 0x2f, 0x42, 0x87, 0x9f, 0x1a, 0x7f, 0xf6, + 0x9a, 0x1e, 0x7c, 0x51, 0xb0, 0x4e, 0x6d, 0x48, 0x26, 0x64, 0x76, 0xe3, 0x6c, 0x1a, 0xf7, 0x3c, + 0x15, 0xb7, 0xf4, 0x5b, 0x4f, 0x9e, 0x0f, 0x2e, 0xff, 0x1c, 0x07, 0xa2, 0xd5, 0xb1, 0x57, 0x74, + 0xe8, 0x54, 0x0e, 0x58, 0xba, 0x70, 0xcf, 0x5b, 0xdc, 0xef, 0xb5, 0xf8, 0xd8, 0x30, 0xad, 0xb8, + 0x93, 0xb0, 0x47, 0x94, 0x69, 0xf8, 0xe6, 0x16, 0x16, 0xbe, 0x96, 0xa0, 0x25, 0x2c, 0x2c, 0xe8, + 0x34, 0xdc, 0x9f, 0x90, 0xd9, 0x40, 0xdc, 0xa9, 0x3b, 0xf3, 0xb6, 0x31, 0x07, 0x9d, 0xbe, 0x1c, + 0xfc, 0xf8, 0x79, 0x1c, 0x4c, 0x2f, 0x08, 0xbd, 0x75, 0x2d, 0x11, 0x7b, 0x46, 0x0f, 0xd1, 0xa4, + 0x60, 0x94, 0xce, 0xfc, 0x1c, 0x47, 0x67, 0xe3, 0xde, 0x10, 0x1f, 0x6a, 0x48, 0xec, 0x58, 0xf6, + 0x90, 0xde, 0x96, 0xa8, 0x35, 0x48, 0xa7, 0x50, 0x2f, 0x56, 0x58, 0xd8, 0x70, 0x6f, 0xb2, 0x3f, + 0x1b, 0x89, 0xa3, 0xff, 0xd7, 0xef, 0xb0, 0xb0, 0x2c, 0xa4, 0xc3, 0x0a, 0x8c, 0x55, 0xa8, 0x7d, + 0xb6, 0x91, 0xe8, 0xca, 0x36, 0xd2, 0x7b, 0x7a, 0xf3, 0x8d, 0x31, 0x68, 0x04, 0x48, 0x50, 0x85, + 0x63, 0x63, 0x7a, 0xd8, 0x4d, 0xe4, 0x03, 0x0d, 0xc4, 0xae, 0xae, 0xbd, 0x72, 0xb0, 0x76, 0x99, + 0x81, 0xff, 0xb0, 0x91, 0xe8, 0xca, 0xc6, 0xeb, 0x7c, 0x7e, 0xb9, 0x89, 0xc8, 0xd5, 0x26, 0x22, + 0x7f, 0x37, 0x11, 0xb9, 0xd8, 0x46, 0xc1, 0xd5, 0x36, 0x0a, 0x7e, 0x6f, 0xa3, 0xe0, 0xf3, 0x8b, + 0x4c, 0xb9, 0x55, 0x99, 0xc4, 0x12, 0x73, 0x2e, 0xd1, 0xe6, 0x68, 0xb9, 0x4a, 0xe4, 0x49, 0x86, + 0xbc, 0x7a, 0xce, 0x73, 0x4c, 0xcb, 0x35, 0xd8, 0x66, 0xf7, 0x8f, 0x9f, 0x9e, 0x74, 0xeb, 0x77, + 0xdf, 0x0b, 0xb0, 0xc9, 0x81, 0x5f, 0xfd, 0x93, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xcc, 0x31, + 0xc0, 0xc6, 0x6d, 0x02, 0x00, 0x00, +} + +func (m *Upgrade) 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 *Upgrade) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Upgrade) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.NextSequenceSend != 0 { + i = encodeVarintUpgrade(dAtA, i, uint64(m.NextSequenceSend)) + i-- + dAtA[i] = 0x18 + } + { + size, err := m.Timeout.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintUpgrade(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.Fields.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintUpgrade(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *UpgradeFields) 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 *UpgradeFields) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UpgradeFields) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Version) > 0 { + i -= len(m.Version) + copy(dAtA[i:], m.Version) + i = encodeVarintUpgrade(dAtA, i, uint64(len(m.Version))) + i-- + dAtA[i] = 0x1a + } + if len(m.ConnectionHops) > 0 { + for iNdEx := len(m.ConnectionHops) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ConnectionHops[iNdEx]) + copy(dAtA[i:], m.ConnectionHops[iNdEx]) + i = encodeVarintUpgrade(dAtA, i, uint64(len(m.ConnectionHops[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if m.Ordering != 0 { + i = encodeVarintUpgrade(dAtA, i, uint64(m.Ordering)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *ErrorReceipt) 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 *ErrorReceipt) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ErrorReceipt) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Message) > 0 { + i -= len(m.Message) + copy(dAtA[i:], m.Message) + i = encodeVarintUpgrade(dAtA, i, uint64(len(m.Message))) + i-- + dAtA[i] = 0x12 + } + if m.Sequence != 0 { + i = encodeVarintUpgrade(dAtA, i, uint64(m.Sequence)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintUpgrade(dAtA []byte, offset int, v uint64) int { + offset -= sovUpgrade(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Upgrade) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Fields.Size() + n += 1 + l + sovUpgrade(uint64(l)) + l = m.Timeout.Size() + n += 1 + l + sovUpgrade(uint64(l)) + if m.NextSequenceSend != 0 { + n += 1 + sovUpgrade(uint64(m.NextSequenceSend)) + } + return n +} + +func (m *UpgradeFields) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Ordering != 0 { + n += 1 + sovUpgrade(uint64(m.Ordering)) + } + if len(m.ConnectionHops) > 0 { + for _, s := range m.ConnectionHops { + l = len(s) + n += 1 + l + sovUpgrade(uint64(l)) + } + } + l = len(m.Version) + if l > 0 { + n += 1 + l + sovUpgrade(uint64(l)) + } + return n +} + +func (m *ErrorReceipt) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sequence != 0 { + n += 1 + sovUpgrade(uint64(m.Sequence)) + } + l = len(m.Message) + if l > 0 { + n += 1 + l + sovUpgrade(uint64(l)) + } + return n +} + +func sovUpgrade(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozUpgrade(x uint64) (n int) { + return sovUpgrade(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Upgrade) 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 ErrIntOverflowUpgrade + } + 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: Upgrade: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Upgrade: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Fields", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowUpgrade + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthUpgrade + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthUpgrade + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Fields.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Timeout", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowUpgrade + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthUpgrade + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthUpgrade + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Timeout.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NextSequenceSend", wireType) + } + m.NextSequenceSend = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowUpgrade + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NextSequenceSend |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipUpgrade(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthUpgrade + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UpgradeFields) 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 ErrIntOverflowUpgrade + } + 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: UpgradeFields: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UpgradeFields: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Ordering", wireType) + } + m.Ordering = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowUpgrade + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Ordering |= Order(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConnectionHops", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowUpgrade + } + 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 ErrInvalidLengthUpgrade + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthUpgrade + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConnectionHops = append(m.ConnectionHops, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowUpgrade + } + 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 ErrInvalidLengthUpgrade + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthUpgrade + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Version = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipUpgrade(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthUpgrade + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ErrorReceipt) 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 ErrIntOverflowUpgrade + } + 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: ErrorReceipt: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ErrorReceipt: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Sequence", wireType) + } + m.Sequence = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowUpgrade + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Sequence |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Message", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowUpgrade + } + 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 ErrInvalidLengthUpgrade + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthUpgrade + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Message = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipUpgrade(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthUpgrade + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipUpgrade(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, ErrIntOverflowUpgrade + } + 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, ErrIntOverflowUpgrade + } + 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, ErrIntOverflowUpgrade + } + 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, ErrInvalidLengthUpgrade + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupUpgrade + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthUpgrade + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthUpgrade = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowUpgrade = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupUpgrade = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/core/04-channel/types/upgrade_test.go b/modules/core/04-channel/types/upgrade_test.go new file mode 100644 index 00000000000..b1bb8315d46 --- /dev/null +++ b/modules/core/04-channel/types/upgrade_test.go @@ -0,0 +1,261 @@ +package types_test + +import ( + "errors" + "fmt" + + errorsmod "cosmossdk.io/errors" + + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v8/testing" + "github.com/cosmos/ibc-go/v8/testing/mock" +) + +func (suite *TypesTestSuite) TestUpgradeValidateBasic() { + var upgrade types.Upgrade + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "invalid ordering", + func() { + upgrade.Fields.Ordering = types.NONE + }, + false, + }, + { + "connection hops length not equal to 1", + func() { + upgrade.Fields.ConnectionHops = []string{"connection-0", "connection-1"} + }, + false, + }, + { + "empty version", + func() { + upgrade.Fields.Version = " " + }, + false, + }, + { + "invalid timeout", + func() { + upgrade.Timeout.Height = clienttypes.ZeroHeight() + upgrade.Timeout.Timestamp = 0 + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + upgrade = types.NewUpgrade( + types.NewUpgradeFields(types.ORDERED, []string{ibctesting.FirstConnectionID}, mock.Version), + types.NewTimeout(clienttypes.NewHeight(0, 100), 0), + 0, + ) + + tc.malleate() + + err := upgrade.ValidateBasic() + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *TypesTestSuite) TestUpgradeErrorIsOf() { + var ( + upgradeError *types.UpgradeError + inputErr error + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + msg: "standard sdk error", + malleate: func() {}, + expPass: true, + }, + { + msg: "input is upgrade error", + malleate: func() { + inputErr = types.NewUpgradeError(1, types.ErrInvalidChannel) + }, + expPass: true, + }, + { + msg: "input has wrapped upgrade error", + malleate: func() { + wrappedErr := errorsmod.Wrap(types.ErrInvalidChannel, "wrapped upgrade error") + inputErr = types.NewUpgradeError(1, wrappedErr) + }, + expPass: true, + }, + { + msg: "not equal to nil error", + malleate: func() { + upgradeError = &types.UpgradeError{} + }, + expPass: false, + }, + { + msg: "wrapped upgrade error", + malleate: func() { + wrappedErr := errorsmod.Wrap(upgradeError, "wrapped upgrade error") + upgradeError = types.NewUpgradeError(1, wrappedErr) + }, + expPass: true, + }, + { + msg: "empty upgrade and non nil target", + malleate: func() { + upgradeError = &types.UpgradeError{} + }, + expPass: false, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.msg, func() { + upgradeError = types.NewUpgradeError(1, types.ErrInvalidChannel) + inputErr = types.ErrInvalidChannel + + tc.malleate() + + res := errorsmod.IsOf(upgradeError, inputErr) + suite.Require().Equal(tc.expPass, res) + }) + } +} + +// TestGetErrorReceipt tests that the error receipt message is the same for both wrapped and unwrapped errors. +func (suite *TypesTestSuite) TestGetErrorReceipt() { + upgradeError := types.NewUpgradeError(1, types.ErrInvalidChannel) + + wrappedErr := errorsmod.Wrap(upgradeError, "wrapped upgrade error") + suite.Require().True(errorsmod.IsOf(wrappedErr, types.ErrInvalidChannel)) + + upgradeError2 := types.NewUpgradeError(1, wrappedErr) + + suite.Require().Equal(upgradeError2.GetErrorReceipt().Message, upgradeError.GetErrorReceipt().Message) +} + +// TestUpgradeErrorUnwrap tests that the underlying error is returned by Unwrap. +func (suite *TypesTestSuite) TestUpgradeErrorUnwrap() { + testCases := []struct { + msg string + upgradeError *types.UpgradeError + expError error + }{ + { + msg: "no underlying error", + upgradeError: types.NewUpgradeError(1, nil), + expError: nil, + }, + { + msg: "underlying error", + upgradeError: types.NewUpgradeError(1, types.ErrInvalidUpgrade), + expError: types.ErrInvalidUpgrade, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.msg, func() { + upgradeError := tc.upgradeError + err := upgradeError.Unwrap() + suite.Require().Equal(tc.expError, err) + }) + } +} + +func (suite *TypesTestSuite) TestIsUpgradeError() { + var err error + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "true", + func() {}, + true, + }, + { + "true with wrapped upgrade err", + func() { + upgradeError := types.NewUpgradeError(1, types.ErrInvalidChannel) + err = errorsmod.Wrap(upgradeError, "wrapped upgrade error") + }, + true, + }, + { + "true with Errorf wrapped upgrade error", + func() { + err = fmt.Errorf("%w", types.NewUpgradeError(1, types.ErrInvalidChannel)) + }, + true, + }, + { + "true with nested Errorf wrapped upgrade error", + func() { + err = fmt.Errorf("%w", fmt.Errorf("%w", fmt.Errorf("%w", types.NewUpgradeError(1, types.ErrInvalidChannel)))) + }, + true, + }, + { + "false with non upgrade error", + func() { + err = errors.New("error") + }, + false, + }, + { + "false with wrapped non upgrade error", + func() { + randomErr := errors.New("error") + err = errorsmod.Wrap(randomErr, "wrapped random error") + }, + false, + }, + { + "false with nil error", + func() { + err = nil + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.msg, func() { + err = types.NewUpgradeError(1, types.ErrInvalidChannel) + + tc.malleate() + + res := types.IsUpgradeError(err) + suite.Require().Equal(tc.expPass, res) + }) + } +} diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index a72ff9658ec..23fc5705233 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -106,6 +106,57 @@ type IBCModule interface { ) error } +// UpgradableModule defines the callbacks required to perform a channel upgrade. +// Note: applications must ensure that state related to packet processing remains unmodified until the OnChanUpgradeOpen callback is executed. +// This guarantees that in-flight packets are correctly flushed using the existing channel parameters. +type UpgradableModule interface { + // OnChanUpgradeInit enables additional custom logic to be executed when the channel upgrade is initialized. + // It must validate the proposed version, order, and connection hops. + // NOTE: in the case of crossing hellos, this callback may be executed on both chains. + // NOTE: Any IBC application state changes made in this callback handler are not committed. + OnChanUpgradeInit( + ctx sdk.Context, + portID, channelID string, + proposedOrder channeltypes.Order, + proposedConnectionHops []string, + proposedVersion string, + ) (string, error) + + // OnChanUpgradeTry enables additional custom logic to be executed in the ChannelUpgradeTry step of the + // channel upgrade handshake. It must validate the proposed version (provided by the counterparty), order, + // and connection hops. + // NOTE: Any IBC application state changes made in this callback handler are not committed. + OnChanUpgradeTry( + ctx sdk.Context, + portID, channelID string, + proposedOrder channeltypes.Order, + proposedConnectionHops []string, + counterpartyVersion string, + ) (string, error) + + // OnChanUpgradeAck enables additional custom logic to be executed in the ChannelUpgradeAck step of the + // channel upgrade handshake. It must validate the version proposed by the counterparty. + // NOTE: Any IBC application state changes made in this callback handler are not committed. + OnChanUpgradeAck( + ctx sdk.Context, + portID, + channelID, + counterpartyVersion string, + ) error + + // OnChanUpgradeOpen enables additional custom logic to be executed when the channel upgrade has successfully completed, and the channel + // has returned to the OPEN state. Any logic associated with changing of the channel fields should be performed + // in this callback. + OnChanUpgradeOpen( + ctx sdk.Context, + portID, + channelID string, + proposedOrder channeltypes.Order, + proposedConnectionHops []string, + proposedVersion string, + ) +} + // ICS4Wrapper implements the ICS4 interfaces that IBC applications use to send packets and acknowledgements. type ICS4Wrapper interface { SendPacket( diff --git a/modules/core/24-host/channel_keys.go b/modules/core/24-host/channel_keys.go new file mode 100644 index 00000000000..b21666dd3b6 --- /dev/null +++ b/modules/core/24-host/channel_keys.go @@ -0,0 +1,66 @@ +package host + +import "fmt" + +const ( + KeyChannelEndPrefix = "channelEnds" + KeyChannelPrefix = "channels" + KeyChannelUpgradePrefix = "channelUpgrades" + KeyUpgradePrefix = "upgrades" + KeyUpgradeErrorPrefix = "upgradeError" + KeyCounterpartyUpgrade = "counterpartyUpgrade" + KeyChannelCapabilityPrefix = "capabilities" +) + +// ICS04 +// The following paths are the keys to the store as defined in https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#store-paths + +// ChannelPath defines the path under which channels are stored +func ChannelPath(portID, channelID string) string { + return fmt.Sprintf("%s/%s", KeyChannelEndPrefix, channelPath(portID, channelID)) +} + +// ChannelKey returns the store key for a particular channel +func ChannelKey(portID, channelID string) []byte { + return []byte(ChannelPath(portID, channelID)) +} + +// ChannelCapabilityPath defines the path under which capability keys associated +// with a channel are stored +func ChannelCapabilityPath(portID, channelID string) string { + return fmt.Sprintf("%s/%s", KeyChannelCapabilityPrefix, channelPath(portID, channelID)) +} + +// ChannelUpgradeErrorPath defines the path under which the ErrorReceipt is stored in the case that a chain does not accept the proposed upgrade +func ChannelUpgradeErrorPath(portID, channelID string) string { + return fmt.Sprintf("%s/%s/%s", KeyChannelUpgradePrefix, KeyUpgradeErrorPrefix, channelPath(portID, channelID)) +} + +// ChannelUpgradeErrorKey returns the store key for a particular channelEnd used to stor the ErrorReceipt in the case that a chain does not accept the proposed upgrade +func ChannelUpgradeErrorKey(portID, channelID string) []byte { + return []byte(ChannelUpgradeErrorPath(portID, channelID)) +} + +// ChannelUpgradePath defines the path which stores the information related to an upgrade attempt +func ChannelUpgradePath(portID, channelID string) string { + return fmt.Sprintf("%s/%s/%s", KeyChannelUpgradePrefix, KeyUpgradePrefix, channelPath(portID, channelID)) +} + +// ChannelUpgradeKey returns the store key for a particular channel upgrade attempt +func ChannelUpgradeKey(portID, channelID string) []byte { + return []byte(ChannelUpgradePath(portID, channelID)) +} + +// ChannelCounterpartyUpgradeKey returns the store key for the upgrade used on the counterparty channel. +func ChannelCounterpartyUpgradeKey(portID, channelID string) []byte { + return []byte(ChannelCounterpartyUpgradePath(portID, channelID)) +} + +// ChannelCounterpartyUpgradePath defines the path under which the upgrade used on the counterparty channel is stored. +func ChannelCounterpartyUpgradePath(portID, channelID string) string { + return fmt.Sprintf("%s/%s/%s", KeyChannelUpgradePrefix, KeyCounterpartyUpgrade, channelPath(portID, channelID)) +} + +func channelPath(portID, channelID string) string { + return fmt.Sprintf("%s/%s/%s/%s", KeyPortPrefix, portID, KeyChannelPrefix, channelID) +} diff --git a/modules/core/24-host/client_keys.go b/modules/core/24-host/client_keys.go new file mode 100644 index 00000000000..4b12bc63e5a --- /dev/null +++ b/modules/core/24-host/client_keys.go @@ -0,0 +1,86 @@ +package host + +import ( + "fmt" + + "github.com/cosmos/ibc-go/v8/modules/core/exported" +) + +// KeyClientStorePrefix defines the KVStore key prefix for IBC clients +var KeyClientStorePrefix = []byte("clients") + +const ( + KeyClientState = "clientState" + KeyConsensusStatePrefix = "consensusStates" +) + +// FullClientPath returns the full path of a specific client path in the format: +// "clients/{clientID}/{path}" as a string. +func FullClientPath(clientID string, path string) string { + return fmt.Sprintf("%s/%s/%s", KeyClientStorePrefix, clientID, path) +} + +// FullClientKey returns the full path of specific client path in the format: +// "clients/{clientID}/{path}" as a byte array. +func FullClientKey(clientID string, path []byte) []byte { + return []byte(FullClientPath(clientID, string(path))) +} + +// PrefixedClientStorePath returns a key path which can be used for prefixed +// key store iteration. The prefix may be a clientType, clientID, or any +// valid key prefix which may be concatenated with the client store constant. +func PrefixedClientStorePath(prefix []byte) string { + return fmt.Sprintf("%s/%s", KeyClientStorePrefix, prefix) +} + +// PrefixedClientStoreKey returns a key which can be used for prefixed +// key store iteration. The prefix may be a clientType, clientID, or any +// valid key prefix which may be concatenated with the client store constant. +func PrefixedClientStoreKey(prefix []byte) []byte { + return []byte(PrefixedClientStorePath(prefix)) +} + +// ICS02 +// The following paths are the keys to the store as defined in https://github.com/cosmos/ibc/tree/master/spec/core/ics-002-client-semantics#path-space + +// FullClientStatePath takes a client identifier and returns a Path under which to store a +// particular client state +func FullClientStatePath(clientID string) string { + return FullClientPath(clientID, KeyClientState) +} + +// FullClientStateKey takes a client identifier and returns a Key under which to store a +// particular client state. +func FullClientStateKey(clientID string) []byte { + return FullClientKey(clientID, []byte(KeyClientState)) +} + +// ClientStateKey returns a store key under which a particular client state is stored +// in a client prefixed store +func ClientStateKey() []byte { + return []byte(KeyClientState) +} + +// FullConsensusStatePath takes a client identifier and returns a Path under which to +// store the consensus state of a client. +func FullConsensusStatePath(clientID string, height exported.Height) string { + return FullClientPath(clientID, ConsensusStatePath(height)) +} + +// FullConsensusStateKey returns the store key for the consensus state of a particular +// client. +func FullConsensusStateKey(clientID string, height exported.Height) []byte { + return []byte(FullConsensusStatePath(clientID, height)) +} + +// ConsensusStatePath returns the suffix store key for the consensus state at a +// particular height stored in a client prefixed store. +func ConsensusStatePath(height exported.Height) string { + return fmt.Sprintf("%s/%s", KeyConsensusStatePrefix, height) +} + +// ConsensusStateKey returns the store key for a the consensus state of a particular +// client stored in a client prefixed store. +func ConsensusStateKey(height exported.Height) []byte { + return []byte(ConsensusStatePath(height)) +} diff --git a/modules/core/24-host/connection_keys.go b/modules/core/24-host/connection_keys.go new file mode 100644 index 00000000000..fde9ee3b730 --- /dev/null +++ b/modules/core/24-host/connection_keys.go @@ -0,0 +1,28 @@ +package host + +import "fmt" + +const KeyConnectionPrefix = "connections" + +// ICS03 +// The following paths are the keys to the store as defined in https://github.com/cosmos/ibc/blob/master/spec/core/ics-003-connection-semantics#store-paths + +// ClientConnectionsPath defines a reverse mapping from clients to a set of connections +func ClientConnectionsPath(clientID string) string { + return FullClientPath(clientID, KeyConnectionPrefix) +} + +// ClientConnectionsKey returns the store key for the connections of a given client +func ClientConnectionsKey(clientID string) []byte { + return []byte(ClientConnectionsPath(clientID)) +} + +// ConnectionPath defines the path under which connection paths are stored +func ConnectionPath(connectionID string) string { + return fmt.Sprintf("%s/%s", KeyConnectionPrefix, connectionID) +} + +// ConnectionKey returns the store key for a particular connection +func ConnectionKey(connectionID string) []byte { + return []byte(ConnectionPath(connectionID)) +} diff --git a/modules/core/24-host/keys.go b/modules/core/24-host/keys.go deleted file mode 100644 index 9e018f8f0d8..00000000000 --- a/modules/core/24-host/keys.go +++ /dev/null @@ -1,235 +0,0 @@ -package host - -import ( - "fmt" - - "github.com/cosmos/ibc-go/v8/modules/core/exported" -) - -// KVStore key prefixes for IBC -var ( - KeyClientStorePrefix = []byte("clients") -) - -// KVStore key prefixes for IBC -const ( - KeyClientState = "clientState" - KeyConsensusStatePrefix = "consensusStates" - KeyConnectionPrefix = "connections" - KeyChannelEndPrefix = "channelEnds" - KeyChannelPrefix = "channels" - KeyPortPrefix = "ports" - KeySequencePrefix = "sequences" - KeyChannelCapabilityPrefix = "capabilities" - KeyNextSeqSendPrefix = "nextSequenceSend" - KeyNextSeqRecvPrefix = "nextSequenceRecv" - KeyNextSeqAckPrefix = "nextSequenceAck" - KeyPacketCommitmentPrefix = "commitments" - KeyPacketAckPrefix = "acks" - KeyPacketReceiptPrefix = "receipts" -) - -// FullClientPath returns the full path of a specific client path in the format: -// "clients/{clientID}/{path}" as a string. -func FullClientPath(clientID string, path string) string { - return fmt.Sprintf("%s/%s/%s", KeyClientStorePrefix, clientID, path) -} - -// FullClientKey returns the full path of specific client path in the format: -// "clients/{clientID}/{path}" as a byte array. -func FullClientKey(clientID string, path []byte) []byte { - return []byte(FullClientPath(clientID, string(path))) -} - -// PrefixedClientStorePath returns a key path which can be used for prefixed -// key store iteration. The prefix may be a clientType, clientID, or any -// valid key prefix which may be concatenated with the client store constant. -func PrefixedClientStorePath(prefix []byte) string { - return fmt.Sprintf("%s/%s", KeyClientStorePrefix, prefix) -} - -// PrefixedClientStoreKey returns a key which can be used for prefixed -// key store iteration. The prefix may be a clientType, clientID, or any -// valid key prefix which may be concatenated with the client store constant. -func PrefixedClientStoreKey(prefix []byte) []byte { - return []byte(PrefixedClientStorePath(prefix)) -} - -// ICS02 -// The following paths are the keys to the store as defined in https://github.com/cosmos/ibc/tree/master/spec/core/ics-002-client-semantics#path-space - -// FullClientStatePath takes a client identifier and returns a Path under which to store a -// particular client state -func FullClientStatePath(clientID string) string { - return FullClientPath(clientID, KeyClientState) -} - -// FullClientStateKey takes a client identifier and returns a Key under which to store a -// particular client state. -func FullClientStateKey(clientID string) []byte { - return FullClientKey(clientID, []byte(KeyClientState)) -} - -// ClientStateKey returns a store key under which a particular client state is stored -// in a client prefixed store -func ClientStateKey() []byte { - return []byte(KeyClientState) -} - -// FullConsensusStatePath takes a client identifier and returns a Path under which to -// store the consensus state of a client. -func FullConsensusStatePath(clientID string, height exported.Height) string { - return FullClientPath(clientID, ConsensusStatePath(height)) -} - -// FullConsensusStateKey returns the store key for the consensus state of a particular -// client. -func FullConsensusStateKey(clientID string, height exported.Height) []byte { - return []byte(FullConsensusStatePath(clientID, height)) -} - -// ConsensusStatePath returns the suffix store key for the consensus state at a -// particular height stored in a client prefixed store. -func ConsensusStatePath(height exported.Height) string { - return fmt.Sprintf("%s/%s", KeyConsensusStatePrefix, height) -} - -// ConsensusStateKey returns the store key for a the consensus state of a particular -// client stored in a client prefixed store. -func ConsensusStateKey(height exported.Height) []byte { - return []byte(ConsensusStatePath(height)) -} - -// ICS03 -// The following paths are the keys to the store as defined in https://github.com/cosmos/ibc/blob/master/spec/core/ics-003-connection-semantics#store-paths - -// ClientConnectionsPath defines a reverse mapping from clients to a set of connections -func ClientConnectionsPath(clientID string) string { - return FullClientPath(clientID, KeyConnectionPrefix) -} - -// ClientConnectionsKey returns the store key for the connections of a given client -func ClientConnectionsKey(clientID string) []byte { - return []byte(ClientConnectionsPath(clientID)) -} - -// ConnectionPath defines the path under which connection paths are stored -func ConnectionPath(connectionID string) string { - return fmt.Sprintf("%s/%s", KeyConnectionPrefix, connectionID) -} - -// ConnectionKey returns the store key for a particular connection -func ConnectionKey(connectionID string) []byte { - return []byte(ConnectionPath(connectionID)) -} - -// ICS04 -// The following paths are the keys to the store as defined in https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#store-paths - -// ChannelPath defines the path under which channels are stored -func ChannelPath(portID, channelID string) string { - return fmt.Sprintf("%s/%s", KeyChannelEndPrefix, channelPath(portID, channelID)) -} - -// ChannelKey returns the store key for a particular channel -func ChannelKey(portID, channelID string) []byte { - return []byte(ChannelPath(portID, channelID)) -} - -// ChannelCapabilityPath defines the path under which capability keys associated -// with a channel are stored -func ChannelCapabilityPath(portID, channelID string) string { - return fmt.Sprintf("%s/%s", KeyChannelCapabilityPrefix, channelPath(portID, channelID)) -} - -// NextSequenceSendPath defines the next send sequence counter store path -func NextSequenceSendPath(portID, channelID string) string { - return fmt.Sprintf("%s/%s", KeyNextSeqSendPrefix, channelPath(portID, channelID)) -} - -// NextSequenceSendKey returns the store key for the send sequence of a particular -// channel binded to a specific port. -func NextSequenceSendKey(portID, channelID string) []byte { - return []byte(NextSequenceSendPath(portID, channelID)) -} - -// NextSequenceRecvPath defines the next receive sequence counter store path. -func NextSequenceRecvPath(portID, channelID string) string { - return fmt.Sprintf("%s/%s", KeyNextSeqRecvPrefix, channelPath(portID, channelID)) -} - -// NextSequenceRecvKey returns the store key for the receive sequence of a particular -// channel binded to a specific port -func NextSequenceRecvKey(portID, channelID string) []byte { - return []byte(NextSequenceRecvPath(portID, channelID)) -} - -// NextSequenceAckPath defines the next acknowledgement sequence counter store path -func NextSequenceAckPath(portID, channelID string) string { - return fmt.Sprintf("%s/%s", KeyNextSeqAckPrefix, channelPath(portID, channelID)) -} - -// NextSequenceAckKey returns the store key for the acknowledgement sequence of -// a particular channel binded to a specific port. -func NextSequenceAckKey(portID, channelID string) []byte { - return []byte(NextSequenceAckPath(portID, channelID)) -} - -// PacketCommitmentPath defines the commitments to packet data fields store path -func PacketCommitmentPath(portID, channelID string, sequence uint64) string { - return fmt.Sprintf("%s/%d", PacketCommitmentPrefixPath(portID, channelID), sequence) -} - -// PacketCommitmentKey returns the store key of under which a packet commitment -// is stored -func PacketCommitmentKey(portID, channelID string, sequence uint64) []byte { - return []byte(PacketCommitmentPath(portID, channelID, sequence)) -} - -// PacketCommitmentPrefixPath defines the prefix for commitments to packet data fields store path. -func PacketCommitmentPrefixPath(portID, channelID string) string { - return fmt.Sprintf("%s/%s/%s", KeyPacketCommitmentPrefix, channelPath(portID, channelID), KeySequencePrefix) -} - -// PacketAcknowledgementPath defines the packet acknowledgement store path -func PacketAcknowledgementPath(portID, channelID string, sequence uint64) string { - return fmt.Sprintf("%s/%d", PacketAcknowledgementPrefixPath(portID, channelID), sequence) -} - -// PacketAcknowledgementKey returns the store key of under which a packet -// acknowledgement is stored -func PacketAcknowledgementKey(portID, channelID string, sequence uint64) []byte { - return []byte(PacketAcknowledgementPath(portID, channelID, sequence)) -} - -// PacketAcknowledgementPrefixPath defines the prefix for commitments to packet data fields store path. -func PacketAcknowledgementPrefixPath(portID, channelID string) string { - return fmt.Sprintf("%s/%s/%s", KeyPacketAckPrefix, channelPath(portID, channelID), KeySequencePrefix) -} - -// PacketReceiptPath defines the packet receipt store path -func PacketReceiptPath(portID, channelID string, sequence uint64) string { - return fmt.Sprintf("%s/%s/%s", KeyPacketReceiptPrefix, channelPath(portID, channelID), sequencePath(sequence)) -} - -// PacketReceiptKey returns the store key of under which a packet -// receipt is stored -func PacketReceiptKey(portID, channelID string, sequence uint64) []byte { - return []byte(PacketReceiptPath(portID, channelID, sequence)) -} - -func channelPath(portID, channelID string) string { - return fmt.Sprintf("%s/%s/%s/%s", KeyPortPrefix, portID, KeyChannelPrefix, channelID) -} - -func sequencePath(sequence uint64) string { - return fmt.Sprintf("%s/%d", KeySequencePrefix, sequence) -} - -// ICS05 -// The following paths are the keys to the store as defined in https://github.com/cosmos/ibc/tree/master/spec/core/ics-005-port-allocation#store-paths - -// PortPath defines the path under which ports paths are stored on the capability module -func PortPath(portID string) string { - return fmt.Sprintf("%s/%s", KeyPortPrefix, portID) -} diff --git a/modules/core/24-host/packet_keys.go b/modules/core/24-host/packet_keys.go new file mode 100644 index 00000000000..d2eedcaa68f --- /dev/null +++ b/modules/core/24-host/packet_keys.go @@ -0,0 +1,118 @@ +package host + +import "fmt" + +const ( + KeySequencePrefix = "sequences" + KeyNextSeqSendPrefix = "nextSequenceSend" + KeyNextSeqRecvPrefix = "nextSequenceRecv" + KeyNextSeqAckPrefix = "nextSequenceAck" + KeyPacketCommitmentPrefix = "commitments" + KeyPacketAckPrefix = "acks" + KeyPacketReceiptPrefix = "receipts" + KeyPruningSequenceStart = "pruningSequenceStart" + KeyRecvStartSequence = "recvStartSequence" +) + +// ICS04 +// The following paths are the keys to the store as defined in https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#store-paths + +// NextSequenceSendPath defines the next send sequence counter store path +func NextSequenceSendPath(portID, channelID string) string { + return fmt.Sprintf("%s/%s", KeyNextSeqSendPrefix, channelPath(portID, channelID)) +} + +// NextSequenceSendKey returns the store key for the send sequence of a particular +// channel binded to a specific port. +func NextSequenceSendKey(portID, channelID string) []byte { + return []byte(NextSequenceSendPath(portID, channelID)) +} + +// NextSequenceRecvPath defines the next receive sequence counter store path. +func NextSequenceRecvPath(portID, channelID string) string { + return fmt.Sprintf("%s/%s", KeyNextSeqRecvPrefix, channelPath(portID, channelID)) +} + +// NextSequenceRecvKey returns the store key for the receive sequence of a particular +// channel binded to a specific port +func NextSequenceRecvKey(portID, channelID string) []byte { + return []byte(NextSequenceRecvPath(portID, channelID)) +} + +// NextSequenceAckPath defines the next acknowledgement sequence counter store path +func NextSequenceAckPath(portID, channelID string) string { + return fmt.Sprintf("%s/%s", KeyNextSeqAckPrefix, channelPath(portID, channelID)) +} + +// NextSequenceAckKey returns the store key for the acknowledgement sequence of +// a particular channel binded to a specific port. +func NextSequenceAckKey(portID, channelID string) []byte { + return []byte(NextSequenceAckPath(portID, channelID)) +} + +// PacketCommitmentPath defines the commitments to packet data fields store path +func PacketCommitmentPath(portID, channelID string, sequence uint64) string { + return fmt.Sprintf("%s/%d", PacketCommitmentPrefixPath(portID, channelID), sequence) +} + +// PacketCommitmentKey returns the store key of under which a packet commitment +// is stored +func PacketCommitmentKey(portID, channelID string, sequence uint64) []byte { + return []byte(PacketCommitmentPath(portID, channelID, sequence)) +} + +// PacketCommitmentPrefixPath defines the prefix for commitments to packet data fields store path. +func PacketCommitmentPrefixPath(portID, channelID string) string { + return fmt.Sprintf("%s/%s/%s", KeyPacketCommitmentPrefix, channelPath(portID, channelID), KeySequencePrefix) +} + +// PacketAcknowledgementPath defines the packet acknowledgement store path +func PacketAcknowledgementPath(portID, channelID string, sequence uint64) string { + return fmt.Sprintf("%s/%d", PacketAcknowledgementPrefixPath(portID, channelID), sequence) +} + +// PacketAcknowledgementKey returns the store key of under which a packet +// acknowledgement is stored +func PacketAcknowledgementKey(portID, channelID string, sequence uint64) []byte { + return []byte(PacketAcknowledgementPath(portID, channelID, sequence)) +} + +// PacketAcknowledgementPrefixPath defines the prefix for commitments to packet data fields store path. +func PacketAcknowledgementPrefixPath(portID, channelID string) string { + return fmt.Sprintf("%s/%s/%s", KeyPacketAckPrefix, channelPath(portID, channelID), KeySequencePrefix) +} + +// PacketReceiptPath defines the packet receipt store path +func PacketReceiptPath(portID, channelID string, sequence uint64) string { + return fmt.Sprintf("%s/%s/%s", KeyPacketReceiptPrefix, channelPath(portID, channelID), sequencePath(sequence)) +} + +// PacketReceiptKey returns the store key of under which a packet +// receipt is stored +func PacketReceiptKey(portID, channelID string, sequence uint64) []byte { + return []byte(PacketReceiptPath(portID, channelID, sequence)) +} + +// PruningSequenceStartPath defines the path under which the pruning sequence starting value is stored +func PruningSequenceStartPath(portID, channelID string) string { + return fmt.Sprintf("%s/%s", KeyPruningSequenceStart, channelPath(portID, channelID)) +} + +// PruningSequenceStartKey returns the store key for the pruning sequence start of a particular channel +func PruningSequenceStartKey(portID, channelID string) []byte { + return []byte(PruningSequenceStartPath(portID, channelID)) +} + +// RecvStartSequencePath defines the path under which the recv start sequence is stored +func RecvStartSequencePath(portID, channelID string) string { + return fmt.Sprintf("%s/%s", KeyRecvStartSequence, channelPath(portID, channelID)) +} + +// RecvStartSequenceKey returns the store key for the recv start sequence of a particular channel +func RecvStartSequenceKey(portID, channelID string) []byte { + return []byte(RecvStartSequencePath(portID, channelID)) +} + +func sequencePath(sequence uint64) string { + return fmt.Sprintf("%s/%d", KeySequencePrefix, sequence) +} diff --git a/modules/core/24-host/port_keys.go b/modules/core/24-host/port_keys.go new file mode 100644 index 00000000000..9bd720065c2 --- /dev/null +++ b/modules/core/24-host/port_keys.go @@ -0,0 +1,15 @@ +package host + +import "fmt" + +const ( + KeyPortPrefix = "ports" +) + +// ICS05 +// The following paths are the keys to the store as defined in https://github.com/cosmos/ibc/tree/master/spec/core/ics-005-port-allocation#store-paths + +// PortPath defines the path under which ports paths are stored on the capability module +func PortPath(portID string) string { + return fmt.Sprintf("%s/%s", KeyPortPrefix, portID) +} diff --git a/modules/core/ante/ante.go b/modules/core/ante/ante.go index a64a5f0146a..96bf9e5bc8d 100644 --- a/modules/core/ante/ante.go +++ b/modules/core/ante/ante.go @@ -1,6 +1,8 @@ package ante import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" @@ -30,10 +32,22 @@ func (rrd RedundantRelayDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula for _, m := range tx.GetMsgs() { switch msg := m.(type) { case *channeltypes.MsgRecvPacket: - response, err := rrd.k.RecvPacket(ctx, msg) + var ( + response *channeltypes.MsgRecvPacketResponse + err error + ) + // when we are in ReCheckTx mode, ctx.IsCheckTx() will also return true + // therefore we must start the if statement on ctx.IsReCheckTx() to correctly + // determine which mode we are in + if ctx.IsReCheckTx() { + response, err = rrd.recvPacketReCheckTx(ctx, msg) + } else { + response, err = rrd.recvPacketCheckTx(ctx, msg) + } if err != nil { return ctx, err } + if response.Result == channeltypes.NOOP { redundancies++ } @@ -90,3 +104,49 @@ func (rrd RedundantRelayDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula } return next(ctx, tx, simulate) } + +// recvPacketCheckTx runs a subset of ibc recv packet logic to be used specifically within the RedundantRelayDecorator AnteHandler. +// It only performs core IBC receiving logic and skips any application logic. +func (rrd RedundantRelayDecorator) recvPacketCheckTx(ctx sdk.Context, msg *channeltypes.MsgRecvPacket) (*channeltypes.MsgRecvPacketResponse, error) { + // grab channel capability + _, capability, err := rrd.k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.DestinationPort, msg.Packet.DestinationChannel) + if err != nil { + return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") + } + + // If the packet was already received, perform a no-op + // Use a cached context to prevent accidental state changes + cacheCtx, writeFn := ctx.CacheContext() + err = rrd.k.ChannelKeeper.RecvPacket(cacheCtx, capability, msg.Packet, msg.ProofCommitment, msg.ProofHeight) + + switch err { + case nil: + writeFn() + case channeltypes.ErrNoOpMsg: + return &channeltypes.MsgRecvPacketResponse{Result: channeltypes.NOOP}, nil + default: + return nil, errorsmod.Wrap(err, "receive packet verification failed") + } + + return &channeltypes.MsgRecvPacketResponse{Result: channeltypes.SUCCESS}, nil +} + +// recvPacketReCheckTx runs a subset of ibc recv packet logic to be used specifically within the RedundantRelayDecorator AnteHandler. +// It only performs core IBC receiving logic and skips any application logic. +func (rrd RedundantRelayDecorator) recvPacketReCheckTx(ctx sdk.Context, msg *channeltypes.MsgRecvPacket) (*channeltypes.MsgRecvPacketResponse, error) { + // If the packet was already received, perform a no-op + // Use a cached context to prevent accidental state changes + cacheCtx, writeFn := ctx.CacheContext() + err := rrd.k.ChannelKeeper.RecvPacketReCheckTx(cacheCtx, msg.Packet) + + switch err { + case nil: + writeFn() + case channeltypes.ErrNoOpMsg: + return &channeltypes.MsgRecvPacketResponse{Result: channeltypes.NOOP}, nil + default: + return nil, errorsmod.Wrap(err, "receive packet verification failed") + } + + return &channeltypes.MsgRecvPacketResponse{Result: channeltypes.SUCCESS}, nil +} diff --git a/modules/core/ante/ante_test.go b/modules/core/ante/ante_test.go index 1b9a8c15c64..3de738dcc89 100644 --- a/modules/core/ante/ante_test.go +++ b/modules/core/ante/ante_test.go @@ -1,6 +1,7 @@ package ante_test import ( + "fmt" "testing" "github.com/stretchr/testify/require" @@ -46,7 +47,7 @@ func TestAnteTestSuite(t *testing.T) { } // createRecvPacketMessage creates a RecvPacket message for a packet sent from chain A to chain B. -func (suite *AnteTestSuite) createRecvPacketMessage(isRedundant bool) sdk.Msg { +func (suite *AnteTestSuite) createRecvPacketMessage(isRedundant bool) *channeltypes.MsgRecvPacket { sequence, err := suite.path.EndpointA.SendPacket(clienttypes.NewHeight(2, 0), 0, ibctesting.MockPacketData) suite.Require().NoError(err) @@ -145,9 +146,9 @@ func (suite *AnteTestSuite) createTimeoutOnCloseMessage(isRedundant bool) sdk.Ms proof, proofHeight := suite.chainA.QueryProof(packetKey) channelKey := host.ChannelKey(packet.GetDestPort(), packet.GetDestChannel()) - proofClosed, _ := suite.chainA.QueryProof(channelKey) + closedProof, _ := suite.chainA.QueryProof(channelKey) - return channeltypes.NewMsgTimeoutOnClose(packet, 1, proof, proofClosed, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String()) + return channeltypes.NewMsgTimeoutOnClose(packet, 1, proof, closedProof, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String()) } func (suite *AnteTestSuite) createUpdateClientMessage() sdk.Msg { @@ -174,7 +175,7 @@ func (suite *AnteTestSuite) createUpdateClientMessage() sdk.Msg { return msg } -func (suite *AnteTestSuite) TestAnteDecorator() { +func (suite *AnteTestSuite) TestAnteDecoratorCheckTx() { testCases := []struct { name string malleate func(suite *AnteTestSuite) []sdk.Msg @@ -342,6 +343,20 @@ func (suite *AnteTestSuite) TestAnteDecorator() { }, true, }, + { + "success on app callback error, app callbacks are skipped for performance", + func(suite *AnteTestSuite) []sdk.Msg { + suite.chainB.GetSimApp().IBCMockModule.IBCApp.OnRecvPacket = func( + ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, + ) exported.Acknowledgement { + panic(fmt.Errorf("failed OnRecvPacket mock callback")) + } + + // the RecvPacket message has not been submitted to the chain yet, so it will succeed + return []sdk.Msg{suite.createRecvPacketMessage(false)} + }, + true, + }, { "no success on one redundant RecvPacket message", func(suite *AnteTestSuite) []sdk.Msg { @@ -451,6 +466,15 @@ func (suite *AnteTestSuite) TestAnteDecorator() { }, false, }, + { + "no success on recvPacket checkTx, no capability found", + func(suite *AnteTestSuite) []sdk.Msg { + msg := suite.createRecvPacketMessage(false) + msg.Packet.DestinationPort = "invalid-port" + return []sdk.Msg{msg} + }, + false, + }, } for _, tc := range testCases { @@ -488,3 +512,95 @@ func (suite *AnteTestSuite) TestAnteDecorator() { }) } } + +func (suite *AnteTestSuite) TestAnteDecoratorReCheckTx() { + testCases := []struct { + name string + malleate func(suite *AnteTestSuite) []sdk.Msg + expError error + }{ + { + "success on one new RecvPacket message", + func(suite *AnteTestSuite) []sdk.Msg { + // the RecvPacket message has not been submitted to the chain yet, so it will succeed + return []sdk.Msg{suite.createRecvPacketMessage(false)} + }, + nil, + }, + { + "success on one redundant and one new RecvPacket message", + func(suite *AnteTestSuite) []sdk.Msg { + return []sdk.Msg{ + suite.createRecvPacketMessage(true), + suite.createRecvPacketMessage(false), + } + }, + nil, + }, + { + "success on invalid proof (proof checks occur in checkTx)", + func(suite *AnteTestSuite) []sdk.Msg { + msg := suite.createRecvPacketMessage(false) + msg.ProofCommitment = []byte("invalid-proof") + return []sdk.Msg{msg} + }, + nil, + }, + { + "success on app callback error, app callbacks are skipped for performance", + func(suite *AnteTestSuite) []sdk.Msg { + suite.chainB.GetSimApp().IBCMockModule.IBCApp.OnRecvPacket = func( + ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, + ) exported.Acknowledgement { + panic(fmt.Errorf("failed OnRecvPacket mock callback")) + } + + // the RecvPacket message has not been submitted to the chain yet, so it will succeed + return []sdk.Msg{suite.createRecvPacketMessage(false)} + }, + nil, + }, + { + "no success on one redundant RecvPacket message", + func(suite *AnteTestSuite) []sdk.Msg { + return []sdk.Msg{suite.createRecvPacketMessage(true)} + }, + channeltypes.ErrRedundantTx, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + // reset suite + suite.SetupTest() + + k := suite.chainB.App.GetIBCKeeper() + decorator := ante.NewRedundantRelayDecorator(k) + + msgs := tc.malleate(suite) + + deliverCtx := suite.chainB.GetContext().WithIsCheckTx(false) + reCheckCtx := suite.chainB.GetContext().WithIsReCheckTx(true) + + // create multimsg tx + txBuilder := suite.chainB.TxConfig.NewTxBuilder() + err := txBuilder.SetMsgs(msgs...) + suite.Require().NoError(err) + tx := txBuilder.GetTx() + + next := func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { return ctx, nil } + + _, err = decorator.AnteHandle(deliverCtx, tx, false, next) + suite.Require().NoError(err, "antedecorator should not error on DeliverTx") + + _, err = decorator.AnteHandle(reCheckCtx, tx, false, next) + if tc.expError == nil { + suite.Require().NoError(err, "non-strict decorator did not pass as expected") + } else { + suite.Require().ErrorIs(err, tc.expError, "non-strict antehandler did not return error as expected") + } + }) + } +} diff --git a/modules/core/exported/client.go b/modules/core/exported/client.go index cf5d11ca617..a8f0bfb0240 100644 --- a/modules/core/exported/client.go +++ b/modules/core/exported/client.go @@ -136,8 +136,8 @@ type ClientState interface { store storetypes.KVStore, newClient ClientState, newConsState ConsensusState, - proofUpgradeClient, - proofUpgradeConsState []byte, + upgradeClientProof, + upgradeConsensusStateProof []byte, ) error } diff --git a/modules/core/integration_test.go b/modules/core/integration_test.go new file mode 100644 index 00000000000..c1b165b4d01 --- /dev/null +++ b/modules/core/integration_test.go @@ -0,0 +1,98 @@ +package ibc_test + +import ( + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + ibctesting "github.com/cosmos/ibc-go/v8/testing" + ibcmock "github.com/cosmos/ibc-go/v8/testing/mock" +) + +// If packet receipts are pruned, it may be possible to double spend via a +// replay attack by resubmitting the same proof used to process the original receive. +// Core IBC performs an additional check to ensure that any packet being received +// MUST NOT be in the range of packet receipts which are allowed to be pruned thus +// adding replay protection for upgraded channels. +// This test has been added to ensure we have replay protection after +// pruning stale state upon the successful completion of a channel upgrade. +func (suite *IBCTestSuite) TestReplayProtectionAfterReceivePruning() { + var path *ibctesting.Path + + testCases := []struct { + name string + malleate func() + }{ + { + "unordered channel upgrades version", + func() { + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + }, + }, + { + "ordered channel upgrades to unordered channel", + func() { + path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED + path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Ordering = channeltypes.UNORDERED + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Ordering = channeltypes.UNORDERED + }, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + path = ibctesting.NewPath(suite.chainA, suite.chainB) + + tc.malleate() + + suite.coordinator.Setup(path) + + // Setup replay attack by sending a packet. We will save the receive + // proof to replay relaying after the channel upgrade compeletes. + disabledTimeoutTimestamp := uint64(0) + timeoutHeight := clienttypes.NewHeight(1, 110) + sequence, err := path.EndpointA.SendPacket(timeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + packet := channeltypes.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, disabledTimeoutTimestamp) + + // save receive proof for replay submission + packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + proof, proofHeight := path.EndpointA.Chain.QueryProof(packetKey) + recvMsg := channeltypes.NewMsgRecvPacket(packet, proof, proofHeight, path.EndpointB.Chain.SenderAccount.GetAddress().String()) + + err = path.RelayPacket(packet) + suite.Require().NoError(err) + + // perform upgrade + err = path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeAck() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeConfirm() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeOpen() + suite.Require().NoError(err) + + // prune stale receive state + msgPrune := channeltypes.NewMsgPruneAcknowledgements(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, 1, path.EndpointB.Chain.SenderAccount.GetAddress().String()) + res, err := path.EndpointB.Chain.SendMsgs(msgPrune) + suite.Require().NotNil(res) + suite.Require().NoError(err) + + // replay initial packet send + res, err = path.EndpointB.Chain.SendMsgs(recvMsg) + suite.Require().NotNil(res) + suite.Require().ErrorContains(err, channeltypes.ErrPacketReceived.Error(), "replay protection missing") + }) + } +} diff --git a/modules/core/keeper/events_test.go b/modules/core/keeper/events_test.go new file mode 100644 index 00000000000..d7912dc6944 --- /dev/null +++ b/modules/core/keeper/events_test.go @@ -0,0 +1,106 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v8/modules/core/keeper" + "github.com/cosmos/ibc-go/v8/modules/core/types" +) + +func TestConvertToErrorEvents(t *testing.T) { + var ( + events sdk.Events + expEvents sdk.Events + ) + + tc := []struct { + name string + malleate func() + }{ + { + "success: nil events", + func() { + events = nil + expEvents = nil + }, + }, + { + "success: empty events", + func() { + events = sdk.Events{} + expEvents = sdk.Events{} + }, + }, + { + "success: event with no attributes", + func() { + events = sdk.Events{ + sdk.NewEvent("testevent"), + } + expEvents = sdk.Events{ + sdk.NewEvent(types.ErrorAttributeKeyPrefix + "testevent"), + } + }, + }, + { + "success: event with attributes", + func() { + events = sdk.Events{ + sdk.NewEvent("testevent", + sdk.NewAttribute("key1", "value1"), + sdk.NewAttribute("key2", "value2"), + ), + } + expEvents = sdk.Events{ + sdk.NewEvent(types.ErrorAttributeKeyPrefix+"testevent", + sdk.NewAttribute(types.ErrorAttributeKeyPrefix+"key1", "value1"), + sdk.NewAttribute(types.ErrorAttributeKeyPrefix+"key2", "value2"), + ), + } + }, + }, + { + "success: multiple events with attributes", + func() { + events = sdk.Events{ + sdk.NewEvent("testevent1", + sdk.NewAttribute("key1", "value1"), + sdk.NewAttribute("key2", "value2"), + ), + sdk.NewEvent("testevent2", + sdk.NewAttribute("key3", "value3"), + sdk.NewAttribute("key4", "value4"), + ), + } + expEvents = sdk.Events{ + sdk.NewEvent(types.ErrorAttributeKeyPrefix+"testevent1", + sdk.NewAttribute(types.ErrorAttributeKeyPrefix+"key1", "value1"), + sdk.NewAttribute(types.ErrorAttributeKeyPrefix+"key2", "value2"), + ), + sdk.NewEvent(types.ErrorAttributeKeyPrefix+"testevent2", + sdk.NewAttribute(types.ErrorAttributeKeyPrefix+"key3", "value3"), + sdk.NewAttribute(types.ErrorAttributeKeyPrefix+"key4", "value4"), + ), + } + }, + }, + } + + for _, tc := range tc { + t.Run(tc.name, func(t *testing.T) { + // initial events and expected events are reset so that the test fails if + // the malleate function does not set them + events = nil + expEvents = sdk.Events{} + + tc.malleate() + + newEvents := keeper.ConvertToErrorEvents(events) + require.Equal(t, expEvents, newEvents) + }) + } +} diff --git a/modules/core/keeper/export_test.go b/modules/core/keeper/export_test.go new file mode 100644 index 00000000000..81d79ea7aa9 --- /dev/null +++ b/modules/core/keeper/export_test.go @@ -0,0 +1,9 @@ +package keeper + +import sdk "github.com/cosmos/cosmos-sdk/types" + +// ConvertToErrorEvents is a wrapper around convertToErrorEvents +// to allow the function to be directly called in tests. +func ConvertToErrorEvents(events sdk.Events) sdk.Events { + return convertToErrorEvents(events) +} diff --git a/modules/core/keeper/grpc_query.go b/modules/core/keeper/grpc_query.go index 68b6d38c0f2..259fb55e7d2 100644 --- a/modules/core/keeper/grpc_query.go +++ b/modules/core/keeper/grpc_query.go @@ -157,3 +157,18 @@ func (k Keeper) NextSequenceReceive(c context.Context, req *channeltypes.QueryNe func (k Keeper) NextSequenceSend(c context.Context, req *channeltypes.QueryNextSequenceSendRequest) (*channeltypes.QueryNextSequenceSendResponse, error) { return k.ChannelKeeper.NextSequenceSend(c, req) } + +// UpgradeError implements the IBC QueryServer interface +func (k Keeper) UpgradeError(c context.Context, req *channeltypes.QueryUpgradeErrorRequest) (*channeltypes.QueryUpgradeErrorResponse, error) { + return k.ChannelKeeper.UpgradeErrorReceipt(c, req) +} + +// Upgrade implements the IBC QueryServer interface +func (k Keeper) Upgrade(c context.Context, req *channeltypes.QueryUpgradeRequest) (*channeltypes.QueryUpgradeResponse, error) { + return k.ChannelKeeper.Upgrade(c, req) +} + +// ChannelParams implements the IBC QueryServer interface +func (k Keeper) ChannelParams(c context.Context, req *channeltypes.QueryChannelParamsRequest) (*channeltypes.QueryChannelParamsResponse, error) { + return k.ChannelKeeper.ChannelParams(c, req) +} diff --git a/modules/core/keeper/keeper.go b/modules/core/keeper/keeper.go index 08ee5dc027e..d8df3b6b96a 100644 --- a/modules/core/keeper/keeper.go +++ b/modules/core/keeper/keeper.go @@ -2,6 +2,7 @@ package keeper import ( "errors" + "fmt" "reflect" "strings" @@ -17,6 +18,7 @@ import ( portkeeper "github.com/cosmos/ibc-go/v8/modules/core/05-port/keeper" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" "github.com/cosmos/ibc-go/v8/modules/core/types" + ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" ) var _ types.QueryServer = (*Keeper)(nil) @@ -64,7 +66,7 @@ func NewKeeper( portKeeper := portkeeper.NewKeeper(scopedKeeper) channelKeeper := channelkeeper.NewKeeper(cdc, key, clientKeeper, connectionKeeper, &portKeeper, scopedKeeper) - return &Keeper{ + keeper := &Keeper{ cdc: cdc, ClientKeeper: clientKeeper, ConnectionKeeper: connectionKeeper, @@ -72,6 +74,10 @@ func NewKeeper( PortKeeper: &portKeeper, authority: authority, } + + keeper.SetConsensusHost(ibctm.NewConsensusHost(stakingKeeper)) + + return keeper } // Codec returns the IBC module codec. @@ -79,6 +85,16 @@ func (k Keeper) Codec() codec.BinaryCodec { return k.cdc } +// SetConsensusHost sets a custom ConsensusHost for self client state and consensus state validation. +func (k *Keeper) SetConsensusHost(consensusHost clienttypes.ConsensusHost) { + if consensusHost == nil { + panic(fmt.Errorf("cannot set a nil self consensus host")) + } + + k.ClientKeeper.SetConsensusHost(consensusHost) + k.ConnectionKeeper.SetConsensusHost(consensusHost) +} + // SetRouter sets the Router in IBC Keeper and seals it. The method panics if // there is an existing router that's already sealed. func (k *Keeper) SetRouter(rtr *porttypes.Router) { diff --git a/modules/core/keeper/migrations.go b/modules/core/keeper/migrations.go deleted file mode 100644 index 9afaddcb3c7..00000000000 --- a/modules/core/keeper/migrations.go +++ /dev/null @@ -1,23 +0,0 @@ -package keeper - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - - clientkeeper "github.com/cosmos/ibc-go/v8/modules/core/02-client/keeper" -) - -// Migrator is a struct for handling in-place store migrations. -type Migrator struct { - keeper Keeper -} - -// NewMigrator returns a new Migrator. -func NewMigrator(keeper Keeper) Migrator { - return Migrator{keeper: keeper} -} - -// Migrate2to3 migrates from version 2 to 3. See 02-client keeper function Migrate2to3. -func (m Migrator) Migrate2to3(ctx sdk.Context) error { - clientMigrator := clientkeeper.NewMigrator(m.keeper.ClientKeeper) - return clientMigrator.Migrate2to3(ctx) -} diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 922c365842b..27dae2e0c2e 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -12,6 +12,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v8/modules/core/04-channel/keeper" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" @@ -431,7 +432,7 @@ func (k Keeper) ChannelCloseConfirm(goCtx context.Context, msg *channeltypes.Msg return nil, errorsmod.Wrapf(err, "channel close confirm callback failed for port ID: %s, channel ID: %s", msg.PortId, msg.ChannelId) } - err = k.ChannelKeeper.ChanCloseConfirm(ctx, msg.PortId, msg.ChannelId, capability, msg.ProofInit, msg.ProofHeight) + err = k.ChannelKeeper.ChanCloseConfirmWithCounterpartyUpgradeSequence(ctx, msg.PortId, msg.ChannelId, capability, msg.ProofInit, msg.ProofHeight, msg.CounterpartyUpgradeSequence) if err != nil { ctx.Logger().Error("channel close confirm failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", err.Error()) return nil, errorsmod.Wrap(err, "channel handshake close confirm failed") @@ -493,6 +494,9 @@ func (k Keeper) RecvPacket(goCtx context.Context, msg *channeltypes.MsgRecvPacke if ack == nil || ack.Success() { // write application state changes for asynchronous and successful acknowledgements writeFn() + } else { + // Modify events in cached context to reflect unsuccessful acknowledgement + ctx.EventManager().EmitEvents(convertToErrorEvents(cacheCtx.EventManager().Events())) } // Set packet acknowledgement only if the acknowledgement is not nil. @@ -563,6 +567,11 @@ func (k Keeper) Timeout(goCtx context.Context, msg *channeltypes.MsgTimeout) (*c return nil, errorsmod.Wrap(err, "timeout packet verification failed") } + // Delete packet commitment + if err = k.ChannelKeeper.TimeoutExecuted(ctx, capability, msg.Packet); err != nil { + return nil, err + } + // Perform application logic callback err = cbs.OnTimeoutPacket(ctx, msg.Packet, relayer) if err != nil { @@ -570,11 +579,6 @@ func (k Keeper) Timeout(goCtx context.Context, msg *channeltypes.MsgTimeout) (*c return nil, errorsmod.Wrap(err, "timeout packet callback failed") } - // Delete packet commitment - if err = k.ChannelKeeper.TimeoutExecuted(ctx, capability, msg.Packet); err != nil { - return nil, err - } - defer telemetry.IncrCounterWithLabels( []string{"ibc", "timeout", "packet"}, 1, @@ -621,7 +625,7 @@ func (k Keeper) TimeoutOnClose(goCtx context.Context, msg *channeltypes.MsgTimeo // If the timeout was already received, perform a no-op // Use a cached context to prevent accidental state changes cacheCtx, writeFn := ctx.CacheContext() - err = k.ChannelKeeper.TimeoutOnClose(cacheCtx, capability, msg.Packet, msg.ProofUnreceived, msg.ProofClose, msg.ProofHeight, msg.NextSequenceRecv) + err = k.ChannelKeeper.TimeoutOnCloseWithCounterpartyUpgradeSequence(cacheCtx, capability, msg.Packet, msg.ProofUnreceived, msg.ProofClose, msg.ProofHeight, msg.NextSequenceRecv, msg.CounterpartyUpgradeSequence) switch err { case nil: @@ -635,6 +639,11 @@ func (k Keeper) TimeoutOnClose(goCtx context.Context, msg *channeltypes.MsgTimeo return nil, errorsmod.Wrap(err, "timeout on close packet verification failed") } + // Delete packet commitment + if err = k.ChannelKeeper.TimeoutExecuted(ctx, capability, msg.Packet); err != nil { + return nil, err + } + // Perform application logic callback // // NOTE: MsgTimeout and MsgTimeoutOnClose use the same "OnTimeoutPacket" @@ -645,11 +654,6 @@ func (k Keeper) TimeoutOnClose(goCtx context.Context, msg *channeltypes.MsgTimeo return nil, errorsmod.Wrap(err, "timeout on close callback failed") } - // Delete packet commitment - if err = k.ChannelKeeper.TimeoutExecuted(ctx, capability, msg.Packet); err != nil { - return nil, err - } - defer telemetry.IncrCounterWithLabels( []string{"ibc", "timeout", "packet"}, 1, @@ -733,6 +737,368 @@ func (k Keeper) Acknowledgement(goCtx context.Context, msg *channeltypes.MsgAckn return &channeltypes.MsgAcknowledgementResponse{Result: channeltypes.SUCCESS}, nil } +// ChannelUpgradeInit defines a rpc handler method for MsgChannelUpgradeInit. +func (k Keeper) ChannelUpgradeInit(goCtx context.Context, msg *channeltypes.MsgChannelUpgradeInit) (*channeltypes.MsgChannelUpgradeInitResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + if k.GetAuthority() != msg.Signer { + return nil, errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "expected %s, got %s", k.GetAuthority(), msg.Signer) + } + + module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) + if err != nil { + ctx.Logger().Error("channel upgrade init failed", "port-id", msg.PortId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) + return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") + } + + app, ok := k.Router.GetRoute(module) + if !ok { + ctx.Logger().Error("channel upgrade init failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + } + + cbs, ok := app.(porttypes.UpgradableModule) + if !ok { + ctx.Logger().Error("channel upgrade init failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", module)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", module) + } + + upgrade, err := k.ChannelKeeper.ChanUpgradeInit(ctx, msg.PortId, msg.ChannelId, msg.Fields) + if err != nil { + ctx.Logger().Error("channel upgrade init failed", "error", errorsmod.Wrap(err, "channel upgrade init failed")) + return nil, errorsmod.Wrap(err, "channel upgrade init failed") + } + + // NOTE: a cached context is used to discard ibc application state changes and events. + // IBC applications must flush in-flight packets using the pre-upgrade channel parameters. + cacheCtx, _ := ctx.CacheContext() + upgradeVersion, err := cbs.OnChanUpgradeInit(cacheCtx, msg.PortId, msg.ChannelId, upgrade.Fields.Ordering, upgrade.Fields.ConnectionHops, upgrade.Fields.Version) + if err != nil { + ctx.Logger().Error("channel upgrade init callback failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", err.Error()) + return nil, errorsmod.Wrapf(err, "channel upgrade init callback failed for port ID: %s, channel ID: %s", msg.PortId, msg.ChannelId) + } + + channel, upgrade := k.ChannelKeeper.WriteUpgradeInitChannel(ctx, msg.PortId, msg.ChannelId, upgrade, upgradeVersion) + + ctx.Logger().Info("channel upgrade init succeeded", "channel-id", msg.ChannelId, "version", upgradeVersion) + keeper.EmitChannelUpgradeInitEvent(ctx, msg.PortId, msg.ChannelId, channel, upgrade) + + return &channeltypes.MsgChannelUpgradeInitResponse{ + Upgrade: upgrade, + UpgradeSequence: channel.UpgradeSequence, + }, nil +} + +// ChannelUpgradeTry defines a rpc handler method for MsgChannelUpgradeTry. +func (k Keeper) ChannelUpgradeTry(goCtx context.Context, msg *channeltypes.MsgChannelUpgradeTry) (*channeltypes.MsgChannelUpgradeTryResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) + if err != nil { + ctx.Logger().Error("channel upgrade try failed", "port-id", msg.PortId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) + return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") + } + + app, ok := k.Router.GetRoute(module) + if !ok { + ctx.Logger().Error("channel upgrade try failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + } + + cbs, ok := app.(porttypes.UpgradableModule) + if !ok { + ctx.Logger().Error("channel upgrade try failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", module)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", module) + } + + channel, upgrade, err := k.ChannelKeeper.ChanUpgradeTry(ctx, msg.PortId, msg.ChannelId, msg.ProposedUpgradeConnectionHops, msg.CounterpartyUpgradeFields, msg.CounterpartyUpgradeSequence, msg.ProofChannel, msg.ProofUpgrade, msg.ProofHeight) + if err != nil { + ctx.Logger().Error("channel upgrade try failed", "error", errorsmod.Wrap(err, "channel upgrade try failed")) + if channeltypes.IsUpgradeError(err) { + k.ChannelKeeper.WriteErrorReceipt(ctx, msg.PortId, msg.ChannelId, err.(*channeltypes.UpgradeError)) + // NOTE: a FAILURE result is returned to the client and an error receipt is written to state. + // This signals to the relayer to begin the cancel upgrade handshake subprotocol. + return &channeltypes.MsgChannelUpgradeTryResponse{Result: channeltypes.FAILURE}, nil + } + + // NOTE: an error is returned to baseapp and transaction state is not committed. + return nil, errorsmod.Wrap(err, "channel upgrade try failed") + } + + // NOTE: a cached context is used to discard ibc application state changes and events. + // IBC applications must flush in-flight packets using the pre-upgrade channel parameters. + cacheCtx, _ := ctx.CacheContext() + upgradeVersion, err := cbs.OnChanUpgradeTry(cacheCtx, msg.PortId, msg.ChannelId, upgrade.Fields.Ordering, upgrade.Fields.ConnectionHops, upgrade.Fields.Version) + if err != nil { + ctx.Logger().Error("channel upgrade try callback failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", err.Error()) + return nil, errorsmod.Wrapf(err, "channel upgrade try callback failed for port ID: %s, channel ID: %s", msg.PortId, msg.ChannelId) + } + + channel, upgrade = k.ChannelKeeper.WriteUpgradeTryChannel(ctx, msg.PortId, msg.ChannelId, upgrade, upgradeVersion) + + ctx.Logger().Info("channel upgrade try succeeded", "port-id", msg.PortId, "channel-id", msg.ChannelId) + keeper.EmitChannelUpgradeTryEvent(ctx, msg.PortId, msg.ChannelId, channel, upgrade) + + return &channeltypes.MsgChannelUpgradeTryResponse{ + Result: channeltypes.SUCCESS, + Upgrade: upgrade, + UpgradeSequence: channel.UpgradeSequence, + }, nil +} + +// ChannelUpgradeAck defines a rpc handler method for MsgChannelUpgradeAck. +func (k Keeper) ChannelUpgradeAck(goCtx context.Context, msg *channeltypes.MsgChannelUpgradeAck) (*channeltypes.MsgChannelUpgradeAckResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) + if err != nil { + ctx.Logger().Error("channel upgrade ack failed", "port-id", msg.PortId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) + return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") + } + + app, ok := k.Router.GetRoute(module) + if !ok { + err = errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + ctx.Logger().Error("channel upgrade ack failed", "port-id", msg.PortId, "error", err) + return nil, err + } + + cbs, ok := app.(porttypes.UpgradableModule) + if !ok { + err = errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", module) + ctx.Logger().Error("channel upgrade ack failed", "port-id", msg.PortId, "error", err) + return nil, err + } + + err = k.ChannelKeeper.ChanUpgradeAck(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyUpgrade, msg.ProofChannel, msg.ProofUpgrade, msg.ProofHeight) + if err != nil { + ctx.Logger().Error("channel upgrade ack failed", "error", errorsmod.Wrap(err, "channel upgrade ack failed")) + if channeltypes.IsUpgradeError(err) { + k.ChannelKeeper.MustAbortUpgrade(ctx, msg.PortId, msg.ChannelId, err) + + // NOTE: a FAILURE result is returned to the client and an error receipt is written to state. + // This signals to the relayer to begin the cancel upgrade handshake subprotocol. + return &channeltypes.MsgChannelUpgradeAckResponse{Result: channeltypes.FAILURE}, nil + } + + // NOTE: an error is returned to baseapp and transaction state is not committed. + return nil, errorsmod.Wrap(err, "channel upgrade ack failed") + } + + // NOTE: a cached context is used to discard ibc application state changes and events. + // IBC applications must flush in-flight packets using the pre-upgrade channel parameters. + cacheCtx, _ := ctx.CacheContext() + err = cbs.OnChanUpgradeAck(cacheCtx, msg.PortId, msg.ChannelId, msg.CounterpartyUpgrade.Fields.Version) + if err != nil { + channel, found := k.ChannelKeeper.GetChannel(ctx, msg.PortId, msg.ChannelId) + if !found { + return nil, errorsmod.Wrapf(channeltypes.ErrChannelNotFound, "channel not found for port ID (%s) channel ID (%s)", msg.PortId, msg.ChannelId) + } + + ctx.Logger().Error("channel upgrade ack callback failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", err.Error()) + + // explicitly wrap the application callback in an upgrade error with the correct upgrade sequence. + // this prevents any errors caused from the application returning an UpgradeError with an incorrect sequence. + k.ChannelKeeper.MustAbortUpgrade(ctx, msg.PortId, msg.ChannelId, channeltypes.NewUpgradeError(channel.UpgradeSequence, err)) + + return &channeltypes.MsgChannelUpgradeAckResponse{Result: channeltypes.FAILURE}, nil + } + + channel, upgrade := k.ChannelKeeper.WriteUpgradeAckChannel(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyUpgrade) + + ctx.Logger().Info("channel upgrade ack succeeded", "port-id", msg.PortId, "channel-id", msg.ChannelId) + keeper.EmitChannelUpgradeAckEvent(ctx, msg.PortId, msg.ChannelId, channel, upgrade) + + return &channeltypes.MsgChannelUpgradeAckResponse{Result: channeltypes.SUCCESS}, nil +} + +// ChannelUpgradeConfirm defines a rpc handler method for MsgChannelUpgradeConfirm. +func (k Keeper) ChannelUpgradeConfirm(goCtx context.Context, msg *channeltypes.MsgChannelUpgradeConfirm) (*channeltypes.MsgChannelUpgradeConfirmResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) + if err != nil { + ctx.Logger().Error("channel upgrade confirm failed", "port-id", msg.PortId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) + return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") + } + + app, ok := k.Router.GetRoute(module) + if !ok { + err = errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + ctx.Logger().Error("channel upgrade confirm failed", "port-id", msg.PortId, "error", err) + return nil, err + } + + cbs, ok := app.(porttypes.UpgradableModule) + if !ok { + err = errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", module) + ctx.Logger().Error("channel upgrade confirm failed", "port-id", msg.PortId, "error", err) + return nil, err + } + + err = k.ChannelKeeper.ChanUpgradeConfirm(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyChannelState, msg.CounterpartyUpgrade, msg.ProofChannel, msg.ProofUpgrade, msg.ProofHeight) + if err != nil { + ctx.Logger().Error("channel upgrade confirm failed", "error", errorsmod.Wrap(err, "channel upgrade confirm failed")) + if channeltypes.IsUpgradeError(err) { + k.ChannelKeeper.MustAbortUpgrade(ctx, msg.PortId, msg.ChannelId, err) + + // NOTE: a FAILURE result is returned to the client and an error receipt is written to state. + // This signals to the relayer to begin the cancel upgrade handshake subprotocol. + return &channeltypes.MsgChannelUpgradeConfirmResponse{Result: channeltypes.FAILURE}, nil + } + + // NOTE: an error is returned to baseapp and transaction state is not committed. + return nil, errorsmod.Wrap(err, "channel upgrade confirm failed") + } + + channel := k.ChannelKeeper.WriteUpgradeConfirmChannel(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyUpgrade) + ctx.Logger().Info("channel upgrade confirm succeeded", "port-id", msg.PortId, "channel-id", msg.ChannelId) + keeper.EmitChannelUpgradeConfirmEvent(ctx, msg.PortId, msg.ChannelId, channel) + + // Move channel to OPEN state if both chains have finished flushing in-flight packets. + // Counterparty channel state has been verified in ChanUpgradeConfirm. + if channel.State == channeltypes.FLUSHCOMPLETE && msg.CounterpartyChannelState == channeltypes.FLUSHCOMPLETE { + upgrade, found := k.ChannelKeeper.GetUpgrade(ctx, msg.PortId, msg.ChannelId) + if !found { + return nil, errorsmod.Wrapf(channeltypes.ErrUpgradeNotFound, "failed to retrieve channel upgrade: port ID (%s) channel ID (%s)", msg.PortId, msg.ChannelId) + } + + cbs.OnChanUpgradeOpen(ctx, msg.PortId, msg.ChannelId, upgrade.Fields.Ordering, upgrade.Fields.ConnectionHops, upgrade.Fields.Version) + channel := k.ChannelKeeper.WriteUpgradeOpenChannel(ctx, msg.PortId, msg.ChannelId) + + ctx.Logger().Info("channel upgrade open succeeded", "port-id", msg.PortId, "channel-id", msg.ChannelId) + keeper.EmitChannelUpgradeOpenEvent(ctx, msg.PortId, msg.ChannelId, channel) + } + + return &channeltypes.MsgChannelUpgradeConfirmResponse{Result: channeltypes.SUCCESS}, nil +} + +// ChannelUpgradeOpen defines a rpc handler method for MsgChannelUpgradeOpen. +func (k Keeper) ChannelUpgradeOpen(goCtx context.Context, msg *channeltypes.MsgChannelUpgradeOpen) (*channeltypes.MsgChannelUpgradeOpenResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) + if err != nil { + ctx.Logger().Error("channel upgrade open failed", "port-id", msg.PortId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) + return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") + } + + app, ok := k.Router.GetRoute(module) + if !ok { + err = errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + ctx.Logger().Error("channel upgrade open failed", "port-id", msg.PortId, "error", err) + return nil, err + } + + cbs, ok := app.(porttypes.UpgradableModule) + if !ok { + err = errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", module) + ctx.Logger().Error("channel upgrade open failed", "port-id", msg.PortId, "error", err) + return nil, err + } + + if err = k.ChannelKeeper.ChanUpgradeOpen(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyChannelState, msg.CounterpartyUpgradeSequence, msg.ProofChannel, msg.ProofHeight); err != nil { + ctx.Logger().Error("channel upgrade open failed", "error", errorsmod.Wrap(err, "channel upgrade open failed")) + return nil, errorsmod.Wrap(err, "channel upgrade open failed") + } + + upgrade, found := k.ChannelKeeper.GetUpgrade(ctx, msg.PortId, msg.ChannelId) + if !found { + return nil, errorsmod.Wrapf(channeltypes.ErrUpgradeNotFound, "failed to retrieve channel upgrade: port ID (%s) channel ID (%s)", msg.PortId, msg.ChannelId) + } + + cbs.OnChanUpgradeOpen(ctx, msg.PortId, msg.ChannelId, upgrade.Fields.Ordering, upgrade.Fields.ConnectionHops, upgrade.Fields.Version) + channel := k.ChannelKeeper.WriteUpgradeOpenChannel(ctx, msg.PortId, msg.ChannelId) + + ctx.Logger().Info("channel upgrade open succeeded", "port-id", msg.PortId, "channel-id", msg.ChannelId) + keeper.EmitChannelUpgradeOpenEvent(ctx, msg.PortId, msg.ChannelId, channel) + + return &channeltypes.MsgChannelUpgradeOpenResponse{}, nil +} + +// ChannelUpgradeTimeout defines a rpc handler method for MsgChannelUpgradeTimeout. +func (k Keeper) ChannelUpgradeTimeout(goCtx context.Context, msg *channeltypes.MsgChannelUpgradeTimeout) (*channeltypes.MsgChannelUpgradeTimeoutResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + if err := k.ChannelKeeper.ChanUpgradeTimeout(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyChannel, msg.ProofChannel, msg.ProofHeight); err != nil { + return nil, errorsmod.Wrapf(err, "could not timeout upgrade for channel: %s", msg.ChannelId) + } + + channel, upgrade := k.ChannelKeeper.WriteUpgradeTimeoutChannel(ctx, msg.PortId, msg.ChannelId) + + ctx.Logger().Info("channel upgrade timeout callback succeeded: portID %s, channelID %s", msg.PortId, msg.ChannelId) + keeper.EmitChannelUpgradeTimeoutEvent(ctx, msg.PortId, msg.ChannelId, channel, upgrade) + + return &channeltypes.MsgChannelUpgradeTimeoutResponse{}, nil +} + +// ChannelUpgradeCancel defines a rpc handler method for MsgChannelUpgradeCancel. +func (k Keeper) ChannelUpgradeCancel(goCtx context.Context, msg *channeltypes.MsgChannelUpgradeCancel) (*channeltypes.MsgChannelUpgradeCancelResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + channel, found := k.ChannelKeeper.GetChannel(ctx, msg.PortId, msg.ChannelId) + if !found { + return nil, errorsmod.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", msg.PortId, msg.ChannelId) + } + + // if the msgSender is authorized to make and cancel upgrades AND the current channel has not already reached FLUSHCOMPLETE + // then we can restore immediately without any additional checks + isAuthority := k.GetAuthority() == msg.Signer + if isAuthority && channel.State != channeltypes.FLUSHCOMPLETE { + upgrade, found := k.ChannelKeeper.GetUpgrade(ctx, msg.PortId, msg.ChannelId) + if !found { + return nil, errorsmod.Wrapf(channeltypes.ErrUpgradeNotFound, "failed to retrieve channel upgrade: port ID (%s) channel ID (%s)", msg.PortId, msg.ChannelId) + } + + k.ChannelKeeper.WriteUpgradeCancelChannel(ctx, msg.PortId, msg.ChannelId, channel.UpgradeSequence) + + ctx.Logger().Info("channel upgrade cancel succeeded", "port-id", msg.PortId, "channel-id", msg.ChannelId) + + keeper.EmitChannelUpgradeCancelEvent(ctx, msg.PortId, msg.ChannelId, channel, upgrade) + + return &channeltypes.MsgChannelUpgradeCancelResponse{}, nil + } + + if err := k.ChannelKeeper.ChanUpgradeCancel(ctx, msg.PortId, msg.ChannelId, msg.ErrorReceipt, msg.ProofErrorReceipt, msg.ProofHeight); err != nil { + ctx.Logger().Error("channel upgrade cancel failed", "port-id", msg.PortId, "error", err.Error()) + return nil, errorsmod.Wrap(err, "channel upgrade cancel failed") + } + + // get upgrade here since it will be deleted in WriteUpgradeCancelChannel + upgrade, found := k.ChannelKeeper.GetUpgrade(ctx, msg.PortId, msg.ChannelId) + if !found { + return nil, errorsmod.Wrapf(channeltypes.ErrUpgradeNotFound, "failed to retrieve channel upgrade: port ID (%s) channel ID (%s)", msg.PortId, msg.ChannelId) + } + + k.ChannelKeeper.WriteUpgradeCancelChannel(ctx, msg.PortId, msg.ChannelId, msg.ErrorReceipt.Sequence) + + ctx.Logger().Info("channel upgrade cancel succeeded", "port-id", msg.PortId, "channel-id", msg.ChannelId) + + // get channel here again to get latest state after write + channel, found = k.ChannelKeeper.GetChannel(ctx, msg.PortId, msg.ChannelId) + if !found { + return nil, errorsmod.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", msg.PortId, msg.ChannelId) + } + keeper.EmitChannelUpgradeCancelEvent(ctx, msg.PortId, msg.ChannelId, channel, upgrade) + + return &channeltypes.MsgChannelUpgradeCancelResponse{}, nil +} + +// PruneAcknowledgements defines a rpc handler method for MsgPruneAcknowledgements. +func (k Keeper) PruneAcknowledgements(goCtx context.Context, msg *channeltypes.MsgPruneAcknowledgements) (*channeltypes.MsgPruneAcknowledgementsResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + pruned, remaining, err := k.ChannelKeeper.PruneAcknowledgements(ctx, msg.PortId, msg.ChannelId, msg.Limit) + if err != nil { + return nil, err + } + + return &channeltypes.MsgPruneAcknowledgementsResponse{ + TotalPrunedSequences: pruned, + TotalRemainingSequences: remaining, + }, nil +} + // UpdateClientParams defines a rpc handler method for MsgUpdateParams. func (k Keeper) UpdateClientParams(goCtx context.Context, msg *clienttypes.MsgUpdateParams) (*clienttypes.MsgUpdateParamsResponse, error) { if k.GetAuthority() != msg.Signer { @@ -756,3 +1122,35 @@ func (k Keeper) UpdateConnectionParams(goCtx context.Context, msg *connectiontyp return &connectiontypes.MsgUpdateParamsResponse{}, nil } + +// UpdateChannelParams defines a rpc handler method for MsgUpdateParams. +func (k Keeper) UpdateChannelParams(goCtx context.Context, msg *channeltypes.MsgUpdateParams) (*channeltypes.MsgUpdateParamsResponse, error) { + if k.GetAuthority() != msg.Authority { + return nil, errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "expected %s, got %s", k.GetAuthority(), msg.Authority) + } + + ctx := sdk.UnwrapSDKContext(goCtx) + k.ChannelKeeper.SetParams(ctx, msg.Params) + + return &channeltypes.MsgUpdateParamsResponse{}, nil +} + +// convertToErrorEvents converts all events to error events by appending the +// error attribute prefix to each event's attribute key. +func convertToErrorEvents(events sdk.Events) sdk.Events { + if events == nil { + return nil + } + + newEvents := make(sdk.Events, len(events)) + for i, event := range events { + newAttributes := make([]sdk.Attribute, len(event.Attributes)) + for j, attribute := range event.Attributes { + newAttributes[j] = sdk.NewAttribute(coretypes.ErrorAttributeKeyPrefix+attribute.Key, attribute.Value) + } + + newEvents[i] = sdk.NewEvent(coretypes.ErrorAttributeKeyPrefix+event.Type, newAttributes...) + } + + return newEvents +} diff --git a/modules/core/keeper/msg_server_test.go b/modules/core/keeper/msg_server_test.go index 84298ae0481..6e799de8fb6 100644 --- a/modules/core/keeper/msg_server_test.go +++ b/modules/core/keeper/msg_server_test.go @@ -2,14 +2,20 @@ package keeper_test import ( "errors" + "fmt" upgradetypes "cosmossdk.io/x/upgrade/types" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + abci "github.com/cometbft/cometbft/abci/types" + + capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" @@ -34,7 +40,6 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() { var ( packet channeltypes.Packet path *ibctesting.Path - async bool // indicate no ack written ) testCases := []struct { @@ -42,6 +47,8 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() { malleate func() expPass bool expRevert bool + async bool // indicate no ack written + replay bool // indicate replay (no-op) }{ {"success: ORDERED", func() { path.SetChannelOrdered() @@ -51,7 +58,7 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() { suite.Require().NoError(err) packet = channeltypes.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) - }, true, false}, + }, true, false, false, false}, {"success: UNORDERED", func() { suite.coordinator.Setup(path) @@ -59,7 +66,7 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() { suite.Require().NoError(err) packet = channeltypes.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) - }, true, false}, + }, true, false, false, false}, {"success: UNORDERED out of order packet", func() { // setup uses an UNORDERED channel suite.coordinator.Setup(path) @@ -71,7 +78,7 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() { packet = channeltypes.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) } - }, true, false}, + }, true, false, false, false}, {"success: OnRecvPacket callback returns revert=true", func() { suite.coordinator.Setup(path) @@ -79,26 +86,24 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() { suite.Require().NoError(err) packet = channeltypes.NewPacket(ibctesting.MockFailPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) - }, true, true}, + }, true, true, false, false}, {"success: ORDERED - async acknowledgement", func() { path.SetChannelOrdered() suite.coordinator.Setup(path) - async = true sequence, err := path.EndpointA.SendPacket(timeoutHeight, 0, ibcmock.MockAsyncPacketData) suite.Require().NoError(err) packet = channeltypes.NewPacket(ibcmock.MockAsyncPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) - }, true, false}, + }, true, false, true, false}, {"success: UNORDERED - async acknowledgement", func() { suite.coordinator.Setup(path) - async = true sequence, err := path.EndpointA.SendPacket(timeoutHeight, 0, ibcmock.MockAsyncPacketData) suite.Require().NoError(err) packet = channeltypes.NewPacket(ibcmock.MockAsyncPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) - }, true, false}, + }, true, false, true, false}, {"failure: ORDERED out of order packet", func() { path.SetChannelOrdered() suite.coordinator.Setup(path) @@ -110,15 +115,15 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() { packet = channeltypes.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) } - }, false, false}, + }, false, false, false, false}, {"channel does not exist", func() { // any non-nil value of packet is valid suite.Require().NotNil(packet) - }, false, false}, + }, false, false, false, false}, {"packet not sent", func() { suite.coordinator.Setup(path) packet = channeltypes.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) - }, false, false}, + }, false, false, false, false}, {"successful no-op: ORDERED - packet already received (replay)", func() { // mock will panic if application callback is called twice on the same packet path.SetChannelOrdered() @@ -130,7 +135,7 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() { packet = channeltypes.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) err = path.EndpointB.RecvPacket(packet) suite.Require().NoError(err) - }, true, false}, + }, true, false, false, true}, {"successful no-op: UNORDERED - packet already received (replay)", func() { // mock will panic if application callback is called twice on the same packet suite.coordinator.Setup(path) @@ -141,7 +146,7 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() { packet = channeltypes.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) err = path.EndpointB.RecvPacket(packet) suite.Require().NoError(err) - }, true, false}, + }, true, false, false, true}, } for _, tc := range testCases { @@ -149,7 +154,6 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() { suite.Run(tc.name, func() { suite.SetupTest() // reset - async = false // reset path = ibctesting.NewPath(suite.chainA, suite.chainB) tc.malleate() @@ -167,7 +171,10 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() { msg := channeltypes.NewMsgRecvPacket(packet, proof, proofHeight, suite.chainB.SenderAccount.GetAddress().String()) - _, err := keeper.Keeper.RecvPacket(*suite.chainB.App.GetIBCKeeper(), suite.chainB.GetContext(), msg) + ctx := suite.chainB.GetContext() + _, err := keeper.Keeper.RecvPacket(*suite.chainB.App.GetIBCKeeper(), ctx, msg) + + events := ctx.EventManager().Events() if tc.expPass { suite.Require().NoError(err) @@ -180,14 +187,27 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() { _, exists := suite.chainB.GetSimApp().ScopedIBCMockKeeper.GetCapability(suite.chainB.GetContext(), ibcmock.GetMockRecvCanaryCapabilityName(packet)) if tc.expRevert { suite.Require().False(exists, "capability exists in store even after callback reverted") + + // context events should contain error events + suite.Require().Contains(events, keeper.ConvertToErrorEvents(sdk.Events{ibcmock.NewMockRecvPacketEvent()})[0]) + suite.Require().NotContains(events, ibcmock.NewMockRecvPacketEvent()) } else { suite.Require().True(exists, "callback state not persisted when revert is false") + + if tc.replay { + // context should not contain application events + suite.Require().NotContains(events, ibcmock.NewMockRecvPacketEvent()) + suite.Require().NotContains(events, keeper.ConvertToErrorEvents(sdk.Events{ibcmock.NewMockRecvPacketEvent()})[0]) + } else { + // context events should contain application events + suite.Require().Contains(events, ibcmock.NewMockRecvPacketEvent()) + } } // verify if ack was written ack, found := suite.chainB.App.GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(suite.chainB.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - if async { + if tc.async { suite.Require().Nil(ack) suite.Require().False(found) @@ -202,6 +222,82 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() { } } +func (suite *KeeperTestSuite) TestRecoverClient() { + var msg *clienttypes.MsgRecoverClient + + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success: recover client", + func() {}, + nil, + }, + { + "signer doesn't match authority", + func() { + msg.Signer = ibctesting.InvalidID + }, + ibcerrors.ErrUnauthorized, + }, + { + "invalid subject client", + func() { + msg.SubjectClientId = ibctesting.InvalidID + }, + clienttypes.ErrClientNotFound, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + subjectPath := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupClients(subjectPath) + subject := subjectPath.EndpointA.ClientID + subjectClientState := suite.chainA.GetClientState(subject) + + substitutePath := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupClients(substitutePath) + substitute := substitutePath.EndpointA.ClientID + + // update substitute twice + err := substitutePath.EndpointA.UpdateClient() + suite.Require().NoError(err) + err = substitutePath.EndpointA.UpdateClient() + suite.Require().NoError(err) + + tmClientState, ok := subjectClientState.(*ibctm.ClientState) + suite.Require().True(ok) + tmClientState.FrozenHeight = tmClientState.LatestHeight + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) + + msg = clienttypes.NewMsgRecoverClient(suite.chainA.App.GetIBCKeeper().GetAuthority(), subject, substitute) + + tc.malleate() + + _, err = keeper.Keeper.RecoverClient(*suite.chainA.App.GetIBCKeeper(), suite.chainA.GetContext(), msg) + + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + + // Assert that client status is now Active + clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), subjectPath.EndpointA.ClientID) + tmClientState := subjectPath.EndpointA.GetClientState().(*ibctm.ClientState) + suite.Require().Equal(tmClientState.Status(suite.chainA.GetContext(), clientStore, suite.chainA.App.AppCodec()), exported.Active) + } else { + suite.Require().Error(err) + suite.Require().ErrorIs(err, tc.expErr) + } + }) + } +} + // tests the IBC handler acknowledgement of a packet on ordered and unordered // channels. It verifies that the deletion of packet commitments from state // occurs. It test high level properties like ordering and basic sanity @@ -217,6 +313,7 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() { name string malleate func() expPass bool + replay bool // indicate replay (no-op) }{ {"success: ORDERED", func() { path.SetChannelOrdered() @@ -228,7 +325,7 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() { packet = channeltypes.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) err = path.EndpointB.RecvPacket(packet) suite.Require().NoError(err) - }, true}, + }, true, false}, {"success: UNORDERED", func() { suite.coordinator.Setup(path) @@ -238,7 +335,7 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() { packet = channeltypes.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) err = path.EndpointB.RecvPacket(packet) suite.Require().NoError(err) - }, true}, + }, true, false}, {"success: UNORDERED acknowledge out of order packet", func() { // setup uses an UNORDERED channel suite.coordinator.Setup(path) @@ -252,7 +349,7 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() { err = path.EndpointB.RecvPacket(packet) suite.Require().NoError(err) } - }, true}, + }, true, false}, {"failure: ORDERED acknowledge out of order packet", func() { path.SetChannelOrdered() suite.coordinator.Setup(path) @@ -266,11 +363,11 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() { err = path.EndpointB.RecvPacket(packet) suite.Require().NoError(err) } - }, false}, + }, false, false}, {"channel does not exist", func() { // any non-nil value of packet is valid suite.Require().NotNil(packet) - }, false}, + }, false, false}, {"packet not received", func() { suite.coordinator.Setup(path) @@ -278,7 +375,7 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() { suite.Require().NoError(err) packet = channeltypes.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) - }, false}, + }, false, false}, {"successful no-op: ORDERED - packet already acknowledged (replay)", func() { suite.coordinator.Setup(path) @@ -291,7 +388,7 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() { err = path.EndpointA.AcknowledgePacket(packet, ibctesting.MockAcknowledgement) suite.Require().NoError(err) - }, true}, + }, true, true}, {"successful no-op: UNORDERED - packet already acknowledged (replay)", func() { suite.coordinator.Setup(path) @@ -304,7 +401,7 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() { err = path.EndpointA.AcknowledgePacket(packet, ibctesting.MockAcknowledgement) suite.Require().NoError(err) - }, true}, + }, true, true}, } for _, tc := range testCases { @@ -327,7 +424,10 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() { msg := channeltypes.NewMsgAcknowledgement(packet, ibcmock.MockAcknowledgement.Acknowledgement(), proof, proofHeight, suite.chainA.SenderAccount.GetAddress().String()) - _, err := keeper.Keeper.Acknowledgement(*suite.chainA.App.GetIBCKeeper(), suite.chainA.GetContext(), msg) + ctx := suite.chainA.GetContext() + _, err := keeper.Keeper.Acknowledgement(*suite.chainA.App.GetIBCKeeper(), ctx, msg) + + events := ctx.EventManager().Events() if tc.expPass { suite.Require().NoError(err) @@ -339,6 +439,14 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() { // replay should not error as it is treated as a no-op _, err := keeper.Keeper.Acknowledgement(*suite.chainA.App.GetIBCKeeper(), suite.chainA.GetContext(), msg) suite.Require().NoError(err) + + if tc.replay { + // context should not contain application events + suite.Require().NotContains(events, ibcmock.NewMockAckPacketEvent()) + } else { + // context events should contain application events + suite.Require().Contains(events, ibcmock.NewMockAckPacketEvent()) + } } else { suite.Require().Error(err) } @@ -362,6 +470,7 @@ func (suite *KeeperTestSuite) TestHandleTimeoutPacket() { name string malleate func() expPass bool + noop bool // indicate no-op }{ {"success: ORDERED", func() { path.SetChannelOrdered() @@ -380,7 +489,7 @@ func (suite *KeeperTestSuite) TestHandleTimeoutPacket() { packet = channeltypes.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) packetKey = host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel()) - }, true}, + }, true, false}, {"success: UNORDERED", func() { suite.coordinator.Setup(path) @@ -397,7 +506,7 @@ func (suite *KeeperTestSuite) TestHandleTimeoutPacket() { packet = channeltypes.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) packetKey = host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - }, true}, + }, true, false}, {"success: UNORDERED timeout out of order packet", func() { // setup uses an UNORDERED channel suite.coordinator.Setup(path) @@ -418,7 +527,7 @@ func (suite *KeeperTestSuite) TestHandleTimeoutPacket() { suite.Require().NoError(err) packetKey = host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - }, true}, + }, true, false}, {"success: ORDERED timeout out of order packet", func() { path.SetChannelOrdered() suite.coordinator.Setup(path) @@ -439,18 +548,19 @@ func (suite *KeeperTestSuite) TestHandleTimeoutPacket() { suite.Require().NoError(err) packetKey = host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel()) - }, true}, + }, true, false}, {"channel does not exist", func() { // any non-nil value of packet is valid suite.Require().NotNil(packet) packetKey = host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel()) - }, false}, + }, false, false}, {"successful no-op: UNORDERED - packet not sent", func() { suite.coordinator.Setup(path) + packet = channeltypes.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(0, 1), 0) packetKey = host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - }, true}, + }, true, true}, } for _, tc := range testCases { @@ -472,7 +582,10 @@ func (suite *KeeperTestSuite) TestHandleTimeoutPacket() { msg := channeltypes.NewMsgTimeout(packet, 1, proof, proofHeight, suite.chainA.SenderAccount.GetAddress().String()) - _, err := keeper.Keeper.Timeout(*suite.chainA.App.GetIBCKeeper(), suite.chainA.GetContext(), msg) + ctx := suite.chainA.GetContext() + _, err := keeper.Keeper.Timeout(*suite.chainA.App.GetIBCKeeper(), ctx, msg) + + events := ctx.EventManager().Events() if tc.expPass { suite.Require().NoError(err) @@ -485,6 +598,14 @@ func (suite *KeeperTestSuite) TestHandleTimeoutPacket() { has := suite.chainA.App.GetIBCKeeper().ChannelKeeper.HasPacketCommitment(suite.chainA.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) suite.Require().False(has) + if tc.noop { + // context should not contain application events + suite.Require().NotContains(events, ibcmock.NewMockTimeoutPacketEvent()) + } else { + // context should contain application events + suite.Require().Contains(events, ibcmock.NewMockTimeoutPacketEvent()) + } + } else { suite.Require().Error(err) } @@ -499,9 +620,10 @@ func (suite *KeeperTestSuite) TestHandleTimeoutPacket() { // 'TimeoutExecuted' can be found in the 04-channel/keeper/timeout_test.go. func (suite *KeeperTestSuite) TestHandleTimeoutOnClosePacket() { var ( - packet channeltypes.Packet - packetKey []byte - path *ibctesting.Path + packet channeltypes.Packet + packetKey []byte + path *ibctesting.Path + counterpartyUpgradeSequence uint64 ) testCases := []struct { @@ -636,9 +758,9 @@ func (suite *KeeperTestSuite) TestHandleTimeoutOnClosePacket() { proof, proofHeight := suite.chainB.QueryProof(packetKey) channelKey := host.ChannelKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - proofClosed, _ := suite.chainB.QueryProof(channelKey) + closedProof, _ := suite.chainB.QueryProof(channelKey) - msg := channeltypes.NewMsgTimeoutOnClose(packet, 1, proof, proofClosed, proofHeight, suite.chainA.SenderAccount.GetAddress().String()) + msg := channeltypes.NewMsgTimeoutOnCloseWithCounterpartyUpgradeSequence(packet, 1, proof, closedProof, proofHeight, suite.chainA.SenderAccount.GetAddress().String(), counterpartyUpgradeSequence) _, err := keeper.Keeper.TimeoutOnClose(*suite.chainA.App.GetIBCKeeper(), suite.chainA.GetContext(), msg) @@ -706,11 +828,11 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradeClient, _ := suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ := suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradeClientProof, _ := suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ := suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) msg, err = clienttypes.NewMsgUpgradeClient(path.EndpointA.ClientID, upgradedClient, upgradedConsState, - proofUpgradeClient, proofUpgradedConsState, suite.chainA.SenderAccount.GetAddress().String()) + upgradeClientProof, upgradedConsensusStateProof, suite.chainA.SenderAccount.GetAddress().String()) suite.Require().NoError(err) }, expPass: true, @@ -780,122 +902,1682 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { } } -func (suite *KeeperTestSuite) TestRecoverClient() { - var msg *clienttypes.MsgRecoverClient +func (suite *KeeperTestSuite) TestChannelUpgradeInit() { + var ( + path *ibctesting.Path + msg *channeltypes.MsgChannelUpgradeInit + ) - testCases := []struct { - name string - malleate func() - expErr error + cases := []struct { + name string + malleate func() + expResult func(res *channeltypes.MsgChannelUpgradeInitResponse, events []abci.Event, err error) }{ { - "success: recover client", - func() {}, - nil, + "success", + func() { + msg = channeltypes.NewMsgChannelUpgradeInit( + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + path.EndpointA.GetProposedUpgrade().Fields, + path.EndpointA.Chain.GetSimApp().IBCKeeper.GetAuthority(), + ) + }, + func(res *channeltypes.MsgChannelUpgradeInitResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(uint64(1), res.UpgradeSequence) + + upgrade := path.EndpointA.GetChannelUpgrade() + channel := path.EndpointA.GetChannel() + + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeInit: { + channeltypes.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyConnectionHops: upgrade.Fields.ConnectionHops[0], + channeltypes.AttributeVersion: upgrade.Fields.Version, + channeltypes.AttributeKeyOrdering: upgrade.Fields.Ordering.String(), + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: channeltypes.AttributeValueCategory, + }, + } + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + }, }, { - "signer doesn't match authority", + "authority is not signer of the upgrade init msg", func() { - msg.Signer = ibctesting.InvalidID + msg = channeltypes.NewMsgChannelUpgradeInit( + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + path.EndpointA.GetProposedUpgrade().Fields, + path.EndpointA.Chain.SenderAccount.String(), + ) + }, + func(res *channeltypes.MsgChannelUpgradeInitResponse, events []abci.Event, err error) { + suite.Require().Error(err) + suite.Require().ErrorContains(err, ibcerrors.ErrUnauthorized.Error()) + suite.Require().Nil(res) + + suite.Require().Empty(events) }, - ibcerrors.ErrUnauthorized, }, { - "invalid subject client", + "ibc application does not implement the UpgradeableModule interface", func() { - msg.SubjectClientId = ibctesting.InvalidID + path = ibctesting.NewPath(suite.chainA, suite.chainB) + path.EndpointA.ChannelConfig.PortID = ibcmock.MockBlockUpgrade + path.EndpointB.ChannelConfig.PortID = ibcmock.MockBlockUpgrade + + suite.coordinator.Setup(path) + + msg = channeltypes.NewMsgChannelUpgradeInit( + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + path.EndpointA.GetProposedUpgrade().Fields, + path.EndpointA.Chain.GetSimApp().IBCKeeper.GetAuthority(), + ) + }, + func(res *channeltypes.MsgChannelUpgradeInitResponse, events []abci.Event, err error) { + suite.Require().ErrorIs(err, porttypes.ErrInvalidRoute) + suite.Require().Nil(res) + + suite.Require().Empty(events) + }, + }, + { + "ibc application does not commit state changes in callback", + func() { + msg = channeltypes.NewMsgChannelUpgradeInit( + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + path.EndpointA.GetProposedUpgrade().Fields, + path.EndpointA.Chain.GetSimApp().IBCKeeper.GetAuthority(), + ) + + suite.chainA.GetSimApp().IBCMockModule.IBCApp.OnChanUpgradeInit = func(ctx sdk.Context, portID, channelID string, order channeltypes.Order, connectionHops []string, version string) (string, error) { + storeKey := suite.chainA.GetSimApp().GetKey(exported.ModuleName) + store := ctx.KVStore(storeKey) + store.Set(ibcmock.TestKey, ibcmock.TestValue) + + ctx.EventManager().EmitEvent(sdk.NewEvent(ibcmock.MockEventType)) + return ibcmock.UpgradeVersion, nil + } + }, + func(res *channeltypes.MsgChannelUpgradeInitResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(uint64(1), res.UpgradeSequence) + + storeKey := suite.chainA.GetSimApp().GetKey(exported.ModuleName) + store := suite.chainA.GetContext().KVStore(storeKey) + suite.Require().Nil(store.Get(ibcmock.TestKey)) + + for _, event := range events { + if event.GetType() == ibcmock.MockEventType { + suite.Fail("expected application callback events to be discarded") + } + } }, - clienttypes.ErrClientNotFound, }, } - for _, tc := range testCases { + for _, tc := range cases { tc := tc suite.Run(tc.name, func() { suite.SetupTest() - subjectPath := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.SetupClients(subjectPath) - subject := subjectPath.EndpointA.ClientID - subjectClientState := suite.chainA.GetClientState(subject) - - substitutePath := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.SetupClients(substitutePath) - substitute := substitutePath.EndpointA.ClientID - - // update substitute twice - err := substitutePath.EndpointA.UpdateClient() - suite.Require().NoError(err) - err = substitutePath.EndpointA.UpdateClient() - suite.Require().NoError(err) - - tmClientState, ok := subjectClientState.(*ibctm.ClientState) - suite.Require().True(ok) - tmClientState.FrozenHeight = tmClientState.LatestHeight - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) - msg = clienttypes.NewMsgRecoverClient(suite.chainA.App.GetIBCKeeper().GetAuthority(), subject, substitute) + // configure the channel upgrade version on testing endpoints + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion tc.malleate() - _, err = keeper.Keeper.RecoverClient(*suite.chainA.App.GetIBCKeeper(), suite.chainA.GetContext(), msg) - - expPass := tc.expErr == nil - if expPass { - suite.Require().NoError(err) + ctx := suite.chainA.GetContext() + res, err := suite.chainA.GetSimApp().GetIBCKeeper().ChannelUpgradeInit(ctx, msg) + events := ctx.EventManager().Events().ToABCIEvents() - // Assert that client status is now Active - clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), subjectPath.EndpointA.ClientID) - tmClientState := subjectPath.EndpointA.GetClientState().(*ibctm.ClientState) - suite.Require().Equal(tmClientState.Status(suite.chainA.GetContext(), clientStore, suite.chainA.App.AppCodec()), exported.Active) - } else { - suite.Require().Error(err) - suite.Require().ErrorIs(err, tc.expErr) - } + tc.expResult(res, events, err) }) } } -// TestIBCSoftwareUpgrade tests the IBCSoftwareUpgrade rpc handler -func (suite *KeeperTestSuite) TestIBCSoftwareUpgrade() { - var msg *clienttypes.MsgIBCSoftwareUpgrade - testCases := []struct { - name string - malleate func() - expError error +func (suite *KeeperTestSuite) TestChannelUpgradeTry() { + var ( + path *ibctesting.Path + msg *channeltypes.MsgChannelUpgradeTry + ) + + cases := []struct { + name string + malleate func() + expResult func(res *channeltypes.MsgChannelUpgradeTryResponse, events []abci.Event, err error) }{ { - "success: valid authority and client upgrade", + "success", func() {}, - nil, + func(res *channeltypes.MsgChannelUpgradeTryResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(channeltypes.SUCCESS, res.Result) + + channel := path.EndpointB.GetChannel() + suite.Require().Equal(channeltypes.FLUSHING, channel.State) + suite.Require().Equal(uint64(1), channel.UpgradeSequence) + + upgrade := path.EndpointB.GetChannelUpgrade() + + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeTry: { + channeltypes.AttributeKeyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeKeyConnectionHops: upgrade.Fields.ConnectionHops[0], + channeltypes.AttributeVersion: upgrade.Fields.Version, + channeltypes.AttributeKeyOrdering: upgrade.Fields.Ordering.String(), + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: channeltypes.AttributeValueCategory, + }, + } + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + }, }, { - "failure: invalid authority address", + "module capability not found", func() { - msg.Signer = suite.chainA.SenderAccount.GetAddress().String() + msg.PortId = "invalid-port" + msg.ChannelId = "invalid-channel" + }, + func(res *channeltypes.MsgChannelUpgradeTryResponse, events []abci.Event, err error) { + suite.Require().Error(err) + suite.Require().Nil(res) + + suite.Require().ErrorIs(err, capabilitytypes.ErrCapabilityNotFound) + suite.Require().Empty(events) }, - ibcerrors.ErrUnauthorized, }, { - "failure: invalid clientState", + "unsynchronized upgrade sequence writes upgrade error receipt", func() { - msg.UpgradedClientState = nil + channel := path.EndpointB.GetChannel() + channel.UpgradeSequence = 99 + + path.EndpointB.SetChannel(channel) + }, + func(res *channeltypes.MsgChannelUpgradeTryResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + + suite.Require().NotNil(res) + suite.Require().Equal(channeltypes.FAILURE, res.Result) + + errorReceipt, found := suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetUpgradeErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().True(found) + suite.Require().Equal(uint64(99), errorReceipt.Sequence) + + channel := path.EndpointB.GetChannel() + + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeError: { + channeltypes.AttributeKeyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + // need to manually insert this because the errorReceipt is a string constant as it is written into state + channeltypes.AttributeKeyErrorReceipt: "counterparty upgrade sequence < current upgrade sequence (1 < 99): invalid upgrade sequence", + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: channeltypes.AttributeValueCategory, + }, + } + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) }, - clienttypes.ErrInvalidClientType, }, { - "failure: failed to schedule client upgrade", + "ibc application does not implement the UpgradeableModule interface", func() { - msg.Plan.Height = 0 + path = ibctesting.NewPath(suite.chainA, suite.chainB) + path.EndpointA.ChannelConfig.PortID = ibcmock.MockBlockUpgrade + path.EndpointB.ChannelConfig.PortID = ibcmock.MockBlockUpgrade + + suite.coordinator.Setup(path) + + msg.PortId = path.EndpointB.ChannelConfig.PortID + msg.ChannelId = path.EndpointB.ChannelID + }, + func(res *channeltypes.MsgChannelUpgradeTryResponse, events []abci.Event, err error) { + suite.Require().ErrorIs(err, porttypes.ErrInvalidRoute) + suite.Require().Nil(res) + + suite.Require().Empty(events) }, - sdkerrors.ErrInvalidRequest, }, - } + { + "ibc application does not commit state changes in callback", + func() { + suite.chainA.GetSimApp().IBCMockModule.IBCApp.OnChanUpgradeTry = func(ctx sdk.Context, portID, channelID string, order channeltypes.Order, connectionHops []string, counterpartyVersion string) (string, error) { + storeKey := suite.chainA.GetSimApp().GetKey(exported.ModuleName) + store := ctx.KVStore(storeKey) + store.Set(ibcmock.TestKey, ibcmock.TestValue) - for _, tc := range testCases { - tc := tc - suite.Run(tc.name, func() { - path := ibctesting.NewPath(suite.chainA, suite.chainB) + ctx.EventManager().EmitEvent(sdk.NewEvent(ibcmock.MockEventType)) + return ibcmock.UpgradeVersion, nil + } + }, + func(res *channeltypes.MsgChannelUpgradeTryResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(uint64(1), res.UpgradeSequence) + + storeKey := suite.chainA.GetSimApp().GetKey(exported.ModuleName) + store := suite.chainA.GetContext().KVStore(storeKey) + suite.Require().Nil(store.Get(ibcmock.TestKey)) + + for _, event := range events { + if event.GetType() == ibcmock.MockEventType { + suite.Fail("expected application callback events to be discarded") + } + } + }, + }, + } + + for _, tc := range cases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + // configure the channel upgrade version on testing endpoints + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.UpdateClient() + suite.Require().NoError(err) + + counterpartySequence := path.EndpointA.GetChannel().UpgradeSequence + counterpartyUpgrade, found := suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.GetUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + + channelProof, upgradeProof, proofHeight := path.EndpointA.QueryChannelUpgradeProof() + + msg = &channeltypes.MsgChannelUpgradeTry{ + PortId: path.EndpointB.ChannelConfig.PortID, + ChannelId: path.EndpointB.ChannelID, + ProposedUpgradeConnectionHops: []string{ibctesting.FirstConnectionID}, + CounterpartyUpgradeSequence: counterpartySequence, + CounterpartyUpgradeFields: counterpartyUpgrade.Fields, + ProofChannel: channelProof, + ProofUpgrade: upgradeProof, + ProofHeight: proofHeight, + Signer: suite.chainB.SenderAccount.GetAddress().String(), + } + + tc.malleate() + + ctx := suite.chainB.GetContext() + res, err := suite.chainB.GetSimApp().GetIBCKeeper().ChannelUpgradeTry(ctx, msg) + events := ctx.EventManager().Events().ToABCIEvents() + + tc.expResult(res, events, err) + }) + } +} + +func (suite *KeeperTestSuite) TestChannelUpgradeAck() { + var ( + path *ibctesting.Path + msg *channeltypes.MsgChannelUpgradeAck + ) + + cases := []struct { + name string + malleate func() + expResult func(res *channeltypes.MsgChannelUpgradeAckResponse, events []abci.Event, err error) + }{ + { + "success, no pending in-flight packets", + func() {}, + func(res *channeltypes.MsgChannelUpgradeAckResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(channeltypes.SUCCESS, res.Result) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(channeltypes.FLUSHCOMPLETE, channel.State) + suite.Require().Equal(uint64(1), channel.UpgradeSequence) + + upgrade := path.EndpointA.GetChannelUpgrade() + + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeAck: { + channeltypes.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyConnectionHops: upgrade.Fields.ConnectionHops[0], + channeltypes.AttributeVersion: upgrade.Fields.Version, + channeltypes.AttributeKeyOrdering: upgrade.Fields.Ordering.String(), + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: channeltypes.AttributeValueCategory, + }, + } + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + }, + }, + { + "success, pending in-flight packets", + func() { + portID := path.EndpointA.ChannelConfig.PortID + channelID := path.EndpointA.ChannelID + // Set a dummy packet commitment to simulate in-flight packets + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainA.GetContext(), portID, channelID, 1, []byte("hash")) + }, + func(res *channeltypes.MsgChannelUpgradeAckResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(channeltypes.SUCCESS, res.Result) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(channeltypes.FLUSHING, channel.State) + suite.Require().Equal(uint64(1), channel.UpgradeSequence) + + upgrade := path.EndpointA.GetChannelUpgrade() + + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeAck: { + channeltypes.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyConnectionHops: upgrade.Fields.ConnectionHops[0], + channeltypes.AttributeVersion: upgrade.Fields.Version, + channeltypes.AttributeKeyOrdering: upgrade.Fields.Ordering.String(), + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: channeltypes.AttributeValueCategory, + }, + } + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + }, + }, + { + "module capability not found", + func() { + msg.PortId = ibctesting.InvalidID + msg.ChannelId = ibctesting.InvalidID + }, + func(res *channeltypes.MsgChannelUpgradeAckResponse, events []abci.Event, err error) { + suite.Require().Error(err) + suite.Require().Nil(res) + + suite.Require().ErrorIs(err, capabilitytypes.ErrCapabilityNotFound) + suite.Require().Empty(events) + }, + }, + { + "core handler returns error and no upgrade error receipt is written", + func() { + // force an error by overriding the channel state to an invalid value + channel := path.EndpointA.GetChannel() + channel.State = channeltypes.CLOSED + + path.EndpointA.SetChannel(channel) + }, + func(res *channeltypes.MsgChannelUpgradeAckResponse, events []abci.Event, err error) { + suite.Require().Error(err) + suite.Require().Nil(res) + suite.Require().ErrorIs(err, channeltypes.ErrInvalidChannelState) + + errorReceipt, found := suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.GetUpgradeErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().Empty(errorReceipt) + suite.Require().False(found) + + suite.Require().Empty(events) + }, + }, + { + "core handler returns error and writes upgrade error receipt", + func() { + // force an upgrade error by modifying the channel upgrade ordering to an incompatible value + upgrade := path.EndpointA.GetChannelUpgrade() + upgrade.Fields.Ordering = channeltypes.NONE + + path.EndpointA.SetChannelUpgrade(upgrade) + }, + func(res *channeltypes.MsgChannelUpgradeAckResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + + suite.Require().NotNil(res) + suite.Require().Equal(channeltypes.FAILURE, res.Result) + + errorReceipt, found := suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.GetUpgradeErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(uint64(1), errorReceipt.Sequence) + + channel := path.EndpointB.GetChannel() + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeError: { + channeltypes.AttributeKeyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + // need to manually insert this because the errorReceipt is a string constant as it is written into state + channeltypes.AttributeKeyErrorReceipt: "expected upgrade ordering (ORDER_NONE_UNSPECIFIED) to match counterparty upgrade ordering (ORDER_UNORDERED): incompatible counterparty upgrade", + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: channeltypes.AttributeValueCategory, + }, + } + + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + }, + }, + { + "application callback returns error and error receipt is written", + func() { + suite.chainA.GetSimApp().IBCMockModule.IBCApp.OnChanUpgradeAck = func( + ctx sdk.Context, portID, channelID, counterpartyVersion string, + ) error { + // set arbitrary value in store to mock application state changes + store := ctx.KVStore(suite.chainA.GetSimApp().GetKey(exported.ModuleName)) + store.Set([]byte("foo"), []byte("bar")) + return fmt.Errorf("mock app callback failed") + } + }, + func(res *channeltypes.MsgChannelUpgradeAckResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + + suite.Require().NotNil(res) + suite.Require().Equal(channeltypes.FAILURE, res.Result) + + errorReceipt, found := suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.GetUpgradeErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(uint64(1), errorReceipt.Sequence) + + // assert application state changes are not committed + store := suite.chainA.GetContext().KVStore(suite.chainA.GetSimApp().GetKey(exported.ModuleName)) + suite.Require().False(store.Has([]byte("foo"))) + + channel := path.EndpointB.GetChannel() + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeError: { + channeltypes.AttributeKeyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + // need to manually insert this because the errorReceipt is a string constant as it is written into state + channeltypes.AttributeKeyErrorReceipt: "mock app callback failed", + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: channeltypes.AttributeValueCategory, + }, + } + + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + }, + }, + { + "ibc application does not implement the UpgradeableModule interface", + func() { + path = ibctesting.NewPath(suite.chainA, suite.chainB) + path.EndpointA.ChannelConfig.PortID = ibcmock.MockBlockUpgrade + path.EndpointB.ChannelConfig.PortID = ibcmock.MockBlockUpgrade + + suite.coordinator.Setup(path) + + msg.PortId = path.EndpointB.ChannelConfig.PortID + msg.ChannelId = path.EndpointB.ChannelID + }, + func(res *channeltypes.MsgChannelUpgradeAckResponse, events []abci.Event, err error) { + suite.Require().ErrorIs(err, porttypes.ErrInvalidRoute) + suite.Require().Nil(res) + suite.Require().Empty(events) + }, + }, + { + "application callback returns an upgrade error", + func() { + suite.chainA.GetSimApp().IBCMockModule.IBCApp.OnChanUpgradeAck = func(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { + return channeltypes.NewUpgradeError(10000000, ibcmock.MockApplicationCallbackError) + } + }, + func(res *channeltypes.MsgChannelUpgradeAckResponse, events []abci.Event, err error) { + suite.Require().Equal(channeltypes.FAILURE, res.Result) + suite.Require().Equal(uint64(1), path.EndpointA.GetChannel().UpgradeSequence, "application callback upgrade sequence should not be used") + }, + }, + { + "ibc application does not commit state changes in callback", + func() { + suite.chainA.GetSimApp().IBCMockModule.IBCApp.OnChanUpgradeAck = func(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { + storeKey := suite.chainA.GetSimApp().GetKey(exported.ModuleName) + store := ctx.KVStore(storeKey) + store.Set(ibcmock.TestKey, ibcmock.TestValue) + + ctx.EventManager().EmitEvent(sdk.NewEvent(ibcmock.MockEventType)) + return nil + } + }, + func(res *channeltypes.MsgChannelUpgradeAckResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + suite.Require().NotNil(res) + + storeKey := suite.chainA.GetSimApp().GetKey(exported.ModuleName) + store := suite.chainA.GetContext().KVStore(storeKey) + suite.Require().Nil(store.Get(ibcmock.TestKey)) + + for _, event := range events { + if event.GetType() == ibcmock.MockEventType { + suite.Fail("expected application callback events to be discarded") + } + } + }, + }, + } + + for _, tc := range cases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + // configure the channel upgrade version on testing endpoints + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + counterpartyUpgrade := path.EndpointB.GetChannelUpgrade() + + channelProof, upgradeProof, proofHeight := path.EndpointB.QueryChannelUpgradeProof() + + msg = &channeltypes.MsgChannelUpgradeAck{ + PortId: path.EndpointA.ChannelConfig.PortID, + ChannelId: path.EndpointA.ChannelID, + CounterpartyUpgrade: counterpartyUpgrade, + ProofChannel: channelProof, + ProofUpgrade: upgradeProof, + ProofHeight: proofHeight, + Signer: suite.chainA.SenderAccount.GetAddress().String(), + } + + tc.malleate() + + ctx := suite.chainA.GetContext() + res, err := suite.chainA.GetSimApp().GetIBCKeeper().ChannelUpgradeAck(ctx, msg) + events := ctx.EventManager().Events().ToABCIEvents() + + tc.expResult(res, events, err) + }) + } +} + +func (suite *KeeperTestSuite) TestChannelUpgradeConfirm() { + var ( + path *ibctesting.Path + msg *channeltypes.MsgChannelUpgradeConfirm + ) + + cases := []struct { + name string + malleate func() + expResult func(res *channeltypes.MsgChannelUpgradeConfirmResponse, events []abci.Event, err error) + }{ + { + "success, no pending in-flight packets", + func() {}, + func(res *channeltypes.MsgChannelUpgradeConfirmResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(channeltypes.SUCCESS, res.Result) + + channel := path.EndpointB.GetChannel() + suite.Require().Equal(channeltypes.OPEN, channel.State) + suite.Require().Equal(uint64(1), channel.UpgradeSequence) + + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeConfirm: { + channeltypes.AttributeKeyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyChannelState: channeltypes.FLUSHCOMPLETE.String(), + channeltypes.AttributeCounterpartyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + }, + channeltypes.EventTypeChannelUpgradeOpen: { + channeltypes.AttributeKeyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeKeyChannelState: channeltypes.OPEN.String(), + channeltypes.AttributeKeyConnectionHops: channel.ConnectionHops[0], + channeltypes.AttributeVersion: channel.Version, + channeltypes.AttributeKeyOrdering: channel.Ordering.String(), + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: channeltypes.AttributeValueCategory, + }, + } + + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + }, + }, + { + "success, pending in-flight packets on init chain", + func() { + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + seq, err := path.EndpointA.SendPacket(path.EndpointB.Chain.GetTimeoutHeight(), 0, ibctesting.MockPacketData) + suite.Require().Equal(uint64(1), seq) + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeAck() + suite.Require().NoError(err) + + err = path.EndpointB.UpdateClient() + suite.Require().NoError(err) + + counterpartyChannelState := path.EndpointA.GetChannel().State + counterpartyUpgrade := path.EndpointA.GetChannelUpgrade() + + channelProof, upgradeProof, proofHeight := path.EndpointA.QueryChannelUpgradeProof() + + msg = &channeltypes.MsgChannelUpgradeConfirm{ + PortId: path.EndpointB.ChannelConfig.PortID, + ChannelId: path.EndpointB.ChannelID, + CounterpartyChannelState: counterpartyChannelState, + CounterpartyUpgrade: counterpartyUpgrade, + ProofChannel: channelProof, + ProofUpgrade: upgradeProof, + ProofHeight: proofHeight, + Signer: suite.chainA.SenderAccount.GetAddress().String(), + } + }, + func(res *channeltypes.MsgChannelUpgradeConfirmResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(channeltypes.SUCCESS, res.Result) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(channeltypes.FLUSHING, channel.State) + suite.Require().Equal(uint64(1), channel.UpgradeSequence) + + channel = path.EndpointB.GetChannel() + suite.Require().Equal(channeltypes.FLUSHCOMPLETE, channel.State) + suite.Require().Equal(uint64(1), channel.UpgradeSequence) + + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeConfirm: { + channeltypes.AttributeKeyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyChannelState: channeltypes.FLUSHCOMPLETE.String(), + channeltypes.AttributeCounterpartyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + }, + } + + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + }, + }, + { + "success, pending in-flight packets on try chain", + func() { + portID, channelID := path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID + suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), portID, channelID, 1, []byte("hash")) + }, + func(res *channeltypes.MsgChannelUpgradeConfirmResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(channeltypes.SUCCESS, res.Result) + + channel := path.EndpointB.GetChannel() + suite.Require().Equal(channeltypes.FLUSHING, channel.State) + suite.Require().Equal(uint64(1), channel.UpgradeSequence) + + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeConfirm: { + channeltypes.AttributeKeyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyChannelState: channeltypes.FLUSHING.String(), + channeltypes.AttributeCounterpartyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + }, + } + + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + }, + }, + { + "module capability not found", + func() { + msg.PortId = ibctesting.InvalidID + msg.ChannelId = ibctesting.InvalidID + }, + func(res *channeltypes.MsgChannelUpgradeConfirmResponse, events []abci.Event, err error) { + suite.Require().Error(err) + suite.Require().Nil(res) + + suite.Require().ErrorIs(err, capabilitytypes.ErrCapabilityNotFound) + suite.Require().Empty(events) + }, + }, + { + "core handler returns error and no upgrade error receipt is written", + func() { + // force an error by overriding the channel state to an invalid value + channel := path.EndpointB.GetChannel() + channel.State = channeltypes.CLOSED + + path.EndpointB.SetChannel(channel) + }, + func(res *channeltypes.MsgChannelUpgradeConfirmResponse, events []abci.Event, err error) { + suite.Require().Error(err) + suite.Require().Nil(res) + suite.Require().ErrorIs(err, channeltypes.ErrInvalidChannelState) + + errorReceipt, found := suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetUpgradeErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().Empty(errorReceipt) + suite.Require().False(found) + + suite.Require().Empty(events) + }, + }, + { + "core handler returns error and writes upgrade error receipt", + func() { + // force an upgrade error by modifying the counterparty channel upgrade timeout to be elapsed + upgrade := path.EndpointA.GetChannelUpgrade() + upgrade.Timeout = channeltypes.NewTimeout(clienttypes.ZeroHeight(), uint64(path.EndpointB.Chain.CurrentHeader.Time.UnixNano())) + + path.EndpointA.SetChannelUpgrade(upgrade) + + suite.coordinator.CommitBlock(suite.chainA) + + err := path.EndpointB.UpdateClient() + suite.Require().NoError(err) + + channelProof, upgradeProof, proofHeight := path.EndpointA.QueryChannelUpgradeProof() + + msg.CounterpartyUpgrade = upgrade + msg.ProofChannel = channelProof + msg.ProofUpgrade = upgradeProof + msg.ProofHeight = proofHeight + }, + func(res *channeltypes.MsgChannelUpgradeConfirmResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + + suite.Require().NotNil(res) + suite.Require().Equal(channeltypes.FAILURE, res.Result) + + errorReceipt, found := suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetUpgradeErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().True(found) + suite.Require().Equal(uint64(1), errorReceipt.Sequence) + + channel := path.EndpointB.GetChannel() + + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeError: { + channeltypes.AttributeKeyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + // need to manually insert this because the errorReceipt is a string constant as it is written into state + channeltypes.AttributeKeyErrorReceipt: "counterparty upgrade timeout elapsed: current timestamp: 1578269010000000000, timeout timestamp 1578268995000000000: timeout elapsed", + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: channeltypes.AttributeValueCategory, + }, + } + + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + }, + }, + { + "ibc application does not implement the UpgradeableModule interface", + func() { + path = ibctesting.NewPath(suite.chainA, suite.chainB) + path.EndpointA.ChannelConfig.PortID = ibcmock.MockBlockUpgrade + path.EndpointB.ChannelConfig.PortID = ibcmock.MockBlockUpgrade + + suite.coordinator.Setup(path) + + msg.PortId = path.EndpointB.ChannelConfig.PortID + msg.ChannelId = path.EndpointB.ChannelID + }, + func(res *channeltypes.MsgChannelUpgradeConfirmResponse, events []abci.Event, err error) { + suite.Require().ErrorIs(err, porttypes.ErrInvalidRoute) + suite.Require().Nil(res) + + suite.Require().Empty(events) + }, + }, + } + + for _, tc := range cases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + // configure the channel upgrade version on testing endpoints + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeAck() + suite.Require().NoError(err) + + err = path.EndpointB.UpdateClient() + suite.Require().NoError(err) + + counterpartyChannelState := path.EndpointA.GetChannel().State + counterpartyUpgrade := path.EndpointA.GetChannelUpgrade() + + channelProof, upgradeProof, proofHeight := path.EndpointA.QueryChannelUpgradeProof() + + msg = &channeltypes.MsgChannelUpgradeConfirm{ + PortId: path.EndpointB.ChannelConfig.PortID, + ChannelId: path.EndpointB.ChannelID, + CounterpartyChannelState: counterpartyChannelState, + CounterpartyUpgrade: counterpartyUpgrade, + ProofChannel: channelProof, + ProofUpgrade: upgradeProof, + ProofHeight: proofHeight, + Signer: suite.chainA.SenderAccount.GetAddress().String(), + } + + tc.malleate() + + ctx := suite.chainB.GetContext() + res, err := suite.chainB.GetSimApp().GetIBCKeeper().ChannelUpgradeConfirm(ctx, msg) + events := ctx.EventManager().Events().ToABCIEvents() + + tc.expResult(res, events, err) + }) + } +} + +func (suite *KeeperTestSuite) TestChannelUpgradeOpen() { + var ( + path *ibctesting.Path + msg *channeltypes.MsgChannelUpgradeOpen + ) + + cases := []struct { + name string + malleate func() + expResult func(res *channeltypes.MsgChannelUpgradeOpenResponse, events []abci.Event, err error) + }{ + { + "success", + func() {}, + func(res *channeltypes.MsgChannelUpgradeOpenResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + suite.Require().NotNil(res) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(channeltypes.OPEN, channel.State) + + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeOpen: { + channeltypes.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyChannelState: channeltypes.OPEN.String(), + channeltypes.AttributeKeyConnectionHops: channel.ConnectionHops[0], + channeltypes.AttributeVersion: channel.Version, + channeltypes.AttributeKeyOrdering: channel.Ordering.String(), + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: channeltypes.AttributeValueCategory, + }, + } + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + }, + }, + { + "success with counterparty at greater upgrade sequence", + func() { + // create reason to upgrade + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + "additional upgrade" + + err := path.EndpointB.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + counterpartyChannel := path.EndpointB.GetChannel() + channelKey := host.ChannelKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + channelProof, proofHeight := path.EndpointB.QueryProof(channelKey) + + msg.ProofChannel = channelProof + msg.ProofHeight = proofHeight + msg.CounterpartyUpgradeSequence = counterpartyChannel.UpgradeSequence + }, + func(res *channeltypes.MsgChannelUpgradeOpenResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + suite.Require().NotNil(res) + + channel := path.EndpointA.GetChannel() + suite.Require().Equal(channeltypes.OPEN, channel.State) + + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeOpen: { + channeltypes.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyChannelState: channeltypes.OPEN.String(), + channeltypes.AttributeKeyConnectionHops: channel.ConnectionHops[0], + channeltypes.AttributeVersion: channel.Version, + channeltypes.AttributeKeyOrdering: channel.Ordering.String(), + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: channeltypes.AttributeValueCategory, + }, + } + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + }, + }, + { + "module capability not found", + func() { + msg.PortId = ibctesting.InvalidID + msg.ChannelId = ibctesting.InvalidID + }, + func(res *channeltypes.MsgChannelUpgradeOpenResponse, events []abci.Event, err error) { + suite.Require().Error(err) + suite.Require().Nil(res) + + suite.Require().ErrorIs(err, capabilitytypes.ErrCapabilityNotFound) + suite.Require().Empty(events) + }, + }, + { + "core handler fails", + func() { + channel := path.EndpointA.GetChannel() + channel.State = channeltypes.FLUSHING + path.EndpointA.SetChannel(channel) + }, + func(res *channeltypes.MsgChannelUpgradeOpenResponse, events []abci.Event, err error) { + suite.Require().Error(err) + suite.Require().Nil(res) + + suite.Require().ErrorIs(err, channeltypes.ErrInvalidChannelState) + suite.Require().Empty(events) + }, + }, + { + "ibc application does not implement the UpgradeableModule interface", + func() { + path = ibctesting.NewPath(suite.chainA, suite.chainB) + path.EndpointA.ChannelConfig.PortID = ibcmock.MockBlockUpgrade + path.EndpointB.ChannelConfig.PortID = ibcmock.MockBlockUpgrade + + suite.coordinator.Setup(path) + + msg.PortId = path.EndpointB.ChannelConfig.PortID + msg.ChannelId = path.EndpointB.ChannelID + }, + func(res *channeltypes.MsgChannelUpgradeOpenResponse, events []abci.Event, err error) { + suite.Require().ErrorIs(err, porttypes.ErrInvalidRoute) + suite.Require().Nil(res) + + suite.Require().Empty(events) + }, + }, + } + + for _, tc := range cases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + // configure the channel upgrade version on testing endpoints + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeAck() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeConfirm() + suite.Require().NoError(err) + + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + counterpartyChannel := path.EndpointB.GetChannel() + channelKey := host.ChannelKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + channelProof, proofHeight := path.EndpointB.QueryProof(channelKey) + + msg = &channeltypes.MsgChannelUpgradeOpen{ + PortId: path.EndpointA.ChannelConfig.PortID, + ChannelId: path.EndpointA.ChannelID, + CounterpartyChannelState: counterpartyChannel.State, + CounterpartyUpgradeSequence: counterpartyChannel.UpgradeSequence, + ProofChannel: channelProof, + ProofHeight: proofHeight, + Signer: suite.chainA.SenderAccount.GetAddress().String(), + } + + tc.malleate() + + ctx := suite.chainA.GetContext() + res, err := suite.chainA.GetSimApp().GetIBCKeeper().ChannelUpgradeOpen(ctx, msg) + events := ctx.EventManager().Events().ToABCIEvents() + + tc.expResult(res, events, err) + }) + } +} + +func (suite *KeeperTestSuite) TestChannelUpgradeCancel() { + var ( + path *ibctesting.Path + msg *channeltypes.MsgChannelUpgradeCancel + ) + + cases := []struct { + name string + malleate func() + expResult func(res *channeltypes.MsgChannelUpgradeCancelResponse, events []abci.Event, err error) + }{ + { + "success: keeper is not authority, valid error receipt so channnel changed to match error receipt seq", + func() {}, + func(res *channeltypes.MsgChannelUpgradeCancelResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + suite.Require().NotNil(res) + + channel := path.EndpointA.GetChannel() + // Channel state should be reverted back to open. + suite.Require().Equal(channeltypes.OPEN, channel.State) + // Upgrade sequence should be changed to match sequence on error receipt. + suite.Require().Equal(uint64(2), channel.UpgradeSequence) + + // we need to find the event values from the proposed upgrade as the actual upgrade has been deleted. + proposedUpgrade := path.EndpointA.GetProposedUpgrade() + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeCancel: { + channeltypes.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyConnectionHops: proposedUpgrade.Fields.ConnectionHops[0], + channeltypes.AttributeVersion: proposedUpgrade.Fields.Version, + channeltypes.AttributeKeyOrdering: proposedUpgrade.Fields.Ordering.String(), + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + }, + channeltypes.EventTypeChannelUpgradeError: { + channeltypes.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + // need to manually insert this because the errorReceipt is a string constant as it is written into state + channeltypes.AttributeKeyErrorReceipt: "invalid upgrade", + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: channeltypes.AttributeValueCategory, + }, + } + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + }, + }, + { + "success: keeper is authority & channel state in FLUSHING, so error receipt is ignored and channel is restored to initial upgrade sequence", + func() { + msg.Signer = suite.chainA.App.GetIBCKeeper().GetAuthority() + + channel := path.EndpointA.GetChannel() + channel.State = channeltypes.FLUSHING + channel.UpgradeSequence = uint64(3) + path.EndpointA.SetChannel(channel) + }, + func(res *channeltypes.MsgChannelUpgradeCancelResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + suite.Require().NotNil(res) + + channel := path.EndpointA.GetChannel() + // Channel state should be reverted back to open. + suite.Require().Equal(channeltypes.OPEN, channel.State) + // Upgrade sequence should be changed to match initial upgrade sequence. + suite.Require().Equal(uint64(3), channel.UpgradeSequence) + + // we need to find the event values from the proposed upgrade as the actual upgrade has been deleted. + proposedUpgrade := path.EndpointA.GetProposedUpgrade() + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeCancel: { + channeltypes.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyConnectionHops: proposedUpgrade.Fields.ConnectionHops[0], + channeltypes.AttributeVersion: proposedUpgrade.Fields.Version, + channeltypes.AttributeKeyOrdering: proposedUpgrade.Fields.Ordering.String(), + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + }, + channeltypes.EventTypeChannelUpgradeError: { + channeltypes.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + // need to manually insert this because the errorReceipt is a string constant as it is written into state + channeltypes.AttributeKeyErrorReceipt: "invalid upgrade", + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: channeltypes.AttributeValueCategory, + }, + } + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + }, + }, + { + "success: keeper is authority & channel state in FLUSHING, can be cancelled even with invalid error receipt", + func() { + msg.Signer = suite.chainA.App.GetIBCKeeper().GetAuthority() + msg.ProofErrorReceipt = []byte("invalid proof") + + channel := path.EndpointA.GetChannel() + channel.State = channeltypes.FLUSHING + channel.UpgradeSequence = uint64(1) + path.EndpointA.SetChannel(channel) + }, + func(res *channeltypes.MsgChannelUpgradeCancelResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + suite.Require().NotNil(res) + + channel := path.EndpointA.GetChannel() + // Channel state should be reverted back to open. + suite.Require().Equal(channeltypes.OPEN, channel.State) + // Upgrade sequence should be changed to match initial upgrade sequence. + suite.Require().Equal(uint64(1), channel.UpgradeSequence) + + // we need to find the event values from the proposed upgrade as the actual upgrade has been deleted. + proposedUpgrade := path.EndpointA.GetProposedUpgrade() + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeCancel: { + channeltypes.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyConnectionHops: proposedUpgrade.Fields.ConnectionHops[0], + channeltypes.AttributeVersion: proposedUpgrade.Fields.Version, + channeltypes.AttributeKeyOrdering: proposedUpgrade.Fields.Ordering.String(), + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + }, + channeltypes.EventTypeChannelUpgradeError: { + channeltypes.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + // need to manually insert this because the errorReceipt is a string constant as it is written into state + channeltypes.AttributeKeyErrorReceipt: "invalid upgrade", + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: channeltypes.AttributeValueCategory, + }, + } + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + }, + }, + { + "success: keeper is authority & channel state in FLUSHING, can be cancelled even with empty error receipt", + func() { + msg.Signer = suite.chainA.App.GetIBCKeeper().GetAuthority() + msg.ProofErrorReceipt = nil + + channel := path.EndpointA.GetChannel() + channel.State = channeltypes.FLUSHING + channel.UpgradeSequence = uint64(1) + path.EndpointA.SetChannel(channel) + }, + func(res *channeltypes.MsgChannelUpgradeCancelResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + suite.Require().NotNil(res) + + channel := path.EndpointA.GetChannel() + // Channel state should be reverted back to open. + suite.Require().Equal(channeltypes.OPEN, channel.State) + // Upgrade sequence should be changed to match initial upgrade sequence. + suite.Require().Equal(uint64(1), channel.UpgradeSequence) + + // we need to find the event values from the proposed upgrade as the actual upgrade has been deleted. + proposedUpgrade := path.EndpointA.GetProposedUpgrade() + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeCancel: { + channeltypes.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyConnectionHops: proposedUpgrade.Fields.ConnectionHops[0], + channeltypes.AttributeVersion: proposedUpgrade.Fields.Version, + channeltypes.AttributeKeyOrdering: proposedUpgrade.Fields.Ordering.String(), + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + }, + channeltypes.EventTypeChannelUpgradeError: { + channeltypes.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + // need to manually insert this because the errorReceipt is a string constant as it is written into state + channeltypes.AttributeKeyErrorReceipt: "invalid upgrade", + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: channeltypes.AttributeValueCategory, + }, + } + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + }, + }, + { + "success: keeper is authority but channel state in FLUSHCOMPLETE, requires valid error receipt", + func() { + msg.Signer = suite.chainA.App.GetIBCKeeper().GetAuthority() + + channel := path.EndpointA.GetChannel() + channel.State = channeltypes.FLUSHCOMPLETE + channel.UpgradeSequence = uint64(2) // When in FLUSHCOMPLETE the sequence of the error receipt and the channel must match + path.EndpointA.SetChannel(channel) + }, + func(res *channeltypes.MsgChannelUpgradeCancelResponse, events []abci.Event, err error) { + suite.Require().NoError(err) + suite.Require().NotNil(res) + + channel := path.EndpointA.GetChannel() + // Channel state should be reverted back to open. + suite.Require().Equal(channeltypes.OPEN, channel.State) + // Upgrade sequence should not be changed. + suite.Require().Equal(uint64(2), channel.UpgradeSequence) + + // we need to find the event values from the proposed upgrade as the actual upgrade has been deleted. + proposedUpgrade := path.EndpointA.GetProposedUpgrade() + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeCancel: { + channeltypes.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyConnectionHops: proposedUpgrade.Fields.ConnectionHops[0], + channeltypes.AttributeVersion: proposedUpgrade.Fields.Version, + channeltypes.AttributeKeyOrdering: proposedUpgrade.Fields.Ordering.String(), + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + }, + channeltypes.EventTypeChannelUpgradeError: { + channeltypes.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + // need to manually insert this because the errorReceipt is a string constant as it is written into state + channeltypes.AttributeKeyErrorReceipt: "invalid upgrade", + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: channeltypes.AttributeValueCategory, + }, + } + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + }, + }, + { + "failure: keeper is authority and channel state in FLUSHCOMPLETE, but error receipt and channel upgrade sequences do not match", + func() { + msg.Signer = suite.chainA.App.GetIBCKeeper().GetAuthority() + + suite.Require().NoError(path.EndpointA.SetChannelState(channeltypes.FLUSHCOMPLETE)) + }, + func(res *channeltypes.MsgChannelUpgradeCancelResponse, events []abci.Event, err error) { + suite.Require().Error(err) + suite.Require().Nil(res) + suite.Require().ErrorIs(err, channeltypes.ErrInvalidUpgradeSequence) + + channel := path.EndpointA.GetChannel() + // Channel state should not be reverted back to open. + suite.Require().Equal(channeltypes.FLUSHCOMPLETE, channel.State) + // Upgrade sequence should not be changed. + suite.Require().Equal(uint64(1), channel.UpgradeSequence) + }, + }, + { + "core handler fails: invalid proof", + func() { + msg.ProofErrorReceipt = []byte("invalid proof") + + // Force set to STATE_FLUSHCOMPLETE to check that state is not changed. + channel := path.EndpointA.GetChannel() + channel.State = channeltypes.FLUSHCOMPLETE + channel.UpgradeSequence = uint64(2) // When in FLUSHCOMPLETE the sequence of the error receipt and the channel must match + path.EndpointA.SetChannel(channel) + }, + func(res *channeltypes.MsgChannelUpgradeCancelResponse, events []abci.Event, err error) { + suite.Require().Error(err) + suite.Require().Nil(res) + + channel := path.EndpointA.GetChannel() + suite.Require().ErrorIs(err, commitmenttypes.ErrInvalidProof) + // Channel state should not be changed. + suite.Require().Equal(channeltypes.FLUSHCOMPLETE, channel.State) + // Upgrade sequence should not be changed. + suite.Require().Equal(uint64(2), channel.UpgradeSequence) + + suite.Require().Empty(events) + }, + }, + } + + for _, tc := range cases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + // configure the channel upgrade version on testing endpoints + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + // cause the upgrade to fail on chain b so an error receipt is written. + // if the counterparty (chain A) upgrade sequence is less than the current sequence, (chain B) + // an upgrade error will be returned by chain B during ChanUpgradeTry. + channel := path.EndpointA.GetChannel() + channel.UpgradeSequence = 1 + path.EndpointA.SetChannel(channel) + + channel = path.EndpointB.GetChannel() + channel.UpgradeSequence = 2 + path.EndpointB.SetChannel(channel) + + suite.Require().NoError(path.EndpointA.UpdateClient()) + suite.Require().NoError(path.EndpointB.UpdateClient()) + + suite.Require().NoError(path.EndpointB.ChanUpgradeTry()) + + suite.Require().NoError(path.EndpointA.UpdateClient()) + + upgradeErrorReceiptKey := host.ChannelUpgradeErrorKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + errorReceiptProof, proofHeight := path.EndpointB.QueryProof(upgradeErrorReceiptKey) + + errorReceipt, ok := suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.GetUpgradeErrorReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().True(ok) + + msg = &channeltypes.MsgChannelUpgradeCancel{ + PortId: path.EndpointA.ChannelConfig.PortID, + ChannelId: path.EndpointA.ChannelID, + ErrorReceipt: errorReceipt, + ProofErrorReceipt: errorReceiptProof, + ProofHeight: proofHeight, + Signer: suite.chainA.SenderAccount.GetAddress().String(), + } + + tc.malleate() + + ctx := suite.chainA.GetContext() + res, err := suite.chainA.GetSimApp().GetIBCKeeper().ChannelUpgradeCancel(ctx, msg) + events := ctx.EventManager().Events().ToABCIEvents() + + tc.expResult(res, events, err) + }) + } +} + +func (suite *KeeperTestSuite) TestChannelUpgradeTimeout() { + var ( + path *ibctesting.Path + msg *channeltypes.MsgChannelUpgradeTimeout + ) + + timeoutUpgrade := func() { + upgrade := path.EndpointA.GetProposedUpgrade() + upgrade.Timeout = channeltypes.NewTimeout(clienttypes.ZeroHeight(), 1) + path.EndpointA.SetChannelUpgrade(upgrade) + suite.Require().NoError(path.EndpointB.UpdateClient()) + } + + cases := []struct { + name string + malleate func() + expResult func(res *channeltypes.MsgChannelUpgradeTimeoutResponse, events []abci.Event, err error) + }{ + { + "success", + func() { + timeoutUpgrade() + + suite.Require().NoError(path.EndpointA.UpdateClient()) + + channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channelProof, proofHeight := path.EndpointB.QueryProof(channelKey) + + msg.ProofChannel = channelProof + msg.ProofHeight = proofHeight + }, + func(res *channeltypes.MsgChannelUpgradeTimeoutResponse, events []abci.Event, err error) { + channel := path.EndpointA.GetChannel() + + suite.Require().Equalf(channeltypes.OPEN, channel.State, "channel state should be %s", channeltypes.OPEN.String()) + + _, found := path.EndpointA.Chain.GetSimApp().IBCKeeper.ChannelKeeper.GetUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().False(found, "channel upgrade should be nil") + + suite.Require().NotNil(res) + suite.Require().NoError(err) + + errorReceipt, found := suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.GetUpgradeErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(uint64(1), errorReceipt.Sequence) + + // we need to find the event values from the proposed upgrade as the actual upgrade has been deleted. + proposedUpgrade := path.EndpointA.GetProposedUpgrade() + // use the timeout we set in the malleate function + timeout := channeltypes.NewTimeout(clienttypes.ZeroHeight(), 1) + expEvents := ibctesting.EventsMap{ + channeltypes.EventTypeChannelUpgradeTimeout: { + channeltypes.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyConnectionHops: proposedUpgrade.Fields.ConnectionHops[0], + channeltypes.AttributeVersion: proposedUpgrade.Fields.Version, + channeltypes.AttributeKeyOrdering: proposedUpgrade.Fields.Ordering.String(), + channeltypes.AttributeKeyUpgradeTimeoutHeight: timeout.Height.String(), + channeltypes.AttributeKeyUpgradeTimeoutTimestamp: fmt.Sprintf("%d", timeout.Timestamp), + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + }, + channeltypes.EventTypeChannelUpgradeError: { + channeltypes.AttributeKeyPortID: path.EndpointA.ChannelConfig.PortID, + channeltypes.AttributeKeyChannelID: path.EndpointA.ChannelID, + channeltypes.AttributeCounterpartyPortID: path.EndpointB.ChannelConfig.PortID, + channeltypes.AttributeCounterpartyChannelID: path.EndpointB.ChannelID, + channeltypes.AttributeKeyUpgradeSequence: fmt.Sprintf("%d", channel.UpgradeSequence), + // need to manually insert this because the errorReceipt is a string constant as it is written into state + channeltypes.AttributeKeyErrorReceipt: "upgrade timed-out", + }, + sdk.EventTypeMessage: { + sdk.AttributeKeyModule: channeltypes.AttributeValueCategory, + }, + } + ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + }, + }, + { + "core handler fails: invalid proof", + func() { + timeoutUpgrade() + + suite.Require().NoError(path.EndpointA.UpdateClient()) + + _, _, proofHeight := path.EndpointB.QueryChannelUpgradeProof() + + msg.ProofHeight = proofHeight + msg.ProofChannel = []byte("invalid proof") + }, + func(res *channeltypes.MsgChannelUpgradeTimeoutResponse, events []abci.Event, err error) { + suite.Require().Error(err) + suite.Require().ErrorIs(err, commitmenttypes.ErrInvalidProof) + + channel := path.EndpointA.GetChannel() + suite.Require().Equalf(channeltypes.FLUSHCOMPLETE, channel.State, "channel state should be %s", channeltypes.OPEN) + suite.Require().Equal(uint64(1), channel.UpgradeSequence, "channel upgrade sequence should not incremented") + + _, found := path.EndpointA.Chain.GetSimApp().IBCKeeper.ChannelKeeper.GetUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found, "channel upgrade should not be nil") + + suite.Require().Empty(events) + }, + }, + } + + for _, tc := range cases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + + suite.Require().NoError(path.EndpointA.ChanUpgradeInit()) + suite.Require().NoError(path.EndpointB.ChanUpgradeTry()) + suite.Require().NoError(path.EndpointA.ChanUpgradeAck()) + + channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channelProof, proofHeight := path.EndpointB.QueryProof(channelKey) + + msg = &channeltypes.MsgChannelUpgradeTimeout{ + PortId: path.EndpointA.ChannelConfig.PortID, + ChannelId: path.EndpointA.ChannelID, + CounterpartyChannel: path.EndpointB.GetChannel(), + ProofChannel: channelProof, + ProofHeight: proofHeight, + Signer: suite.chainA.SenderAccount.GetAddress().String(), + } + + tc.malleate() + + ctx := suite.chainA.GetContext() + res, err := suite.chainA.GetSimApp().GetIBCKeeper().ChannelUpgradeTimeout(ctx, msg) + events := ctx.EventManager().Events().ToABCIEvents() + + tc.expResult(res, events, err) + }) + } +} + +// TestIBCSoftwareUpgrade tests the IBCSoftwareUpgrade rpc handler +func (suite *KeeperTestSuite) TestIBCSoftwareUpgrade() { + var msg *clienttypes.MsgIBCSoftwareUpgrade + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success: valid authority and client upgrade", + func() {}, + nil, + }, + { + "failure: invalid authority address", + func() { + msg.Signer = suite.chainA.SenderAccount.GetAddress().String() + }, + ibcerrors.ErrUnauthorized, + }, + { + "failure: invalid clientState", + func() { + msg.UpgradedClientState = nil + }, + clienttypes.ErrInvalidClientType, + }, + { + "failure: failed to schedule client upgrade", + func() { + msg.Plan.Height = 0 + }, + sdkerrors.ErrInvalidRequest, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + path := ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(path) validAuthority := suite.chainA.App.GetIBCKeeper().GetAuthority() plan := upgradetypes.Plan{ @@ -1040,3 +2722,133 @@ func (suite *KeeperTestSuite) TestUpdateConnectionParams() { }) } } + +// TestUpdateChannelParams tests the UpdateChannelParams rpc handler +func (suite *KeeperTestSuite) TestUpdateChannelParams() { + authority := suite.chainA.App.GetIBCKeeper().GetAuthority() + testCases := []struct { + name string + msg *channeltypes.MsgUpdateParams + expError error + }{ + { + "success: valid authority and default params", + channeltypes.NewMsgUpdateChannelParams(authority, channeltypes.DefaultParams()), + nil, + }, + { + "failure: malformed authority address", + channeltypes.NewMsgUpdateChannelParams(ibctesting.InvalidID, channeltypes.DefaultParams()), + ibcerrors.ErrUnauthorized, + }, + { + "failure: empty authority address", + channeltypes.NewMsgUpdateChannelParams("", channeltypes.DefaultParams()), + ibcerrors.ErrUnauthorized, + }, + { + "failure: empty signer", + channeltypes.NewMsgUpdateChannelParams("", channeltypes.DefaultParams()), + ibcerrors.ErrUnauthorized, + }, + { + "failure: unauthorized authority address", + channeltypes.NewMsgUpdateChannelParams(ibctesting.TestAccAddress, channeltypes.DefaultParams()), + ibcerrors.ErrUnauthorized, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + resp, err := keeper.Keeper.UpdateChannelParams(*suite.chainA.App.GetIBCKeeper(), suite.chainA.GetContext(), tc.msg) + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err) + suite.Require().NotNil(resp) + p := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetParams(suite.chainA.GetContext()) + suite.Require().Equal(tc.msg.Params, p) + } else { + suite.Require().Nil(resp) + suite.Require().ErrorIs(tc.expError, err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestPruneAcknowledgements() { + var msg *channeltypes.MsgPruneAcknowledgements + + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success", + func() {}, + nil, + }, + { + "failure: core keeper function fails, pruning sequence end not found", + func() { + msg.PortId = "portidone" + }, + channeltypes.ErrRecvStartSequenceNotFound, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + // configure the channel upgrade version on testing endpoints + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = ibcmock.UpgradeVersion + + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeAck() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeConfirm() + suite.Require().NoError(err) + + err = path.EndpointA.ChanUpgradeOpen() + suite.Require().NoError(err) + + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + msg = channeltypes.NewMsgPruneAcknowledgements( + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + 10, + suite.chainA.SenderAccount.GetAddress().String(), + ) + + tc.malleate() + + resp, err := suite.chainA.App.GetIBCKeeper().PruneAcknowledgements(suite.chainA.GetContext(), msg) + + if tc.expErr == nil { + suite.Require().NoError(err) + suite.Require().NotNil(resp) + suite.Require().Equal(uint64(0), resp.TotalPrunedSequences) + suite.Require().Equal(uint64(0), resp.TotalRemainingSequences) + } else { + suite.Require().Error(err) + suite.Require().Nil(resp) + } + }) + } +} diff --git a/modules/core/module.go b/modules/core/module.go index 27edd09a143..e7f6ebd4a94 100644 --- a/modules/core/module.go +++ b/modules/core/module.go @@ -22,6 +22,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectionkeeper "github.com/cosmos/ibc-go/v8/modules/core/03-connection/keeper" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" + channelkeeper "github.com/cosmos/ibc-go/v8/modules/core/04-channel/keeper" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" "github.com/cosmos/ibc-go/v8/modules/core/client/cli" "github.com/cosmos/ibc-go/v8/modules/core/exported" @@ -157,6 +158,12 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { }); err != nil { panic(err) } + + channelMigrator := channelkeeper.NewMigrator(am.keeper.ChannelKeeper) + err := cfg.RegisterMigration(exported.ModuleName, 5, channelMigrator.MigrateParams) + if err != nil { + panic(err) + } } // InitGenesis performs genesis initialization for the ibc module. It returns @@ -177,7 +184,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw } // ConsensusVersion implements AppModule/ConsensusVersion. -func (AppModule) ConsensusVersion() uint64 { return 5 } +func (AppModule) ConsensusVersion() uint64 { return 6 } // BeginBlock returns the begin blocker for the ibc module. func (am AppModule) BeginBlock(ctx context.Context) error { diff --git a/modules/core/types/events.go b/modules/core/types/events.go new file mode 100644 index 00000000000..be5c20efe12 --- /dev/null +++ b/modules/core/types/events.go @@ -0,0 +1,3 @@ +package types + +const ErrorAttributeKeyPrefix = "ibccallbackerror-" diff --git a/modules/light-clients/07-tendermint/consensus_host.go b/modules/light-clients/07-tendermint/consensus_host.go new file mode 100644 index 00000000000..0ce7bb4e802 --- /dev/null +++ b/modules/light-clients/07-tendermint/consensus_host.go @@ -0,0 +1,134 @@ +package tendermint + +import ( + "context" + "reflect" + "time" + + errorsmod "cosmossdk.io/errors" + upgradetypes "cosmossdk.io/x/upgrade/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + "github.com/cometbft/cometbft/light" + + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" + "github.com/cosmos/ibc-go/v8/modules/core/exported" +) + +var _ clienttypes.ConsensusHost = (*ConsensusHost)(nil) + +// ConsensusHost implements the 02-client clienttypes.ConsensusHost interface. +type ConsensusHost struct { + stakingKeeper StakingKeeper +} + +// StakingKeeper defines an expected interface for the tendermint ConsensusHost. +type StakingKeeper interface { + GetHistoricalInfo(ctx context.Context, height int64) (stakingtypes.HistoricalInfo, error) + UnbondingTime(ctx context.Context) (time.Duration, error) +} + +// NewConsensusHost creates and returns a new ConsensusHost for tendermint consensus. +func NewConsensusHost(stakingKeeper clienttypes.StakingKeeper) clienttypes.ConsensusHost { + return &ConsensusHost{ + stakingKeeper: stakingKeeper, + } +} + +// GetSelfConsensusState implements the 02-client clienttypes.ConsensusHost interface. +func (c *ConsensusHost) GetSelfConsensusState(ctx sdk.Context, height exported.Height) (exported.ConsensusState, error) { + selfHeight, ok := height.(clienttypes.Height) + if !ok { + return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidType, "expected %T, got %T", clienttypes.Height{}, height) + } + + // check that height revision matches chainID revision + revision := clienttypes.ParseChainID(ctx.ChainID()) + if revision != height.GetRevisionNumber() { + return nil, errorsmod.Wrapf(clienttypes.ErrInvalidHeight, "chainID revision number does not match height revision number: expected %d, got %d", revision, height.GetRevisionNumber()) + } + + histInfo, err := c.stakingKeeper.GetHistoricalInfo(ctx, int64(selfHeight.RevisionHeight)) + if err != nil { + return nil, errorsmod.Wrapf(err, "height %d", selfHeight.RevisionHeight) + } + + consensusState := &ConsensusState{ + Timestamp: histInfo.Header.Time, + Root: commitmenttypes.NewMerkleRoot(histInfo.Header.GetAppHash()), + NextValidatorsHash: histInfo.Header.NextValidatorsHash, + } + + return consensusState, nil +} + +// ValidateSelfClient implements the 02-client clienttypes.ConsensusHost interface. +func (c *ConsensusHost) ValidateSelfClient(ctx sdk.Context, clientState exported.ClientState) error { + tmClient, ok := clientState.(*ClientState) + if !ok { + return errorsmod.Wrapf(clienttypes.ErrInvalidClient, "client must be a Tendermint client, expected: %T, got: %T", &ClientState{}, tmClient) + } + + if !tmClient.FrozenHeight.IsZero() { + return clienttypes.ErrClientFrozen + } + + if ctx.ChainID() != tmClient.ChainId { + return errorsmod.Wrapf(clienttypes.ErrInvalidClient, "invalid chain-id. expected: %s, got: %s", + ctx.ChainID(), tmClient.ChainId) + } + + revision := clienttypes.ParseChainID(ctx.ChainID()) + + // client must be in the same revision as executing chain + if tmClient.LatestHeight.RevisionNumber != revision { + return errorsmod.Wrapf(clienttypes.ErrInvalidClient, "client is not in the same revision as the chain. expected revision: %d, got: %d", + tmClient.LatestHeight.RevisionNumber, revision) + } + + selfHeight := clienttypes.NewHeight(revision, uint64(ctx.BlockHeight())) + if tmClient.LatestHeight.GTE(selfHeight) { + return errorsmod.Wrapf(clienttypes.ErrInvalidClient, "client has LatestHeight %d greater than or equal to chain height %d", + tmClient.LatestHeight, selfHeight) + } + + expectedProofSpecs := commitmenttypes.GetSDKSpecs() + if !reflect.DeepEqual(expectedProofSpecs, tmClient.ProofSpecs) { + return errorsmod.Wrapf(clienttypes.ErrInvalidClient, "client has invalid proof specs. expected: %v got: %v", + expectedProofSpecs, tmClient.ProofSpecs) + } + + if err := light.ValidateTrustLevel(tmClient.TrustLevel.ToTendermint()); err != nil { + return errorsmod.Wrapf(clienttypes.ErrInvalidClient, "trust-level invalid: %v", err) + } + + expectedUbdPeriod, err := c.stakingKeeper.UnbondingTime(ctx) + if err != nil { + return errorsmod.Wrapf(err, "failed to retrieve unbonding period") + } + + if expectedUbdPeriod != tmClient.UnbondingPeriod { + return errorsmod.Wrapf(clienttypes.ErrInvalidClient, "invalid unbonding period. expected: %s, got: %s", + expectedUbdPeriod, tmClient.UnbondingPeriod) + } + + if tmClient.UnbondingPeriod < tmClient.TrustingPeriod { + return errorsmod.Wrapf(clienttypes.ErrInvalidClient, "unbonding period must be greater than trusting period. unbonding period (%d) < trusting period (%d)", + tmClient.UnbondingPeriod, tmClient.TrustingPeriod) + } + + if len(tmClient.UpgradePath) != 0 { + // For now, SDK IBC implementation assumes that upgrade path (if defined) is defined by SDK upgrade module + expectedUpgradePath := []string{upgradetypes.StoreKey, upgradetypes.KeyUpgradedIBCState} + if !reflect.DeepEqual(expectedUpgradePath, tmClient.UpgradePath) { + return errorsmod.Wrapf(clienttypes.ErrInvalidClient, "upgrade path must be the upgrade path defined by upgrade module. expected %v, got %v", + expectedUpgradePath, tmClient.UpgradePath) + } + } + + return nil +} diff --git a/modules/light-clients/07-tendermint/consensus_host_test.go b/modules/light-clients/07-tendermint/consensus_host_test.go new file mode 100644 index 00000000000..bb2f03d5b1b --- /dev/null +++ b/modules/light-clients/07-tendermint/consensus_host_test.go @@ -0,0 +1,249 @@ +package tendermint_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v8/modules/core/exported" + solomachine "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine" + ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v8/testing" + "github.com/cosmos/ibc-go/v8/testing/mock" +) + +func (suite *TendermintTestSuite) TestGetSelfConsensusState() { + var height clienttypes.Height + + cases := []struct { + name string + malleate func() + expError error + }{ + { + name: "zero height", + malleate: func() {}, + expError: clienttypes.ErrInvalidHeight, + }, + { + name: "height > latest height", + malleate: func() { + height = clienttypes.NewHeight(1, uint64(suite.chainA.GetContext().BlockHeight())+1) + }, + expError: stakingtypes.ErrNoHistoricalInfo, + }, + { + name: "pruned historical info", + malleate: func() { + height = clienttypes.NewHeight(1, uint64(suite.chainA.GetContext().BlockHeight())-1) + + err := suite.chainA.GetSimApp().StakingKeeper.DeleteHistoricalInfo(suite.chainA.GetContext(), int64(height.GetRevisionHeight())) + suite.Require().NoError(err) + }, + expError: stakingtypes.ErrNoHistoricalInfo, + }, + { + name: "custom consensus host: failure", + malleate: func() { + consensusHost := &mock.ConsensusHost{ + GetSelfConsensusStateFn: func(ctx sdk.Context, height exported.Height) (exported.ConsensusState, error) { + return nil, mock.MockApplicationCallbackError + }, + } + suite.chainA.GetSimApp().GetIBCKeeper().SetConsensusHost(consensusHost) + }, + expError: mock.MockApplicationCallbackError, + }, + { + name: "custom consensus host: success", + malleate: func() { + consensusHost := &mock.ConsensusHost{ + GetSelfConsensusStateFn: func(ctx sdk.Context, height exported.Height) (exported.ConsensusState, error) { + return &solomachine.ConsensusState{}, nil + }, + } + suite.chainA.GetSimApp().GetIBCKeeper().SetConsensusHost(consensusHost) + }, + expError: nil, + }, + { + name: "latest height - 1", + malleate: func() { + height = clienttypes.NewHeight(1, uint64(suite.chainA.GetContext().BlockHeight())-1) + }, + expError: nil, + }, + { + name: "latest height", + malleate: func() { + // historical info is set on BeginBlock in x/staking, which is now encapsulated within the FinalizeBlock abci method, + // thus, we do not have historical info for current height due to how the ibctesting library operates. + // ibctesting calls app.Commit() as a final step on NextBlock and we invoke test code before FinalizeBlock is called at the current height once again. + err := suite.chainA.GetSimApp().StakingKeeper.TrackHistoricalInfo(suite.chainA.GetContext()) + suite.Require().NoError(err) + + height = clienttypes.GetSelfHeight(suite.chainA.GetContext()) + }, + expError: nil, + }, + } + + for i, tc := range cases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + height = clienttypes.ZeroHeight() + + tc.malleate() + + cs, err := suite.chainA.GetSimApp().GetIBCKeeper().ClientKeeper.GetSelfConsensusState(suite.chainA.GetContext(), height) + + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err, "Case %d should have passed: %s", i, tc.name) + suite.Require().NotNil(cs, "Case %d should have passed: %s", i, tc.name) + } else { + suite.Require().ErrorIs(err, tc.expError, "Case %d should have failed: %s", i, tc.name) + suite.Require().Nil(cs, "Case %d should have failed: %s", i, tc.name) + } + }) + } +} + +func (suite *TendermintTestSuite) TestValidateSelfClient() { + testClientHeight := clienttypes.GetSelfHeight(suite.chainA.GetContext()) + testClientHeight.RevisionHeight-- + + var clientState exported.ClientState + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + name: "success", + malleate: func() { + clientState = ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath) + }, + expError: nil, + }, + { + name: "success with nil UpgradePath", + malleate: func() { + clientState = ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), nil) + }, + expError: nil, + }, + { + name: "success with custom self validator: solomachine", + malleate: func() { + clientState = solomachine.NewClientState(1, &solomachine.ConsensusState{}) + + smConsensusHost := &mock.ConsensusHost{ + ValidateSelfClientFn: func(ctx sdk.Context, clientState exported.ClientState) error { + smClientState, ok := clientState.(*solomachine.ClientState) + suite.Require().True(ok) + suite.Require().Equal(uint64(1), smClientState.Sequence) + + return nil + }, + } + + // add mock validation logic + suite.chainA.App.GetIBCKeeper().SetConsensusHost(smConsensusHost) + }, + expError: nil, + }, + { + name: "frozen client", + malleate: func() { + clientState = &ibctm.ClientState{ChainId: suite.chainA.ChainID, TrustLevel: ibctm.DefaultTrustLevel, TrustingPeriod: trustingPeriod, UnbondingPeriod: ubdPeriod, MaxClockDrift: maxClockDrift, FrozenHeight: testClientHeight, LatestHeight: testClientHeight, ProofSpecs: commitmenttypes.GetSDKSpecs(), UpgradePath: ibctesting.UpgradePath} + }, + expError: clienttypes.ErrClientFrozen, + }, + { + name: "incorrect chainID", + malleate: func() { + clientState = ibctm.NewClientState("gaiatestnet", ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath) + }, + expError: clienttypes.ErrInvalidClient, + }, + { + name: "invalid client height", + malleate: func() { + clientState = ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.GetSelfHeight(suite.chainA.GetContext()).Increment().(clienttypes.Height), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath) + }, + expError: clienttypes.ErrInvalidClient, + }, + { + name: "invalid client type", + malleate: func() { + clientState = solomachine.NewClientState(0, &solomachine.ConsensusState{}) + }, + expError: clienttypes.ErrInvalidClient, + }, + { + name: "invalid client revision", + malleate: func() { + clientState = ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(1, 5), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath) + }, + expError: clienttypes.ErrInvalidClient, + }, + { + name: "invalid proof specs", + malleate: func() { + clientState = ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, nil, ibctesting.UpgradePath) + }, + expError: clienttypes.ErrInvalidClient, + }, + { + name: "invalid trust level", + malleate: func() { + clientState = ibctm.NewClientState(suite.chainA.ChainID, ibctm.Fraction{Numerator: 0, Denominator: 1}, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath) + }, + expError: clienttypes.ErrInvalidClient, + }, + { + name: "invalid unbonding period", + malleate: func() { + clientState = ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod+10, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath) + }, + expError: clienttypes.ErrInvalidClient, + }, + { + name: "invalid trusting period", + malleate: func() { + clientState = ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, ubdPeriod+10, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath) + }, + expError: clienttypes.ErrInvalidClient, + }, + { + name: "invalid upgrade path", + malleate: func() { + clientState = ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), []string{"bad", "upgrade", "path"}) + }, + expError: clienttypes.ErrInvalidClient, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + tc.malleate() + + err := suite.chainA.App.GetIBCKeeper().ClientKeeper.ValidateSelfClient(suite.chainA.GetContext(), clientState) + + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err, "expected valid client for case: %s", tc.name) + } else { + suite.Require().Error(err, "expected invalid client for case: %s", tc.name) + } + }) + } +} diff --git a/modules/light-clients/07-tendermint/update.go b/modules/light-clients/07-tendermint/update.go index c884b4bfba9..5c5fbca840c 100644 --- a/modules/light-clients/07-tendermint/update.go +++ b/modules/light-clients/07-tendermint/update.go @@ -2,7 +2,6 @@ package tendermint import ( "bytes" - "fmt" errorsmod "cosmossdk.io/errors" storetypes "cosmossdk.io/store/types" @@ -131,13 +130,19 @@ func (cs *ClientState) verifyHeader( // UpdateState must only be used to update within a single revision, thus header revision number and trusted height's revision // number must be the same. To update to a new revision, use a separate upgrade path // UpdateState will prune the oldest consensus state if it is expired. +// If the provided clientMsg is not of type of Header then the handler will noop and empty slice is returned. func (cs ClientState) UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, clientStore storetypes.KVStore, clientMsg exported.ClientMessage) []exported.Height { header, ok := clientMsg.(*Header) if !ok { - panic(fmt.Errorf("expected type %T, got %T", &Header{}, clientMsg)) + // clientMsg is invalid Misbehaviour, no update necessary + return []exported.Height{} } - cs.pruneOldestConsensusState(ctx, cdc, clientStore) + // performance: do not prune in checkTx + // simulation must prune for accurate gas estimation + if (!ctx.IsCheckTx() && !ctx.IsReCheckTx()) || ctx.ExecMode() == sdk.ExecModeSimulate { + cs.pruneOldestConsensusState(ctx, cdc, clientStore) + } // check for duplicate update if _, found := GetConsensusState(clientStore, cdc, header.GetHeight()); found { diff --git a/modules/light-clients/07-tendermint/update_test.go b/modules/light-clients/07-tendermint/update_test.go index d6b8de6e091..1176a053b9d 100644 --- a/modules/light-clients/07-tendermint/update_test.go +++ b/modules/light-clients/07-tendermint/update_test.go @@ -5,6 +5,8 @@ import ( storetypes "cosmossdk.io/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + tmtypes "github.com/cometbft/cometbft/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" @@ -509,9 +511,12 @@ func (suite *TendermintTestSuite) TestUpdateState() { suite.Require().Equal(expConsensusState, updatedConsensusState) } else { - suite.Require().Panics(func() { - clientState.UpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, clientMessage) - }) + consensusHeights = clientState.UpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, clientMessage) + suite.Require().Empty(consensusHeights) + + consensusState, found := suite.chainA.GetSimApp().GetIBCKeeper().ClientKeeper.GetClientConsensusState(suite.chainA.GetContext(), path.EndpointA.ClientID, clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()))) + suite.Require().False(found) + suite.Require().Nil(consensusState) } // perform custom checks @@ -520,6 +525,75 @@ func (suite *TendermintTestSuite) TestUpdateState() { } } +func (suite *TendermintTestSuite) TestUpdateStateCheckTx() { + path := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupClients(path) + + createClientMessage := func() exported.ClientMessage { + header, err := suite.chainA.ConstructUpdateTMClientHeader(suite.chainB, path.EndpointA.ClientID) + suite.Require().NoError(err) + return header + } + + // get the first height as it will be pruned first. + var pruneHeight exported.Height + getFirstHeightCb := func(height exported.Height) bool { + pruneHeight = height + return true + } + ctx := path.EndpointA.Chain.GetContext() + clientStore := path.EndpointA.Chain.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) + ibctm.IterateConsensusStateAscending(clientStore, getFirstHeightCb) + + // Increment the time by a week + suite.coordinator.IncrementTimeBy(7 * 24 * time.Hour) + + cs := path.EndpointA.GetClientState() + ctx = path.EndpointA.Chain.GetContext().WithIsCheckTx(true) + + cs.UpdateState(ctx, suite.chainA.GetSimApp().AppCodec(), clientStore, createClientMessage()) + + // Increment the time by another week, then update the client. + // This will cause the first two consensus states to become expired. + suite.coordinator.IncrementTimeBy(7 * 24 * time.Hour) + ctx = path.EndpointA.Chain.GetContext().WithIsCheckTx(true) + cs.UpdateState(ctx, suite.chainA.GetSimApp().AppCodec(), clientStore, createClientMessage()) + + assertPrune := func(pruned bool) { + // check consensus states and associated metadata + consState, ok := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, pruneHeight) + suite.Require().Equal(!pruned, ok) + + processTime, ok := ibctm.GetProcessedTime(clientStore, pruneHeight) + suite.Require().Equal(!pruned, ok) + + processHeight, ok := ibctm.GetProcessedHeight(clientStore, pruneHeight) + suite.Require().Equal(!pruned, ok) + + consKey := ibctm.GetIterationKey(clientStore, pruneHeight) + + if pruned { + suite.Require().Nil(consState, "expired consensus state not pruned") + suite.Require().Empty(processTime, "processed time metadata not pruned") + suite.Require().Nil(processHeight, "processed height metadata not pruned") + suite.Require().Nil(consKey, "iteration key not pruned") + } else { + suite.Require().NotNil(consState, "expired consensus state pruned") + suite.Require().NotEqual(uint64(0), processTime, "processed time metadata pruned") + suite.Require().NotNil(processHeight, "processed height metadata pruned") + suite.Require().NotNil(consKey, "iteration key pruned") + } + } + + assertPrune(false) + + // simulation mode must prune to calculate gas correctly + ctx = ctx.WithExecMode(sdk.ExecModeSimulate) + cs.UpdateState(ctx, suite.chainA.GetSimApp().AppCodec(), clientStore, createClientMessage()) + + assertPrune(true) +} + func (suite *TendermintTestSuite) TestPruneConsensusState() { // create path and setup clients path := ibctesting.NewPath(suite.chainA, suite.chainB) diff --git a/modules/light-clients/07-tendermint/upgrade.go b/modules/light-clients/07-tendermint/upgrade.go index a3159459816..59dfe066419 100644 --- a/modules/light-clients/07-tendermint/upgrade.go +++ b/modules/light-clients/07-tendermint/upgrade.go @@ -30,7 +30,7 @@ import ( func (cs ClientState) VerifyUpgradeAndUpdateState( ctx sdk.Context, cdc codec.BinaryCodec, clientStore storetypes.KVStore, upgradedClient exported.ClientState, upgradedConsState exported.ConsensusState, - proofUpgradeClient, proofUpgradeConsState []byte, + upgradeClientProof, upgradeConsStateProof []byte, ) error { if len(cs.UpgradePath) == 0 { return errorsmod.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade client, no upgrade path set") @@ -60,10 +60,10 @@ func (cs ClientState) VerifyUpgradeAndUpdateState( // unmarshal proofs var merkleProofClient, merkleProofConsState commitmenttypes.MerkleProof - if err := cdc.Unmarshal(proofUpgradeClient, &merkleProofClient); err != nil { + if err := cdc.Unmarshal(upgradeClientProof, &merkleProofClient); err != nil { return errorsmod.Wrapf(commitmenttypes.ErrInvalidProof, "could not unmarshal client merkle proof: %v", err) } - if err := cdc.Unmarshal(proofUpgradeConsState, &merkleProofConsState); err != nil { + if err := cdc.Unmarshal(upgradeConsStateProof, &merkleProofConsState); err != nil { return errorsmod.Wrapf(commitmenttypes.ErrInvalidProof, "could not unmarshal consensus state merkle proof: %v", err) } diff --git a/modules/light-clients/07-tendermint/upgrade_test.go b/modules/light-clients/07-tendermint/upgrade_test.go index 9cedda0b206..3663a04938b 100644 --- a/modules/light-clients/07-tendermint/upgrade_test.go +++ b/modules/light-clients/07-tendermint/upgrade_test.go @@ -12,14 +12,14 @@ import ( func (suite *TendermintTestSuite) TestVerifyUpgrade() { var ( - newChainID string - upgradedClient exported.ClientState - upgradedConsState exported.ConsensusState - lastHeight clienttypes.Height - path *ibctesting.Path - proofUpgradedClient, proofUpgradedConsState []byte - upgradedClientBz, upgradedConsStateBz []byte - err error + newChainID string + upgradedClient exported.ClientState + upgradedConsState exported.ConsensusState + lastHeight clienttypes.Height + path *ibctesting.Path + upgradedClientProof, upgradedConsensusStateProof []byte + upgradedClientBz, upgradedConsStateBz []byte + err error ) testCases := []struct { @@ -46,8 +46,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) }, expPass: true, }, @@ -75,8 +75,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) }, expPass: true, }, @@ -100,8 +100,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) }, expPass: false, }, @@ -129,8 +129,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) }, expPass: false, }, @@ -154,8 +154,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) }, expPass: false, }, @@ -176,8 +176,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) }, expPass: false, }, @@ -205,8 +205,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) }, expPass: false, }, @@ -218,9 +218,9 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedClient = []byte("proof") + upgradedClientProof = []byte("proof") }, expPass: false, }, @@ -232,9 +232,9 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState = []byte("proof") + upgradedConsensusStateProof = []byte("proof") }, expPass: false, }, @@ -251,8 +251,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) }, expPass: false, }, @@ -269,8 +269,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) }, expPass: false, }, @@ -292,8 +292,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) // SetClientState with empty upgrade path tmClient, _ := cs.(*ibctm.ClientState) @@ -320,8 +320,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) }, expPass: false, }, @@ -343,8 +343,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) }, expPass: false, }, @@ -366,8 +366,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) }, expPass: false, }, @@ -389,8 +389,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) }, expPass: false, }, @@ -418,8 +418,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) }, expPass: false, }, @@ -467,8 +467,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { clientStore, upgradedClient, upgradedConsState, - proofUpgradedClient, - proofUpgradedConsState, + upgradedClientProof, + upgradedConsensusStateProof, ) if tc.expPass { diff --git a/modules/light-clients/09-localhost/client_state_test.go b/modules/light-clients/09-localhost/client_state_test.go index d1059fac5e2..7764289768d 100644 --- a/modules/light-clients/09-localhost/client_state_test.go +++ b/modules/light-clients/09-localhost/client_state_test.go @@ -281,7 +281,8 @@ func (suite *LocalhostTestSuite) TestVerifyMembership() { path = merklePath - channel.State = channeltypes.CLOSED // modify the channel before marshalling to value bz + // modify the channel before marshalling to value bz + channel.State = channeltypes.CLOSED value = suite.chain.Codec.MustMarshal(&channel) }, false, diff --git a/proto/ibc/applications/interchain_accounts/controller/v1/tx.proto b/proto/ibc/applications/interchain_accounts/controller/v1/tx.proto index 1287cfa2d37..ec5c2e62eac 100644 --- a/proto/ibc/applications/interchain_accounts/controller/v1/tx.proto +++ b/proto/ibc/applications/interchain_accounts/controller/v1/tx.proto @@ -8,6 +8,7 @@ import "gogoproto/gogo.proto"; import "ibc/applications/interchain_accounts/v1/packet.proto"; import "ibc/applications/interchain_accounts/controller/v1/controller.proto"; import "cosmos/msg/v1/msg.proto"; +import "ibc/core/channel/v1/channel.proto"; // Msg defines the 27-interchain-accounts/controller Msg service. service Msg { @@ -27,9 +28,10 @@ message MsgRegisterInterchainAccount { option (gogoproto.goproto_getters) = false; - string owner = 1; - string connection_id = 2; - string version = 3; + string owner = 1; + string connection_id = 2; + string version = 3; + ibc.core.channel.v1.Order ordering = 4; } // MsgRegisterInterchainAccountResponse defines the response for Msg/RegisterAccount diff --git a/proto/ibc/applications/interchain_accounts/host/v1/host.proto b/proto/ibc/applications/interchain_accounts/host/v1/host.proto index f036857113a..9165f36e794 100644 --- a/proto/ibc/applications/interchain_accounts/host/v1/host.proto +++ b/proto/ibc/applications/interchain_accounts/host/v1/host.proto @@ -12,3 +12,14 @@ message Params { // allow_messages defines a list of sdk message typeURLs allowed to be executed on a host chain. repeated string allow_messages = 2; } + +// QueryRequest defines the parameters for a particular query request +// by an interchain account. +message QueryRequest { + // path defines the path of the query request as defined by ADR-021. + // https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-021-protobuf-query-encoding.md#custom-query-registration-and-routing + string path = 1; + // data defines the payload of the query request as defined by ADR-021. + // https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-021-protobuf-query-encoding.md#custom-query-registration-and-routing + bytes data = 2; +} diff --git a/proto/ibc/applications/interchain_accounts/host/v1/tx.proto b/proto/ibc/applications/interchain_accounts/host/v1/tx.proto index 5a8073bc931..22e8c9b3567 100644 --- a/proto/ibc/applications/interchain_accounts/host/v1/tx.proto +++ b/proto/ibc/applications/interchain_accounts/host/v1/tx.proto @@ -14,6 +14,9 @@ service Msg { // UpdateParams defines a rpc handler for MsgUpdateParams. rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); + + // ModuleQuerySafe defines a rpc handler for MsgModuleQuerySafe. + rpc ModuleQuerySafe(MsgModuleQuerySafe) returns (MsgModuleQuerySafeResponse); } // MsgUpdateParams defines the payload for Msg/UpdateParams @@ -33,3 +36,25 @@ message MsgUpdateParams { // MsgUpdateParamsResponse defines the response for Msg/UpdateParams message MsgUpdateParamsResponse {} + +// MsgModuleQuerySafe defines the payload for Msg/ModuleQuerySafe +message MsgModuleQuerySafe { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + // signer address + string signer = 1; + + // requests defines the module safe queries to execute. + repeated QueryRequest requests = 2; +} + +// MsgModuleQuerySafeResponse defines the response for Msg/ModuleQuerySafe +message MsgModuleQuerySafeResponse { + // height at which the responses were queried + uint64 height = 1; + + // protobuf encoded responses for each query + repeated bytes responses = 2; +} diff --git a/proto/ibc/applications/transfer/v1/authz.proto b/proto/ibc/applications/transfer/v1/authz.proto index 7b7a9f0846a..5c4b71d3479 100644 --- a/proto/ibc/applications/transfer/v1/authz.proto +++ b/proto/ibc/applications/transfer/v1/authz.proto @@ -19,6 +19,9 @@ message Allocation { [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; // allow list of receivers, an empty allow list permits any receiver address repeated string allow_list = 4; + // allow list of memo strings, an empty list prohibits all memo strings; + // a list only with "*" permits any memo string + repeated string allowed_packet_data = 5; } // TransferAuthorization allows the grantee to spend up to spend_limit coins from diff --git a/proto/ibc/applications/transfer/v1/transfer.proto b/proto/ibc/applications/transfer/v1/transfer.proto index 12914b7a4b8..7f77237621f 100644 --- a/proto/ibc/applications/transfer/v1/transfer.proto +++ b/proto/ibc/applications/transfer/v1/transfer.proto @@ -25,4 +25,4 @@ message Params { // receive_enabled enables or disables all cross-chain token transfers to this // chain. bool receive_enabled = 2; -} \ No newline at end of file +} diff --git a/proto/ibc/core/channel/v1/channel.proto b/proto/ibc/core/channel/v1/channel.proto index 44c3240e2bc..05a18fefb78 100644 --- a/proto/ibc/core/channel/v1/channel.proto +++ b/proto/ibc/core/channel/v1/channel.proto @@ -24,6 +24,9 @@ message Channel { repeated string connection_hops = 4; // opaque channel version, which is agreed upon during the handshake string version = 5; + // upgrade sequence indicates the latest upgrade attempt performed by this channel + // the value of 0 indicates the channel has never been upgraded + uint64 upgrade_sequence = 6; } // IdentifiedChannel defines a channel with additional port and channel @@ -46,10 +49,13 @@ message IdentifiedChannel { string port_id = 6; // channel identifier string channel_id = 7; + // upgrade sequence indicates the latest upgrade attempt performed by this channel + // the value of 0 indicates the channel has never been upgraded + uint64 upgrade_sequence = 8; } // State defines if a channel is in one of the following states: -// CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. +// CLOSED, INIT, TRYOPEN, OPEN, FLUSHING, FLUSHCOMPLETE or UNINITIALIZED. enum State { option (gogoproto.goproto_enum_prefix) = false; @@ -65,6 +71,10 @@ enum State { // A channel has been closed and can no longer be used to send or receive // packets. STATE_CLOSED = 4 [(gogoproto.enumvalue_customname) = "CLOSED"]; + // A channel has just accepted the upgrade handshake attempt and is flushing in-flight packets. + STATE_FLUSHING = 5 [(gogoproto.enumvalue_customname) = "FLUSHING"]; + // A channel has just completed flushing any in-flight packets. + STATE_FLUSHCOMPLETE = 6 [(gogoproto.enumvalue_customname) = "FLUSHCOMPLETE"]; } // Order defines if a channel is ORDERED or UNORDERED @@ -169,3 +179,9 @@ message Timeout { // block timestamp (in nanoseconds) after which the packet or upgrade times out uint64 timestamp = 2; } + +// Params defines the set of IBC channel parameters. +message Params { + // the relative timeout after which channel upgrades will time out. + Timeout upgrade_timeout = 1 [(gogoproto.nullable) = false]; +} diff --git a/proto/ibc/core/channel/v1/genesis.proto b/proto/ibc/core/channel/v1/genesis.proto index 382a8048d45..665b2b1562f 100644 --- a/proto/ibc/core/channel/v1/genesis.proto +++ b/proto/ibc/core/channel/v1/genesis.proto @@ -18,6 +18,7 @@ message GenesisState { repeated PacketSequence ack_sequences = 7 [(gogoproto.nullable) = false]; // the sequence for the next generated channel identifier uint64 next_channel_sequence = 8; + Params params = 9 [(gogoproto.nullable) = false]; } // PacketSequence defines the genesis type necessary to retrieve and store diff --git a/proto/ibc/core/channel/v1/query.proto b/proto/ibc/core/channel/v1/query.proto index 42c4caea7d0..f89d212736a 100644 --- a/proto/ibc/core/channel/v1/query.proto +++ b/proto/ibc/core/channel/v1/query.proto @@ -10,6 +10,7 @@ import "ibc/core/channel/v1/channel.proto"; import "google/api/annotations.proto"; import "google/protobuf/any.proto"; import "gogoproto/gogo.proto"; +import "ibc/core/channel/v1/upgrade.proto"; // Query provides defines the gRPC querier service service Query { @@ -104,6 +105,23 @@ service Query { option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" "ports/{port_id}/next_sequence_send"; } + + // UpgradeError returns the error receipt if the upgrade handshake failed. + rpc UpgradeError(QueryUpgradeErrorRequest) returns (QueryUpgradeErrorResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" + "ports/{port_id}/upgrade_error"; + } + + // Upgrade returns the upgrade for a given port and channel id. + rpc Upgrade(QueryUpgradeRequest) returns (QueryUpgradeResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" + "ports/{port_id}/upgrade"; + } + + // ChannelParams queries all parameters of the ibc channel submodule. + rpc ChannelParams(QueryChannelParamsRequest) returns (QueryChannelParamsResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/params"; + } } // QueryChannelRequest is the request type for the Query/Channel RPC method @@ -370,7 +388,7 @@ message QueryNextSequenceReceiveRequest { string channel_id = 2; } -// QuerySequenceResponse is the request type for the +// QuerySequenceResponse is the response type for the // Query/QueryNextSequenceReceiveResponse RPC method message QueryNextSequenceReceiveResponse { // next sequence receive number @@ -399,4 +417,43 @@ message QueryNextSequenceSendResponse { bytes proof = 2; // height at which the proof was retrieved ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryUpgradeErrorRequest is the request type for the Query/QueryUpgradeError RPC method +message QueryUpgradeErrorRequest { + string port_id = 1; + string channel_id = 2; +} + +// QueryUpgradeErrorResponse is the response type for the Query/QueryUpgradeError RPC method +message QueryUpgradeErrorResponse { + ErrorReceipt error_receipt = 1 [(gogoproto.nullable) = false]; + // merkle proof of existence + bytes proof = 2; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryUpgradeRequest is the request type for the QueryUpgradeRequest RPC method +message QueryUpgradeRequest { + string port_id = 1; + string channel_id = 2; +} + +// QueryUpgradeResponse is the response type for the QueryUpgradeResponse RPC method +message QueryUpgradeResponse { + Upgrade upgrade = 1 [(gogoproto.nullable) = false]; + // merkle proof of existence + bytes proof = 2; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryChannelParamsRequest is the request type for the Query/ChannelParams RPC method. +message QueryChannelParamsRequest {} + +// QueryChannelParamsResponse is the response type for the Query/ChannelParams RPC method. +message QueryChannelParamsResponse { + // params defines the parameters of the module. + Params params = 1; } \ No newline at end of file diff --git a/proto/ibc/core/channel/v1/tx.proto b/proto/ibc/core/channel/v1/tx.proto index 4b9ad3d75cd..3f30e8b8c97 100644 --- a/proto/ibc/core/channel/v1/tx.proto +++ b/proto/ibc/core/channel/v1/tx.proto @@ -5,9 +5,10 @@ package ibc.core.channel.v1; option go_package = "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"; import "gogoproto/gogo.proto"; +import "cosmos/msg/v1/msg.proto"; import "ibc/core/client/v1/client.proto"; import "ibc/core/channel/v1/channel.proto"; -import "cosmos/msg/v1/msg.proto"; +import "ibc/core/channel/v1/upgrade.proto"; // Msg defines the ibc/channel Msg service. service Msg { @@ -43,6 +44,33 @@ service Msg { // Acknowledgement defines a rpc handler method for MsgAcknowledgement. rpc Acknowledgement(MsgAcknowledgement) returns (MsgAcknowledgementResponse); + + // ChannelUpgradeInit defines a rpc handler method for MsgChannelUpgradeInit. + rpc ChannelUpgradeInit(MsgChannelUpgradeInit) returns (MsgChannelUpgradeInitResponse); + + // ChannelUpgradeTry defines a rpc handler method for MsgChannelUpgradeTry. + rpc ChannelUpgradeTry(MsgChannelUpgradeTry) returns (MsgChannelUpgradeTryResponse); + + // ChannelUpgradeAck defines a rpc handler method for MsgChannelUpgradeAck. + rpc ChannelUpgradeAck(MsgChannelUpgradeAck) returns (MsgChannelUpgradeAckResponse); + + // ChannelUpgradeConfirm defines a rpc handler method for MsgChannelUpgradeConfirm. + rpc ChannelUpgradeConfirm(MsgChannelUpgradeConfirm) returns (MsgChannelUpgradeConfirmResponse); + + // ChannelUpgradeOpen defines a rpc handler method for MsgChannelUpgradeOpen. + rpc ChannelUpgradeOpen(MsgChannelUpgradeOpen) returns (MsgChannelUpgradeOpenResponse); + + // ChannelUpgradeTimeout defines a rpc handler method for MsgChannelUpgradeTimeout. + rpc ChannelUpgradeTimeout(MsgChannelUpgradeTimeout) returns (MsgChannelUpgradeTimeoutResponse); + + // ChannelUpgradeCancel defines a rpc handler method for MsgChannelUpgradeCancel. + rpc ChannelUpgradeCancel(MsgChannelUpgradeCancel) returns (MsgChannelUpgradeCancelResponse); + + // UpdateChannelParams defines a rpc handler method for MsgUpdateParams. + rpc UpdateChannelParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); + + // PruneAcknowledgements defines a rpc handler method for MsgPruneAcknowledgements. + rpc PruneAcknowledgements(MsgPruneAcknowledgements) returns (MsgPruneAcknowledgementsResponse); } // ResponseResultType defines the possible outcomes of the execution of a message @@ -55,6 +83,8 @@ enum ResponseResultType { RESPONSE_RESULT_TYPE_NOOP = 1 [(gogoproto.enumvalue_customname) = "NOOP"]; // The message was executed successfully RESPONSE_RESULT_TYPE_SUCCESS = 2 [(gogoproto.enumvalue_customname) = "SUCCESS"]; + // The message was executed unsuccessfully + RESPONSE_RESULT_TYPE_FAILURE = 3 [(gogoproto.enumvalue_customname) = "FAILURE"]; } // MsgChannelOpenInit defines an sdk.Msg to initialize a channel handshake. It @@ -106,6 +136,9 @@ message MsgChannelOpenTryResponse { // MsgChannelOpenAck defines a msg sent by a Relayer to Chain A to acknowledge // the change of channel state to TRYOPEN on Chain B. +// WARNING: a channel upgrade MUST NOT initialize an upgrade for this channel +// in the same block as executing this message otherwise the counterparty will +// be incapable of opening. message MsgChannelOpenAck { option (cosmos.msg.v1.signer) = "signer"; @@ -163,11 +196,12 @@ message MsgChannelCloseConfirm { option (gogoproto.goproto_getters) = false; - string port_id = 1; - string channel_id = 2; - bytes proof_init = 3; - ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; - string signer = 5; + string port_id = 1; + string channel_id = 2; + bytes proof_init = 3; + ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; + string signer = 5; + uint64 counterparty_upgrade_sequence = 6; } // MsgChannelCloseConfirmResponse defines the Msg/ChannelCloseConfirm response @@ -219,12 +253,13 @@ message MsgTimeoutOnClose { option (gogoproto.goproto_getters) = false; - Packet packet = 1 [(gogoproto.nullable) = false]; - bytes proof_unreceived = 2; - bytes proof_close = 3; - ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; - uint64 next_sequence_recv = 5; - string signer = 6; + Packet packet = 1 [(gogoproto.nullable) = false]; + bytes proof_unreceived = 2; + bytes proof_close = 3; + ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; + uint64 next_sequence_recv = 5; + string signer = 6; + uint64 counterparty_upgrade_sequence = 7; } // MsgTimeoutOnCloseResponse defines the Msg/TimeoutOnClose response type. @@ -253,3 +288,182 @@ message MsgAcknowledgementResponse { ResponseResultType result = 1; } + +// MsgChannelUpgradeInit defines the request type for the ChannelUpgradeInit rpc +// WARNING: Initializing a channel upgrade in the same block as opening the channel +// may result in the counterparty being incapable of opening. +message MsgChannelUpgradeInit { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + UpgradeFields fields = 3 [(gogoproto.nullable) = false]; + string signer = 4; +} + +// MsgChannelUpgradeInitResponse defines the MsgChannelUpgradeInit response type +message MsgChannelUpgradeInitResponse { + option (gogoproto.goproto_getters) = false; + + Upgrade upgrade = 1 [(gogoproto.nullable) = false]; + uint64 upgrade_sequence = 2; +} + +// MsgChannelUpgradeTry defines the request type for the ChannelUpgradeTry rpc +message MsgChannelUpgradeTry { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + repeated string proposed_upgrade_connection_hops = 3; + UpgradeFields counterparty_upgrade_fields = 4 [(gogoproto.nullable) = false]; + uint64 counterparty_upgrade_sequence = 5; + bytes proof_channel = 6; + bytes proof_upgrade = 7; + ibc.core.client.v1.Height proof_height = 8 [(gogoproto.nullable) = false]; + string signer = 9; +} + +// MsgChannelUpgradeTryResponse defines the MsgChannelUpgradeTry response type +message MsgChannelUpgradeTryResponse { + option (gogoproto.goproto_getters) = false; + + Upgrade upgrade = 1 [(gogoproto.nullable) = false]; + uint64 upgrade_sequence = 2; + ResponseResultType result = 3; +} + +// MsgChannelUpgradeAck defines the request type for the ChannelUpgradeAck rpc +message MsgChannelUpgradeAck { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + string port_id = 1; + string channel_id = 2; + Upgrade counterparty_upgrade = 3 [(gogoproto.nullable) = false]; + bytes proof_channel = 4; + bytes proof_upgrade = 5; + ibc.core.client.v1.Height proof_height = 6 [(gogoproto.nullable) = false]; + string signer = 7; +} + +// MsgChannelUpgradeAckResponse defines MsgChannelUpgradeAck response type +message MsgChannelUpgradeAckResponse { + option (gogoproto.goproto_getters) = false; + + ResponseResultType result = 1; +} + +// MsgChannelUpgradeConfirm defines the request type for the ChannelUpgradeConfirm rpc +message MsgChannelUpgradeConfirm { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + string port_id = 1; + string channel_id = 2; + State counterparty_channel_state = 3; + Upgrade counterparty_upgrade = 4 [(gogoproto.nullable) = false]; + bytes proof_channel = 5; + bytes proof_upgrade = 6; + ibc.core.client.v1.Height proof_height = 7 [(gogoproto.nullable) = false]; + string signer = 8; +} + +// MsgChannelUpgradeConfirmResponse defines MsgChannelUpgradeConfirm response type +message MsgChannelUpgradeConfirmResponse { + option (gogoproto.goproto_getters) = false; + + ResponseResultType result = 1; +} + +// MsgChannelUpgradeOpen defines the request type for the ChannelUpgradeOpen rpc +message MsgChannelUpgradeOpen { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + string port_id = 1; + string channel_id = 2; + State counterparty_channel_state = 3; + uint64 counterparty_upgrade_sequence = 4; + bytes proof_channel = 5; + ibc.core.client.v1.Height proof_height = 6 [(gogoproto.nullable) = false]; + string signer = 7; +} + +// MsgChannelUpgradeOpenResponse defines the MsgChannelUpgradeOpen response type +message MsgChannelUpgradeOpenResponse {} + +// MsgChannelUpgradeTimeout defines the request type for the ChannelUpgradeTimeout rpc +message MsgChannelUpgradeTimeout { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + Channel counterparty_channel = 3 [(gogoproto.nullable) = false]; + bytes proof_channel = 4; + ibc.core.client.v1.Height proof_height = 5 [(gogoproto.nullable) = false]; + string signer = 6; +} + +// MsgChannelUpgradeTimeoutRepsonse defines the MsgChannelUpgradeTimeout response type +message MsgChannelUpgradeTimeoutResponse {} + +// MsgChannelUpgradeCancel defines the request type for the ChannelUpgradeCancel rpc +message MsgChannelUpgradeCancel { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + ErrorReceipt error_receipt = 3 [(gogoproto.nullable) = false]; + bytes proof_error_receipt = 4; + ibc.core.client.v1.Height proof_height = 5 [(gogoproto.nullable) = false]; + string signer = 6; +} + +// MsgChannelUpgradeCancelResponse defines the MsgChannelUpgradeCancel response type +message MsgChannelUpgradeCancelResponse {} + +// MsgUpdateParams is the MsgUpdateParams request type. +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "authority"; + + option (gogoproto.goproto_getters) = false; + + // authority is the address that controls the module (defaults to x/gov unless overwritten). + string authority = 1; + + // params defines the channel parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [(gogoproto.nullable) = false]; +} + +// MsgUpdateParamsResponse defines the MsgUpdateParams response type. +message MsgUpdateParamsResponse {} + +// MsgPruneAcknowledgements defines the request type for the PruneAcknowledgements rpc. +message MsgPruneAcknowledgements { + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + uint64 limit = 3; + string signer = 4; +} + +// MsgPruneAcknowledgementsResponse defines the response type for the PruneAcknowledgements rpc. +message MsgPruneAcknowledgementsResponse { + // Number of sequences pruned (includes both packet acknowledgements and packet receipts where appropriate). + uint64 total_pruned_sequences = 1; + // Number of sequences left after pruning. + uint64 total_remaining_sequences = 2; +} diff --git a/proto/ibc/core/channel/v1/upgrade.proto b/proto/ibc/core/channel/v1/upgrade.proto new file mode 100644 index 00000000000..81530ed2a28 --- /dev/null +++ b/proto/ibc/core/channel/v1/upgrade.proto @@ -0,0 +1,43 @@ +syntax = "proto3"; + +package ibc.core.channel.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"; + +import "gogoproto/gogo.proto"; +import "ibc/core/channel/v1/channel.proto"; + +// Upgrade is a verifiable type which contains the relevant information +// for an attempted upgrade. It provides the proposed changes to the channel +// end, the timeout for this upgrade attempt and the next packet sequence +// which allows the counterparty to efficiently know the highest sequence it has received. +// The next sequence send is used for pruning and upgrading from unordered to ordered channels. +message Upgrade { + option (gogoproto.goproto_getters) = false; + + UpgradeFields fields = 1 [(gogoproto.nullable) = false]; + Timeout timeout = 2 [(gogoproto.nullable) = false]; + uint64 next_sequence_send = 3; +} + +// UpgradeFields are the fields in a channel end which may be changed +// during a channel upgrade. +message UpgradeFields { + option (gogoproto.goproto_getters) = false; + + Order ordering = 1; + repeated string connection_hops = 2; + string version = 3; +} + +// ErrorReceipt defines a type which encapsulates the upgrade sequence and error associated with the +// upgrade handshake failure. When a channel upgrade handshake is aborted both chains are expected to increment to the +// next sequence. +message ErrorReceipt { + option (gogoproto.goproto_getters) = false; + + // the channel upgrade sequence + uint64 sequence = 1; + // the error message detailing the cause of failure + string message = 2; +} diff --git a/proto/ibc/lightclients/wasm/v1/query.proto b/proto/ibc/lightclients/wasm/v1/query.proto index bc6650a1de2..bbbed29dda1 100644 --- a/proto/ibc/lightclients/wasm/v1/query.proto +++ b/proto/ibc/lightclients/wasm/v1/query.proto @@ -13,7 +13,7 @@ service Query { option (google.api.http).get = "/ibc/lightclients/wasm/v1/checksums"; } - // Get Wasm code for given code hash + // Get Wasm code for given checksum rpc Code(QueryCodeRequest) returns (QueryCodeResponse) { option (google.api.http).get = "/ibc/lightclients/wasm/v1/checksums/{checksum}/code"; } diff --git a/testing/chain.go b/testing/chain.go index 77580935e57..a9466575a6a 100644 --- a/testing/chain.go +++ b/testing/chain.go @@ -279,9 +279,9 @@ func (chain *TestChain) QueryConsensusStateProof(clientID string) ([]byte, clien consensusHeight := clientState.GetLatestHeight().(clienttypes.Height) consensusKey := host.FullConsensusStateKey(clientID, consensusHeight) - proofConsensus, _ := chain.QueryProof(consensusKey) + consensusProof, _ := chain.QueryProof(consensusKey) - return proofConsensus, consensusHeight + return consensusProof, consensusHeight } // NextBlock sets the last header to the current header and increments the current header to be @@ -344,6 +344,14 @@ func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*abci.ExecTxResult, error) { // ensure the chain has the latest time chain.Coordinator.UpdateTimeForChain(chain) + // increment acc sequence regardless of success or failure tx execution + defer func() { + err := chain.SenderAccount.SetSequence(chain.SenderAccount.GetSequence() + 1) + if err != nil { + panic(err) + } + }() + resp, err := simapp.SignAndDeliver( chain.TB, chain.TxConfig, @@ -370,12 +378,6 @@ func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*abci.ExecTxResult, error) { return txResult, fmt.Errorf("%s/%d: %q", txResult.Codespace, txResult.Code, txResult.Log) } - // increment sequence for successful transaction execution - err = chain.SenderAccount.SetSequence(chain.SenderAccount.GetSequence() + 1) - if err != nil { - return nil, err - } - chain.Coordinator.IncrementTime() return txResult, nil @@ -641,3 +643,10 @@ func (chain *TestChain) GetChannelCapability(portID, channelID string) *capabili func (chain *TestChain) GetTimeoutHeight() clienttypes.Height { return clienttypes.NewHeight(clienttypes.ParseChainID(chain.ChainID), uint64(chain.GetContext().BlockHeight())+100) } + +// DeleteKey deletes the specified key from the ibc store. +func (chain *TestChain) DeleteKey(key []byte) { + storeKey := chain.GetSimApp().GetKey(exported.StoreKey) + kvStore := chain.GetContext().KVStore(storeKey) + kvStore.Delete(key) +} diff --git a/testing/config.go b/testing/config.go index 46dae7899d9..4c1cba8005b 100644 --- a/testing/config.go +++ b/testing/config.go @@ -47,9 +47,10 @@ func NewConnectionConfig() *ConnectionConfig { } type ChannelConfig struct { - PortID string - Version string - Order channeltypes.Order + PortID string + Version string + Order channeltypes.Order + ProposedUpgrade channeltypes.Upgrade } func NewChannelConfig() *ChannelConfig { diff --git a/testing/endpoint.go b/testing/endpoint.go index 76ba78fe77e..66a380faddc 100644 --- a/testing/endpoint.go +++ b/testing/endpoint.go @@ -7,6 +7,8 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" abci "github.com/cometbft/cometbft/abci/types" @@ -230,12 +232,12 @@ func (endpoint *Endpoint) ConnOpenTry() error { err := endpoint.UpdateClient() require.NoError(endpoint.Chain.TB, err) - counterpartyClient, proofClient, proofConsensus, consensusHeight, proofInit, proofHeight := endpoint.QueryConnectionHandshakeProof() + counterpartyClient, clientProof, consensusProof, consensusHeight, initProof, proofHeight := endpoint.QueryConnectionHandshakeProof() msg := connectiontypes.NewMsgConnectionOpenTry( endpoint.ClientID, endpoint.Counterparty.ConnectionID, endpoint.Counterparty.ClientID, counterpartyClient, endpoint.Counterparty.Chain.GetPrefix(), []*connectiontypes.Version{ConnectionVersion}, endpoint.ConnectionConfig.DelayPeriod, - proofInit, proofClient, proofConsensus, + initProof, clientProof, consensusProof, proofHeight, consensusHeight, endpoint.Chain.SenderAccount.GetAddress().String(), ) @@ -257,11 +259,11 @@ func (endpoint *Endpoint) ConnOpenAck() error { err := endpoint.UpdateClient() require.NoError(endpoint.Chain.TB, err) - counterpartyClient, proofClient, proofConsensus, consensusHeight, proofTry, proofHeight := endpoint.QueryConnectionHandshakeProof() + counterpartyClient, clientProof, consensusProof, consensusHeight, tryProof, proofHeight := endpoint.QueryConnectionHandshakeProof() msg := connectiontypes.NewMsgConnectionOpenAck( endpoint.ConnectionID, endpoint.Counterparty.ConnectionID, counterpartyClient, // testing doesn't use flexible selection - proofTry, proofClient, proofConsensus, + tryProof, clientProof, consensusProof, proofHeight, consensusHeight, ConnectionVersion, endpoint.Chain.SenderAccount.GetAddress().String(), @@ -290,28 +292,28 @@ func (endpoint *Endpoint) ConnOpenConfirm() error { // client state, proof of the counterparty consensus state, the consensus state height, proof of // the counterparty connection, and the proof height for all the proofs returned. func (endpoint *Endpoint) QueryConnectionHandshakeProof() ( - clientState exported.ClientState, proofClient, - proofConsensus []byte, consensusHeight clienttypes.Height, - proofConnection []byte, proofHeight clienttypes.Height, + clientState exported.ClientState, clientProof, + consensusProof []byte, consensusHeight clienttypes.Height, + connectioProof []byte, proofHeight clienttypes.Height, ) { // obtain the client state on the counterparty chain clientState = endpoint.Counterparty.Chain.GetClientState(endpoint.Counterparty.ClientID) // query proof for the client state on the counterparty clientKey := host.FullClientStateKey(endpoint.Counterparty.ClientID) - proofClient, proofHeight = endpoint.Counterparty.QueryProof(clientKey) + clientProof, proofHeight = endpoint.Counterparty.QueryProof(clientKey) consensusHeight = clientState.GetLatestHeight().(clienttypes.Height) // query proof for the consensus state on the counterparty consensusKey := host.FullConsensusStateKey(endpoint.Counterparty.ClientID, consensusHeight) - proofConsensus, _ = endpoint.Counterparty.QueryProofAtHeight(consensusKey, proofHeight.GetRevisionHeight()) + consensusProof, _ = endpoint.Counterparty.QueryProofAtHeight(consensusKey, proofHeight.GetRevisionHeight()) // query proof for the connection on the counterparty connectionKey := host.ConnectionKey(endpoint.Counterparty.ConnectionID) - proofConnection, _ = endpoint.Counterparty.QueryProofAtHeight(connectionKey, proofHeight.GetRevisionHeight()) + connectioProof, _ = endpoint.Counterparty.QueryProofAtHeight(connectionKey, proofHeight.GetRevisionHeight()) - return clientState, proofClient, proofConsensus, consensusHeight, proofConnection, proofHeight + return clientState, clientProof, consensusProof, consensusHeight, connectioProof, proofHeight } // ChanOpenInit will construct and execute a MsgChannelOpenInit on the associated endpoint. @@ -333,6 +335,7 @@ func (endpoint *Endpoint) ChanOpenInit() error { // update version to selected app version // NOTE: this update must be performed after SendMsgs() endpoint.ChannelConfig.Version = endpoint.GetChannel().Version + endpoint.Counterparty.ChannelConfig.Version = endpoint.GetChannel().Version return nil } @@ -365,6 +368,7 @@ func (endpoint *Endpoint) ChanOpenTry() error { // update version to selected app version // NOTE: this update must be performed after the endpoint channelID is set endpoint.ChannelConfig.Version = endpoint.GetChannel().Version + endpoint.Counterparty.ChannelConfig.Version = endpoint.GetChannel().Version return nil } @@ -553,19 +557,211 @@ func (endpoint *Endpoint) TimeoutOnClose(packet channeltypes.Packet) error { proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) channelKey := host.ChannelKey(packet.GetDestPort(), packet.GetDestChannel()) - proofClosed, _ := endpoint.Counterparty.QueryProof(channelKey) + closedProof, _ := endpoint.Counterparty.QueryProof(channelKey) nextSeqRecv, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceRecv(endpoint.Counterparty.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) require.True(endpoint.Chain.TB, found) - timeoutOnCloseMsg := channeltypes.NewMsgTimeoutOnClose( + timeoutOnCloseMsg := channeltypes.NewMsgTimeoutOnCloseWithCounterpartyUpgradeSequence( packet, nextSeqRecv, - proof, proofClosed, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(), + proof, closedProof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(), + endpoint.Counterparty.GetChannel().UpgradeSequence, ) return endpoint.Chain.sendMsgs(timeoutOnCloseMsg) } +// QueryChannelUpgradeProof returns all the proofs necessary to execute UpgradeTry/UpgradeAck/UpgradeOpen. +// It returns the proof for the channel on the endpoint's chain, the proof for the upgrade attempt on the +// endpoint's chain, and the height at which the proof was queried. +func (endpoint *Endpoint) QueryChannelUpgradeProof() ([]byte, []byte, clienttypes.Height) { + channelKey := host.ChannelKey(endpoint.ChannelConfig.PortID, endpoint.ChannelID) + channelProof, height := endpoint.QueryProof(channelKey) + + upgradeKey := host.ChannelUpgradeKey(endpoint.ChannelConfig.PortID, endpoint.ChannelID) + upgradeProof, _ := endpoint.QueryProof(upgradeKey) + + return channelProof, upgradeProof, height +} + +// ChanUpgradeInit sends a MsgChannelUpgradeInit on the associated endpoint. +// A default upgrade proposal is used with overrides from the ProposedUpgrade +// in the channel config, and submitted via governance proposal +func (endpoint *Endpoint) ChanUpgradeInit() error { + upgrade := endpoint.GetProposedUpgrade() + + // create upgrade init message via gov proposal and submit the proposal + msg := channeltypes.NewMsgChannelUpgradeInit( + endpoint.ChannelConfig.PortID, + endpoint.ChannelID, + upgrade.Fields, + endpoint.Chain.GetSimApp().IBCKeeper.GetAuthority(), + ) + + proposal, err := govtypesv1.NewMsgSubmitProposal( + []sdk.Msg{msg}, + sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, govtypesv1.DefaultMinDepositTokens)), + endpoint.Chain.SenderAccount.GetAddress().String(), + endpoint.ChannelID, + "upgrade-init", + fmt.Sprintf("gov proposal for initialising channel upgrade: %s", endpoint.ChannelID), + false, + ) + require.NoError(endpoint.Chain.TB, err) + + var proposalID uint64 + res, err := endpoint.Chain.SendMsgs(proposal) + if err != nil { + return err + } + + proposalID, err = ParseProposalIDFromEvents(res.Events) + require.NoError(endpoint.Chain.TB, err) + + return VoteAndCheckProposalStatus(endpoint, proposalID) +} + +// ChanUpgradeTry sends a MsgChannelUpgradeTry on the associated endpoint. +func (endpoint *Endpoint) ChanUpgradeTry() error { + err := endpoint.UpdateClient() + require.NoError(endpoint.Chain.TB, err) + + upgrade := endpoint.GetProposedUpgrade() + channelProof, upgradeProof, height := endpoint.Counterparty.QueryChannelUpgradeProof() + + counterpartyUpgrade, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetUpgrade(endpoint.Counterparty.Chain.GetContext(), endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) + require.True(endpoint.Chain.TB, found) + + if !found { + return fmt.Errorf("could not find upgrade for channel %s", endpoint.ChannelID) + } + + msg := channeltypes.NewMsgChannelUpgradeTry( + endpoint.ChannelConfig.PortID, + endpoint.ChannelID, + upgrade.Fields.ConnectionHops, + counterpartyUpgrade.Fields, + endpoint.Counterparty.GetChannel().UpgradeSequence, + channelProof, + upgradeProof, + height, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + + return endpoint.Chain.sendMsgs(msg) +} + +// ChanUpgradeAck sends a MsgChannelUpgradeAck to the associated endpoint. +func (endpoint *Endpoint) ChanUpgradeAck() error { + err := endpoint.UpdateClient() + require.NoError(endpoint.Chain.TB, err) + + channelProof, upgradeProof, height := endpoint.Counterparty.QueryChannelUpgradeProof() + + counterpartyUpgrade, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetUpgrade(endpoint.Counterparty.Chain.GetContext(), endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) + require.True(endpoint.Chain.TB, found) + + msg := channeltypes.NewMsgChannelUpgradeAck( + endpoint.ChannelConfig.PortID, + endpoint.ChannelID, + counterpartyUpgrade, + channelProof, + upgradeProof, + height, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + + return endpoint.Chain.sendMsgs(msg) +} + +// ChanUpgradeConfirm sends a MsgChannelUpgradeConfirm to the associated endpoint. +func (endpoint *Endpoint) ChanUpgradeConfirm() error { + err := endpoint.UpdateClient() + require.NoError(endpoint.Chain.TB, err) + + channelProof, upgradeProof, height := endpoint.Counterparty.QueryChannelUpgradeProof() + + counterpartyUpgrade, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetUpgrade(endpoint.Counterparty.Chain.GetContext(), endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) + require.True(endpoint.Chain.TB, found) + + msg := channeltypes.NewMsgChannelUpgradeConfirm( + endpoint.ChannelConfig.PortID, + endpoint.ChannelID, + endpoint.Counterparty.GetChannel().State, + counterpartyUpgrade, + channelProof, + upgradeProof, + height, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + + return endpoint.Chain.sendMsgs(msg) +} + +// ChanUpgradeOpen sends a MsgChannelUpgradeOpen to the associated endpoint. +func (endpoint *Endpoint) ChanUpgradeOpen() error { + err := endpoint.UpdateClient() + require.NoError(endpoint.Chain.TB, err) + + channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) + channelProof, height := endpoint.Counterparty.QueryProof(channelKey) + + msg := channeltypes.NewMsgChannelUpgradeOpen( + endpoint.ChannelConfig.PortID, + endpoint.ChannelID, + endpoint.Counterparty.GetChannel().State, + endpoint.Counterparty.GetChannel().UpgradeSequence, + channelProof, + height, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + + return endpoint.Chain.sendMsgs(msg) +} + +// ChanUpgradeTimeout sends a MsgChannelUpgradeTimeout to the associated endpoint. +func (endpoint *Endpoint) ChanUpgradeTimeout() error { + err := endpoint.UpdateClient() + require.NoError(endpoint.Chain.TB, err) + + channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) + channelProof, height := endpoint.Counterparty.Chain.QueryProof(channelKey) + + msg := channeltypes.NewMsgChannelUpgradeTimeout( + endpoint.ChannelConfig.PortID, + endpoint.ChannelID, + endpoint.Counterparty.GetChannel(), + channelProof, + height, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + + return endpoint.Chain.sendMsgs(msg) +} + +// ChanUpgradeCancel sends a MsgChannelUpgradeCancel to the associated endpoint. +func (endpoint *Endpoint) ChanUpgradeCancel() error { + err := endpoint.UpdateClient() + require.NoError(endpoint.Chain.TB, err) + + errorReceiptKey := host.ChannelUpgradeErrorKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) + proofErrorReceipt, height := endpoint.Counterparty.Chain.QueryProof(errorReceiptKey) + + errorReceipt, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetUpgradeErrorReceipt(endpoint.Counterparty.Chain.GetContext(), endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) + require.True(endpoint.Chain.TB, found) + + msg := channeltypes.NewMsgChannelUpgradeCancel( + endpoint.ChannelConfig.PortID, + endpoint.ChannelID, + errorReceipt, + proofErrorReceipt, + height, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + + return endpoint.Chain.sendMsgs(msg) +} + // SetChannelState sets a channel state func (endpoint *Endpoint) SetChannelState(state channeltypes.State) error { channel := endpoint.GetChannel() @@ -631,6 +827,25 @@ func (endpoint *Endpoint) SetChannel(channel channeltypes.Channel) { endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SetChannel(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, channel) } +// GetChannelUpgrade retrieves an IBC Channel Upgrade for the endpoint. The upgrade +// is expected to exist otherwise testing will fail. +func (endpoint *Endpoint) GetChannelUpgrade() channeltypes.Upgrade { + upgrade, found := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetUpgrade(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) + require.True(endpoint.Chain.TB, found) + + return upgrade +} + +// SetChannelUpgrade sets the channel upgrade for this endpoint. +func (endpoint *Endpoint) SetChannelUpgrade(upgrade channeltypes.Upgrade) { + endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SetUpgrade(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, upgrade) +} + +// SetChannelCounterpartyUpgrade sets the channel counterparty upgrade for this endpoint. +func (endpoint *Endpoint) SetChannelCounterpartyUpgrade(upgrade channeltypes.Upgrade) { + endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SetCounterpartyUpgrade(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, upgrade) +} + // QueryClientStateProof performs and abci query for a client stat associated // with this endpoint and returns the ClientState along with the proof. func (endpoint *Endpoint) QueryClientStateProof() (exported.ClientState, []byte) { @@ -638,7 +853,44 @@ func (endpoint *Endpoint) QueryClientStateProof() (exported.ClientState, []byte) clientState := endpoint.GetClientState() clientKey := host.FullClientStateKey(endpoint.ClientID) - proofClient, _ := endpoint.QueryProof(clientKey) + clientProof, _ := endpoint.QueryProof(clientKey) + + return clientState, clientProof +} + +// GetProposedUpgrade returns a valid upgrade which can be used for UpgradeInit and UpgradeTry. +// By default, the endpoint's existing channel fields will be used for the upgrade fields and +// a sane default timeout will be used by querying the counterparty's latest height. +// If any non-empty values are specified in the ChannelConfig's ProposedUpgrade, +// those values will be used in the returned upgrade. +func (endpoint *Endpoint) GetProposedUpgrade() channeltypes.Upgrade { + // create a default upgrade + upgrade := channeltypes.Upgrade{ + Fields: channeltypes.UpgradeFields{ + Ordering: endpoint.ChannelConfig.Order, + ConnectionHops: []string{endpoint.ConnectionID}, + Version: endpoint.ChannelConfig.Version, + }, + Timeout: channeltypes.NewTimeout(endpoint.Counterparty.Chain.GetTimeoutHeight(), 0), + NextSequenceSend: 0, + } + + override := endpoint.ChannelConfig.ProposedUpgrade + if override.Timeout.IsValid() { + upgrade.Timeout = override.Timeout + } + + if override.Fields.Ordering != channeltypes.NONE { + upgrade.Fields.Ordering = override.Fields.Ordering + } + + if override.Fields.Version != "" { + upgrade.Fields.Version = override.Fields.Version + } + + if len(override.Fields.ConnectionHops) != 0 { + upgrade.Fields.ConnectionHops = override.Fields.ConnectionHops + } - return clientState, proofClient + return upgrade } diff --git a/testing/events.go b/testing/events.go index 9ccfaea96fa..b26b970659e 100644 --- a/testing/events.go +++ b/testing/events.go @@ -135,6 +135,19 @@ func ParseAckFromEvents(events []abci.Event) ([]byte, error) { return nil, fmt.Errorf("acknowledgement event attribute not found") } +// ParseProposalIDFromEvents parses events emitted from MsgSubmitProposal and returns proposalID +func ParseProposalIDFromEvents(events []abci.Event) (uint64, error) { + for _, event := range events { + for _, attribute := range event.Attributes { + if attribute.Key == "proposal_id" { + return strconv.ParseUint(attribute.Value, 10, 64) + } + } + } + + return 0, fmt.Errorf("proposalID event attribute not found") +} + // AssertEventsLegacy asserts that expected events are present in the actual events. // Expected map needs to be a subset of actual events to pass. func AssertEventsLegacy( diff --git a/testing/mock/consensus_host.go b/testing/mock/consensus_host.go new file mode 100644 index 00000000000..4ce25373a53 --- /dev/null +++ b/testing/mock/consensus_host.go @@ -0,0 +1,31 @@ +package mock + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v8/modules/core/exported" +) + +var _ clienttypes.ConsensusHost = (*ConsensusHost)(nil) + +type ConsensusHost struct { + GetSelfConsensusStateFn func(ctx sdk.Context, height exported.Height) (exported.ConsensusState, error) + ValidateSelfClientFn func(ctx sdk.Context, clientState exported.ClientState) error +} + +func (cv *ConsensusHost) GetSelfConsensusState(ctx sdk.Context, height exported.Height) (exported.ConsensusState, error) { + if cv.GetSelfConsensusStateFn == nil { + return nil, nil + } + + return cv.GetSelfConsensusStateFn(ctx, height) +} + +func (cv *ConsensusHost) ValidateSelfClient(ctx sdk.Context, clientState exported.ClientState) error { + if cv.ValidateSelfClientFn == nil { + return nil + } + + return cv.ValidateSelfClientFn(ctx, clientState) +} diff --git a/testing/mock/events.go b/testing/mock/events.go new file mode 100644 index 00000000000..124705962a5 --- /dev/null +++ b/testing/mock/events.go @@ -0,0 +1,40 @@ +package mock + +import sdk "github.com/cosmos/cosmos-sdk/types" + +const ( + MockEventType = "mock-event-type" + MockEventTypeRecvPacket = "mock-recv-packet" + MockEventTypeAckPacket = "mock-ack-packet" + MockEventTypeTimeoutPacket = "mock-timeout" + + MockAttributeKey1 = "mock-attribute-key-1" + MockAttributeKey2 = "mock-attribute-key-2" + + MockAttributeValue1 = "mock-attribute-value-1" + MockAttributeValue2 = "mock-attribute-value-2" +) + +// NewMockRecvPacketEvent returns a mock receive packet event +func NewMockRecvPacketEvent() sdk.Event { + return newMockEvent(MockEventTypeRecvPacket) +} + +// NewMockAckPacketEvent returns a mock acknowledgement packet event +func NewMockAckPacketEvent() sdk.Event { + return newMockEvent(MockEventTypeAckPacket) +} + +// NewMockTimeoutPacketEvent emits a mock timeout packet event +func NewMockTimeoutPacketEvent() sdk.Event { + return newMockEvent(MockEventTypeTimeoutPacket) +} + +// emitMockEvent returns a mock event with the given event type +func newMockEvent(eventType string) sdk.Event { + return sdk.NewEvent( + eventType, + sdk.NewAttribute(MockAttributeKey1, MockAttributeValue1), + sdk.NewAttribute(MockAttributeKey2, MockAttributeValue2), + ) +} diff --git a/testing/mock/ibc_app.go b/testing/mock/ibc_app.go index 72b6d4da100..026a5d0873d 100644 --- a/testing/mock/ibc_app.go +++ b/testing/mock/ibc_app.go @@ -85,6 +85,38 @@ type IBCApp struct { packet channeltypes.Packet, relayer sdk.AccAddress, ) error + + OnChanUpgradeInit func( + ctx sdk.Context, + portID, channelID string, + order channeltypes.Order, + connectionHops []string, + version string, + ) (string, error) + + OnChanUpgradeTry func( + ctx sdk.Context, + portID, channelID string, + order channeltypes.Order, + connectionHops []string, + counterpartyVersion string, + ) (string, error) + + OnChanUpgradeAck func( + ctx sdk.Context, + portID, + channelID, + counterpartyVersion string, + ) error + + OnChanUpgradeOpen func( + ctx sdk.Context, + portID, + channelID string, + order channeltypes.Order, + connectionHops []string, + version string, + ) } // NewIBCApp returns a IBCApp. An empty PortID indicates the mock app doesn't bind/claim ports. diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index 5a01fa2cb47..b3bd2432de3 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -19,6 +19,7 @@ import ( var ( _ porttypes.IBCModule = (*IBCModule)(nil) _ porttypes.PacketDataUnmarshaler = (*IBCModule)(nil) + _ porttypes.UpgradableModule = (*IBCModule)(nil) ) // applicationCallbackError is a custom error type that will be unique for testing purposes. @@ -135,6 +136,8 @@ func (im IBCModule) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, re panic(err) } + ctx.EventManager().EmitEvent(NewMockRecvPacketEvent()) + if bytes.Equal(MockPacketData, packet.GetData()) { return MockAcknowledgement } else if bytes.Equal(MockAsyncPacketData, packet.GetData()) { @@ -157,6 +160,8 @@ func (im IBCModule) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes panic(err) } + ctx.EventManager().EmitEvent(NewMockAckPacketEvent()) + return nil } @@ -173,9 +178,45 @@ func (im IBCModule) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, panic(err) } + ctx.EventManager().EmitEvent(NewMockTimeoutPacketEvent()) + return nil } +// OnChanUpgradeInit implements the IBCModule interface +func (im IBCModule) OnChanUpgradeInit(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) (string, error) { + if im.IBCApp.OnChanUpgradeInit != nil { + return im.IBCApp.OnChanUpgradeInit(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion) + } + + return proposedVersion, nil +} + +// OnChanUpgradeTry implements the IBCModule interface +func (im IBCModule) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, counterpartyVersion string) (string, error) { + if im.IBCApp.OnChanUpgradeTry != nil { + return im.IBCApp.OnChanUpgradeTry(ctx, portID, channelID, proposedOrder, proposedConnectionHops, counterpartyVersion) + } + + return counterpartyVersion, nil +} + +// OnChanUpgradeAck implements the IBCModule interface +func (im IBCModule) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { + if im.IBCApp.OnChanUpgradeAck != nil { + return im.IBCApp.OnChanUpgradeAck(ctx, portID, channelID, counterpartyVersion) + } + + return nil +} + +// OnChanUpgradeOpen implements the IBCModule interface +func (im IBCModule) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) { + if im.IBCApp.OnChanUpgradeOpen != nil { + im.IBCApp.OnChanUpgradeOpen(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion) + } +} + // UnmarshalPacketData returns the MockPacketData. This function implements the optional // PacketDataUnmarshaler interface required for ADR 008 support. func (IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { diff --git a/testing/mock/middleware.go b/testing/mock/middleware.go new file mode 100644 index 00000000000..954132d0cff --- /dev/null +++ b/testing/mock/middleware.go @@ -0,0 +1,197 @@ +package mock + +import ( + "bytes" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + + capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + "github.com/cosmos/ibc-go/v8/modules/core/exported" +) + +const ( + MockBlockUpgrade = "mockblockupgrade" +) + +var _ porttypes.Middleware = (*BlockUpgradeMiddleware)(nil) + +// BlockUpgradeMiddleware does not implement the UpgradeableModule interface +type BlockUpgradeMiddleware struct { + appModule *AppModule + IBCApp *IBCApp // base application of an IBC middleware stack +} + +// NewIBCModule creates a new IBCModule given the underlying mock IBC application and scopedKeeper. +func NewBlockUpgradeMiddleware(appModule *AppModule, app *IBCApp) BlockUpgradeMiddleware { + appModule.ibcApps = append(appModule.ibcApps, app) + return BlockUpgradeMiddleware{ + appModule: appModule, + IBCApp: app, + } +} + +// OnChanOpenInit implements the IBCModule interface. +func (im BlockUpgradeMiddleware) OnChanOpenInit( + ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, + channelID string, chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, +) (string, error) { + if strings.TrimSpace(version) == "" { + version = Version + } + + if im.IBCApp.OnChanOpenInit != nil { + return im.IBCApp.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version) + } + + if chanCap != nil { + // Claim channel capability passed back by IBC module + if err := im.IBCApp.ScopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + return "", err + } + } + + return version, nil +} + +// OnChanOpenTry implements the IBCModule interface. +func (im BlockUpgradeMiddleware) OnChanOpenTry( + ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, + channelID string, chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, counterpartyVersion string, +) (version string, err error) { + if im.IBCApp.OnChanOpenTry != nil { + return im.IBCApp.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, counterpartyVersion) + } + + if chanCap != nil { + // Claim channel capability passed back by IBC module + if err := im.IBCApp.ScopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + return "", err + } + } + + return Version, nil +} + +// OnChanOpenAck implements the IBCModule interface. +func (im BlockUpgradeMiddleware) OnChanOpenAck(ctx sdk.Context, portID string, channelID string, counterpartyChannelID string, counterpartyVersion string) error { + if im.IBCApp.OnChanOpenAck != nil { + return im.IBCApp.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) + } + + return nil +} + +// OnChanOpenConfirm implements the IBCModule interface. +func (im BlockUpgradeMiddleware) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string) error { + if im.IBCApp.OnChanOpenConfirm != nil { + return im.IBCApp.OnChanOpenConfirm(ctx, portID, channelID) + } + + return nil +} + +// OnChanCloseInit implements the IBCModule interface. +func (im BlockUpgradeMiddleware) OnChanCloseInit(ctx sdk.Context, portID, channelID string) error { + if im.IBCApp.OnChanCloseInit != nil { + return im.IBCApp.OnChanCloseInit(ctx, portID, channelID) + } + + return nil +} + +// OnChanCloseConfirm implements the IBCModule interface. +func (im BlockUpgradeMiddleware) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string) error { + if im.IBCApp.OnChanCloseConfirm != nil { + return im.IBCApp.OnChanCloseConfirm(ctx, portID, channelID) + } + + return nil +} + +// OnRecvPacket implements the IBCModule interface. +func (im BlockUpgradeMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) exported.Acknowledgement { + if im.IBCApp.OnRecvPacket != nil { + return im.IBCApp.OnRecvPacket(ctx, packet, relayer) + } + + // set state by claiming capability to check if revert happens return + capName := GetMockRecvCanaryCapabilityName(packet) + if _, err := im.IBCApp.ScopedKeeper.NewCapability(ctx, capName); err != nil { + // application callback called twice on same packet sequence + // must never occur + panic(err) + } + + if bytes.Equal(MockPacketData, packet.GetData()) { + return MockAcknowledgement + } else if bytes.Equal(MockAsyncPacketData, packet.GetData()) { + return nil + } + + return MockFailAcknowledgement +} + +// OnAcknowledgementPacket implements the IBCModule interface. +func (im BlockUpgradeMiddleware) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte, relayer sdk.AccAddress) error { + if im.IBCApp.OnAcknowledgementPacket != nil { + return im.IBCApp.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) + } + + capName := GetMockAckCanaryCapabilityName(packet) + if _, err := im.IBCApp.ScopedKeeper.NewCapability(ctx, capName); err != nil { + // application callback called twice on same packet sequence + // must never occur + panic(err) + } + + return nil +} + +// OnTimeoutPacket implements the IBCModule interface. +func (im BlockUpgradeMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) error { + if im.IBCApp.OnTimeoutPacket != nil { + return im.IBCApp.OnTimeoutPacket(ctx, packet, relayer) + } + + capName := GetMockTimeoutCanaryCapabilityName(packet) + if _, err := im.IBCApp.ScopedKeeper.NewCapability(ctx, capName); err != nil { + // application callback called twice on same packet sequence + // must never occur + panic(err) + } + + return nil +} + +// SendPacket implements the ICS4 Wrapper interface +func (BlockUpgradeMiddleware) SendPacket( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + sourcePort string, + sourceChannel string, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + data []byte, +) (uint64, error) { + return 0, nil +} + +// WriteAcknowledgement implements the ICS4 Wrapper interface +func (BlockUpgradeMiddleware) WriteAcknowledgement( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + packet exported.PacketI, + ack exported.Acknowledgement, +) error { + return nil +} + +// GetAppVersion returns the application version of the underlying application +func (BlockUpgradeMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { + return Version, true +} diff --git a/testing/mock/mock.go b/testing/mock/mock.go index 96da67a25c7..1d90491f43e 100644 --- a/testing/mock/mock.go +++ b/testing/mock/mock.go @@ -43,11 +43,17 @@ var ( MockRecvCanaryCapabilityName = "mock receive canary capability name" MockAckCanaryCapabilityName = "mock acknowledgement canary capability name" MockTimeoutCanaryCapabilityName = "mock timeout canary capability name" + UpgradeVersion = fmt.Sprintf("%s-v2", Version) // MockApplicationCallbackError should be returned when an application callback should fail. It is possible to // test that this error was returned using ErrorIs. MockApplicationCallbackError error = &applicationCallbackError{} ) +var ( + TestKey = []byte("test-key") + TestValue = []byte("test-value") +) + var ( _ module.AppModuleBasic = (*AppModuleBasic)(nil) _ appmodule.AppModule = (*AppModule)(nil) diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 754353c6ba2..da2b35cc60c 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -214,6 +214,7 @@ type SimApp struct { // make IBC modules public for test purposes // these modules are never directly routed to by the IBC Router + IBCMockModule ibcmock.IBCModule ICAAuthModule ibcmock.IBCModule FeeMockModule ibcmock.IBCModule @@ -340,6 +341,7 @@ func NewSimApp( // NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do // not replicate if you do not need to test core IBC or light clients. scopedIBCMockKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.ModuleName) + scopedIBCMockBlockUpgradeKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.MockBlockUpgrade) scopedFeeMockKeeper := app.CapabilityKeeper.ScopeToModule(MockFeePort) scopedICAMockKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.ModuleName + icacontrollertypes.SubModuleName) @@ -456,10 +458,11 @@ func NewSimApp( app.ICAHostKeeper = icahostkeeper.NewKeeper( appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), app.IBCFeeKeeper, // use ics29 fee as ics4Wrapper in middleware stack - app.IBCKeeper.ChannelKeeper, app.IBCKeeper.PortKeeper, - app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), + app.IBCKeeper.ChannelKeeper, app.IBCKeeper.PortKeeper, app.AccountKeeper, + scopedICAHostKeeper, app.MsgServiceRouter(), authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) + app.ICAHostKeeper.WithQueryRouter(app.GRPCQueryRouter()) // Create IBC Router ibcRouter := porttypes.NewRouter() @@ -485,8 +488,16 @@ func NewSimApp( // The mock module is used for testing IBC mockIBCModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp(ibcmock.ModuleName, scopedIBCMockKeeper)) + app.IBCMockModule = mockIBCModule ibcRouter.AddRoute(ibcmock.ModuleName, mockIBCModule) + // Mock IBC app wrapped with a middleware which does not implement the UpgradeableModule interface. + // NOTE: this is used to test integration with apps which do not yet fulfill the UpgradeableModule interface and error when + // an upgrade is tried on the channel. + mockBlockUpgradeIBCModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp(ibcmock.MockBlockUpgrade, scopedIBCMockBlockUpgradeKeeper)) + mockBlockUpgradeMw := ibcmock.NewBlockUpgradeMiddleware(&mockModule, mockBlockUpgradeIBCModule.IBCApp) + ibcRouter.AddRoute(ibcmock.MockBlockUpgrade, mockBlockUpgradeMw) + // Create Transfer Stack // SendPacket, since it is originating from the application to core IBC: // transferKeeper.SendPacket -> fee.SendPacket -> channel.SendPacket diff --git a/testing/simapp/upgrades.go b/testing/simapp/upgrades.go index 81b4902da4c..58139ee6271 100644 --- a/testing/simapp/upgrades.go +++ b/testing/simapp/upgrades.go @@ -55,7 +55,15 @@ func (app *SimApp) registerUpgradeHandlers() { app.UpgradeKeeper.SetUpgradeHandler( upgrades.V8, - upgrades.CreateV8UpgradeHandler( + upgrades.CreateDefaultUpgradeHandler( + app.ModuleManager, + app.configurator, + ), + ) + + app.UpgradeKeeper.SetUpgradeHandler( + upgrades.V8_1, + upgrades.CreateDefaultUpgradeHandler( app.ModuleManager, app.configurator, ), diff --git a/testing/simapp/upgrades/upgrades.go b/testing/simapp/upgrades/upgrades.go index ff9b6579560..03ddbb75502 100644 --- a/testing/simapp/upgrades/upgrades.go +++ b/testing/simapp/upgrades/upgrades.go @@ -32,6 +32,8 @@ const ( V7_1 = "v7.1" // V8 defines the upgrade name for the ibc-go/v8 upgrade handler. V8 = "v8" + // V8_1 defines the upgrade name for the ibc-go/v8.1 upgrade handler. + V8_1 = "v8.1" ) // CreateDefaultUpgradeHandler creates an upgrade handler which can be used for regular upgrade tests @@ -107,10 +109,3 @@ func CreateV7LocalhostUpgradeHandler( return mm.RunMigrations(ctx, configurator, vm) } } - -// CreateV8UpgradeHandler creates an upgrade handler for the ibc-go/v8 SimApp upgrade. -func CreateV8UpgradeHandler(mm *module.Manager, configurator module.Configurator) upgradetypes.UpgradeHandler { - return func(ctx context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { - return mm.RunMigrations(ctx, configurator, vm) - } -} diff --git a/testing/solomachine.go b/testing/solomachine.go index 2293f285bec..72b05f7c407 100644 --- a/testing/solomachine.go +++ b/testing/solomachine.go @@ -286,18 +286,18 @@ func (solo *Solomachine) ConnOpenInit(chain *TestChain, clientID string) string // ConnOpenAck performs the connection open ack handshake step on the tendermint chain for the associated // solo machine client. func (solo *Solomachine) ConnOpenAck(chain *TestChain, clientID, connectionID string) { - proofTry := solo.GenerateConnOpenTryProof(clientID, connectionID) + tryProof := solo.GenerateConnOpenTryProof(clientID, connectionID) clientState := ibctm.NewClientState(chain.ChainID, DefaultTrustLevel, TrustingPeriod, UnbondingPeriod, MaxClockDrift, chain.LastHeader.GetHeight().(clienttypes.Height), commitmenttypes.GetSDKSpecs(), UpgradePath) - proofClient := solo.GenerateClientStateProof(clientState) + clientProof := solo.GenerateClientStateProof(clientState) consensusState := chain.LastHeader.ConsensusState() consensusHeight := chain.LastHeader.GetHeight() - proofConsensus := solo.GenerateConsensusStateProof(consensusState, consensusHeight) + consensusProof := solo.GenerateConsensusStateProof(consensusState, consensusHeight) msgConnOpenAck := connectiontypes.NewMsgConnectionOpenAck( connectionID, connectionIDSolomachine, clientState, - proofTry, proofClient, proofConsensus, + tryProof, clientProof, consensusProof, clienttypes.ZeroHeight(), clientState.GetLatestHeight().(clienttypes.Height), ConnectionVersion, chain.SenderAccount.GetAddress().String(), @@ -332,13 +332,13 @@ func (solo *Solomachine) ChanOpenInit(chain *TestChain, connectionID string) str // ChanOpenAck performs the channel open ack handshake step on the tendermint chain for the associated // solo machine client. func (solo *Solomachine) ChanOpenAck(chain *TestChain, channelID string) { - proofTry := solo.GenerateChanOpenTryProof(transfertypes.PortID, transfertypes.Version, channelID) + tryProof := solo.GenerateChanOpenTryProof(transfertypes.PortID, transfertypes.Version, channelID) msgChanOpenAck := channeltypes.NewMsgChannelOpenAck( transfertypes.PortID, channelID, channelIDSolomachine, transfertypes.Version, - proofTry, + tryProof, clienttypes.ZeroHeight(), chain.SenderAccount.GetAddress().String(), ) @@ -351,11 +351,11 @@ func (solo *Solomachine) ChanOpenAck(chain *TestChain, channelID string) { // ChanCloseConfirm performs the channel close confirm handshake step on the tendermint chain for the associated // solo machine client. func (solo *Solomachine) ChanCloseConfirm(chain *TestChain, portID, channelID string) { - proofInit := solo.GenerateChanClosedProof(portID, transfertypes.Version, channelID) + initProof := solo.GenerateChanClosedProof(portID, transfertypes.Version, channelID) msgChanCloseConfirm := channeltypes.NewMsgChannelCloseConfirm( portID, channelID, - proofInit, + initProof, clienttypes.ZeroHeight(), chain.SenderAccount.GetAddress().String(), ) @@ -408,11 +408,11 @@ func (solo *Solomachine) RecvPacket(chain *TestChain, packet channeltypes.Packet // AcknowledgePacket creates an acknowledgement proof and broadcasts a MsgAcknowledgement. func (solo *Solomachine) AcknowledgePacket(chain *TestChain, packet channeltypes.Packet) { - proofAck := solo.GenerateAcknowledgementProof(packet) + ackProof := solo.GenerateAcknowledgementProof(packet) transferAck := channeltypes.NewResultAcknowledgement([]byte{byte(1)}).Acknowledgement() msgAcknowledgement := channeltypes.NewMsgAcknowledgement( packet, transferAck, - proofAck, + ackProof, clienttypes.ZeroHeight(), chain.SenderAccount.GetAddress().String(), ) @@ -424,11 +424,11 @@ func (solo *Solomachine) AcknowledgePacket(chain *TestChain, packet channeltypes // TimeoutPacket creates a unreceived packet proof and broadcasts a MsgTimeout. func (solo *Solomachine) TimeoutPacket(chain *TestChain, packet channeltypes.Packet) { - proofUnreceived := solo.GenerateReceiptAbsenceProof(packet) + unreceivedProof := solo.GenerateReceiptAbsenceProof(packet) msgTimeout := channeltypes.NewMsgTimeout( packet, 1, // nextSequenceRecv is unused for UNORDERED channels - proofUnreceived, + unreceivedProof, clienttypes.ZeroHeight(), chain.SenderAccount.GetAddress().String(), ) @@ -440,13 +440,13 @@ func (solo *Solomachine) TimeoutPacket(chain *TestChain, packet channeltypes.Pac // TimeoutPacket creates a channel closed and unreceived packet proof and broadcasts a MsgTimeoutOnClose. func (solo *Solomachine) TimeoutPacketOnClose(chain *TestChain, packet channeltypes.Packet, channelID string) { - proofClosed := solo.GenerateChanClosedProof(transfertypes.PortID, transfertypes.Version, channelID) - proofUnreceived := solo.GenerateReceiptAbsenceProof(packet) + closedProof := solo.GenerateChanClosedProof(transfertypes.PortID, transfertypes.Version, channelID) + unreceivedProof := solo.GenerateReceiptAbsenceProof(packet) msgTimeout := channeltypes.NewMsgTimeoutOnClose( packet, 1, // nextSequenceRecv is unused for UNORDERED channels - proofUnreceived, - proofClosed, + unreceivedProof, + closedProof, clienttypes.ZeroHeight(), chain.SenderAccount.GetAddress().String(), ) diff --git a/testing/utils.go b/testing/utils.go index a1178929e3f..907dae0f0e7 100644 --- a/testing/utils.go +++ b/testing/utils.go @@ -1,11 +1,14 @@ package ibctesting import ( + "fmt" "math/rand" "testing" "github.com/stretchr/testify/require" + govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + abci "github.com/cometbft/cometbft/abci/types" tmtypes "github.com/cometbft/cometbft/types" ) @@ -25,6 +28,29 @@ func ApplyValSetChanges(tb testing.TB, valSet *tmtypes.ValidatorSet, valUpdates return newVals } +// VoteAndCheckProposalStatus votes on a gov proposal, checks if the proposal has passed, and returns an error if it has not with the failure reason. +func VoteAndCheckProposalStatus(endpoint *Endpoint, proposalID uint64) error { + // vote on proposal + ctx := endpoint.Chain.GetContext() + require.NoError(endpoint.Chain.TB, endpoint.Chain.GetSimApp().GovKeeper.AddVote(ctx, proposalID, endpoint.Chain.SenderAccount.GetAddress(), govtypesv1.NewNonSplitVoteOption(govtypesv1.OptionYes), "")) + + // fast forward the chain context to end the voting period + params, err := endpoint.Chain.GetSimApp().GovKeeper.Params.Get(ctx) + require.NoError(endpoint.Chain.TB, err) + + endpoint.Chain.Coordinator.IncrementTimeBy(*params.VotingPeriod + *params.MaxDepositPeriod) + endpoint.Chain.NextBlock() + + // check if proposal passed or failed on msg execution + // we need to grab the context again since the previous context is no longer valid as the chain header time has been incremented + p, err := endpoint.Chain.GetSimApp().GovKeeper.Proposals.Get(endpoint.Chain.GetContext(), proposalID) + require.NoError(endpoint.Chain.TB, err) + if p.Status != govtypesv1.StatusPassed { + return fmt.Errorf("proposal failed: %s", p.FailedReason) + } + return nil +} + // GenerateString generates a random string of the given length in bytes func GenerateString(length uint) string { bytes := make([]byte, length)