From f57170b1d4dd202a3c6c1c61dcf302b6a9546405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 8 Aug 2022 18:38:29 +0200 Subject: [PATCH] 02-client refactor (#1871) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: Remove GetClientID() From Misbehaviour Interface (#897) * chore: remove GetClientID() from Misbehaviour interface * chore: changed too much * chore: fix test and add changelog entry Co-authored-by: Shake Shack * chore: add 668 functions to localhost client (#908) * chore: rename 06-solomachine type Misbehaviour to DuplicateSignatures (#1093) * updating protos and codegen * renaming solomachine Mishaviour to DuplicateSignatureHeader * renaming DuplicateSignatureHeader to DuplicateSignatures * updating changelog and godocs as per review * chore: reverting renaming of Misbehaviour (#1099) * remove GetClientID from 07-tendermint misbehaviour (#1097) * remove GetClientID from 07-tendermint misbehaviour and deprecate the ClientId field in 07-tendermint Misbehaviour * add changelog entry Co-authored-by: Damian Nolan * chore: remove GetClientID from 06-solomachine type Misbehaviour (#1100) * reverting renaming of Misbehaviour * removing client id from 06-solomachine type Misbehaviour * adding changelog * client-02 update to latest from main (#1106) * refactor: allow the mock module to be used multiple times as base ibc application in middleware stack (#892) ## Description Currently the `AppModule` assumes a single scoped keeper. This doesn't allow the mock module to be used as a base application for different middleware stack (ica stack, fee stack, etc) I broke the API because I think it is cleaner. If we want this to be non API breaking, I can try to readjust ref: #891 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * feat: adding Pack/Unpack acknowledgement helper fns (#895) * feat: adding Pack/Unpack acknowledgement helper fns * chore: changelog * fix: docs * Update modules/core/04-channel/types/codec.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * imp: support custom keys for testing (#893) * chore: add ParsePacketFromEvents testing helper function (#904) ## Description ref: #891 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * fix: correctly claim capability for mock module, handle genesis exports (#921) ## Description This contains two fixes: - the capability being claimed by the scoped keeper was incorrect (mock.ModuleName -> port ID) - the mock module wasn't accounting for non empty genesis state in capabilities (after genesis export, capability will create the bound ports so rebinding doesn't need to happen) closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * docs: update migration docs for upgrade proposal in relation to ICS27 (#920) ## Description closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * chore(ica): add trail of bits audit report (#903) * chore(ica): add trail of bits audit report * relocate the audit report for ICA Co-authored-by: Carlos Rodriguez * testing: adding multiple sender accounts for testing purposes (#935) * testing: adding multiple sender accounts for testing puproses * fix genesis setup (#936) * Update testing/chain.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * refactor: code hygiene * Update testing/chain.go Co-authored-by: Aditya * fix: setting totalySupply to empty * nit: CamelCase not UPPERCASE Co-authored-by: Aditya Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Create test chain with multiple validators (#942) * testing: adding multiple sender accounts for testing puproses * fix genesis setup (#936) * Update testing/chain.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * refactor: code hygiene * Update testing/chain.go Co-authored-by: Aditya * multi validator commit taken from @saione * add function to pass custom valset * add changelog Co-authored-by: Sean King Co-authored-by: Sean King Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * add changelog entry for SDK bump * fix: classify client states without consensus states as expired (#941) ## Description closes: #850 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * chore: fix broken link (#972) * add backport actions for v1.3.x and v2.1.x (#958) * Revert "feat: adding Pack/Unpack acknowledgement helper fns (#895)" (#973) This reverts commit 843b459635da8cedd92945141c4efe3a762f305d. Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> * chore: update migration docs (#985) * chore: update migration docs * Update docs/migrations/v2-to-v3.md Co-authored-by: Damian Nolan Co-authored-by: Damian Nolan * chore: fix mispelled words (#991) * fix: remove go mod tidy from proto-gen script (#989) * bug: support base denoms with slashes (#978) * bug: support base denoms with slashes * add changelog entry Co-authored-by: Carlos Rodriguez * upgrade ics23 to v0.7 (#948) * upgrade ics23 to v0.7-rc * add changelog entry * update ics23 to final 0.7 Co-authored-by: Carlos Rodriguez * ibctesting: make `testing.T` public (#1020) * add changelog entry for #941 * fix package import (#1007) * feat: Add a function to initialize the ICS27 module via an upgrade proposal (#1037) ## Description closes: #1034 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * docs: add missing args to NewKeeper in integration docs (#1038) ## Description This add some missing arguments to `ibckeeper.NewKeeper` and `ibctransferkeeper.NewKeeper` in integration docs --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [x] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * small fixes for v2 to v3 migration (#1016) * small fixes for v2 to v3 migration * review comment * Update v2-to-v3.md * add store upgrade documentation Co-authored-by: Carlos Rodriguez * add missing slash * build(deps): bump actions/checkout from 2.4.0 to 3 (#1045) Bumps [actions/checkout](https://github.com/actions/checkout) from 2.4.0 to 3.
Release notes

Sourced from actions/checkout's releases.

v3.0.0

  • Update default runtime to node16
Changelog

Sourced from actions/checkout's changelog.

Changelog

v2.3.1

v2.3.0

v2.2.0

v2.1.1

  • Changes to support GHES (here and here)

v2.1.0

v2.0.0

v2 (beta)

  • Improved fetch performance
    • The default behavior now fetches only the SHA being checked-out
  • Script authenticated git commands
    • Persists with.token in the local git config
    • Enables your scripts to run authenticated git commands
    • Post-job cleanup removes the token
    • Coming soon: Opt out by setting with.persist-credentials to false
  • Creates a local branch
    • No longer detached HEAD when checking out a branch
    • A local branch is created with the corresponding upstream branch set
  • Improved layout

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=2.4.0&new-version=3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
* call packet.GetSequence() rather than passing the func as argument (#995) * Add counterpartyChannelID param to IBCModule.OnChanOpenAck (#1086) * add counterpartyChannelID param to IBCModule OnChanOpenAck() * change testing mock * change ica IBCModules ChannelOpenAck * change transfer IBCModules ChannelOpenAck * change core keeper ChannelOpenAck() * CHANGELOG.md * update v2-to-v3 migration doc * Update docs/migrations/v2-to-v3.md Co-authored-by: Carlos Rodriguez Co-authored-by: Carlos Rodriguez * fix mirgation docs (#1091) * fix: handle testing update client errors (#1094) * replace channel keeper with IBC keeper in AnteDecorator (#950) * replace channel keeper with IBC keeper in AnteDecorator and pass message to rpc handler * fix error checking condition * fix for proper way of getting go context * refactor tests for ante handler * review comment * review comments and some fixes * review comments * execute message for update client as well * add migration Co-authored-by: Carlos Rodriguez * add backport rules for v1.4.x and v2.2.x (#1085) * ibctesting: custom voting power reduction for testing (#939) * ibctesting: custom voting power reduction for testing * changelog * fix * make T public * fix * revert changes * fix test Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Carlos Rodriguez Co-authored-by: Carlos Rodriguez Co-authored-by: Aditya Co-authored-by: Tim Lind Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Damian Nolan Co-authored-by: daeMOn Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Joe Bowman Co-authored-by: khanh <50263489+catShaark@users.noreply.github.com> * 02-client: merge misbehavior & header interfaces (#1107) * refactor: allow the mock module to be used multiple times as base ibc application in middleware stack (#892) ## Description Currently the `AppModule` assumes a single scoped keeper. This doesn't allow the mock module to be used as a base application for different middleware stack (ica stack, fee stack, etc) I broke the API because I think it is cleaner. If we want this to be non API breaking, I can try to readjust ref: #891 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * feat: adding Pack/Unpack acknowledgement helper fns (#895) * feat: adding Pack/Unpack acknowledgement helper fns * chore: changelog * fix: docs * Update modules/core/04-channel/types/codec.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * imp: support custom keys for testing (#893) * chore: add ParsePacketFromEvents testing helper function (#904) ## Description ref: #891 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * fix: correctly claim capability for mock module, handle genesis exports (#921) ## Description This contains two fixes: - the capability being claimed by the scoped keeper was incorrect (mock.ModuleName -> port ID) - the mock module wasn't accounting for non empty genesis state in capabilities (after genesis export, capability will create the bound ports so rebinding doesn't need to happen) closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * docs: update migration docs for upgrade proposal in relation to ICS27 (#920) ## Description closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * chore(ica): add trail of bits audit report (#903) * chore(ica): add trail of bits audit report * relocate the audit report for ICA Co-authored-by: Carlos Rodriguez * testing: adding multiple sender accounts for testing purposes (#935) * testing: adding multiple sender accounts for testing puproses * fix genesis setup (#936) * Update testing/chain.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * refactor: code hygiene * Update testing/chain.go Co-authored-by: Aditya * fix: setting totalySupply to empty * nit: CamelCase not UPPERCASE Co-authored-by: Aditya Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Create test chain with multiple validators (#942) * testing: adding multiple sender accounts for testing puproses * fix genesis setup (#936) * Update testing/chain.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * refactor: code hygiene * Update testing/chain.go Co-authored-by: Aditya * multi validator commit taken from @saione * add function to pass custom valset * add changelog Co-authored-by: Sean King Co-authored-by: Sean King Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * add changelog entry for SDK bump * fix: classify client states without consensus states as expired (#941) ## Description closes: #850 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * chore: fix broken link (#972) * add backport actions for v1.3.x and v2.1.x (#958) * Revert "feat: adding Pack/Unpack acknowledgement helper fns (#895)" (#973) This reverts commit 843b459635da8cedd92945141c4efe3a762f305d. Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> * chore: update migration docs (#985) * chore: update migration docs * Update docs/migrations/v2-to-v3.md Co-authored-by: Damian Nolan Co-authored-by: Damian Nolan * chore: fix mispelled words (#991) * fix: remove go mod tidy from proto-gen script (#989) * bug: support base denoms with slashes (#978) * bug: support base denoms with slashes * add changelog entry Co-authored-by: Carlos Rodriguez * upgrade ics23 to v0.7 (#948) * upgrade ics23 to v0.7-rc * add changelog entry * update ics23 to final 0.7 Co-authored-by: Carlos Rodriguez * ibctesting: make `testing.T` public (#1020) * add changelog entry for #941 * fix package import (#1007) * feat: Add a function to initialize the ICS27 module via an upgrade proposal (#1037) ## Description closes: #1034 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * docs: add missing args to NewKeeper in integration docs (#1038) ## Description This add some missing arguments to `ibckeeper.NewKeeper` and `ibctransferkeeper.NewKeeper` in integration docs --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [x] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * small fixes for v2 to v3 migration (#1016) * small fixes for v2 to v3 migration * review comment * Update v2-to-v3.md * add store upgrade documentation Co-authored-by: Carlos Rodriguez * add missing slash * build(deps): bump actions/checkout from 2.4.0 to 3 (#1045) Bumps [actions/checkout](https://github.com/actions/checkout) from 2.4.0 to 3.
Release notes

Sourced from actions/checkout's releases.

v3.0.0

  • Update default runtime to node16
Changelog

Sourced from actions/checkout's changelog.

Changelog

v2.3.1

v2.3.0

v2.2.0

v2.1.1

  • Changes to support GHES (here and here)

v2.1.0

v2.0.0

v2 (beta)

  • Improved fetch performance
    • The default behavior now fetches only the SHA being checked-out
  • Script authenticated git commands
    • Persists with.token in the local git config
    • Enables your scripts to run authenticated git commands
    • Post-job cleanup removes the token
    • Coming soon: Opt out by setting with.persist-credentials to false
  • Creates a local branch
    • No longer detached HEAD when checking out a branch
    • A local branch is created with the corresponding upstream branch set
  • Improved layout

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=2.4.0&new-version=3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
* call packet.GetSequence() rather than passing the func as argument (#995) * Add counterpartyChannelID param to IBCModule.OnChanOpenAck (#1086) * add counterpartyChannelID param to IBCModule OnChanOpenAck() * change testing mock * change ica IBCModules ChannelOpenAck * change transfer IBCModules ChannelOpenAck * change core keeper ChannelOpenAck() * CHANGELOG.md * update v2-to-v3 migration doc * Update docs/migrations/v2-to-v3.md Co-authored-by: Carlos Rodriguez Co-authored-by: Carlos Rodriguez * fix mirgation docs (#1091) * fix: handle testing update client errors (#1094) * replace channel keeper with IBC keeper in AnteDecorator (#950) * replace channel keeper with IBC keeper in AnteDecorator and pass message to rpc handler * fix error checking condition * fix for proper way of getting go context * refactor tests for ante handler * review comment * review comments and some fixes * review comments * execute message for update client as well * add migration Co-authored-by: Carlos Rodriguez * add backport rules for v1.4.x and v2.2.x (#1085) * ibctesting: custom voting power reduction for testing (#939) * ibctesting: custom voting power reduction for testing * changelog * fix * make T public * fix * revert changes * fix test * merging Header & Misbehavior interfaces into ClientMessage & fixing associated 02-client helpers * fix: update related functions * chore: comments * Update modules/core/02-client/types/encoding.go Co-authored-by: Damian Nolan * chore: changelog * chore: comment Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Carlos Rodriguez Co-authored-by: Carlos Rodriguez Co-authored-by: Aditya Co-authored-by: Tim Lind Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Damian Nolan Co-authored-by: daeMOn Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Joe Bowman Co-authored-by: khanh <50263489+catShaark@users.noreply.github.com> * chore: 06-solomachine rename checkHeader to VerifyClientMessage (#1109) * adding VerifyClientMessage and tests * splitting tests for verify header and misbehaviour * cleaning up error handling * adding additional test for old misbehaviour is sucessful * split type switch logic into verifyHeader and verifyMisbehaviour priv funcs * updating godoc for VerifyClientMessage * refactor: modify VerifyUpgradeAndUpdateState to set upgraded client and consensus state (#598) * modify VerifyUpgradeAndUpdateState interface function to remove returned client and consensus state removes the client and consensus state from the return values in VerifyUpgradeAndUpdateState client state interface function Updates light client implementations to set client and consensus state in client store Fixes and updates tests * add changelog entry * add migration docs * use upgraded client to emit height in events * chore: 06-solomachine rename update to UpdateState (#1110) * adding VerifyClientMessage and tests * splitting tests for verify header and misbehaviour * rename update to UpdateState * cleaning up error handling * adding additional test for old misbehaviour is sucessful * split type switch logic into verifyHeader and verifyMisbehaviour priv funcs * adding in place test function for solomachine UpdateState * rename update to UpdateState * adding in place test function for solomachine UpdateState * chore: 06-solomachine adding CheckForMisbehaviour and UpdateStateOnMisbehaviour (#1111) * adding VerifyClientMessage and tests * splitting tests for verify header and misbehaviour * rename update to UpdateState * adding CheckForMisbehaviour and UpdateStateOnMisbehaviour * adding misbehaviour checks * updating CheckForMisbehaviour codestyle and adding basic test cases * chore: 02-client-refactor: merge main into feature branch (#1149) * refactor: allow the mock module to be used multiple times as base ibc application in middleware stack (#892) ## Description Currently the `AppModule` assumes a single scoped keeper. This doesn't allow the mock module to be used as a base application for different middleware stack (ica stack, fee stack, etc) I broke the API because I think it is cleaner. If we want this to be non API breaking, I can try to readjust ref: #891 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * feat: adding Pack/Unpack acknowledgement helper fns (#895) * feat: adding Pack/Unpack acknowledgement helper fns * chore: changelog * fix: docs * Update modules/core/04-channel/types/codec.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * imp: support custom keys for testing (#893) * chore: add ParsePacketFromEvents testing helper function (#904) ## Description ref: #891 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * fix: correctly claim capability for mock module, handle genesis exports (#921) ## Description This contains two fixes: - the capability being claimed by the scoped keeper was incorrect (mock.ModuleName -> port ID) - the mock module wasn't accounting for non empty genesis state in capabilities (after genesis export, capability will create the bound ports so rebinding doesn't need to happen) closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * docs: update migration docs for upgrade proposal in relation to ICS27 (#920) ## Description closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * chore(ica): add trail of bits audit report (#903) * chore(ica): add trail of bits audit report * relocate the audit report for ICA Co-authored-by: Carlos Rodriguez * testing: adding multiple sender accounts for testing purposes (#935) * testing: adding multiple sender accounts for testing puproses * fix genesis setup (#936) * Update testing/chain.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * refactor: code hygiene * Update testing/chain.go Co-authored-by: Aditya * fix: setting totalySupply to empty * nit: CamelCase not UPPERCASE Co-authored-by: Aditya Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Create test chain with multiple validators (#942) * testing: adding multiple sender accounts for testing puproses * fix genesis setup (#936) * Update testing/chain.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * refactor: code hygiene * Update testing/chain.go Co-authored-by: Aditya * multi validator commit taken from @saione * add function to pass custom valset * add changelog Co-authored-by: Sean King Co-authored-by: Sean King Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * add changelog entry for SDK bump * fix: classify client states without consensus states as expired (#941) ## Description closes: #850 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * chore: fix broken link (#972) * add backport actions for v1.3.x and v2.1.x (#958) * Revert "feat: adding Pack/Unpack acknowledgement helper fns (#895)" (#973) This reverts commit 843b459635da8cedd92945141c4efe3a762f305d. Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> * chore: update migration docs (#985) * chore: update migration docs * Update docs/migrations/v2-to-v3.md Co-authored-by: Damian Nolan Co-authored-by: Damian Nolan * chore: fix mispelled words (#991) * fix: remove go mod tidy from proto-gen script (#989) * bug: support base denoms with slashes (#978) * bug: support base denoms with slashes * add changelog entry Co-authored-by: Carlos Rodriguez * upgrade ics23 to v0.7 (#948) * upgrade ics23 to v0.7-rc * add changelog entry * update ics23 to final 0.7 Co-authored-by: Carlos Rodriguez * ibctesting: make `testing.T` public (#1020) * add changelog entry for #941 * fix package import (#1007) * feat: Add a function to initialize the ICS27 module via an upgrade proposal (#1037) ## Description closes: #1034 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * docs: add missing args to NewKeeper in integration docs (#1038) ## Description This add some missing arguments to `ibckeeper.NewKeeper` and `ibctransferkeeper.NewKeeper` in integration docs --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [x] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * small fixes for v2 to v3 migration (#1016) * small fixes for v2 to v3 migration * review comment * Update v2-to-v3.md * add store upgrade documentation Co-authored-by: Carlos Rodriguez * add missing slash * build(deps): bump actions/checkout from 2.4.0 to 3 (#1045) Bumps [actions/checkout](https://github.com/actions/checkout) from 2.4.0 to 3.
Release notes

Sourced from actions/checkout's releases.

v3.0.0

  • Update default runtime to node16
Changelog

Sourced from actions/checkout's changelog.

Changelog

v2.3.1

v2.3.0

v2.2.0

v2.1.1

  • Changes to support GHES (here and here)

v2.1.0

v2.0.0

v2 (beta)

  • Improved fetch performance
    • The default behavior now fetches only the SHA being checked-out
  • Script authenticated git commands
    • Persists with.token in the local git config
    • Enables your scripts to run authenticated git commands
    • Post-job cleanup removes the token
    • Coming soon: Opt out by setting with.persist-credentials to false
  • Creates a local branch
    • No longer detached HEAD when checking out a branch
    • A local branch is created with the corresponding upstream branch set
  • Improved layout

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=2.4.0&new-version=3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
* call packet.GetSequence() rather than passing the func as argument (#995) * Add counterpartyChannelID param to IBCModule.OnChanOpenAck (#1086) * add counterpartyChannelID param to IBCModule OnChanOpenAck() * change testing mock * change ica IBCModules ChannelOpenAck * change transfer IBCModules ChannelOpenAck * change core keeper ChannelOpenAck() * CHANGELOG.md * update v2-to-v3 migration doc * Update docs/migrations/v2-to-v3.md Co-authored-by: Carlos Rodriguez Co-authored-by: Carlos Rodriguez * fix mirgation docs (#1091) * fix: handle testing update client errors (#1094) * replace channel keeper with IBC keeper in AnteDecorator (#950) * replace channel keeper with IBC keeper in AnteDecorator and pass message to rpc handler * fix error checking condition * fix for proper way of getting go context * refactor tests for ante handler * review comment * review comments and some fixes * review comments * execute message for update client as well * add migration Co-authored-by: Carlos Rodriguez * add backport rules for v1.4.x and v2.2.x (#1085) * ibctesting: custom voting power reduction for testing (#939) * ibctesting: custom voting power reduction for testing * changelog * fix * make T public * fix * revert changes * fix test * build(deps): bump github.com/spf13/cobra from 1.3.0 to 1.4.0 (#1105) * build(deps): bump google.golang.org/grpc from 1.44.0 to 1.45.0 (#1098) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.44.0 to 1.45.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.44.0...v1.45.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: adjust InitModule to account for empty controller and host keepers (#1120) ## Description closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [x] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [x] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [x] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [x] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [x] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [x] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [x] Review `Codecov Report` in the comment section below once CI passes * Merge pull request from GHSA-j658-c98j-fww4 Co-authored-by: Carlos Rodriguez * fixes for the documentation about handling ack for SDK <= 0.45 (#1122) * fixes for documentation * review comment Co-authored-by: Carlos Rodriguez * Allow testing to update ValidatorSet (#1003) * testing: adding multiple sender accounts for testing puproses * fix genesis setup (#936) * Update testing/chain.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * refactor: code hygiene * Update testing/chain.go Co-authored-by: Aditya * multi validator commit taken from @saione * add function to pass custom valset * create simplest failing test * progress * fix changevalset test * fix errors in tendermint package * fix client types test * fix client keeper * fix cap functions * fix genesis core tests * fix ica tests * fix doc * CHANGELOG * replace signer array with signer map * add documentation * fix merge * documentation * ordered signer array doc * add new delegation and comment to change valset test Co-authored-by: Sean King Co-authored-by: Sean King Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Carlos Rodriguez * imp: create codeql-analysis action (#1128) ## Description Noticed that [CodeQL](https://codeql.github.com/) wasn't enabled on the IBC-go repo --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * update changelog (#1131) * update changelog * fix typo * build(deps): bump github.com/stretchr/testify from 1.7.0 to 1.7.1 (#1134) Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.7.0 to 1.7.1. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.7.0...v1.7.1) --- updated-dependencies: - dependency-name: github.com/stretchr/testify dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Damian Nolan * call packet.GetSequence() rather than passing the func as argument (#1130) * call packet.GetSequence() rather than passing the func as argument * add changelog entry Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Carlos Rodriguez Co-authored-by: Carlos Rodriguez Co-authored-by: Aditya Co-authored-by: Tim Lind Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Damian Nolan Co-authored-by: daeMOn Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Joe Bowman Co-authored-by: khanh <50263489+catShaark@users.noreply.github.com> Co-authored-by: Carlos Rodriguez * 02-client-refactor: rename update to UpdateState for 07-tendermint (#1117) * rename update to UpdateState rename 07-tendermint update function to UpdateState add pruneOldestConsensusState function add check for duplicate update * fix: duplicate update check was performing incorrect logic * update godoc * add UpdateState tests * update godoc * chore: fix code spacing Co-authored-by: Sean King * chore: adding UpdateStateOnMisbehaviour to 07-tendermint (#1168) * adding UpdateStateOnMisbehaviour with basic test * removing redundant return values * removing unnecessary CommitBlock in test func * Update modules/light-clients/07-tendermint/types/update.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * chore: add solomachine client storage (#1144) * WIP: solomachine UpdateState now handles storage of ClientState and ConsensusState * applying suggestions for review * removing unnecessary consensus state storage * updating tests to use store in favour of return values * refactor: adding CheckForMisbehaviour to 07-tendermint client (#1163) * adding CheckForMisbehaviour to tendermint ClientState * adding initial testcases for CheckForMisbehaviour * updating tests * updating tests * cleaning up code comments * updating godocs * fixing logic and updating tests * removing Misbehaviour verification and tests * fixing code structure after merge conflict * 02-client refactor: Adding VerifyClientMessage helper fn (#1119) * refactor: Adding VerifyClientMessage helper fn to ClientState * refactor: creating verifyHeader priv fn and respective test * refactor: adding initial test cases * refactor: add more test cases * nit: move fns * remove clientState var * refactor: adding different val set test case * refactor: add test case for header with next height and diff validator set * refactor: adding remaining test cases * chore: uncomment previous tests: * fix: chainA -> chainB * chore: comment * refactor: remove consState from api + fix tests * refactor: add verifyHeader to clientState * fix: incorret trusted validators for concensus state test * Update modules/light-clients/07-tendermint/types/update_test.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * chore: add comment * fix: params * refactor: remove timestamp from api * refactor: switch and type * fix: remove height+1 * 02-client refactor: add tests for verifyMisbehaviour (#1166) * refactor: move misbehaviour validation into verifyMisbehaviour function * begin writing misbehaviour tests * fix misbehaviour test * continue adding misbehaviour test cases * add more test cases to verifyMisbehaviour test * add changing validator set tests * finish rest of tests except revision height testing * Update modules/light-clients/07-tendermint/types/misbehaviour_handle_test.go Co-authored-by: Damian Nolan * add back misbehaviour type assertion Co-authored-by: Damian Nolan Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Damian Nolan * refactor: removing GetRoot from ConsensusState interface (#1186) * refactor: removing GetRoot from ConsensusState interface * refactor: remove unnecessary GetRoot definitions * chore: changelog * Adding VerifyClientMessage to ClientState interface (#1196) * feat: adding VerifyClientMessage to ClientState interface * fix: legacy * remove todo + fix test * Update modules/core/exported/client.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update modules/core/02-client/legacy/v100/solomachine.go Co-authored-by: Damian Nolan * chore: changelog Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Damian Nolan * chore: CheckSubstituteAndUpdateState stores client state in lightclients impl (#1170) * set client state in store in lightclient * adding changelog entry * chore: 07-tendermint set client/consensus states in UpdateState (#1199) * adding storage ops to 07-tendermint UpdateState, updating tests * use clientMessage.GetHeight() as per review suggestions * updating tests to obtain previous client/consensus state in malleate * chore: update 07-tendermint GetConsensusState to return bool over error (#1180) * updating 07-tendermint GetConsensusState to return bool over error * panic on unmarshal and type assertion failure, update tests * updating to use MustUnmarshalConsensusState directly * Update modules/light-clients/07-tendermint/types/misbehaviour_handle.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update modules/light-clients/07-tendermint/types/misbehaviour_handle.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * removing comments and updating godoc Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * feat: adding UpdateStateOnMisbehaviour to ClientState interface (#1198) * feat: adding UpdateStateOnMisbehaviour to ClientState interface * Update modules/core/exported/client.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * fix: return values * chore: changelog Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * refactor: remove localhost client implementation (#1187) * refactor: remove localhost light client implementation * chore: readding CreateLocalhost field * chore: readding createLocalhost field * chore: changelog * fix: BeginBlocker * fix: removing CreateLocalhost * chore: remove unused code * refactor: keeper tests * refactor: genesis type test add case for invalid client type * fix: add back tests * fix: remove unncessary if statement * chore: adding UpdateState to ClientState interface (#1206) * adding UpdateState to ClientState interface and updating surrounds * updating godoc * adding changelog entry * Update modules/core/exported/client.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * fixing typo in changelog Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * feat: adding CheckForMisbehaviour to ClientState interface (#1197) * feat: adding CheckForMisbehaviour to ClientState interface * fix: comment * nit: fix todo * chore: changelog * Replace CheckHeaderAndUpdateState with new ClientState functions (#1208) * refactor: replace CheckHeaderAndUpdateState with VerifyClientMessage, CheckForMisbehaviour, UpdateStateOnMisbehaviour, and UpdateState * add changelog entry * fix tests * refactor: removing CheckHeaderAndUpdateState from ClientState (#1210) * refactor: removing CheckHeaderAndUpdateState from ClientState interface & light client implementations * chore: fix changelog * refactor: routing MsgSubmitMisbehaviour to UpdateClient keeper fn (#1188) * refactor: routing MsgSubmitMisbehaviour to UpdateClient keeper fn * chore: updating changelog and comment for deprecated notice * fix: channel proto file linter issue + adding deprecated flag to MsgSubmitMisbehavior * chore: fix changelog * refactor: removing CheckMisbehaviourAndUpdateState from ClientState interface (#1212) * refactor: removing CheckForMisbehaviourAndUpdateState from ClientState interface and associated client implemtations * chore: changelog * fix: rm AllowUpdateAfter... check (#1118) * update code & test * update proto and adr026 * update CHANGELOG * update cli docs * update broken milestone link * chore: update 02-client-refactor branch with latest main (#1286) * refactor: allow the mock module to be used multiple times as base ibc application in middleware stack (#892) ## Description Currently the `AppModule` assumes a single scoped keeper. This doesn't allow the mock module to be used as a base application for different middleware stack (ica stack, fee stack, etc) I broke the API because I think it is cleaner. If we want this to be non API breaking, I can try to readjust ref: #891 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * feat: adding Pack/Unpack acknowledgement helper fns (#895) * feat: adding Pack/Unpack acknowledgement helper fns * chore: changelog * fix: docs * Update modules/core/04-channel/types/codec.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * imp: support custom keys for testing (#893) * chore: add ParsePacketFromEvents testing helper function (#904) ## Description ref: #891 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * fix: correctly claim capability for mock module, handle genesis exports (#921) ## Description This contains two fixes: - the capability being claimed by the scoped keeper was incorrect (mock.ModuleName -> port ID) - the mock module wasn't accounting for non empty genesis state in capabilities (after genesis export, capability will create the bound ports so rebinding doesn't need to happen) closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * docs: update migration docs for upgrade proposal in relation to ICS27 (#920) ## Description closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * chore(ica): add trail of bits audit report (#903) * chore(ica): add trail of bits audit report * relocate the audit report for ICA Co-authored-by: Carlos Rodriguez * testing: adding multiple sender accounts for testing purposes (#935) * testing: adding multiple sender accounts for testing puproses * fix genesis setup (#936) * Update testing/chain.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * refactor: code hygiene * Update testing/chain.go Co-authored-by: Aditya * fix: setting totalySupply to empty * nit: CamelCase not UPPERCASE Co-authored-by: Aditya Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Create test chain with multiple validators (#942) * testing: adding multiple sender accounts for testing puproses * fix genesis setup (#936) * Update testing/chain.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * refactor: code hygiene * Update testing/chain.go Co-authored-by: Aditya * multi validator commit taken from @saione * add function to pass custom valset * add changelog Co-authored-by: Sean King Co-authored-by: Sean King Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * add changelog entry for SDK bump * fix: classify client states without consensus states as expired (#941) ## Description closes: #850 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * chore: fix broken link (#972) * add backport actions for v1.3.x and v2.1.x (#958) * Revert "feat: adding Pack/Unpack acknowledgement helper fns (#895)" (#973) This reverts commit 843b459635da8cedd92945141c4efe3a762f305d. Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> * chore: update migration docs (#985) * chore: update migration docs * Update docs/migrations/v2-to-v3.md Co-authored-by: Damian Nolan Co-authored-by: Damian Nolan * chore: fix mispelled words (#991) * fix: remove go mod tidy from proto-gen script (#989) * bug: support base denoms with slashes (#978) * bug: support base denoms with slashes * add changelog entry Co-authored-by: Carlos Rodriguez * upgrade ics23 to v0.7 (#948) * upgrade ics23 to v0.7-rc * add changelog entry * update ics23 to final 0.7 Co-authored-by: Carlos Rodriguez * ibctesting: make `testing.T` public (#1020) * add changelog entry for #941 * fix package import (#1007) * feat: Add a function to initialize the ICS27 module via an upgrade proposal (#1037) ## Description closes: #1034 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * docs: add missing args to NewKeeper in integration docs (#1038) ## Description This add some missing arguments to `ibckeeper.NewKeeper` and `ibctransferkeeper.NewKeeper` in integration docs --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [x] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * small fixes for v2 to v3 migration (#1016) * small fixes for v2 to v3 migration * review comment * Update v2-to-v3.md * add store upgrade documentation Co-authored-by: Carlos Rodriguez * add missing slash * build(deps): bump actions/checkout from 2.4.0 to 3 (#1045) Bumps [actions/checkout](https://github.com/actions/checkout) from 2.4.0 to 3.
Release notes

Sourced from actions/checkout's releases.

v3.0.0

  • Update default runtime to node16
Changelog

Sourced from actions/checkout's changelog.

Changelog

v2.3.1

v2.3.0

v2.2.0

v2.1.1

  • Changes to support GHES (here and here)

v2.1.0

v2.0.0

v2 (beta)

  • Improved fetch performance
    • The default behavior now fetches only the SHA being checked-out
  • Script authenticated git commands
    • Persists with.token in the local git config
    • Enables your scripts to run authenticated git commands
    • Post-job cleanup removes the token
    • Coming soon: Opt out by setting with.persist-credentials to false
  • Creates a local branch
    • No longer detached HEAD when checking out a branch
    • A local branch is created with the corresponding upstream branch set
  • Improved layout

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=2.4.0&new-version=3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
* call packet.GetSequence() rather than passing the func as argument (#995) * Add counterpartyChannelID param to IBCModule.OnChanOpenAck (#1086) * add counterpartyChannelID param to IBCModule OnChanOpenAck() * change testing mock * change ica IBCModules ChannelOpenAck * change transfer IBCModules ChannelOpenAck * change core keeper ChannelOpenAck() * CHANGELOG.md * update v2-to-v3 migration doc * Update docs/migrations/v2-to-v3.md Co-authored-by: Carlos Rodriguez Co-authored-by: Carlos Rodriguez * fix mirgation docs (#1091) * fix: handle testing update client errors (#1094) * replace channel keeper with IBC keeper in AnteDecorator (#950) * replace channel keeper with IBC keeper in AnteDecorator and pass message to rpc handler * fix error checking condition * fix for proper way of getting go context * refactor tests for ante handler * review comment * review comments and some fixes * review comments * execute message for update client as well * add migration Co-authored-by: Carlos Rodriguez * add backport rules for v1.4.x and v2.2.x (#1085) * ibctesting: custom voting power reduction for testing (#939) * ibctesting: custom voting power reduction for testing * changelog * fix * make T public * fix * revert changes * fix test * build(deps): bump github.com/spf13/cobra from 1.3.0 to 1.4.0 (#1105) * build(deps): bump google.golang.org/grpc from 1.44.0 to 1.45.0 (#1098) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.44.0 to 1.45.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.44.0...v1.45.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: adjust InitModule to account for empty controller and host keepers (#1120) ## Description closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [x] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [x] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [x] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [x] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [x] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [x] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [x] Review `Codecov Report` in the comment section below once CI passes * Merge pull request from GHSA-j658-c98j-fww4 Co-authored-by: Carlos Rodriguez * fixes for the documentation about handling ack for SDK <= 0.45 (#1122) * fixes for documentation * review comment Co-authored-by: Carlos Rodriguez * Allow testing to update ValidatorSet (#1003) * testing: adding multiple sender accounts for testing puproses * fix genesis setup (#936) * Update testing/chain.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * refactor: code hygiene * Update testing/chain.go Co-authored-by: Aditya * multi validator commit taken from @saione * add function to pass custom valset * create simplest failing test * progress * fix changevalset test * fix errors in tendermint package * fix client types test * fix client keeper * fix cap functions * fix genesis core tests * fix ica tests * fix doc * CHANGELOG * replace signer array with signer map * add documentation * fix merge * documentation * ordered signer array doc * add new delegation and comment to change valset test Co-authored-by: Sean King Co-authored-by: Sean King Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Carlos Rodriguez * imp: create codeql-analysis action (#1128) ## Description Noticed that [CodeQL](https://codeql.github.com/) wasn't enabled on the IBC-go repo --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * update changelog (#1131) * update changelog * fix typo * build(deps): bump github.com/stretchr/testify from 1.7.0 to 1.7.1 (#1134) Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.7.0 to 1.7.1. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.7.0...v1.7.1) --- updated-dependencies: - dependency-name: github.com/stretchr/testify dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Damian Nolan * call packet.GetSequence() rather than passing the func as argument (#1130) * call packet.GetSequence() rather than passing the func as argument * add changelog entry * fix: prefix ResponseResultType enum for proto linting (#1143) * build(deps): bump actions/cache from 2.1.7 to 3 (#1150) Bumps [actions/cache](https://github.com/actions/cache) from 2.1.7 to 3. - [Release notes](https://github.com/actions/cache/releases) - [Commits](https://github.com/actions/cache/compare/v2.1.7...v3) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fixes for go-releaser configuration (#1148) * set the pre-release status if the tag contains alpha, beta or rc * add separate filter for final releases * add banner image (#1158) Co-authored-by: Carlos Rodriguez * Add alpha, beta, and rc release definitions (#1151) ## Description The proposed definitions for each phase of our release cycle. Please feel free to adjust my wording closes: #881 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * build(deps): bump google.golang.org/protobuf from 1.27.1 to 1.28.0 (#1164) Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.27.1 to 1.28.0.
Release notes

Sourced from google.golang.org/protobuf's releases.

v1.28.0

Overview

The release provides a new unmarshal option for limiting the recursion depth when unmarshalling nested messages to prevent stack overflows. (UnmarshalOptions.RecursionLimit).

Notable changes

New features:

  • CL/340489: testing/protocmp: add Message.Unwrap

Documentation improvements:

  • CL/339569: reflect/protoreflect: add more docs on Value aliasing

Updated supported versions:

UnmarshalOption RecursionLimit

  • CL/385854: all: implement depth limit for unmarshalling

The new UnmarshalOptions.RecursionLimit limits the maximum recursion depth when unmarshalling messages. The limit is applied for nested messages. When messages are nested deeper than the specified limit the unmarshalling will fail. If unspecified, a default limit of 10,000 is applied.

In addition to the configurable limit for message nesting a non-configurable recursion limit for group nesting of 10,000 was introduced.

Upcoming breakage changes

The default recursion limit of 10,000 introduced in the release is subject to change. We want to align this limit with implementations for other languages in the long term. C++ and Java use a limit of 100 which is also the target for the Go implementation.

Commits
  • 32051b4 all: release v1.28.0
  • 3992ea8 all: implement depth limit for unmarshaling
  • e5db296 all: update supported versions
  • 3a9e1dc all: gofmt all
  • 26e8bcb all: remove unnecessary string([]byte) conversion in fmt.Sprintf with %s
  • 5aec41b testing/protocmp: add Message.Unwrap
  • 05be61f reflect/protoreflect: add more docs on Value aliasing
  • b03064a all: start v1.27.1-devel
  • See full diff in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=google.golang.org/protobuf&package-manager=go_modules&previous-version=1.27.1&new-version=1.28.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
* fix typos in the controller params (#1172) ## Description closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * add versions for new releases (#1175) ## Description closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * fix: link checker reporting broken milestone link (#1200) * update roadmap for q2 2022 and deleted history roadmap (don't think we'll need it) * requirements document for ICA (#1173) * add requirements document for interchain accounts * fix branch * added number in tittle. * apply suggestions from review Co-authored-by: Aditya * review comment Co-authored-by: Carlos Rodriguez Co-authored-by: Aditya * imp: improve Logger performance (#1160) * fix: Logger marshal errors * changelog * update * ICS 29: Fee Middleware (#276) * scaffolding for 29-fee (#274) * scaffolding for 29-fee * fix build * update keeper test * remove module test * feat: adding proto files for fee payment middleware (#272) * feat: adding proto files for fee payment middleware * grammar * fix: remove generated .pb files * fix: comment * feat: adding PacketId type * refactor: fee / genesis * refactor: escrowed fees map * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update proto/ibc/applications/middleware/fee/v1/tx.proto Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update proto/ibc/applications/middleware/fee/v1/tx.proto Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update proto/ibc/applications/middleware/fee/v1/tx.proto Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * refactor: use packetID + minor changes * feat: adding query for all incentivized packets + some fixes * feat: adding pagination to incentivized query * fix: removing generated ibc directory + adding import/yaml * fix: naming * increase max depth for proto file searching and make proto all * Update proto/ibc/applications/middleware/fee/v1/fee.proto Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * refactor: remove file imports/add yaml/add argument for requests * refactor: updating IdentifiedPacketFee * fix: remove hidden file * removing middleware dir & adding query * remove junk file and update query rpcs * Apply suggestions from code review * Apply suggestions from code review * remove query yaml, make proto-all Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Aditya Sripal * fix: removing unncessary fields MsgEscrow & adding query params (#300) * fix: removing unncessary fields MsgEscrow & adding query params * fix: grammar * fix: add yaml * feat: #258 Register Counterparty Address (#376) * feat: adding MsgServer for RegisterCounterPartyAddress & EscrowPacketFree * test: adding test for ValidateBasic * fix: removing validate basic check * fix: removing empty file * Update modules/apps/29-fee/keeper/msg_server.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update modules/apps/29-fee/types/msgs.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update modules/apps/29-fee/types/keys.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update modules/apps/29-fee/keeper/keeper.go Co-authored-by: Aditya * fix: fixing typos, variable names, comments * fix: updating import comments * test: adding test for KeyRelayerAddress * update: comments & key_test * Update modules/apps/29-fee/keeper/msg_server.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * fix: error message * docs: updating RegisterCounterpartyAddress fn description Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Aditya * fix: remove comments for imports (#385) * feat: Add handshake logic to ics29 (#307) * do handshake logic, create test file * do cap logic and fix build * open handshake implementation and tests * remove prints * Update modules/apps/29-fee/module.go Co-authored-by: Sean King * debugging progress * fee enabled flag * cleanup handshake logic * fix tests * much cleaner simapp * split module.go file * cleanup and docs * assert IBC interfaces are fulfilled in middleware * Update modules/apps/transfer/module.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * fix unnecessary crossing hello logic * fix version negotiation bugs and improve tests * cleanup tests * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * address rest of colin comments Co-authored-by: Sean King Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Fee Middleware: Escrow logic (#465) * fix: adding second endpoint for async pay fee + renaming types * feat: adding escrow logic * feat: updating proto types & escrow logic * fix: stub fn & proto comment * feat: adding PayFee & PayFeeTimeout & escrow_test * test: adding happy path for EscrowPacketFee * fix: comments, error handling * fix: comments & grammar * test: adding unhappy path for escrow * tests(escrow): adding hasBalance check for module acc * test(PayFee): adding happy path for PayFee tests * tests(PayFee, PayFeeTimeout): adding tests * fix: adding relayers back to IdentifiedPacket * fix: removing refund acc from key * fix: storing IdentifiedPacketFee in state instead of Fee * feat: adding msg_server test for registerCPAddr, wiring for codec + stubs for sdk.Msg interface * test: adding msg_server test for PayPacketFee * test: adding PayPacketFeeAsync msg_server test * chore: updating PayFee -> DistributeFee & minor nits * nit: removing unnecessary nil check * refactor: add portId to store key & use packetId as param * fix: add DeleteFeeInEscrow & remove fee on successful distribution * tests: adding validation & signer tests for PayFee/Async & updating proto to use Signer sdk standard * chore: adding NewIdentifiedPacketFee fn * fix: getter/setter for counterparty address + fix NewIdentifiedPacketFee * fix: updating EscrowPacketFee with correct usage of coins api * test: adding balance check for refund acc after escrow * fix: remove unncessary errors * test: updating escrow tests + miscellaneous fixes * nit: updating var names * docs: godoc * refactor: IdentifiedPacketFee & Fee no longer pointers * fixes: small fixes * Update modules/apps/29-fee/keeper/escrow.go Co-authored-by: Aditya * Update modules/apps/29-fee/keeper/escrow.go Co-authored-by: Aditya * Update modules/apps/29-fee/keeper/keeper.go Co-authored-by: Aditya * Update modules/apps/29-fee/keeper/msg_server.go Co-authored-by: Aditya * Update modules/apps/29-fee/keeper/msg_server.go Co-authored-by: Aditya * Update modules/apps/29-fee/types/msgs.go Co-authored-by: Aditya * nit: proto doc & error fix * fix: escrow test * test: updating distribute fee tests * test: adding validation check for fee and updating tests * test: allow counterparty address to be arbitrary string * fix: message validation should pass if one fee is valid * Update modules/apps/29-fee/keeper/escrow.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update modules/apps/29-fee/keeper/escrow.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * fix: nits * Update modules/apps/29-fee/keeper/escrow.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * test: adding isZero check for msgs Co-authored-by: Aditya Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * feat: update protos, grpc queries (#488) * store refund address in IdentifiedPacketFee (#546) * 29-Fee: Genesis (#557) * proto: adding genesis state * feat: add GetAllIdentifiedPacketFees * feat: adding genesis.go & updating proto + app.go * fix: removing PortId from genesis * feat: adding GetAll for relayer addr/fee enabled chan + update genesis * test: TestExportGenesis * feat: update type + hook up to module.go * fix: remove PortKey * fix: imports + remove scoped keeper * nit: using NewPacketId helper and updating helper def to have correct params * feat: adding genesis validation + tests (#561) * feat: adding genesis validation + tests * fix: imports * Update modules/apps/29-fee/types/genesis.go * fix: nit * Update modules/apps/29-fee/types/genesis_test.go Co-authored-by: Aditya * nit: imporve default gen val test * chore: move packetId + val to channeltypes and use validate fn Co-authored-by: Aditya * feat: add incentivised ack proto (#564) * proto file * incentivized ack proto * Fee Closing Handshake (#551) * add iterate logic * add closing logic with tests * add comments for panic * change invariant breaking recovery to disabling middleware rather than panicing * docs, tests, minor refactor * Fee Middleware: Add ICS4 wrapper (#562) * chore: add ICS4 wrapper * fix: remove channelKeeper sender packet * chore: add WriteAck * feat: ics 29 packet callbacks (#357) * update imports to v3 * regenerate proto files * fix build * fix: event caching for fee distribution (#661) * proto file * initial impl * apply self review suggestions Deduplicate fee distribution code. Rename DistributeFee to DistributePacketFees. Rename DistributeFeeTimeout to DistributePacketFeesOnTimeout * fixup tests rename validCoins. DistributePacketFeesOnTimeout no longer has a valid error case Add test case for invalid forward relayer address on DistributePacketFees. * partially fix tests timeout fee is still being distributed depsite WriteFn() not being called * fix tests * address code nit Co-authored-by: Colin Axnér <25233464+colin-axner@users.noreply.github.com> * ics4 callbacks fee middleware (#580) * feat: adding WriteAcknowledgement * updating genesis & relayer prefix * fix: comment * fix: comments * Update modules/apps/29-fee/keeper/relay.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * feat: add DeleteForwardRelayerAddr helper + use Set in ack * fix: SetForwardAddr * chore: add panic * fix: remove fmt * test: add WriteAcknowledgement test * Update modules/apps/29-fee/ibc_module.go Co-authored-by: Aditya * fix: remove print * fix: WriteAck * fix: use constructor * Update modules/apps/29-fee/keeper/keeper.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * fix: nits * fix: remove found var not used * test: adding check that forward relayer address is successfully deleted if set * fix: merge issues Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Aditya * chore: making PacketId non nullable (#737) * nits: proto spacing + naming (#739) * nits: proto spacing + naming * nit: update comment * fix: go.mod * nit: option above import proto * fix: spacing * sean/fix-proto-identified-fee-not-null (#746) * nits: more ics29 nits (#741) * nits: remove capital from error + add godoc * nit: add Wrapf * nit: use strings.TrimSpace * nit: add err type for MsgPayPacketFee * refactor: app version + add comment (#750) * chore: remove error * test: add test for whitespaced empty string * nit: update err syntax (#747) * nit: update err syntax * nit: more * nit: err syntax * feat: adding Route, Type, GetSignBytes for all messages (#743) * feat: adding Route, Type, GetSignBytes for all messages * tests: adding tests for Route/Type/GetSignBytes * hygiene: add validate fn for Fee (#748) * hygiene: add validate fn for Fee * Update modules/apps/29-fee/types/msgs.go Co-authored-by: Damian Nolan * fix: error message * test: move Validate to fee.go & abstract out test * chore: remove test cases Co-authored-by: Damian Nolan * fix: app.go (#789) * refactor: ics29 json encoded version metadata (#883) * adding metadata type to ics29 protos * updating ics29 handshake handlers to support json encoded metadata * updating tests to support json encoded metadata * Update modules/apps/29-fee/ibc_module.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update modules/apps/29-fee/ibc_module.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * renaming metadata version to fee_version Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * fix: return nil on OnRecvPacket for async pay (#911) * nit: ics29 comments (#910) * fix: comments * Update modules/apps/29-fee/keeper/escrow.go Co-authored-by: Aditya * chore: Add transfer test for ics29 (#901) * begin writing transfer test for ics29 * finish writing transfer test * refactor: ics29 OnChanOpenInit callback tests now use mock module (#924) * refactor: OnChanOpenInit callback tests now use mock module * Update modules/apps/29-fee/fee_test.go * feat: allow multiple addrs to incentivize packets (#915) * [WIP] allow multiple addresses to incentivize a packet * distribute multiple fees, fix broken tests * use NewIdentifiedPacketFees in EscrowPacketFee * cleanup var naming * removing commented out code and adding test case * Update modules/apps/29-fee/ibc_module.go Co-authored-by: Aditya * fix: refund RecvFee if ForwardAddr is invalid * test: update tests to distribute multiple identified fees * refactor: clean up DistrPacketFees * refactor: using .Empty() helper func for code hygiene Co-authored-by: Aditya Co-authored-by: Sean King Co-authored-by: Sean King * chore: remove spec directory from ics29 (#934) * refactor: use mock module for ics29 closing handshakes (#926) * refactor: use mock module for closing handshakes in ics29 * self-review fix * refactor: use mock module for ics29 grpc_query_test.go (#933) * refactor: readjust keeper_test.go to use mock module (#930) * fix: fields for genesis should be non nullable (#938) * refactor: use mock module for ics29 escrow_test.go (#932) * refactor: use mock module for ics29 genesis_test.go (#931) * ics29:feat: emit event escrow (#914) * feat: emit EventTypeSendIncentivizedPacket event on EscrowPacket * fix: string conversion * refactor: add helper fn for emit event * chore: godoc * nit: use .String()) * refactor: OnRecvPacket to use mock module (#927) Co-authored-by: Sean King * refactor: ics29 OnChanOpenTry/Ack use mock module for testing instead of ics20 (#925) Co-authored-by: Sean King * refactor: use mock module for OnAcknowledgePacket callback testing (#929) Co-authored-by: Sean King * refactor: OnTimeoutPacket to use mock module (#928) Co-authored-by: Sean King * chore: add packet id arg to EscrowPacketFee (#951) * adding packet id arg to EscrowPacketFee * updating tests * review adaptations * chore: remove legacy testing functions (#954) * fix:ics29: WriteAck update + adding success bool to IncentivizedAck (#952) * fix: updating WriteAck & adding Success boolean to IncentivizedAcknowledgement * feat: adding check of is fee enabled * nit: change successful to underlying_application_success * test: adding seperate test for fee disabled write async * Update modules/apps/29-fee/ibc_module_test.go Co-authored-by: Aditya * test: adding check to compare hash of acks * fix: var name Co-authored-by: Aditya * chore: add cli cmd to incentivize existing packet (async) (#965) * chore: add cli to incentivize existing packets * Update modules/apps/29-fee/client/cli/cli.go * Update modules/apps/29-fee/client/cli/cli.go Co-authored-by: Aditya * chore: update cli example Co-authored-by: Aditya * ics29:fix: counterparty addr must contain channelID (#937) * fix: counterparty address must chain channelID * nit: updating var name * test: adding validation check for channelID * nit: fn names * chore: fix err msg (#971) * ics29:fix: store source address for query later on WriteAck (#912) * fix: for async WriteAck store source address for query later * ics29:fix: update genesis type (#913) * fix: adding ForwardRelayerAddresses to genesis * fix: trimspace on string check * nit: err + trimspace error case * refactor: updating WriteAck + keeper fn name * Update modules/apps/29-fee/keeper/relay.go Co-authored-by: Damian Nolan * chore: remove legacy testing functions (#954) * fix:ics29: WriteAck update + adding success bool to IncentivizedAck (#952) * fix: updating WriteAck & adding Success boolean to IncentivizedAcknowledgement * feat: adding check of is fee enabled * nit: change successful to underlying_application_success * test: adding seperate test for fee disabled write async * Update modules/apps/29-fee/ibc_module_test.go Co-authored-by: Aditya * test: adding check to compare hash of acks * fix: var name Co-authored-by: Aditya Co-authored-by: Damian Nolan Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Aditya * refactor: make fee storage more efficient (#956) * adding new proto types and codegen * refactoring ics29 fees for more efficient storage * updating tests * fixing typo in protodoc comments * chore: update ics29 genesis state to support multiple packet fees (#957) * adding new proto types and codegen * refactoring ics29 fees for more efficient storage * updating tests * updating genesis protos to use IdentifiedPacketFees * updating init/export genesis state functionality and tests * chore: update MsgPayPacketFeeAsync fields (#979) * adding new proto types and codegen * refactoring ics29 fees for more efficient storage * updating tests * fixing typo in protodoc comments * updating protos and codegen * updating MsgPayPacketFeeAsync handler and tests * chore: add ParseKeyFeesInEscrow helper function (#998) * chore: update grpc queries to handle multiple fees (#967) * adding new proto types and codegen * refactoring ics29 fees for more efficient storage * updating tests * updating protos and existing queries * updating grpc queries and refactoring tests * format error correct in favour of proto string() method * leveraging ParseKeyFeesInEscrow to obtain packet id in query * feat: CLI cmd for MsgRegisterCounterpartyAddress (#987) * feat: CLI cmd for MsgRegisterCounterpartyAddress * fix: examples * Update modules/apps/29-fee/client/cli/tx.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update modules/apps/29-fee/client/cli/tx.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * chore: remove print * nit: update address for counterparty Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * fix: ics29: switch source with destintion for chan/port IDs (#961) * fix: switch source with destintion for chan/port IDs * fix: blunder * test: adding tests in case of incorrect channel/port id * test: moving check to WriteAcknowledgement * add test case for Get/Set counterparty address * nit: path name * Update modules/apps/29-fee/keeper/msg_server_test.go * test: cleanup 29-fee/types tests (#1006) * feat: grpc query total recv packet fees (#1015) * adding query for total packet recv fees to proto query server * adding total packet recv fee query impl and tests * updating doc comments * chore: switch code ordering (#1025) * feat: Add ParseKeyFeeEnabled and rename FeeEnabledKey -> KeyFeeEnabled (#1023) * chore: add ParseKeyFeesInEscrow helper function * feat: add ParseKeyFeeEnabled function and rename FeeEnabledKey to KeyFeeEnabled * feat: ics29 cli for query total recv fees (#1035) * feat: grpc query total ack fees (#1032) * adding query for total packet recv fees to proto query server * adding total packet recv fee query impl and tests * updating doc comments * adding protos and codegen * adding total ack fees query and tests * fixing protodoc comment * feat: grpc query total timeout fees (#1033) * adding query for total packet recv fees to proto query server * adding total packet recv fee query impl and tests * updating doc comments * adding protos and codegen * adding total ack fees query and tests * adding protos and codegen * adding query total timeout fees and tests * fixing protodoc comment * fixing protodoc comment * feat: adding clis for total ack and timeout queries (#1043) * add ParseKeyForwardRelayerAddress function + test (#1046) * chore: remove unused ics29 keeper funcs (#1044) * removing keys, adding additional test, moving event attribute keys * removing unused code and updating tests * removing unused IdentifiedPacketFee type * chore: add gRPC for querying incentivized packets for a specific channel (#983) * generate proto files * feat: add gRPC for querying incentivized packets for a specific channel * test: add gRPC test for incentivized packets for channel query * fix build * partially fix tests * chore: fix tests * deduplicate code * chore: code cleanup * fix build * remove changes from merge conflict * nit: rename c to goCtx * add function EscrowAccountHasBalance (#1042) * add function EscrowAccountHasBalance * change API to use sdk.Coins * feat: ParseKeyCounterpartyRelayer function (#1047) * chore: adding queries to cmd builder (#1057) * chore: update ics29 protodocs (#1055) * updating protodocs comments and regen code/docs * Update proto/ibc/applications/fee/v1/tx.proto Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * updating incentivized ack doc Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * add counter party channel ID to argument list of on channel open ack (#1159) Co-authored-by: Carlos Rodriguez * ADR 004: Fee module locking in the presence of severe bugs (#1060) * add adr 004 * add to README * Update docs/architecture/adr-004-ics29-lock-fee-module.md Co-authored-by: Aditya * Update docs/architecture/adr-004-ics29-lock-fee-module.md Co-authored-by: Aditya Co-authored-by: Carlos Rodriguez Co-authored-by: Aditya * nit: packetID var name (#1214) * ics29: update with changes from main (#1221) * add banner image (#1158) Co-authored-by: Carlos Rodriguez * Add alpha, beta, and rc release definitions (#1151) ## Description The proposed definitions for each phase of our release cycle. Please feel free to adjust my wording closes: #881 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * build(deps): bump google.golang.org/protobuf from 1.27.1 to 1.28.0 (#1164) Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.27.1 to 1.28.0.
Release notes

Sourced from google.golang.org/protobuf's releases.

v1.28.0

Overview

The release provides a new unmarshal option for limiting the recursion depth when unmarshalling nested messages to prevent stack overflows. (UnmarshalOptions.RecursionLimit).

Notable changes

New features:

  • CL/340489: testing/protocmp: add Message.Unwrap

Documentation improvements:

  • CL/339569: reflect/protoreflect: add more docs on Value aliasing

Updated supported versions:

UnmarshalOption RecursionLimit

  • CL/385854: all: implement depth limit for unmarshalling

The new UnmarshalOptions.RecursionLimit limits the maximum recursion depth when unmarshalling messages. The limit is applied for nested messages. When messages are nested deeper than the specified limit the unmarshalling will fail. If unspecified, a default limit of 10,000 is applied.

In addition to the configurable limit for message nesting a non-configurable recursion limit for group nesting of 10,000 was introduced.

Upcoming breakage changes

The default recursion limit of 10,000 introduced in the release is subject to change. We want to align this limit with implementations for other languages in the long term. C++ and Java use a limit of 100 which is also the target for the Go implementation.

… * chore: remove GetHeight from ClientMessage interface (#1285) * adding new consensus heights return value from UpdateState interface, updating 02-client events emission * removing GetHeight() from ClientMessage interface, updating tests * updating godocs to include returned consensus height data * removing unused event emission func, adding deprecation notice, removing GetHeight from solomachine Header, updating tests * removing error return from UpdateState, returning height on duplicate header update * updating event emissions as per suggestions * update godoc for VerifyClientMessage (#1281) * update godoc * Update modules/core/exported/client.go Co-authored-by: Carlos Rodriguez * update UpdateState godoc * reorganize interface functions logically Co-authored-by: Carlos Rodriguez * Add VerifyMembership to 07-tendermint (#1297) * add VerifyMembership function and initial tests * revert unnecessary code changes * add rest of successful verify test cases * increase code coverage with additional tests * chore: remove field naming from test cases * add test case using VerifyMembership on non IBC store value * chore: MsgUpdateClient rename header to client_message (#1316) * updating MsgUpdateClient to use client_message field in favour of header * updating clis, field naming, and adding deprecation notices * Add migration docs for 02-client refactor (#1287) * add changes on : ClientState, Header, Misbehaviour, ConsensState, light client impl to migration doc * Update docs/migrations/v3-to-v4.md Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update docs/migrations/v3-to-v4.md Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update docs/migrations/v3-to-v4.md Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update docs/migrations/v3-to-v4.md Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update docs/migrations/v3-to-v4.md Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update docs/migrations/v3-to-v4.md Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * add more entries and more description * Update docs/migrations/v3-to-v4.md Co-authored-by: Carlos Rodriguez * Update docs/migrations/v3-to-v4.md Co-authored-by: Carlos Rodriguez * Update docs/migrations/v3-to-v4.md Co-authored-by: Carlos Rodriguez * Update docs/migrations/v3-to-v4.md Co-authored-by: Carlos Rodriguez * Update docs/migrations/v3-to-v4.md Co-authored-by: Carlos Rodriguez * Update docs/migrations/v3-to-v4.md Co-authored-by: Carlos Rodriguez * Update docs/migrations/v3-to-v4.md Co-authored-by: Carlos Rodriguez * Update docs/migrations/v3-to-v4.md Co-authored-by: Carlos Rodriguez * Update docs/migrations/v3-to-v4.md Co-authored-by: Sean King * Update docs/migrations/v3-to-v4.md Co-authored-by: Carlos Rodriguez * update migration doc * update migration doc * update migration doc Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Carlos Rodriguez Co-authored-by: Sean King * Add revision number tests for 07-tendermint (#1302) * add revision tests for VerifyClientMessage adds UpgradeChain which manually upgrades the chainID to the next revision adds test cases for VerifyClientMessage in relation to a changing revision number * fix revision tests * update revision tests, use revision format as default in testing * remove hard coding from upgrade tests * fix misbehaviour handle tests * add changelog entry * fix client state tests * disable updates to previous revisions * fix hard coded tests * add test case for unsuccessful update to previous revision * Update modules/light-clients/07-tendermint/types/update_test.go Co-authored-by: Aditya * add strings trim space * add tests for non revision chainIDs Co-authored-by: Aditya * ADR 005: update client consensus height events (#1315) * adding context section and draft notes for decision section * updating adr with decisions and consequences sections * adding references to adr 005 * removing decision templating * Apply suggestions from code review Co-authored-by: Carlos Rodriguez * adding versioned links * reorder decision points, add additional info on header cross-checking * typo Co-authored-by: Carlos Rodriguez * feat: VerifyNonMembership 07-tendermint implementation (#1611) * chore: making changes based on nits from 02-client refactor audit (#1585) * chore: add generic proof verification methods to ClientState interface (#1645) * adding generic proof verification methods to ClientState interface * adding function boilerplate to solomachine and legacy v100 solomachine * adding comments for todos * chore: add GetTimestampAtHeight to client state #888 (#1659) Co-authored-by: Bo Du * chore: modify connection keeper GetTimestampAtHeight to use the client state interface function (#1666) * updated connection keeper to use clientstate to get timestamp, updated tests * refactor: replace usage of verification funcs in 03-connection (#1647) * replacing 03-connection verifications with generic membership methods * adding inline comments for skipping delay period checks * chore: removing legacy verify funcs from `ClientState` interface (#1649) * removing legacy verify funcs from clientstate interface * chore: remove legacy verify funcs tm client (#1651) * removing legacy verification methods from tendermint client * removing commented out tests * fixing interface definition * Check that client state is zeroed out for ibc client upgrade proposals (#1676) * Zero out client state before upgrading client proof (#1674) * chore: restructuring 07-tendermint lightclient directory layout (#1677) * restructuring 07-tendermint lightclient directory tree * adding changelog entry * chore: restructuring 06-solomachine lightclient directory layout (#1679) * restructing 06-solomachine folder layout * tidy go modules * fixing dead link * adding changelog entry * chore: adding upgrade handler for 09-localhost removal (#1671) * adding localhost migration code with tests * updating test cases * renaming test func * updating migration docs and moving to v4-to-v5.md * fixing indentation of code snippet * Update docs/migrations/v4-to-v5.md * adding sample query check for localhost client to docs * updating changelog to provide info on localhost upgrade handler * updating migrations docs with nit * renaming upgrades to migrations * updating function namings, tests and docs * Update CHANGELOG.md Co-authored-by: Carlos Rodriguez Co-authored-by: Carlos Rodriguez * Emit event upon setting upgrade consensus state (#1741) * chore: removing GetHeight legacy method from 06-solomachine (#1810) * refactor: solomachine generic verification methods and signbytes simplification (#1687) * adding new SignBytes type, generic membership verification implementation and tests * adding protodocs * updating comment * refactor: solomachine misbehaviour checking (#1715) * adding SignatureAndDataV2 proto message type * updating misbehaviour checking * removing dead solomachine code (#1716) * updating tests with concrete ibc core types * refactor: solomachine generic VerifyNonMembership (#1720) * adding verification of non-membership with tests * refactor common code to produceVerificationArgs * removing unused produce args func * Update modules/light-clients/06-solomachine/client_state_test.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * removing V2 suffix from SignBytes and SignatureAndData types * use current diversifier when verifying header details * Add test for new diversifier for solomachine (#1860) * add test for successful new diversifier * add changelog entry * fix tests * restoring solomachine/v2 protos, updadting v2 codegen path and adding solomachine/v3 protobuf defs * adding changelog entries Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * bump version from 3 to 5 * fix merge conflicts * fix build * go imports * make format * fix linter * apply review suggestions * fix: import changes for 02-client-refactor (#1875) * ibctmtypes -> ibctm * tendermint -> ibctmtypes * remove space * make goimports * apply suggested changes (#1877) * documentation fixes (#1876) * fix: complete changes for CheckSubstituteAndUpdateState (#1878) * complete changes for CheckSubstituteAndUpdateState * Update modules/core/02-client/keeper/proposal.go * 02-client refactor: fix changelog (#1873) * chore: changelog * chore: fix * fix: revert unnecessary change in 02-client-refactor branch (#1883) * revert error naming changes * fix error naming in 03-connection usage * updating solomachine to use setClientState helper in update funcs (#1891) * Update CHANGELOG.md Co-authored-by: Aditya * Update docs/migrations/v5-to-v6.md Co-authored-by: Aditya * chore: remove error return in IterateConsensusStateAscending (#1896) * removing error return in tendermint store.go * updating tests and legacy code * updating changelog * removing solomachine consensus state nil check and test cases (#1895) Co-authored-by: default Co-authored-by: Shake Shack Co-authored-by: Damian Nolan Co-authored-by: Sean King Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Carlos Rodriguez Co-authored-by: Carlos Rodriguez Co-authored-by: Aditya Co-authored-by: Tim Lind Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: daeMOn Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Joe Bowman Co-authored-by: khanh <50263489+catShaark@users.noreply.github.com> Co-authored-by: Carlos Rodriguez Co-authored-by: Charly Co-authored-by: Sean King Co-authored-by: Luke Rhoads <51463884+lukerhoads@users.noreply.github.com> Co-authored-by: Dev Ojha Co-authored-by: Jack Zampolin Co-authored-by: Leo Pang <34628052+allthatjazzleo@users.noreply.github.com> Co-authored-by: Barrie Byron Co-authored-by: Tyler <48813565+technicallyty@users.noreply.github.com> Co-authored-by: technicallyty <48813565+tytech3@users.noreply.github.com> Co-authored-by: Barrie Byron Co-authored-by: Marko Co-authored-by: Marko Baricevic Co-authored-by: Aleksandr Bezobchuk Co-authored-by: nir1218 Co-authored-by: Assaf Morami Co-authored-by: Dan McCandless Co-authored-by: Ramiro Carlucho Co-authored-by: frog power 4000 Co-authored-by: vuong <56973102+nguyenvuong1122000@users.noreply.github.com> Co-authored-by: Cian Hatton Co-authored-by: Bo Du --- CHANGELOG.md | 36 +- README.md | 2 - docs/OLD_README.md | 4 +- .../adr-005-consensus-height-events.md | 88 + docs/architecture/adr-027-ibc-wasm.md | 2 +- docs/ibc/integration.md | 11 - docs/ibc/middleware/develop.md | 20 + docs/ibc/proto-docs.md | 222 +- docs/migrations/v5-to-v6.md | 101 + .../host/keeper/relay_test.go | 4 +- modules/apps/29-fee/ica_test.go | 2 +- modules/apps/29-fee/transfer_test.go | 2 +- .../apps/transfer/keeper/mbt_relay_test.go | 4 +- modules/apps/transfer/keeper/relay_test.go | 16 +- modules/apps/transfer/transfer_test.go | 2 +- modules/core/02-client/abci.go | 18 +- modules/core/02-client/abci_test.go | 76 +- modules/core/02-client/client/cli/cli.go | 2 +- modules/core/02-client/client/cli/tx.go | 35 +- modules/core/02-client/client/utils/utils.go | 28 +- modules/core/02-client/genesis.go | 14 +- modules/core/02-client/keeper/client.go | 194 +- modules/core/02-client/keeper/client_test.go | 351 +-- modules/core/02-client/keeper/events.go | 52 +- .../core/02-client/keeper/grpc_query_test.go | 14 +- modules/core/02-client/keeper/keeper.go | 8 +- modules/core/02-client/keeper/keeper_test.go | 86 +- modules/core/02-client/keeper/proposal.go | 17 +- .../core/02-client/keeper/proposal_test.go | 34 +- modules/core/02-client/legacy/v100/genesis.go | 12 +- .../02-client/legacy/v100/genesis_test.go | 18 +- .../core/02-client/legacy/v100/solomachine.go | 73 +- modules/core/02-client/legacy/v100/store.go | 15 +- .../core/02-client/legacy/v100/store_test.go | 24 +- .../migrations/v6}/solomachine.pb.go | 174 +- .../core/02-client/proposal_handler_test.go | 6 +- .../core/02-client/simulation/decoder_test.go | 6 +- modules/core/02-client/types/codec.go | 60 +- modules/core/02-client/types/codec_test.go | 73 +- modules/core/02-client/types/encoding.go | 24 +- modules/core/02-client/types/encoding_test.go | 10 +- modules/core/02-client/types/errors.go | 2 +- modules/core/02-client/types/events.go | 5 +- modules/core/02-client/types/genesis.go | 4 - modules/core/02-client/types/genesis_test.go | 189 +- modules/core/02-client/types/msgs.go | 39 +- modules/core/02-client/types/msgs_test.go | 52 +- modules/core/02-client/types/proposal.go | 7 +- modules/core/02-client/types/proposal_test.go | 29 +- modules/core/02-client/types/tx.pb.go | 108 +- .../03-connection/keeper/handshake_test.go | 14 +- modules/core/03-connection/keeper/keeper.go | 15 +- .../core/03-connection/keeper/keeper_test.go | 16 +- modules/core/03-connection/keeper/verify.go | 174 +- .../core/03-connection/keeper/verify_test.go | 30 +- modules/core/03-connection/types/msgs_test.go | 22 +- modules/core/04-channel/keeper/packet.go | 21 +- modules/core/04-channel/keeper/packet_test.go | 23 +- modules/core/ante/ante_test.go | 10 +- modules/core/exported/client.go | 190 +- modules/core/genesis.go | 2 +- modules/core/genesis_test.go | 41 +- modules/core/keeper/msg_server.go | 12 +- modules/core/keeper/msg_server_test.go | 29 +- modules/core/legacy/v100/genesis_test.go | 2 +- modules/core/migrations/v5/migrations.go | 44 + modules/core/migrations/v5/migrations_test.go | 116 + modules/core/module.go | 5 +- modules/core/simulation/decoder_test.go | 4 +- modules/core/types/codec.go | 8 +- .../06-solomachine/client_state.go | 260 ++ .../06-solomachine/client_state_test.go | 875 ++++++ modules/light-clients/06-solomachine/codec.go | 42 + .../{types => }/consensus_state.go | 7 +- .../{types => }/consensus_state_test.go | 29 +- .../06-solomachine/{types => }/errors.go | 3 +- .../06-solomachine/{types => }/header.go | 11 +- .../06-solomachine/{types => }/header_test.go | 20 +- .../{types => }/misbehaviour.go | 17 +- .../06-solomachine/misbehaviour_handle.go | 46 + .../{types => }/misbehaviour_test.go | 46 +- .../light-clients/06-solomachine/module.go | 6 +- modules/light-clients/06-solomachine/proof.go | 43 + .../06-solomachine/proof_test.go | 67 + .../{types => }/proposal_handle.go | 33 +- .../{types => }/proposal_handle_test.go | 36 +- .../06-solomachine/{types => }/solomachine.go | 14 +- .../06-solomachine/solomachine.pb.go | 2350 +++++++++++++++++ .../{types => }/solomachine_test.go | 19 +- .../06-solomachine/spec/01_concepts.md | 6 +- .../06-solomachine/types/client_state.go | 491 ---- .../06-solomachine/types/client_state_test.go | 844 ------ .../06-solomachine/types/codec.go | 131 - .../06-solomachine/types/codec_test.go | 186 -- .../types/misbehaviour_handle.go | 86 - .../types/misbehaviour_handle_test.go | 264 -- .../06-solomachine/types/proof.go | 477 ---- .../06-solomachine/types/proof_test.go | 103 - .../06-solomachine/types/update.go | 90 - .../06-solomachine/types/update_test.go | 181 -- .../light-clients/06-solomachine/update.go | 140 + .../06-solomachine/update_test.go | 564 ++++ .../07-tendermint/client_state.go | 335 +++ .../07-tendermint/client_state_test.go | 700 +++++ .../07-tendermint/{types => }/codec.go | 6 +- .../{types => }/consensus_state.go | 2 +- .../{types => }/consensus_state_test.go | 50 +- .../07-tendermint/{types => }/errors.go | 2 +- .../07-tendermint/{types => }/fraction.go | 2 +- .../07-tendermint/{types => }/genesis.go | 2 +- .../07-tendermint/{types => }/genesis_test.go | 34 +- .../07-tendermint/{types => }/header.go | 4 +- .../07-tendermint/{types => }/header_test.go | 6 +- .../07-tendermint/{types => }/misbehaviour.go | 15 +- .../{types => }/misbehaviour_handle.go | 66 +- .../07-tendermint/misbehaviour_handle_test.go | 717 +++++ .../{types => }/misbehaviour_test.go | 71 +- modules/light-clients/07-tendermint/module.go | 6 +- .../{types => }/proposal_handle.go | 25 +- .../{types => }/proposal_handle_test.go | 52 +- .../07-tendermint/{types => }/store.go | 60 +- .../07-tendermint/{types => }/store_test.go | 87 +- .../{types => }/tendermint.pb.go | 143 +- .../{types => }/tendermint_test.go | 6 +- .../07-tendermint/types/client_state.go | 583 ---- .../07-tendermint/types/client_state_test.go | 880 ------ .../types/misbehaviour_handle_test.go | 425 --- .../07-tendermint/types/update_test.go | 450 ---- .../07-tendermint/{types => }/update.go | 335 +-- .../07-tendermint/update_test.go | 745 ++++++ .../07-tendermint/{types => }/upgrade.go | 43 +- .../07-tendermint/{types => }/upgrade_test.go | 46 +- modules/light-clients/09-localhost/doc.go | 5 - modules/light-clients/09-localhost/module.go | 10 - .../09-localhost/types/client_state.go | 340 --- .../09-localhost/types/client_state_test.go | 526 ---- .../light-clients/09-localhost/types/codec.go | 16 - .../09-localhost/types/errors.go | 10 - .../light-clients/09-localhost/types/keys.go | 6 - .../09-localhost/types/localhost.pb.go | 369 --- .../09-localhost/types/localhost_test.go | 41 - proto/ibc/core/client/v1/tx.proto | 13 +- .../lightclients/localhost/v1/localhost.proto | 18 - .../solomachine/v2/solomachine.proto | 2 +- .../solomachine/v3/solomachine.proto | 103 + .../tendermint/v1/tendermint.proto | 5 +- testing/README.md | 4 +- testing/chain.go | 31 +- testing/config.go | 4 +- testing/coordinator.go | 6 +- testing/endpoint.go | 60 +- testing/solomachine.go | 42 +- testing/values.go | 4 +- 153 files changed, 9393 insertions(+), 8760 deletions(-) create mode 100644 docs/architecture/adr-005-consensus-height-events.md create mode 100644 docs/migrations/v5-to-v6.md rename modules/{light-clients/06-solomachine/types => core/02-client/migrations/v6}/solomachine.pb.go (92%) create mode 100644 modules/core/migrations/v5/migrations.go create mode 100644 modules/core/migrations/v5/migrations_test.go create mode 100644 modules/light-clients/06-solomachine/client_state.go create mode 100644 modules/light-clients/06-solomachine/client_state_test.go create mode 100644 modules/light-clients/06-solomachine/codec.go rename modules/light-clients/06-solomachine/{types => }/consensus_state.go (92%) rename modules/light-clients/06-solomachine/{types => }/consensus_state_test.go (62%) rename modules/light-clients/06-solomachine/{types => }/errors.go (85%) rename modules/light-clients/06-solomachine/{types => }/header.go (85%) rename modules/light-clients/06-solomachine/{types => }/header_test.go (82%) rename modules/light-clients/06-solomachine/{types => }/misbehaviour.go (83%) create mode 100644 modules/light-clients/06-solomachine/misbehaviour_handle.go rename modules/light-clients/06-solomachine/{types => }/misbehaviour_test.go (63%) create mode 100644 modules/light-clients/06-solomachine/proof.go create mode 100644 modules/light-clients/06-solomachine/proof_test.go rename modules/light-clients/06-solomachine/{types => }/proposal_handle.go (62%) rename modules/light-clients/06-solomachine/{types => }/proposal_handle_test.go (51%) rename modules/light-clients/06-solomachine/{types => }/solomachine.go (69%) create mode 100644 modules/light-clients/06-solomachine/solomachine.pb.go rename modules/light-clients/06-solomachine/{types => }/solomachine_test.go (85%) delete mode 100644 modules/light-clients/06-solomachine/types/client_state.go delete mode 100644 modules/light-clients/06-solomachine/types/client_state_test.go delete mode 100644 modules/light-clients/06-solomachine/types/codec.go delete mode 100644 modules/light-clients/06-solomachine/types/codec_test.go delete mode 100644 modules/light-clients/06-solomachine/types/misbehaviour_handle.go delete mode 100644 modules/light-clients/06-solomachine/types/misbehaviour_handle_test.go delete mode 100644 modules/light-clients/06-solomachine/types/proof.go delete mode 100644 modules/light-clients/06-solomachine/types/proof_test.go delete mode 100644 modules/light-clients/06-solomachine/types/update.go delete mode 100644 modules/light-clients/06-solomachine/types/update_test.go create mode 100644 modules/light-clients/06-solomachine/update.go create mode 100644 modules/light-clients/06-solomachine/update_test.go create mode 100644 modules/light-clients/07-tendermint/client_state.go create mode 100644 modules/light-clients/07-tendermint/client_state_test.go rename modules/light-clients/07-tendermint/{types => }/codec.go (87%) rename modules/light-clients/07-tendermint/{types => }/consensus_state.go (99%) rename modules/light-clients/07-tendermint/{types => }/consensus_state_test.go (73%) rename modules/light-clients/07-tendermint/{types => }/errors.go (98%) rename modules/light-clients/07-tendermint/{types => }/fraction.go (97%) rename modules/light-clients/07-tendermint/{types => }/genesis.go (97%) rename modules/light-clients/07-tendermint/{types => }/genesis_test.go (77%) rename modules/light-clients/07-tendermint/{types => }/header.go (97%) rename modules/light-clients/07-tendermint/{types => }/header_test.go (94%) rename modules/light-clients/07-tendermint/{types => }/misbehaviour.go (95%) rename modules/light-clients/07-tendermint/{types => }/misbehaviour_handle.go (61%) create mode 100644 modules/light-clients/07-tendermint/misbehaviour_handle_test.go rename modules/light-clients/07-tendermint/{types => }/misbehaviour_test.go (82%) rename modules/light-clients/07-tendermint/{types => }/proposal_handle.go (78%) rename modules/light-clients/07-tendermint/{types => }/proposal_handle_test.go (83%) rename modules/light-clients/07-tendermint/{types => }/store.go (91%) rename modules/light-clients/07-tendermint/{types => }/store_test.go (60%) rename modules/light-clients/07-tendermint/{types => }/tendermint.pb.go (87%) rename modules/light-clients/07-tendermint/{types => }/tendermint_test.go (96%) delete mode 100644 modules/light-clients/07-tendermint/types/client_state.go delete mode 100644 modules/light-clients/07-tendermint/types/client_state_test.go delete mode 100644 modules/light-clients/07-tendermint/types/misbehaviour_handle_test.go delete mode 100644 modules/light-clients/07-tendermint/types/update_test.go rename modules/light-clients/07-tendermint/{types => }/update.go (50%) create mode 100644 modules/light-clients/07-tendermint/update_test.go rename modules/light-clients/07-tendermint/{types => }/upgrade.go (78%) rename modules/light-clients/07-tendermint/{types => }/upgrade_test.go (93%) delete mode 100644 modules/light-clients/09-localhost/doc.go delete mode 100644 modules/light-clients/09-localhost/module.go delete mode 100644 modules/light-clients/09-localhost/types/client_state.go delete mode 100644 modules/light-clients/09-localhost/types/client_state_test.go delete mode 100644 modules/light-clients/09-localhost/types/codec.go delete mode 100644 modules/light-clients/09-localhost/types/errors.go delete mode 100644 modules/light-clients/09-localhost/types/keys.go delete mode 100644 modules/light-clients/09-localhost/types/localhost.pb.go delete mode 100644 modules/light-clients/09-localhost/types/localhost_test.go delete mode 100644 proto/ibc/lightclients/localhost/v1/localhost.proto create mode 100644 proto/ibc/lightclients/solomachine/v3/solomachine.proto diff --git a/CHANGELOG.md b/CHANGELOG.md index 6aff1fcc83e..9845d1492ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,7 +44,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking -* (core/03-connection) [\#1797](https://github.com/cosmos/ibc-go/pull/1797) Remove `PreviousConnectionID` from `NewMsgConnectionOpenTry` arguments. `MsgConnectionOpenTry.ValidateBasic()` returns error if the deprecated `PreviousConnectionID` is not empty. +* (core/03-connection) [\#1797](https://github.com/cosmos/ibc-go/pull/1797) Remove `PreviousConnectionID` from `NewMsgConnectionOpenTry` arguments. `MsgConnectionOpenTry.ValidateBasic()` returns error if the deprecated `PreviousConnectionID` is not empty * (core/04-channel) [\#1792](https://github.com/cosmos/ibc-go/pull/1792) Remove `PreviousChannelID` from `NewMsgChannelOpenTry` arguments. `MsgChannelOpenTry.ValidateBasic()` returns error if the deprecated `PreviousChannelID` is not empty. * (core/04-channel) [\#1418](https://github.com/cosmos/ibc-go/pull/1418) `NewPacketId` has been renamed to `NewPacketID` to comply with go linting rules. * (core/ante) [\#1418](https://github.com/cosmos/ibc-go/pull/1418) `AnteDecorator` has been renamed to `RedundancyDecorator` to comply with go linting rules and to give more clarity to the purpose of the Decorator. @@ -61,6 +61,18 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (transfer)[\#1565](https://github.com/cosmos/ibc-go/pull/1565) Removing `NewErrorAcknowledgement` in favour of `channeltypes.NewErrorAcknowledgement`. * (channel)[\#1565](https://github.com/cosmos/ibc-go/pull/1565) Updating `NewErrorAcknowledgement` to accept an error instead of a string and removing the possibility of non-deterministic writes to application state. * (core/04-channel)[\#1636](https://github.com/cosmos/ibc-go/pull/1636) Removing `SplitChannelVersion` and `MergeChannelVersions` functions since they are not used. +- +* (06-solomachine) [\#1679](https://github.com/cosmos/ibc-go/pull/1679) Remove `types` sub-package from `06-solomachine` lightclient directory. +* (07-tendermint) [\#1677](https://github.com/cosmos/ibc-go/pull/1677) Remove `types` sub-package from `07-tendermint` lightclient directory. +* (06-solomachine) [\#1687](https://github.com/cosmos/ibc-go/pull/1687) Bump `06-solomachine` protobuf version from `v2` to `v3`. +* (06-solomachine) [\#1687](https://github.com/cosmos/ibc-go/pull/1687) Removed `DataType` enum and associated message types from `06-solomachine`. `DataType` has been removed from `SignBytes` and `SignatureAndData` in favour of `path`. +* (02-client) [\#598](https://github.com/cosmos/ibc-go/pull/598) The client state and consensus state return value has been removed from `VerifyUpgradeAndUpdateState`. Light client implementations must update the client state and consensus state after verifying a valid client upgrade. +* (06-solomachine) [\#1100](https://github.com/cosmos/ibc-go/pull/1100) Remove `GetClientID` function from 06-solomachine `Misbehaviour` type. +* (06-solomachine) [\#1100](https://github.com/cosmos/ibc-go/pull/1100) Deprecate `ClientId` field in 06-solomachine `Misbehaviour` type. +* (07-tendermint) [\#1097](https://github.com/cosmos/ibc-go/pull/1097) Remove `GetClientID` function from 07-tendermint `Misbehaviour` type. +* (07-tendermint) [\#1097](https://github.com/cosmos/ibc-go/pull/1097) Deprecate `ClientId` field in 07-tendermint `Misbehaviour` type. +* (modules/core/exported) [\#1107](https://github.com/cosmos/ibc-go/pull/1107) Merging the `Header` and `Misbehaviour` interfaces into a single `ClientMessage` type. +* (07-tendermint) [\#1896](https://github.com/cosmos/ibc-go/pull/1896) Remove error return from `IterateConsensusStateAscending` in `07-tendermint`. ### State Machine Breaking @@ -79,7 +91,22 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (app/29-fee) [\#1341](https://github.com/cosmos/ibc-go/pull/1341) Check if the fee module is locked and if the fee module is enabled before refunding all fees * (transfer) [\#1414](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnRecvPacket` and `OnAcknowledgementPacket`. * (testing/simapp) [\#1397](https://github.com/cosmos/ibc-go/pull/1397) Adding mock module to maccperms and adding check to ensure mock module is not a blocked account address. +- * (modules/light-clients/07-tendermint) [\#1713](https://github.com/cosmos/ibc-go/pull/1713) Allow client upgrade proposals to update `TrustingPeriod`. See ADR-026 for context. +* (modules/core/02-client) [\#1188](https://github.com/cosmos/ibc-go/pull/1188/files) Routing `MsgSubmitMisbehaviour` to `UpdateClient` keeper function. Deprecating `SubmitMisbehaviour` endpoint. +* (modules/core/02-client) [\#1208](https://github.com/cosmos/ibc-go/pull/1208) Replace `CheckHeaderAndUpdateState` usage in 02-client with calls to `VerifyClientMessage`, `CheckForMisbehaviour`, `UpdateStateOnMisbehaviour` and `UpdateState`. +* (modules/light-clients/09-localhost) [\#1187](https://github.com/cosmos/ibc-go/pull/1187/) Removing localhost light client implementation as it is not functional. An upgrade handler is provided in `modules/migrations/v5` to prune `09-localhost` clients and consensus states from the store. +* [\#1186](https://github.com/cosmos/ibc-go/pull/1186/files) Removing `GetRoot` function from ConsensusState interface in `02-client`. `GetRoot` is unused by core IBC. +* (modules/core/02-client) [\#1196](https://github.com/cosmos/ibc-go/pull/1196) Adding VerifyClientMessage to ClientState interface. +* (modules/core/02-client) [\#1198](https://github.com/cosmos/ibc-go/pull/1198) Adding UpdateStateOnMisbehaviour to ClientState interface. +* (modules/core/02-client) [\#1170](https://github.com/cosmos/ibc-go/pull/1170) Updating `ClientUpdateProposal` to set client state in lightclient implementations `CheckSubstituteAndUpdateState` methods. +* (modules/core/02-client) [\#1197](https://github.com/cosmos/ibc-go/pull/1197) Adding `CheckForMisbehaviour` to `ClientState` interface. +* (modules/core/02-client) [\#1195](https://github.com/cosmos/ibc-go/pull/1210) Removing `CheckHeaderAndUpdateState` from `ClientState` interface & associated light client implementations. +* (modules/core/02-client) [\#1189](https://github.com/cosmos/ibc-go/pull/1212) Removing `CheckMisbehaviourAndUpdateState` from `ClientState` interface & associated light client implementations. +* (modules/core/exported) [\#1206](https://github.com/cosmos/ibc-go/pull/1206) Adding new method `UpdateState` to `ClientState` interface. +* (modules/core/02-client) [\#1741](https://github.com/cosmos/ibc-go/pull/1741) Emitting a new `upgrade_chain` event upon setting upgrade consensus state. +* (client) [\#724](https://github.com/cosmos/ibc-go/pull/724) `IsRevisionFormat` and `IsClientIDFormat` have been updated to disallow newlines before the dash used to separate the chainID and revision number, and the client type and client sequence. +* (02-client/cli) [\#897](https://github.com/cosmos/ibc-go/pull/897) Remove `GetClientID()` from `Misbehaviour` interface. Submit client misbehaviour cli command requires an explicit client id now. ### Features @@ -94,6 +121,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (apps/29-fee) [\#1774](https://github.com/cosmos/ibc-go/pull/1774) Change non nil relayer assertion to non empty to avoid import/export issues for genesis upgrades. * (makefile) [\#1785](https://github.com/cosmos/ibc-go/pull/1785) Fetch the correct versions of protocol buffers dependencies from tendermint, cosmos-sdk, and ics23. * (apps/29-fee) [\#1278](https://github.com/cosmos/ibc-go/pull/1278) The URI path for the query to get all incentivized packets for a specific channel did not follow the same format as the rest of queries. +- +* (light-clients/solomachine) [#1839](https://github.com/cosmos/ibc-go/issues/1839) Fixed usage of the new diversifier in validation of changing diversifiers for the solo machine. The current diversifier must sign over the new diversifier. +* (light-clients/07-tendermint) [\#1674](https://github.com/cosmos/ibc-go/pull/1674) Submitted ClientState is zeroed out before checking the proof in order to prevent the proposal from containing information governance is not actually voting on. +* (modules/core/02-client)[\#1676](https://github.com/cosmos/ibc-go/pull/1676) ClientState must be zeroed out for `UpgradeProposals` to pass validation. This prevents a proposal containing information governance is not actually voting on. ## [v3.1.1](https://github.com/cosmos/ibc-go/releases/tag/v3.1.1) - 2022-08-02 @@ -191,6 +222,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* (client) [\#888](https://github.com/cosmos/ibc-go/pull/888) Add `GetTimestampAtHeight` to `ClientState` * (interchain-accounts) [\#1037](https://github.com/cosmos/ibc-go/pull/1037) Add a function `InitModule` to the interchain accounts `AppModule`. This function should be called within the upgrade handler when adding the interchain accounts module to a chain. It should be called in place of InitGenesis (set the consensus version in the version map). * (testing) [\#942](https://github.com/cosmos/ibc-go/pull/942) `NewTestChain` will create 4 validators in validator set by default. A new constructor function `NewTestChainWithValSet` is provided for test writers who want custom control over the validator set of test chains. * (testing) [\#904](https://github.com/cosmos/ibc-go/pull/904) Add `ParsePacketFromEvents` function to the testing package. Useful when sending/relaying packets via the testing package. @@ -200,9 +232,9 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (channel) [\#692](https://github.com/cosmos/ibc-go/pull/692) Minimize channel logging by only emitting the packet sequence, source port/channel, destination port/channel upon packet receives, acknowledgements and timeouts. * [\#383](https://github.com/cosmos/ibc-go/pull/383) Adds helper functions for merging and splitting middleware versions from the underlying app version. * (modules/core/05-port) [\#288](https://github.com/cosmos/ibc-go/issues/288) Making the 05-port keeper function IsBound public. The IsBound function checks if the provided portID is already binded to a module. +* (client) [\#724](https://github.com/cosmos/ibc-go/pull/724) `IsRevisionFormat` and `IsClientIDFormat` have been updated to disallow newlines before the dash used to separate the chainID and revision number, and the client type and client sequence. * (channel) [\#644](https://github.com/cosmos/ibc-go/pull/644) Adds `GetChannelConnection` to the ChannelKeeper. This function returns the connectionID and connection state associated with a channel. * (channel) [\647](https://github.com/cosmos/ibc-go/pull/647) Reorganizes channel handshake handling to set channel state after IBC application callbacks. -* (client) [\#724](https://github.com/cosmos/ibc-go/pull/724) `IsRevisionFormat` and `IsClientIDFormat` have been updated to disallow newlines before the dash used to separate the chainID and revision number, and the client type and client sequence. * (interchain-accounts) [\#1466](https://github.com/cosmos/ibc-go/pull/1466) Emit event when there is an acknowledgement during `OnRecvPacket`. ### Features diff --git a/README.md b/README.md index f4a830c5149..ff3e074b04f 100644 --- a/README.md +++ b/README.md @@ -64,8 +64,6 @@ The Inter-Blockchain Communication protocol (IBC) allows blockchains to talk to 3.2 [ICS 06 Solo Machine](https://github.com/cosmos/ibc-go/tree/main/modules/light-clients/06-solomachine) -Note: The localhost client is currently non-functional. - ## Roadmap For an overview of upcoming changes to ibc-go take a look at the [roadmap](./docs/roadmap/roadmap.md). diff --git a/docs/OLD_README.md b/docs/OLD_README.md index 47bb2547732..df9cd52112a 100644 --- a/docs/OLD_README.md +++ b/docs/OLD_README.md @@ -28,8 +28,6 @@ For the general specification please refer to the [Interchain Standards](https:/ 3.2 [Tendermint Client](./../light-clients/07-tendermint/spec/README.md) - 3.3 [Localhost Client](./../light-clients/09-localhost/spec/README.md) - ## Implementation Details As stated above, the IBC implementation on the Cosmos SDK introduces some changes @@ -114,4 +112,4 @@ x/ibc │   └── 09-localhost/ └── testing/ ``` - \ No newline at end of file + diff --git a/docs/architecture/adr-005-consensus-height-events.md b/docs/architecture/adr-005-consensus-height-events.md new file mode 100644 index 00000000000..430d7064a1e --- /dev/null +++ b/docs/architecture/adr-005-consensus-height-events.md @@ -0,0 +1,88 @@ +# 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-027-ibc-wasm.md b/docs/architecture/adr-027-ibc-wasm.md index d105c9854b4..4197735e3a7 100644 --- a/docs/architecture/adr-027-ibc-wasm.md +++ b/docs/architecture/adr-027-ibc-wasm.md @@ -100,7 +100,7 @@ packaged inside a payload which is json serialized and passed to `callContract` array of bytes returned by the smart contract. This data is deserialized and passed as return argument. ```go -func (c *ClientState) CheckProposedHeaderAndUpdateState(context sdk.Context, marshaler codec.BinaryMarshaler, store sdk.KVStore, header exported.Header) (exported.ClientState, exported.ConsensusState, error) { +func (c *ClientState) CheckProposedHeaderAndUpdateState(context sdk.Context, marshaler codec.BinaryMarshaler, store sdk.KVStore, header exported.ClientMessage) (exported.ClientState, exported.ConsensusState, error) { // get consensus state corresponding to client state to check if the client is expired consensusState, err := GetConsensusState(store, marshaler, c.LatestHeight) if err != nil { diff --git a/docs/ibc/integration.md b/docs/ibc/integration.md index d2d9f057ea3..0b01ffd7347 100644 --- a/docs/ibc/integration.md +++ b/docs/ibc/integration.md @@ -175,17 +175,6 @@ at each height during the `BeginBlock` call. The historical info is required to 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](https://github.com/cosmos/ibc/blob/master/spec/client/ics-009-loopback-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 { diff --git a/docs/ibc/middleware/develop.md b/docs/ibc/middleware/develop.md index 3c0c74a0186..7ee020ca9c8 100644 --- a/docs/ibc/middleware/develop.md +++ b/docs/ibc/middleware/develop.md @@ -408,6 +408,26 @@ func GetAppVersion( 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/ibc/proto-docs.md b/docs/ibc/proto-docs.md index c612a0180b3..48219f3d66b 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -295,9 +295,6 @@ - [ibc/core/types/v1/genesis.proto](#ibc/core/types/v1/genesis.proto) - [GenesisState](#ibc.core.types.v1.GenesisState) -- [ibc/lightclients/localhost/v1/localhost.proto](#ibc/lightclients/localhost/v1/localhost.proto) - - [ClientState](#ibc.lightclients.localhost.v1.ClientState) - - [ibc/lightclients/solomachine/v1/solomachine.proto](#ibc/lightclients/solomachine/v1/solomachine.proto) - [ChannelStateData](#ibc.lightclients.solomachine.v1.ChannelStateData) - [ClientState](#ibc.lightclients.solomachine.v1.ClientState) @@ -338,6 +335,16 @@ - [DataType](#ibc.lightclients.solomachine.v2.DataType) +- [ibc/lightclients/solomachine/v3/solomachine.proto](#ibc/lightclients/solomachine/v3/solomachine.proto) + - [ClientState](#ibc.lightclients.solomachine.v3.ClientState) + - [ConsensusState](#ibc.lightclients.solomachine.v3.ConsensusState) + - [Header](#ibc.lightclients.solomachine.v3.Header) + - [HeaderData](#ibc.lightclients.solomachine.v3.HeaderData) + - [Misbehaviour](#ibc.lightclients.solomachine.v3.Misbehaviour) + - [SignBytes](#ibc.lightclients.solomachine.v3.SignBytes) + - [SignatureAndData](#ibc.lightclients.solomachine.v3.SignatureAndData) + - [TimestampedSignatureData](#ibc.lightclients.solomachine.v3.TimestampedSignatureData) + - [ibc/lightclients/tendermint/v1/tendermint.proto](#ibc/lightclients/tendermint/v1/tendermint.proto) - [ClientState](#ibc.lightclients.tendermint.v1.ClientState) - [ConsensusState](#ibc.lightclients.tendermint.v1.ConsensusState) @@ -3549,13 +3556,14 @@ MsgCreateClientResponse defines the Msg/CreateClient response type. ### MsgSubmitMisbehaviour MsgSubmitMisbehaviour defines an sdk.Msg type that submits Evidence for light client misbehaviour. +Warning: DEPRECATED | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `client_id` | [string](#string) | | client unique identifier | -| `misbehaviour` | [google.protobuf.Any](#google.protobuf.Any) | | misbehaviour used for freezing the light client | -| `signer` | [string](#string) | | signer address | +| `client_id` | [string](#string) | | **Deprecated.** client unique identifier | +| `misbehaviour` | [google.protobuf.Any](#google.protobuf.Any) | | **Deprecated.** misbehaviour used for freezing the light client | +| `signer` | [string](#string) | | **Deprecated.** signer address | @@ -3577,13 +3585,13 @@ type. ### MsgUpdateClient MsgUpdateClient defines an sdk.Msg to update a IBC client state using -the given header. +the given client message. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `client_id` | [string](#string) | | client unique identifier | -| `header` | [google.protobuf.Any](#google.protobuf.Any) | | header to update the light client | +| `client_message` | [google.protobuf.Any](#google.protobuf.Any) | | client message to update the light client | | `signer` | [string](#string) | | signer address | @@ -4316,39 +4324,6 @@ GenesisState defines the ibc module's genesis state. - - - - - - - - - - - -

Top

- -## ibc/lightclients/localhost/v1/localhost.proto - - - - - -### ClientState -ClientState defines a loopback (localhost) client. It requires (read-only) -access to keys outside the client prefix. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `chain_id` | [string](#string) | | self chain ID | -| `height` | [ibc.core.client.v1.Height](#ibc.core.client.v1.Height) | | self latest block height | - - - - - @@ -4995,6 +4970,169 @@ to preserve uniqueness of different data sign byte encodings. + +

Top

+ +## ibc/lightclients/solomachine/v3/solomachine.proto + + + + + +### ClientState +ClientState defines a solo machine client that tracks the current consensus +state and if the client is frozen. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `sequence` | [uint64](#uint64) | | latest sequence of the client state | +| `is_frozen` | [bool](#bool) | | frozen sequence of the solo machine | +| `consensus_state` | [ConsensusState](#ibc.lightclients.solomachine.v3.ConsensusState) | | | +| `allow_update_after_proposal` | [bool](#bool) | | when set to true, will allow governance to update a solo machine client. The client will be unfrozen if it is frozen. | + + + + + + + + +### ConsensusState +ConsensusState defines a solo machine consensus state. The sequence of a +consensus state is contained in the "height" key used in storing the +consensus state. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `public_key` | [google.protobuf.Any](#google.protobuf.Any) | | public key of the solo machine | +| `diversifier` | [string](#string) | | diversifier allows the same public key to be re-used across different solo machine clients (potentially on different chains) without being considered misbehaviour. | +| `timestamp` | [uint64](#uint64) | | | + + + + + + + + +### Header +Header defines a solo machine consensus header + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `sequence` | [uint64](#uint64) | | sequence to update solo machine public key at | +| `timestamp` | [uint64](#uint64) | | | +| `signature` | [bytes](#bytes) | | | +| `new_public_key` | [google.protobuf.Any](#google.protobuf.Any) | | | +| `new_diversifier` | [string](#string) | | | + + + + + + + + +### HeaderData +HeaderData returns the SignBytes data for update verification. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `new_pub_key` | [google.protobuf.Any](#google.protobuf.Any) | | header public key | +| `new_diversifier` | [string](#string) | | header diversifier | + + + + + + + + +### Misbehaviour +Misbehaviour defines misbehaviour for a solo machine which consists +of a sequence and two signatures over different messages at that sequence. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `client_id` | [string](#string) | | **Deprecated.** ClientID is deprecated | +| `sequence` | [uint64](#uint64) | | | +| `signature_one` | [SignatureAndData](#ibc.lightclients.solomachine.v3.SignatureAndData) | | | +| `signature_two` | [SignatureAndData](#ibc.lightclients.solomachine.v3.SignatureAndData) | | | + + + + + + + + +### SignBytes +SignBytes defines the signed bytes used for signature verification. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `sequence` | [uint64](#uint64) | | the sequence number | +| `timestamp` | [uint64](#uint64) | | the proof timestamp | +| `diversifier` | [string](#string) | | the public key diversifier | +| `path` | [bytes](#bytes) | | the standardised path bytes | +| `data` | [bytes](#bytes) | | the marshaled data bytes | + + + + + + + + +### SignatureAndData +SignatureAndData contains a signature and the data signed over to create that +signature. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `signature` | [bytes](#bytes) | | | +| `path` | [bytes](#bytes) | | | +| `data` | [bytes](#bytes) | | | +| `timestamp` | [uint64](#uint64) | | | + + + + + + + + +### TimestampedSignatureData +TimestampedSignatureData contains the signature data and the timestamp of the +signature. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `signature_data` | [bytes](#bytes) | | | +| `timestamp` | [uint64](#uint64) | | | + + + + + + + + + + + + + + +

Top

@@ -5100,7 +5238,7 @@ that implements Misbehaviour interface expected by ICS-02 | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `client_id` | [string](#string) | | | +| `client_id` | [string](#string) | | **Deprecated.** ClientID is deprecated | | `header_1` | [Header](#ibc.lightclients.tendermint.v1.Header) | | | | `header_2` | [Header](#ibc.lightclients.tendermint.v1.Header) | | | diff --git a/docs/migrations/v5-to-v6.md b/docs/migrations/v5-to-v6.md new file mode 100644 index 00000000000..70e9519f4e3 --- /dev/null +++ b/docs/migrations/v5-to-v6.md @@ -0,0 +1,101 @@ +# 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 + +- 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 + +### `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 `CheckHeaderAndUpdateState` function has been split into 4 new functions: + +- `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. + +### `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. + +### Light client implementations + +The `09-localhost` light client implementation has been removed because it is currently non-functional. + +An upgrade handler has been added to supply chain developers with the logic needed to prune the ibc client store and successfully complete the removal of `09-localhost`. +Add the following to the application upgrade handler in `app/app.go`, calling `MigrateToV6` to perform store migration logic. + +```go +import ( + // ... + ibcv6 "github.com/cosmos/ibc-go/v6/modules/core/migrations/v6" +) + +// ... + +app.UpgradeKeeper.SetUpgradeHandler( + upgradeName, + func(ctx sdk.Context, _ upgradetypes.Plan, _ module.VersionMap) (module.VersionMap, error) { + // prune the 09-localhost client from the ibc client store + ibcv6.MigrateToV6(ctx, app.IBCKeeper.ClientKeeper) + + return app.mm.RunMigrations(ctx, app.configurator, fromVM) + }, +) +``` + +Please note the above upgrade handler is optional and should only be run if chains have an existing `09-localhost` client stored in state. +A simple query can be performed to check for a `09-localhost` client on chain. + +For example: + +``` +simd query ibc client states | grep 09-localhost +``` + +### 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`. 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 02d4ff07179..89058aad4e1 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go @@ -308,7 +308,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { Token: sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), Sender: interchainAccountAddr, Receiver: suite.chainA.SenderAccount.GetAddress().String(), - TimeoutHeight: clienttypes.NewHeight(0, 100), + TimeoutHeight: clienttypes.NewHeight(1, 100), TimeoutTimestamp: uint64(0), } @@ -464,7 +464,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, - clienttypes.NewHeight(0, 100), + clienttypes.NewHeight(1, 100), 0, ) diff --git a/modules/apps/29-fee/ica_test.go b/modules/apps/29-fee/ica_test.go index bcc8098d0dc..a1ab7ef6d03 100644 --- a/modules/apps/29-fee/ica_test.go +++ b/modules/apps/29-fee/ica_test.go @@ -189,7 +189,7 @@ func buildInterchainAccountsPacket(path *ibctesting.Path, data []byte, seq uint6 path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, - clienttypes.NewHeight(0, 100), + clienttypes.NewHeight(1, 100), 0, ) diff --git a/modules/apps/29-fee/transfer_test.go b/modules/apps/29-fee/transfer_test.go index 74d7089faf7..8aeb6ffeac0 100644 --- a/modules/apps/29-fee/transfer_test.go +++ b/modules/apps/29-fee/transfer_test.go @@ -30,7 +30,7 @@ func (suite *FeeTestSuite) TestFeeTransfer() { 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, coin, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(0, 100), 0), + transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, coin, 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 diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index a09c4203e8f..6a4706f9f5a 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -313,7 +313,7 @@ func (suite *KeeperTestSuite) TestModelBasedRelay() { description := file_info.Name() + " # " + strconv.Itoa(i+1) suite.Run(fmt.Sprintf("Case %s", description), func() { seq := uint64(1) - packet := channeltypes.NewPacket(tc.packet.Data.GetBytes(), seq, tc.packet.SourcePort, tc.packet.SourceChannel, tc.packet.DestPort, tc.packet.DestChannel, clienttypes.NewHeight(0, 100), 0) + packet := channeltypes.NewPacket(tc.packet.Data.GetBytes(), seq, tc.packet.SourcePort, tc.packet.SourceChannel, tc.packet.DestPort, tc.packet.DestChannel, clienttypes.NewHeight(1, 100), 0) bankBefore := BankFromBalances(tc.bankBefore) realBankBefore := BankOfChain(suite.chainB) // First validate the packet itself (mimics what happens when the packet is being sent and/or received) @@ -345,7 +345,7 @@ func (suite *KeeperTestSuite) TestModelBasedRelay() { sdk.NewCoin(denom, amount), sender, tc.packet.Data.Receiver, - clienttypes.NewHeight(0, 110), + clienttypes.NewHeight(1, 110), 0) } case "OnRecvPacket": diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 7cfb0cae2fc..1e57e3f2236 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -112,13 +112,13 @@ func (suite *KeeperTestSuite) TestSendTransfer() { if !tc.sendFromSource { // send coin from chainB to chainA coinFromBToA := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) - transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, coinFromBToA, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), clienttypes.NewHeight(0, 110), 0) + transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, coinFromBToA, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 110), 0) _, err = suite.chainB.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed // receive coin on chainA from chainB fungibleTokenPacket := types.NewFungibleTokenPacketData(coinFromBToA.Denom, coinFromBToA.Amount.String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String()) - packet := channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, clienttypes.NewHeight(0, 110), 0) + packet := channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, clienttypes.NewHeight(1, 110), 0) // get proof of packet commitment from chainB err = path.EndpointA.UpdateClient() @@ -133,7 +133,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() { err = suite.chainA.GetSimApp().TransferKeeper.SendTransfer( suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, amount, - suite.chainA.SenderAccount.GetAddress(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(0, 110), 0, + suite.chainA.SenderAccount.GetAddress(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 110), 0, ) if tc.expPass { @@ -210,7 +210,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { if tc.recvIsSource { // send coin from chainB to chainA, receive them, acknowledge them, and send back to chainB coinFromBToA := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) - transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, coinFromBToA, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), clienttypes.NewHeight(0, 110), 0) + transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, coinFromBToA, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 110), 0) res, err := suite.chainB.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -229,14 +229,14 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { } // send coin from chainA to chainB - transferMsg := types.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoin(trace.IBCDenom(), amount), suite.chainA.SenderAccount.GetAddress().String(), receiver, clienttypes.NewHeight(0, 110), 0) + transferMsg := types.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoin(trace.IBCDenom(), amount), suite.chainA.SenderAccount.GetAddress().String(), receiver, clienttypes.NewHeight(1, 110), 0) _, err := suite.chainA.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed tc.malleate() data := types.NewFungibleTokenPacketData(trace.GetFullDenomPath(), amount.String(), suite.chainA.SenderAccount.GetAddress().String(), receiver) - packet := channeltypes.NewPacket(data.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0) + packet := channeltypes.NewPacket(data.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) @@ -309,7 +309,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { tc.malleate() data := types.NewFungibleTokenPacketData(trace.GetFullDenomPath(), amount.String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String()) - packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0) + packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) preCoin := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), trace.IBCDenom()) @@ -405,7 +405,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { tc.malleate() data := types.NewFungibleTokenPacketData(trace.GetFullDenomPath(), amount.String(), sender, suite.chainB.SenderAccount.GetAddress().String()) - packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0) + packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) preCoin := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), trace.IBCDenom()) diff --git a/modules/apps/transfer/transfer_test.go b/modules/apps/transfer/transfer_test.go index 95aa0c4d4e3..b6a88f7e651 100644 --- a/modules/apps/transfer/transfer_test.go +++ b/modules/apps/transfer/transfer_test.go @@ -47,7 +47,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { suite.coordinator.Setup(path) // originalBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) - timeoutHeight := clienttypes.NewHeight(0, 110) + timeoutHeight := clienttypes.NewHeight(1, 110) amount, ok := sdk.NewIntFromString("9223372036854775808") // 2^63 (one above int64) suite.Require().True(ok) diff --git a/modules/core/02-client/abci.go b/modules/core/02-client/abci.go index 9fe681e2276..c4fcc91ec37 100644 --- a/modules/core/02-client/abci.go +++ b/modules/core/02-client/abci.go @@ -4,11 +4,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/v5/modules/core/02-client/keeper" - "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ) -// BeginBlocker updates an existing localhost client with the latest block height. +// BeginBlocker is used to perform IBC client upgrades func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { plan, found := k.GetUpgradePlan(ctx) if found { @@ -20,7 +19,7 @@ func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { // within the trusting period of the last block time on this chain. _, exists := k.GetUpgradedClient(ctx, plan.Height) if exists && ctx.BlockHeight() == plan.Height-1 { - upgradedConsState := &ibctmtypes.ConsensusState{ + upgradedConsState := &ibctm.ConsensusState{ Timestamp: ctx.BlockTime(), NextValidatorsHash: ctx.BlockHeader().NextValidatorsHash, } @@ -29,16 +28,7 @@ func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { // SetUpgradedConsensusState always returns nil, hence the blank here. _ = k.SetUpgradedConsensusState(ctx, plan.Height, bz) + keeper.EmitUpgradeChainEvent(ctx, plan.Height) } } - - _, found = k.GetClientState(ctx, exported.Localhost) - if !found { - return - } - - // update the localhost client with the latest block height - if err := k.UpdateClient(ctx, exported.Localhost, nil); err != nil { - panic(err) - } } diff --git a/modules/core/02-client/abci_test.go b/modules/core/02-client/abci_test.go index c3bbb187892..acdfd32f389 100644 --- a/modules/core/02-client/abci_test.go +++ b/modules/core/02-client/abci_test.go @@ -1,8 +1,10 @@ package client_test import ( + "strings" "testing" + sdk "github.com/cosmos/cosmos-sdk/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" @@ -10,9 +12,7 @@ import ( client "github.com/cosmos/ibc-go/v5/modules/core/02-client" "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" - localhosttypes "github.com/cosmos/ibc-go/v5/modules/light-clients/09-localhost/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) @@ -30,13 +30,6 @@ func (suite *ClientTestSuite) SetupTest() { suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) - - // set localhost client - revision := types.ParseChainID(suite.chainA.GetContext().ChainID()) - localHostClient := localhosttypes.NewClientState( - suite.chainA.GetContext().ChainID(), types.NewHeight(revision, uint64(suite.chainA.GetContext().BlockHeight())), - ) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), exported.Localhost, localHostClient) } func TestClientTestSuite(t *testing.T) { @@ -44,11 +37,6 @@ func TestClientTestSuite(t *testing.T) { } func (suite *ClientTestSuite) TestBeginBlocker() { - prevHeight := types.GetSelfHeight(suite.chainA.GetContext()) - - localHostClient := suite.chainA.GetClientState(exported.Localhost) - suite.Require().Equal(prevHeight, localHostClient.GetLatestHeight()) - for i := 0; i < 10; i++ { // increment height suite.coordinator.CommitBlock(suite.chainA, suite.chainB) @@ -56,10 +44,6 @@ func (suite *ClientTestSuite) TestBeginBlocker() { suite.Require().NotPanics(func() { client.BeginBlocker(suite.chainA.GetContext(), suite.chainA.App.GetIBCKeeper().ClientKeeper) }, "BeginBlocker shouldn't panic") - - localHostClient = suite.chainA.GetClientState(exported.Localhost) - suite.Require().Equal(prevHeight.Increment(), localHostClient.GetLatestHeight()) - prevHeight = localHostClient.GetLatestHeight().(types.Height) } } @@ -88,7 +72,59 @@ func (suite *ClientTestSuite) TestBeginBlockerConsensusState() { // plan Height is at ctx.BlockHeight+1 consState, found := suite.chainA.GetSimApp().UpgradeKeeper.GetUpgradedConsensusState(newCtx, plan.Height) suite.Require().True(found) - bz, err = types.MarshalConsensusState(suite.chainA.App.AppCodec(), &ibctmtypes.ConsensusState{Timestamp: newCtx.BlockTime(), NextValidatorsHash: nextValsHash}) + bz, err = types.MarshalConsensusState(suite.chainA.App.AppCodec(), &ibctm.ConsensusState{Timestamp: newCtx.BlockTime(), NextValidatorsHash: nextValsHash}) suite.Require().NoError(err) suite.Require().Equal(bz, consState) } + +func (suite *ClientTestSuite) TestBeginBlockerUpgradeEvents() { + plan := &upgradetypes.Plan{ + Name: "test", + Height: suite.chainA.GetContext().BlockHeight() + 1, + } + // set upgrade plan in the upgrade store + store := suite.chainA.GetContext().KVStore(suite.chainA.GetSimApp().GetKey(upgradetypes.StoreKey)) + bz := suite.chainA.App.AppCodec().MustMarshal(plan) + store.Set(upgradetypes.PlanKey(), bz) + + nextValsHash := []byte("nextValsHash") + newCtx := suite.chainA.GetContext().WithBlockHeader(tmproto.Header{ + Height: suite.chainA.GetContext().BlockHeight(), + NextValidatorsHash: nextValsHash, + }) + + err := suite.chainA.GetSimApp().UpgradeKeeper.SetUpgradedClient(newCtx, plan.Height, []byte("client state")) + suite.Require().NoError(err) + + cacheCtx, writeCache := suite.chainA.GetContext().CacheContext() + + client.BeginBlocker(cacheCtx, suite.chainA.App.GetIBCKeeper().ClientKeeper) + writeCache() + + suite.requireContainsEvent(cacheCtx.EventManager().Events(), types.EventTypeUpgradeChain, true) +} + +func (suite *ClientTestSuite) TestBeginBlockerUpgradeEventsAbsence() { + cacheCtx, writeCache := suite.chainA.GetContext().CacheContext() + client.BeginBlocker(suite.chainA.GetContext(), suite.chainA.App.GetIBCKeeper().ClientKeeper) + writeCache() + suite.requireContainsEvent(cacheCtx.EventManager().Events(), types.EventTypeUpgradeChain, false) +} + +// requireContainsEvent verifies if an event of a specific type was emitted. +func (suite *ClientTestSuite) requireContainsEvent(events sdk.Events, eventType string, shouldContain bool) { + found := false + var eventTypes []string + for _, e := range events { + eventTypes = append(eventTypes, e.Type) + if e.Type == eventType { + found = true + break + } + } + if shouldContain { + suite.Require().True(found, "event type %s was not found in %s", eventType, strings.Join(eventTypes, ",")) + } else { + suite.Require().False(found, "event type %s was found in %s", eventType, strings.Join(eventTypes, ",")) + } +} diff --git a/modules/core/02-client/client/cli/cli.go b/modules/core/02-client/client/cli/cli.go index 57e9425f995..bdf42460573 100644 --- a/modules/core/02-client/client/cli/cli.go +++ b/modules/core/02-client/client/cli/cli.go @@ -45,7 +45,7 @@ func NewTxCmd() *cobra.Command { txCmd.AddCommand( NewCreateClientCmd(), NewUpdateClientCmd(), - NewSubmitMisbehaviourCmd(), + NewSubmitMisbehaviourCmd(), // Deprecated NewUpgradeClientCmd(), ) diff --git a/modules/core/02-client/client/cli/tx.go b/modules/core/02-client/client/cli/tx.go index 71d50f90dae..794b6f5ca5e 100644 --- a/modules/core/02-client/client/cli/tx.go +++ b/modules/core/02-client/client/cli/tx.go @@ -86,10 +86,10 @@ func NewCreateClientCmd() *cobra.Command { // NewUpdateClientCmd defines the command to update an IBC client. func NewUpdateClientCmd() *cobra.Command { return &cobra.Command{ - Use: "update [client-id] [path/to/header.json]", - Short: "update existing client with a header", - Long: "update existing client with a header", - Example: fmt.Sprintf("%s tx ibc %s update [client-id] [path/to/header.json] --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), + Use: "update [client-id] [path/to/client_msg.json]", + Short: "update existing client with a client message", + Long: "update existing client with a client message, for example a header, misbehaviour or batch update", + Example: fmt.Sprintf("%s tx ibc %s update [client-id] [path/to/client_msg.json] --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientTxContext(cmd) @@ -100,22 +100,22 @@ func NewUpdateClientCmd() *cobra.Command { cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) - var header exported.Header - headerContentOrFileName := args[1] - if err := cdc.UnmarshalInterfaceJSON([]byte(headerContentOrFileName), &header); err != nil { + var clientMsg exported.ClientMessage + clientMsgContentOrFileName := args[1] + if err := cdc.UnmarshalInterfaceJSON([]byte(clientMsgContentOrFileName), &clientMsg); err != nil { // check for file path if JSON input is not provided - contents, err := ioutil.ReadFile(headerContentOrFileName) + contents, err := ioutil.ReadFile(clientMsgContentOrFileName) if err != nil { return fmt.Errorf("neither JSON input nor path to .json file for header were provided: %w", err) } - if err := cdc.UnmarshalInterfaceJSON(contents, &header); err != nil { + if err := cdc.UnmarshalInterfaceJSON(contents, &clientMsg); err != nil { return fmt.Errorf("error unmarshalling header file: %w", err) } } - msg, err := types.NewMsgUpdateClient(clientID, header, clientCtx.GetFromAddress().String()) + msg, err := types.NewMsgUpdateClient(clientID, clientMsg, clientCtx.GetFromAddress().String()) if err != nil { return err } @@ -127,13 +127,15 @@ func NewUpdateClientCmd() *cobra.Command { // NewSubmitMisbehaviourCmd defines the command to submit a misbehaviour to prevent // future updates. +// Deprecated: NewSubmitMisbehaviourCmd is deprecated and will be removed in a future release. +// Please use NewUpdateClientCmd instead. func NewSubmitMisbehaviourCmd() *cobra.Command { return &cobra.Command{ - Use: "misbehaviour [path/to/misbehaviour.json]", + Use: "misbehaviour [clientID] [path/to/misbehaviour.json]", Short: "submit a client misbehaviour", Long: "submit a client misbehaviour to prevent future updates", - Example: fmt.Sprintf("%s tx ibc %s misbehaviour [path/to/misbehaviour.json] --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), - Args: cobra.ExactArgs(1), + Example: fmt.Sprintf("%s tx ibc %s misbehaviour [clientID] [path/to/misbehaviour.json] --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientTxContext(cmd) if err != nil { @@ -141,8 +143,9 @@ func NewSubmitMisbehaviourCmd() *cobra.Command { } cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) - var misbehaviour exported.Misbehaviour - misbehaviourContentOrFileName := args[0] + var misbehaviour exported.ClientMessage + clientID := args[0] + misbehaviourContentOrFileName := args[1] if err := cdc.UnmarshalInterfaceJSON([]byte(misbehaviourContentOrFileName), &misbehaviour); err != nil { // check for file path if JSON input is not provided @@ -156,7 +159,7 @@ func NewSubmitMisbehaviourCmd() *cobra.Command { } } - msg, err := types.NewMsgSubmitMisbehaviour(misbehaviour.GetClientID(), misbehaviour, clientCtx.GetFromAddress().String()) + msg, err := types.NewMsgSubmitMisbehaviour(clientID, misbehaviour, clientCtx.GetFromAddress().String()) if err != nil { return err } diff --git a/modules/core/02-client/client/utils/utils.go b/modules/core/02-client/client/utils/utils.go index 6005e58ddce..61e49ae2b3a 100644 --- a/modules/core/02-client/client/utils/utils.go +++ b/modules/core/02-client/client/utils/utils.go @@ -13,7 +13,7 @@ import ( host "github.com/cosmos/ibc-go/v5/modules/core/24-host" ibcclient "github.com/cosmos/ibc-go/v5/modules/core/client" "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ) // QueryClientState returns a client state. If prove is true, it performs an ABCI store query @@ -119,15 +119,15 @@ func QueryConsensusStateABCI( // QueryTendermintHeader takes a client context and returns the appropriate // tendermint header -func QueryTendermintHeader(clientCtx client.Context) (ibctmtypes.Header, int64, error) { +func QueryTendermintHeader(clientCtx client.Context) (ibctm.Header, int64, error) { node, err := clientCtx.GetNode() if err != nil { - return ibctmtypes.Header{}, 0, err + return ibctm.Header{}, 0, err } info, err := node.ABCIInfo(context.Background()) if err != nil { - return ibctmtypes.Header{}, 0, err + return ibctm.Header{}, 0, err } var height int64 @@ -139,7 +139,7 @@ func QueryTendermintHeader(clientCtx client.Context) (ibctmtypes.Header, int64, commit, err := node.Commit(context.Background(), &height) if err != nil { - return ibctmtypes.Header{}, 0, err + return ibctm.Header{}, 0, err } page := 1 @@ -147,16 +147,16 @@ func QueryTendermintHeader(clientCtx client.Context) (ibctmtypes.Header, int64, validators, err := node.Validators(context.Background(), &height, &page, &count) if err != nil { - return ibctmtypes.Header{}, 0, err + return ibctm.Header{}, 0, err } protoCommit := commit.SignedHeader.ToProto() protoValset, err := tmtypes.NewValidatorSet(validators.Validators).ToProto() if err != nil { - return ibctmtypes.Header{}, 0, err + return ibctm.Header{}, 0, err } - header := ibctmtypes.Header{ + header := ibctm.Header{ SignedHeader: protoCommit, ValidatorSet: protoValset, } @@ -166,15 +166,15 @@ func QueryTendermintHeader(clientCtx client.Context) (ibctmtypes.Header, int64, // QuerySelfConsensusState takes a client context and returns the appropriate // tendermint consensus state -func QuerySelfConsensusState(clientCtx client.Context) (*ibctmtypes.ConsensusState, int64, error) { +func QuerySelfConsensusState(clientCtx client.Context) (*ibctm.ConsensusState, int64, error) { node, err := clientCtx.GetNode() if err != nil { - return &ibctmtypes.ConsensusState{}, 0, err + return &ibctm.ConsensusState{}, 0, err } info, err := node.ABCIInfo(context.Background()) if err != nil { - return &ibctmtypes.ConsensusState{}, 0, err + return &ibctm.ConsensusState{}, 0, err } var height int64 @@ -186,7 +186,7 @@ func QuerySelfConsensusState(clientCtx client.Context) (*ibctmtypes.ConsensusSta commit, err := node.Commit(context.Background(), &height) if err != nil { - return &ibctmtypes.ConsensusState{}, 0, err + return &ibctm.ConsensusState{}, 0, err } page := 1 @@ -195,10 +195,10 @@ func QuerySelfConsensusState(clientCtx client.Context) (*ibctmtypes.ConsensusSta nextHeight := height + 1 nextVals, err := node.Validators(context.Background(), &nextHeight, &page, &count) if err != nil { - return &ibctmtypes.ConsensusState{}, 0, err + return &ibctm.ConsensusState{}, 0, err } - state := &ibctmtypes.ConsensusState{ + state := &ibctm.ConsensusState{ Timestamp: commit.Time, Root: commitmenttypes.NewMerkleRoot(commit.AppHash), NextValidatorsHash: tmtypes.NewValidatorSet(nextVals.Validators).Hash(), diff --git a/modules/core/02-client/genesis.go b/modules/core/02-client/genesis.go index 602b13aba42..18dc745620d 100644 --- a/modules/core/02-client/genesis.go +++ b/modules/core/02-client/genesis.go @@ -46,14 +46,9 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, gs types.GenesisState) { } k.SetNextClientSequence(ctx, gs.NextClientSequence) - - // NOTE: localhost creation is specifically disallowed for the time being. - // Issue: https://github.com/cosmos/cosmos-sdk/issues/7871 } // ExportGenesis returns the ibc client submodule's exported genesis. -// NOTE: CreateLocalhost should always be false on export since a -// created localhost will be included in the exported clients. func ExportGenesis(ctx sdk.Context, k keeper.Keeper) types.GenesisState { genClients := k.GetAllGenesisClients(ctx) clientsMetadata, err := k.GetAllClientMetadata(ctx, genClients) @@ -61,10 +56,11 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) types.GenesisState { panic(err) } return types.GenesisState{ - Clients: genClients, - ClientsMetadata: clientsMetadata, - ClientsConsensus: k.GetAllConsensusStates(ctx), - Params: k.GetParams(ctx), + Clients: genClients, + ClientsMetadata: clientsMetadata, + ClientsConsensus: k.GetAllConsensusStates(ctx), + Params: k.GetParams(ctx), + // Warning: CreateLocalhost is deprecated CreateLocalhost: false, NextClientSequence: k.GetNextClientSequence(ctx), } diff --git a/modules/core/02-client/keeper/client.go b/modules/core/02-client/keeper/client.go index fbfe2d0eab5..21ffba25e90 100644 --- a/modules/core/02-client/keeper/client.go +++ b/modules/core/02-client/keeper/client.go @@ -1,8 +1,6 @@ package keeper import ( - "encoding/hex" - metrics "github.com/armon/go-metrics" "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" @@ -27,7 +25,6 @@ func (k Keeper) CreateClient( clientID := k.GenerateClientIdentifier(ctx, clientState.ClientType()) - k.SetClientState(ctx, clientID, clientState) k.Logger(ctx).Info("client created at height", "client-id", clientID, "height", clientState.GetLatestHeight().String()) // verifies initial consensus state against client state and initializes client store with any client-specific metadata @@ -36,20 +33,16 @@ func (k Keeper) CreateClient( return "", err } - // check if consensus state is nil in case the created client is Localhost - if consensusState != nil { - k.SetClientConsensusState(ctx, clientID, clientState.GetLatestHeight(), consensusState) - } + k.SetClientState(ctx, clientID, clientState) + k.SetClientConsensusState(ctx, clientID, clientState.GetLatestHeight(), consensusState) k.Logger(ctx).Info("client created at height", "client-id", clientID, "height", clientState.GetLatestHeight().String()) - defer func() { - telemetry.IncrCounterWithLabels( - []string{"ibc", "client", "create"}, - 1, - []metrics.Label{telemetry.NewLabel(types.LabelClientType, clientState.ClientType())}, - ) - }() + defer telemetry.IncrCounterWithLabels( + []string{"ibc", "client", "create"}, + 1, + []metrics.Label{telemetry.NewLabel(types.LabelClientType, clientState.ClientType())}, + ) EmitCreateClientEvent(ctx, clientID, clientState) @@ -57,7 +50,7 @@ func (k Keeper) CreateClient( } // UpdateClient updates the consensus state and the state root from a provided header. -func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.Header) error { +func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { clientState, found := k.GetClientState(ctx, clientID) if !found { return sdkerrors.Wrapf(types.ErrClientNotFound, "cannot update client with ID %s", clientID) @@ -69,77 +62,48 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H return sdkerrors.Wrapf(types.ErrClientNotActive, "cannot update client (%s) with status %s", clientID, status) } - // Any writes made in CheckHeaderAndUpdateState are persisted on both valid updates and misbehaviour updates. - // Light client implementations are responsible for writing the correct metadata (if any) in either case. - newClientState, newConsensusState, err := clientState.CheckHeaderAndUpdateState(ctx, k.cdc, clientStore, header) - if err != nil { - return sdkerrors.Wrapf(err, "cannot update client with ID %s", clientID) + if err := clientState.VerifyClientMessage(ctx, k.cdc, clientStore, clientMsg); err != nil { + return err } - // emit the full header in events - var ( - headerStr string - consensusHeight exported.Height - ) - if header != nil { - // Marshal the Header as an Any and encode the resulting bytes to hex. - // This prevents the event value from containing invalid UTF-8 characters - // which may cause data to be lost when JSON encoding/decoding. - headerStr = hex.EncodeToString(types.MustMarshalHeader(k.cdc, header)) - // set default consensus height with header height - consensusHeight = header.GetHeight() + foundMisbehaviour := clientState.CheckForMisbehaviour(ctx, k.cdc, clientStore, clientMsg) + if foundMisbehaviour { + clientState.UpdateStateOnMisbehaviour(ctx, k.cdc, clientStore, clientMsg) - } + k.Logger(ctx).Info("client frozen due to misbehaviour", "client-id", clientID) - // set new client state regardless of if update is valid update or misbehaviour - k.SetClientState(ctx, clientID, newClientState) - // If client state is not frozen after clientState CheckHeaderAndUpdateState, - // then update was valid. Write the update state changes, and set new consensus state. - // Else the update was proof of misbehaviour and we must emit appropriate misbehaviour events. - if status := newClientState.Status(ctx, clientStore, k.cdc); status != exported.Frozen { - // if update is not misbehaviour then update the consensus state - // we don't set consensus state for localhost client - if header != nil && clientID != exported.Localhost { - k.SetClientConsensusState(ctx, clientID, header.GetHeight(), newConsensusState) - } else { - consensusHeight = types.GetSelfHeight(ctx) - } - - k.Logger(ctx).Info("client state updated", "client-id", clientID, "height", consensusHeight.String()) - - defer func() { - telemetry.IncrCounterWithLabels( - []string{"ibc", "client", "update"}, - 1, - []metrics.Label{ - telemetry.NewLabel(types.LabelClientType, clientState.ClientType()), - telemetry.NewLabel(types.LabelClientID, clientID), - telemetry.NewLabel(types.LabelUpdateType, "msg"), - }, - ) - }() - - // emitting events in the keeper emits for both begin block and handler client updates - EmitUpdateClientEvent(ctx, clientID, newClientState, consensusHeight, headerStr) - } else { + defer telemetry.IncrCounterWithLabels( + []string{"ibc", "client", "misbehaviour"}, + 1, + []metrics.Label{ + telemetry.NewLabel(types.LabelClientType, clientState.ClientType()), + telemetry.NewLabel(types.LabelClientID, clientID), + telemetry.NewLabel(types.LabelMsgType, "update"), + }, + ) - k.Logger(ctx).Info("client frozen due to misbehaviour", "client-id", clientID) + EmitSubmitMisbehaviourEvent(ctx, clientID, clientState) - defer func() { - telemetry.IncrCounterWithLabels( - []string{"ibc", "client", "misbehaviour"}, - 1, - []metrics.Label{ - telemetry.NewLabel(types.LabelClientType, clientState.ClientType()), - telemetry.NewLabel(types.LabelClientID, clientID), - telemetry.NewLabel(types.LabelMsgType, "update"), - }, - ) - }() - - EmitSubmitMisbehaviourEventOnUpdate(ctx, clientID, newClientState, consensusHeight, headerStr) + return nil } + consensusHeights := clientState.UpdateState(ctx, k.cdc, clientStore, clientMsg) + + k.Logger(ctx).Info("client state updated", "client-id", clientID, "heights", consensusHeights) + + defer telemetry.IncrCounterWithLabels( + []string{"ibc", "client", "update"}, + 1, + []metrics.Label{ + telemetry.NewLabel(types.LabelClientType, clientState.ClientType()), + telemetry.NewLabel(types.LabelClientID, clientID), + telemetry.NewLabel(types.LabelUpdateType, "msg"), + }, + ) + + // emitting events in the keeper emits for both begin block and handler client updates + EmitUpdateClientEvent(ctx, clientID, clientState.ClientType(), consensusHeights, k.cdc, clientMsg) + return nil } @@ -159,72 +123,24 @@ func (k Keeper) UpgradeClient(ctx sdk.Context, clientID string, upgradedClient e return sdkerrors.Wrapf(types.ErrClientNotActive, "cannot upgrade client (%s) with status %s", clientID, status) } - updatedClientState, updatedConsState, err := clientState.VerifyUpgradeAndUpdateState(ctx, k.cdc, clientStore, - upgradedClient, upgradedConsState, proofUpgradeClient, proofUpgradeConsState) - if err != nil { + if err := clientState.VerifyUpgradeAndUpdateState(ctx, k.cdc, clientStore, + upgradedClient, upgradedConsState, proofUpgradeClient, proofUpgradeConsState, + ); err != nil { return sdkerrors.Wrapf(err, "cannot upgrade client with ID %s", clientID) } - k.SetClientState(ctx, clientID, updatedClientState) - k.SetClientConsensusState(ctx, clientID, updatedClientState.GetLatestHeight(), updatedConsState) - - k.Logger(ctx).Info("client state upgraded", "client-id", clientID, "height", updatedClientState.GetLatestHeight().String()) - - defer func() { - telemetry.IncrCounterWithLabels( - []string{"ibc", "client", "upgrade"}, - 1, - []metrics.Label{ - telemetry.NewLabel(types.LabelClientType, updatedClientState.ClientType()), - telemetry.NewLabel(types.LabelClientID, clientID), - }, - ) - }() - - // emitting events in the keeper emits for client upgrades - EmitUpgradeClientEvent(ctx, clientID, updatedClientState) - - return nil -} - -// CheckMisbehaviourAndUpdateState checks for client misbehaviour and freezes the -// client if so. -func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, misbehaviour exported.Misbehaviour) error { - clientState, found := k.GetClientState(ctx, misbehaviour.GetClientID()) - if !found { - return sdkerrors.Wrapf(types.ErrClientNotFound, "cannot check misbehaviour for client with ID %s", misbehaviour.GetClientID()) - } - - clientStore := k.ClientStore(ctx, misbehaviour.GetClientID()) - - if status := clientState.Status(ctx, clientStore, k.cdc); status != exported.Active { - return sdkerrors.Wrapf(types.ErrClientNotActive, "cannot process misbehaviour for client (%s) with status %s", misbehaviour.GetClientID(), status) - } + k.Logger(ctx).Info("client state upgraded", "client-id", clientID, "height", upgradedClient.GetLatestHeight().String()) - if err := misbehaviour.ValidateBasic(); err != nil { - return err - } - - clientState, err := clientState.CheckMisbehaviourAndUpdateState(ctx, k.cdc, clientStore, misbehaviour) - if err != nil { - return err - } - - k.SetClientState(ctx, misbehaviour.GetClientID(), clientState) - k.Logger(ctx).Info("client frozen due to misbehaviour", "client-id", misbehaviour.GetClientID()) - - defer func() { - telemetry.IncrCounterWithLabels( - []string{"ibc", "client", "misbehaviour"}, - 1, - []metrics.Label{ - telemetry.NewLabel(types.LabelClientType, misbehaviour.ClientType()), - telemetry.NewLabel(types.LabelClientID, misbehaviour.GetClientID()), - }, - ) - }() + defer telemetry.IncrCounterWithLabels( + []string{"ibc", "client", "upgrade"}, + 1, + []metrics.Label{ + telemetry.NewLabel(types.LabelClientType, upgradedClient.ClientType()), + telemetry.NewLabel(types.LabelClientID, clientID), + }, + ) - EmitSubmitMisbehaviourEvent(ctx, misbehaviour.GetClientID(), clientState) + EmitUpgradeClientEvent(ctx, clientID, upgradedClient) return nil } diff --git a/modules/core/02-client/keeper/client_test.go b/modules/core/02-client/keeper/client_test.go index 09fd3078cc4..22b3c3556fd 100644 --- a/modules/core/02-client/keeper/client_test.go +++ b/modules/core/02-client/keeper/client_test.go @@ -6,16 +6,14 @@ import ( "time" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" - localhosttypes "github.com/cosmos/ibc-go/v5/modules/light-clients/09-localhost/types" + solomachinetypes "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" - ibctestingmock "github.com/cosmos/ibc-go/v5/testing/mock" ) func (suite *KeeperTestSuite) TestCreateClient() { @@ -24,8 +22,8 @@ func (suite *KeeperTestSuite) TestCreateClient() { clientState exported.ClientState expPass bool }{ - {"success", ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), true}, - {"client type not supported", localhosttypes.NewClientState(testChainID, clienttypes.NewHeight(0, 1)), false}, + {"success", ibctm.NewClientState(testChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), true}, + {"client type not supported", solomachinetypes.NewClientState(0, &solomachinetypes.ConsensusState{suite.solomachine.ConsensusState().PublicKey, suite.solomachine.Diversifier, suite.solomachine.Time}, false), false}, } for i, tc := range cases { @@ -44,20 +42,20 @@ func (suite *KeeperTestSuite) TestCreateClient() { func (suite *KeeperTestSuite) TestUpdateClientTendermint() { var ( path *ibctesting.Path - updateHeader *ibctmtypes.Header + updateHeader *ibctm.Header ) // Must create header creation functions since suite.header gets recreated on each test case - createFutureUpdateFn := func(trustedHeight clienttypes.Height) *ibctmtypes.Header { + createFutureUpdateFn := func(trustedHeight clienttypes.Height) *ibctm.Header { header, err := suite.chainA.ConstructUpdateTMClientHeaderWithTrustedHeight(path.EndpointB.Chain, path.EndpointA.ClientID, trustedHeight) suite.Require().NoError(err) return header } - createPastUpdateFn := func(fillHeight, trustedHeight clienttypes.Height) *ibctmtypes.Header { + createPastUpdateFn := func(fillHeight, trustedHeight clienttypes.Height) *ibctm.Header { consState, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientConsensusState(suite.chainA.GetContext(), path.EndpointA.ClientID, trustedHeight) suite.Require().True(found) - return suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(fillHeight.RevisionHeight), trustedHeight, consState.(*ibctmtypes.ConsensusState).Timestamp.Add(time.Second*5), + return suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(fillHeight.RevisionHeight), trustedHeight, consState.(*ibctm.ConsensusState).Timestamp.Add(time.Second*5), suite.chainB.Vals, suite.chainB.Vals, suite.chainB.Vals, suite.chainB.Signers) } @@ -68,7 +66,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { expFreeze bool }{ {"valid update", func() { - clientState := path.EndpointA.GetClientState().(*ibctmtypes.ClientState) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) trustHeight := clientState.GetLatestHeight().(types.Height) // store intermediate consensus state to check that trustedHeight does not need to be highest consensus state before header height @@ -102,24 +100,24 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { {"valid duplicate update", func() { clientID := path.EndpointA.ClientID - height1 := types.NewHeight(0, 1) + height1 := types.NewHeight(1, 1) // store previous consensus state - prevConsState := &ibctmtypes.ConsensusState{ + prevConsState := &ibctm.ConsensusState{ Timestamp: suite.past, NextValidatorsHash: suite.chainB.Vals.Hash(), } suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), clientID, height1, prevConsState) - height5 := types.NewHeight(0, 5) + height5 := types.NewHeight(1, 5) // store next consensus state to check that trustedHeight does not need to be hightest consensus state before header height - nextConsState := &ibctmtypes.ConsensusState{ + nextConsState := &ibctm.ConsensusState{ Timestamp: suite.past.Add(time.Minute), NextValidatorsHash: suite.chainB.Vals.Hash(), } suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), clientID, height5, nextConsState) - height3 := types.NewHeight(0, 3) + height3 := types.NewHeight(1, 3) // updateHeader will fill in consensus state between prevConsState and suite.consState // clientState should not be updated updateHeader = createPastUpdateFn(height3, height1) @@ -129,23 +127,23 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { {"misbehaviour detection: conflicting header", func() { clientID := path.EndpointA.ClientID - height1 := types.NewHeight(0, 1) + height1 := types.NewHeight(1, 1) // store previous consensus state - prevConsState := &ibctmtypes.ConsensusState{ + prevConsState := &ibctm.ConsensusState{ Timestamp: suite.past, NextValidatorsHash: suite.chainB.Vals.Hash(), } suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), clientID, height1, prevConsState) - height5 := types.NewHeight(0, 5) + height5 := types.NewHeight(1, 5) // store next consensus state to check that trustedHeight does not need to be hightest consensus state before header height - nextConsState := &ibctmtypes.ConsensusState{ + nextConsState := &ibctm.ConsensusState{ Timestamp: suite.past.Add(time.Minute), NextValidatorsHash: suite.chainB.Vals.Hash(), } suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), clientID, height5, nextConsState) - height3 := types.NewHeight(0, 3) + height3 := types.NewHeight(1, 3) // updateHeader will fill in consensus state between prevConsState and suite.consState // clientState should not be updated updateHeader = createPastUpdateFn(height3, height1) @@ -155,21 +153,21 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), clientID, updateHeader.GetHeight(), conflictConsState) }, true, true}, {"misbehaviour detection: monotonic time violation", func() { - clientState := path.EndpointA.GetClientState().(*ibctmtypes.ClientState) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) clientID := path.EndpointA.ClientID trustedHeight := clientState.GetLatestHeight().(types.Height) // store intermediate consensus state at a time greater than updateHeader time // this will break time monotonicity incrementedClientHeight := clientState.GetLatestHeight().Increment().(types.Height) - intermediateConsState := &ibctmtypes.ConsensusState{ + intermediateConsState := &ibctm.ConsensusState{ Timestamp: suite.coordinator.CurrentTime.Add(2 * time.Hour), NextValidatorsHash: suite.chainB.Vals.Hash(), } suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), clientID, incrementedClientHeight, intermediateConsState) // set iteration key clientStore := suite.keeper.ClientStore(suite.ctx, clientID) - ibctmtypes.SetIterationKey(clientStore, incrementedClientHeight) + ibctm.SetIterationKey(clientStore, incrementedClientHeight) clientState.LatestHeight = incrementedClientHeight suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), clientID, clientState) @@ -183,7 +181,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { }, false, false}, {"consensus state not found", func() { clientState := path.EndpointA.GetClientState() - tmClient, ok := clientState.(*ibctmtypes.ClientState) + tmClient, ok := clientState.(*ibctm.ClientState) suite.Require().True(ok) tmClient.LatestHeight = tmClient.LatestHeight.Increment().(types.Height) @@ -191,8 +189,8 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { updateHeader = createFutureUpdateFn(clientState.GetLatestHeight().(types.Height)) }, false, false}, {"client is not active", func() { - clientState := path.EndpointA.GetClientState().(*ibctmtypes.ClientState) - clientState.FrozenHeight = types.NewHeight(0, 1) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) + clientState.FrozenHeight = types.NewHeight(1, 1) suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID, clientState) updateHeader = createFutureUpdateFn(clientState.GetLatestHeight().(types.Height)) }, false, false}, @@ -224,9 +222,9 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { newClientState := path.EndpointA.GetClientState() if tc.expFreeze { - suite.Require().True(!newClientState.(*ibctmtypes.ClientState).FrozenHeight.IsZero(), "client did not freeze after conflicting header was submitted to UpdateClient") + suite.Require().True(!newClientState.(*ibctm.ClientState).FrozenHeight.IsZero(), "client did not freeze after conflicting header was submitted to UpdateClient") } else { - expConsensusState := &ibctmtypes.ConsensusState{ + expConsensusState := &ibctm.ConsensusState{ Timestamp: updateHeader.GetTime(), Root: commitmenttypes.NewMerkleRoot(updateHeader.Header.GetAppHash()), NextValidatorsHash: updateHeader.Header.NextValidatorsHash, @@ -254,19 +252,6 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { } } -func (suite *KeeperTestSuite) TestUpdateClientLocalhost() { - revision := types.ParseChainID(suite.chainA.ChainID) - var localhostClient exported.ClientState = localhosttypes.NewClientState(suite.chainA.ChainID, types.NewHeight(revision, uint64(suite.chainA.GetContext().BlockHeight()))) - - ctx := suite.chainA.GetContext().WithBlockHeight(suite.chainA.GetContext().BlockHeight() + 1) - err := suite.chainA.App.GetIBCKeeper().ClientKeeper.UpdateClient(ctx, exported.Localhost, nil) - suite.Require().NoError(err) - - clientState, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(ctx, exported.Localhost) - suite.Require().True(found) - suite.Require().Equal(localhostClient.GetLatestHeight().(types.Height).Increment(), clientState.GetLatestHeight()) -} - func (suite *KeeperTestSuite) TestUpgradeClient() { var ( path *ibctesting.Path @@ -275,7 +260,6 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { lastHeight exported.Height proofUpgradedClient, proofUpgradedConsState []byte upgradedClientBz, upgradedConsStateBz []byte - err error ) testCases := []struct { @@ -287,7 +271,7 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { name: "successful upgrade", setup: func() { // last Height is at next block - lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) + 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) @@ -296,7 +280,6 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { suite.Require().NoError(err) // commit upgrade store changes and update clients - suite.coordinator.CommitBlock(suite.chainB) err = path.EndpointA.UpdateClient() suite.Require().NoError(err) @@ -313,7 +296,7 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { name: "client state not found", setup: func() { // last Height is at next block - lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) + 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) @@ -343,7 +326,7 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { // client is frozen // last Height is at next block - lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) + 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) @@ -364,9 +347,9 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) // set frozen client in store - tmClient, ok := cs.(*ibctmtypes.ClientState) + tmClient, ok := cs.(*ibctm.ClientState) suite.Require().True(ok) - tmClient.FrozenHeight = types.NewHeight(0, 1) + tmClient.FrozenHeight = types.NewHeight(1, 1) suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID, tmClient) }, expPass: false, @@ -375,7 +358,7 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { name: "tendermint client VerifyUpgrade fails", setup: func() { // last Height is at next block - lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) + 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) @@ -384,7 +367,9 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { suite.Require().NoError(err) // change upgradedClient client-specified parameters - upgradedClient = ibctmtypes.NewClientState("wrongchainID", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, true, true) + tmClient := upgradedClient.(*ibctm.ClientState) + tmClient.ChainId = "wrongchainID" + upgradedClient = tmClient suite.coordinator.CommitBlock(suite.chainB) err = path.EndpointA.UpdateClient() @@ -404,12 +389,19 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { tc := tc path = ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(path) - upgradedClient = ibctmtypes.NewClientState("newChainId-1", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) + + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) + revisionNumber := clienttypes.ParseChainID(clientState.ChainId) + + newChainID, err := clienttypes.SetRevisionNumber(clientState.ChainId, revisionNumber+1) + suite.Require().NoError(err) + + upgradedClient = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, clienttypes.NewHeight(revisionNumber+1, clientState.GetLatestHeight().GetRevisionHeight()+1), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) upgradedClient = upgradedClient.ZeroCustomFields() upgradedClientBz, err = types.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient) suite.Require().NoError(err) - upgradedConsState = &ibctmtypes.ConsensusState{ + upgradedConsState = &ibctm.ConsensusState{ NextValidatorsHash: []byte("nextValsHash"), } upgradedConsStateBz, err = types.MarshalConsensusState(suite.chainA.App.AppCodec(), upgradedConsState) @@ -417,9 +409,6 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { tc.setup() - // Call ZeroCustomFields on upgraded clients to clear any client-chosen parameters in test-case upgradedClient - upgradedClient = upgradedClient.ZeroCustomFields() - err = suite.chainA.App.GetIBCKeeper().ClientKeeper.UpgradeClient(suite.chainA.GetContext(), path.EndpointA.ClientID, upgradedClient, upgradedConsState, proofUpgradedClient, proofUpgradedConsState) if tc.expPass { @@ -430,256 +419,10 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { } } -func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { - var ( - clientID string - err error - ) - - altPrivVal := ibctestingmock.NewPV() - altPubKey, err := altPrivVal.GetPubKey() - suite.Require().NoError(err) - altVal := tmtypes.NewValidator(altPubKey, 4) - - // Set valSet here with suite.valSet, so it doesn't get reset on each testcase - valSet := suite.valSet - valsHash := valSet.Hash() - - // Create bothValSet with both suite validator and altVal - bothValSet := tmtypes.NewValidatorSet(append(suite.valSet.Validators, altVal)) - bothValsHash := bothValSet.Hash() - // Create alternative validator set with only altVal - altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal}) - - // Create signer array and ensure it is in same order as bothValSet - _, suiteVal := suite.valSet.GetByIndex(0) - bothSigners := make(map[string]tmtypes.PrivValidator, 2) - bothSigners[suiteVal.Address.String()] = suite.privVal - bothSigners[altVal.Address.String()] = altPrivVal - - altSigners := make(map[string]tmtypes.PrivValidator, 1) - altSigners[altVal.Address.String()] = altPrivVal - - // Create valid Misbehaviour by making a duplicate header that signs over different block time - altTime := suite.ctx.BlockTime().Add(time.Minute) - - heightPlus3 := types.NewHeight(0, height+3) - heightPlus5 := types.NewHeight(0, height+5) - - testCases := []struct { - name string - misbehaviour *ibctmtypes.Misbehaviour - malleate func() error - expPass bool - }{ - { - "trusting period misbehavior should pass", - &ibctmtypes.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: clientID, - }, - func() error { - suite.consensusState.NextValidatorsHash = bothValsHash - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) - - return err - }, - true, - }, - { - "time misbehavior should pass", - &ibctmtypes.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+5), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: clientID, - }, - func() error { - suite.consensusState.NextValidatorsHash = bothValsHash - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) - - return err - }, - true, - }, - { - "misbehavior at later height should pass", - &ibctmtypes.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, valSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, valSet, bothSigners), - ClientId: clientID, - }, - func() error { - suite.consensusState.NextValidatorsHash = valsHash - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) - - // store intermediate consensus state to check that trustedHeight does not need to be highest consensus state before header height - intermediateConsState := &ibctmtypes.ConsensusState{ - Timestamp: suite.now.Add(time.Minute), - NextValidatorsHash: suite.chainB.Vals.Hash(), - } - suite.keeper.SetClientConsensusState(suite.ctx, clientID, heightPlus3, intermediateConsState) - - clientState.LatestHeight = heightPlus3 - suite.keeper.SetClientState(suite.ctx, clientID, clientState) - - return err - }, - true, - }, - { - "misbehavior at later height with different trusted heights should pass", - &ibctmtypes.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, valSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), heightPlus3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: clientID, - }, - func() error { - suite.consensusState.NextValidatorsHash = valsHash - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) - - // store trusted consensus state for Header2 - intermediateConsState := &ibctmtypes.ConsensusState{ - Timestamp: suite.now.Add(time.Minute), - NextValidatorsHash: bothValsHash, - } - suite.keeper.SetClientConsensusState(suite.ctx, clientID, heightPlus3, intermediateConsState) - - clientState.LatestHeight = heightPlus3 - suite.keeper.SetClientState(suite.ctx, clientID, clientState) - - return err - }, - true, - }, - { - "misbehavior ValidateBasic fails: misbehaviour height is at same height as trusted height", - &ibctmtypes.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, altTime, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: clientID, - }, - func() error { - suite.consensusState.NextValidatorsHash = bothValsHash - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) - - return err - }, - false, - }, - { - "trusted ConsensusState1 not found", - &ibctmtypes.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), heightPlus3, altTime, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, valSet, bothSigners), - ClientId: clientID, - }, - func() error { - suite.consensusState.NextValidatorsHash = valsHash - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) - // intermediate consensus state at height + 3 is not created - return err - }, - false, - }, - { - "trusted ConsensusState2 not found", - &ibctmtypes.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, valSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), heightPlus3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: clientID, - }, - func() error { - suite.consensusState.NextValidatorsHash = valsHash - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) - // intermediate consensus state at height + 3 is not created - return err - }, - false, - }, - { - "client state not found", - &ibctmtypes.Misbehaviour{}, - func() error { return nil }, - false, - }, - { - "client already is not active - client is frozen", - &ibctmtypes.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: clientID, - }, - func() error { - suite.consensusState.NextValidatorsHash = bothValsHash - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) - - clientState.FrozenHeight = types.NewHeight(0, 1) - suite.keeper.SetClientState(suite.ctx, clientID, clientState) - - return err - }, - false, - }, - { - "misbehaviour check failed", - &ibctmtypes.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), altValSet, altValSet, bothValSet, altSigners), - ClientId: clientID, - }, - func() error { - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - if err != nil { - return err - } - clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) - - return err - }, - false, - }, - } - - for i, tc := range testCases { - tc := tc - i := i - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - clientID = testClientID // must be explicitly changed - - err := tc.malleate() - suite.Require().NoError(err) - - tc.misbehaviour.ClientId = clientID - - err = suite.keeper.CheckMisbehaviourAndUpdateState(suite.ctx, tc.misbehaviour) - - if tc.expPass { - suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) - - clientState, found := suite.keeper.GetClientState(suite.ctx, clientID) - suite.Require().True(found, "valid test case %d failed: %s", i, tc.name) - suite.Require().True(!clientState.(*ibctmtypes.ClientState).FrozenHeight.IsZero(), "valid test case %d failed: %s", i, tc.name) - } else { - suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) - } - }) - } -} - func (suite *KeeperTestSuite) TestUpdateClientEventEmission() { path := ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(path) + header, err := suite.chainA.ConstructUpdateTMClientHeader(suite.chainB, path.EndpointA.ClientID) suite.Require().NoError(err) @@ -703,7 +446,7 @@ func (suite *KeeperTestSuite) TestUpdateClientEventEmission() { bz, err := hex.DecodeString(string(attr.Value)) suite.Require().NoError(err) - emittedHeader, err := types.UnmarshalHeader(suite.chainA.App.AppCodec(), bz) + emittedHeader, err := types.UnmarshalClientMessage(suite.chainA.App.AppCodec(), bz) suite.Require().NoError(err) suite.Require().Equal(header, emittedHeader) } diff --git a/modules/core/02-client/keeper/events.go b/modules/core/02-client/keeper/events.go index 2411ad307c4..98a212eefe3 100644 --- a/modules/core/02-client/keeper/events.go +++ b/modules/core/02-client/keeper/events.go @@ -1,9 +1,14 @@ package keeper import ( + "encoding/hex" "fmt" + "strconv" + "strings" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" "github.com/cosmos/ibc-go/v5/modules/core/exported" @@ -26,14 +31,32 @@ func EmitCreateClientEvent(ctx sdk.Context, clientID string, clientState exporte } // EmitUpdateClientEvent emits an update client event -func EmitUpdateClientEvent(ctx sdk.Context, clientID string, clientState exported.ClientState, consensusHeight exported.Height, headerStr string) { +func EmitUpdateClientEvent(ctx sdk.Context, clientID string, clientType string, consensusHeights []exported.Height, cdc codec.BinaryCodec, clientMsg exported.ClientMessage) { + // Marshal the ClientMessage as an Any and encode the resulting bytes to hex. + // This prevents the event value from containing invalid UTF-8 characters + // which may cause data to be lost when JSON encoding/decoding. + clientMsgStr := hex.EncodeToString(types.MustMarshalClientMessage(cdc, clientMsg)) + + var consensusHeightAttr string + if len(consensusHeights) != 0 { + consensusHeightAttr = consensusHeights[0].String() + } + + consensusHeightsAttr := make([]string, len(consensusHeights)) + for i, height := range consensusHeights { + consensusHeightsAttr[i] = height.String() + } + ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeUpdateClient, sdk.NewAttribute(types.AttributeKeyClientID, clientID), - sdk.NewAttribute(types.AttributeKeyClientType, clientState.ClientType()), - sdk.NewAttribute(types.AttributeKeyConsensusHeight, consensusHeight.String()), - sdk.NewAttribute(types.AttributeKeyHeader, headerStr), + sdk.NewAttribute(types.AttributeKeyClientType, clientType), + // Deprecated: AttributeKeyConsensusHeight is deprecated and will be removed in a future release. + // Please use AttributeKeyConsensusHeights instead. + sdk.NewAttribute(types.AttributeKeyConsensusHeight, consensusHeightAttr), + sdk.NewAttribute(types.AttributeKeyConsensusHeights, strings.Join(consensusHeightsAttr, ",")), + sdk.NewAttribute(types.AttributeKeyHeader, clientMsgStr), ), sdk.NewEvent( sdk.EventTypeMessage, @@ -59,13 +82,12 @@ func EmitUpgradeClientEvent(ctx sdk.Context, clientID string, clientState export } // EmitUpdateClientProposalEvent emits an update client proposal event -func EmitUpdateClientProposalEvent(ctx sdk.Context, clientID string, clientState exported.ClientState) { +func EmitUpdateClientProposalEvent(ctx sdk.Context, clientID, clientType string) { ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeUpdateClientProposal, sdk.NewAttribute(types.AttributeKeySubjectClientID, clientID), - sdk.NewAttribute(types.AttributeKeyClientType, clientState.ClientType()), - sdk.NewAttribute(types.AttributeKeyConsensusHeight, clientState.GetLatestHeight().String()), + sdk.NewAttribute(types.AttributeKeyClientType, clientType), ), ) } @@ -92,15 +114,13 @@ func EmitSubmitMisbehaviourEvent(ctx sdk.Context, clientID string, clientState e ) } -// EmitSubmitMisbehaviourEventOnUpdate emits a client misbehaviour event on a client update event -func EmitSubmitMisbehaviourEventOnUpdate(ctx sdk.Context, clientID string, clientState exported.ClientState, consensusHeight exported.Height, headerStr string) { - ctx.EventManager().EmitEvent( +// EmitUpgradeChainEvent emits an upgrade chain event. +func EmitUpgradeChainEvent(ctx sdk.Context, height int64) { + ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( - types.EventTypeSubmitMisbehaviour, - sdk.NewAttribute(types.AttributeKeyClientID, clientID), - sdk.NewAttribute(types.AttributeKeyClientType, clientState.ClientType()), - sdk.NewAttribute(types.AttributeKeyConsensusHeight, consensusHeight.String()), - sdk.NewAttribute(types.AttributeKeyHeader, headerStr), + types.EventTypeUpgradeChain, + sdk.NewAttribute(types.AttributeKeyUpgradePlanHeight, strconv.FormatInt(height, 10)), + sdk.NewAttribute(types.AttributeKeyUpgradeStore, upgradetypes.StoreKey), // which store to query proof of consensus state from ), - ) + }) } diff --git a/modules/core/02-client/keeper/grpc_query_test.go b/modules/core/02-client/keeper/grpc_query_test.go index 0e8277aa971..e66badac616 100644 --- a/modules/core/02-client/keeper/grpc_query_test.go +++ b/modules/core/02-client/keeper/grpc_query_test.go @@ -11,7 +11,7 @@ import ( "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) @@ -142,7 +142,7 @@ func (suite *KeeperTestSuite) TestQueryClientStates() { idcs := types.NewIdentifiedClientState(path1.EndpointA.ClientID, clientStateA1) idcs2 := types.NewIdentifiedClientState(path2.EndpointA.ClientID, clientStateA2) - // order is sorted by client id, localhost is last + // order is sorted by client id expClientStates = types.IdentifiedClientStates{idcs, idcs2}.Sort() req = &types.QueryClientStatesRequest{ Pagination: &query.PageRequest{ @@ -158,13 +158,7 @@ func (suite *KeeperTestSuite) TestQueryClientStates() { for _, tc := range testCases { suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset - expClientStates = nil - tc.malleate() - // always add localhost which is created by default in init genesis - localhostClientState := suite.chainA.GetClientState(exported.Localhost) - identifiedLocalhost := types.NewIdentifiedClientState(exported.Localhost, localhostClientState) - expClientStates = append(expClientStates, identifiedLocalhost) ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) @@ -534,7 +528,7 @@ func (suite *KeeperTestSuite) TestQueryClientStatus() { func() { path := ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(path) - clientState := path.EndpointA.GetClientState().(*ibctmtypes.ClientState) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) // increment latest height so no consensus state is stored clientState.LatestHeight = clientState.LatestHeight.Increment().(types.Height) @@ -551,7 +545,7 @@ func (suite *KeeperTestSuite) TestQueryClientStatus() { func() { path := ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(path) - clientState := path.EndpointA.GetClientState().(*ibctmtypes.ClientState) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) clientState.FrozenHeight = types.NewHeight(0, 1) path.EndpointA.SetClientState(clientState) diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index 81ca1488ba7..33b6a39ac14 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -19,7 +19,7 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" host "github.com/cosmos/ibc-go/v5/modules/core/24-host" "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ) // Keeper represents a type that grants read and write permissions to any client @@ -257,7 +257,7 @@ func (k Keeper) GetSelfConsensusState(ctx sdk.Context, height exported.Height) ( return nil, sdkerrors.Wrapf(sdkerrors.ErrNotFound, "no historical info found at height %d", selfHeight.RevisionHeight) } - consensusState := &ibctmtypes.ConsensusState{ + consensusState := &ibctm.ConsensusState{ Timestamp: histInfo.Header.Time, Root: commitmenttypes.NewMerkleRoot(histInfo.Header.GetAppHash()), NextValidatorsHash: histInfo.Header.NextValidatorsHash, @@ -269,10 +269,10 @@ func (k Keeper) GetSelfConsensusState(ctx sdk.Context, height exported.Height) ( // 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 func (k Keeper) ValidateSelfClient(ctx sdk.Context, clientState exported.ClientState) error { - tmClient, ok := clientState.(*ibctmtypes.ClientState) + tmClient, ok := clientState.(*ibctm.ClientState) if !ok { return sdkerrors.Wrapf(types.ErrInvalidClient, "client must be a Tendermint client, expected: %T, got: %T", - &ibctmtypes.ClientState{}, tmClient) + &ibctm.ClientState{}, tmClient) } if !tmClient.FrozenHeight.IsZero() { diff --git a/modules/core/02-client/keeper/keeper_test.go b/modules/core/02-client/keeper/keeper_test.go index 19694c9fa91..e38f7a0d430 100644 --- a/modules/core/02-client/keeper/keeper_test.go +++ b/modules/core/02-client/keeper/keeper_test.go @@ -19,8 +19,8 @@ import ( "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" - localhosttypes "github.com/cosmos/ibc-go/v5/modules/light-clients/09-localhost/types" + solomachinetypes "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ibctestingmock "github.com/cosmos/ibc-go/v5/testing/mock" "github.com/cosmos/ibc-go/v5/testing/simapp" @@ -44,7 +44,6 @@ const ( var ( testClientHeight = types.NewHeight(0, 5) testClientHeightRevision1 = types.NewHeight(1, 5) - newClientHeight = types.NewHeight(1, 1) ) type KeeperTestSuite struct { @@ -58,13 +57,14 @@ type KeeperTestSuite struct { cdc codec.Codec ctx sdk.Context keeper *keeper.Keeper - consensusState *ibctmtypes.ConsensusState - header *ibctmtypes.Header + consensusState *ibctm.ConsensusState + header *ibctm.Header valSet *tmtypes.ValidatorSet valSetHash tmbytes.HexBytes privVal tmtypes.PrivValidator now time.Time past time.Time + solomachine *ibctesting.Solomachine signers map[string]tmtypes.PrivValidator @@ -102,7 +102,7 @@ func (suite *KeeperTestSuite) SetupTest() { suite.signers[validator.Address.String()] = suite.privVal suite.header = suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeightMinus1, now2, suite.valSet, suite.valSet, suite.valSet, suite.signers) - suite.consensusState = ibctmtypes.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot([]byte("hash")), suite.valSetHash) + suite.consensusState = ibctm.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot([]byte("hash")), suite.valSetHash) var validators stakingtypes.Validators for i := 1; i < 11; i++ { @@ -122,12 +122,7 @@ func (suite *KeeperTestSuite) SetupTest() { app.StakingKeeper.SetHistoricalInfo(suite.ctx, int64(i), &hi) } - // add localhost client - revision := types.ParseChainID(suite.chainA.ChainID) - localHostClient := localhosttypes.NewClientState( - suite.chainA.ChainID, types.NewHeight(revision, uint64(suite.chainA.GetContext().BlockHeight())), - ) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), exported.Localhost, localHostClient) + suite.solomachine = ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachinesingle", "testing", 1) // TODO: deprecate queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, app.InterfaceRegistry()) @@ -140,7 +135,7 @@ func TestKeeperTestSuite(t *testing.T) { } func (suite *KeeperTestSuite) TestSetClientState() { - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) + clientState := ibctm.NewClientState(testChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) suite.keeper.SetClientState(suite.ctx, testClientID, clientState) retrievedState, found := suite.keeper.GetClientState(suite.ctx, testClientID) @@ -154,13 +149,14 @@ func (suite *KeeperTestSuite) TestSetClientConsensusState() { retrievedConsState, found := suite.keeper.GetClientConsensusState(suite.ctx, testClientID, testClientHeight) suite.Require().True(found, "GetConsensusState failed") - tmConsState, ok := retrievedConsState.(*ibctmtypes.ConsensusState) + tmConsState, ok := retrievedConsState.(*ibctm.ConsensusState) suite.Require().True(ok) suite.Require().Equal(suite.consensusState, tmConsState, "ConsensusState not stored correctly") } func (suite *KeeperTestSuite) TestValidateSelfClient() { - testClientHeight := types.NewHeight(0, uint64(suite.chainA.GetContext().BlockHeight()-1)) + testClientHeight := types.GetSelfHeight(suite.chainA.GetContext()) + testClientHeight.RevisionHeight-- testCases := []struct { name string @@ -169,62 +165,62 @@ func (suite *KeeperTestSuite) TestValidateSelfClient() { }{ { "success", - ibctmtypes.NewClientState(suite.chainA.ChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), + ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), true, }, { "success with nil UpgradePath", - ibctmtypes.NewClientState(suite.chainA.ChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), nil, false, false), + ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), nil, false, false), true, }, - { - "invalid client type", - localhosttypes.NewClientState(suite.chainA.ChainID, testClientHeight), - false, - }, { "frozen client", - &ibctmtypes.ClientState{ChainId: suite.chainA.ChainID, TrustLevel: ibctmtypes.DefaultTrustLevel, TrustingPeriod: trustingPeriod, UnbondingPeriod: ubdPeriod, MaxClockDrift: maxClockDrift, FrozenHeight: testClientHeight, LatestHeight: testClientHeight, ProofSpecs: commitmenttypes.GetSDKSpecs(), UpgradePath: ibctesting.UpgradePath, AllowUpdateAfterExpiry: false, AllowUpdateAfterMisbehaviour: false}, + &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, AllowUpdateAfterExpiry: false, AllowUpdateAfterMisbehaviour: false}, false, }, { "incorrect chainID", - ibctmtypes.NewClientState("gaiatestnet", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), + ibctm.NewClientState("gaiatestnet", ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), false, }, { "invalid client height", - ibctmtypes.NewClientState(suite.chainA.ChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.NewHeight(0, uint64(suite.chainA.GetContext().BlockHeight())), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), + ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.GetSelfHeight(suite.chainA.GetContext()).Increment().(types.Height), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), + false, + }, + { + "invalid client type", + solomachinetypes.NewClientState(0, &solomachinetypes.ConsensusState{suite.solomachine.ConsensusState().PublicKey, suite.solomachine.Diversifier, suite.solomachine.Time}, false), false, }, { "invalid client revision", - ibctmtypes.NewClientState(suite.chainA.ChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeightRevision1, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), + ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeightRevision1, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), false, }, { "invalid proof specs", - ibctmtypes.NewClientState(suite.chainA.ChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, nil, ibctesting.UpgradePath, false, false), + ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, nil, ibctesting.UpgradePath, false, false), false, }, { "invalid trust level", - ibctmtypes.NewClientState(suite.chainA.ChainID, ibctmtypes.Fraction{Numerator: 0, Denominator: 1}, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), + ibctm.NewClientState(suite.chainA.ChainID, ibctm.Fraction{Numerator: 0, Denominator: 1}, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), false, }, { "invalid unbonding period", - ibctmtypes.NewClientState(suite.chainA.ChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod+10, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), + ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod+10, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), false, }, { "invalid trusting period", - ibctmtypes.NewClientState(suite.chainA.ChainID, ibctmtypes.DefaultTrustLevel, ubdPeriod+10, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), + ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, ubdPeriod+10, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), false, }, { "invalid upgrade path", - ibctmtypes.NewClientState(suite.chainA.ChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), []string{"bad", "upgrade", "path"}, false, false), + ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), []string{"bad", "upgrade", "path"}, false, false), false, }, } @@ -244,9 +240,9 @@ func (suite KeeperTestSuite) TestGetAllGenesisClients() { testClientID2, testClientID3, testClientID, } expClients := []exported.ClientState{ - ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), - ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), - ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), + ibctm.NewClientState(testChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), + ibctm.NewClientState(testChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), + ibctm.NewClientState(testChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), } expGenClients := make(types.IdentifiedClientStates, len(expClients)) @@ -256,11 +252,6 @@ func (suite KeeperTestSuite) TestGetAllGenesisClients() { expGenClients[i] = types.NewIdentifiedClientState(clientIDs[i], expClients[i]) } - // add localhost client - localHostClient, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), exported.Localhost) - suite.Require().True(found) - expGenClients = append(expGenClients, types.NewIdentifiedClientState(exported.Localhost, localHostClient)) - genClients := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetAllGenesisClients(suite.chainA.GetContext()) suite.Require().Equal(expGenClients.Sort(), genClients) @@ -271,23 +262,22 @@ func (suite KeeperTestSuite) TestGetAllGenesisMetadata() { types.NewIdentifiedGenesisMetadata( "07-tendermint-1", []types.GenesisMetadata{ - types.NewGenesisMetadata(ibctmtypes.ProcessedTimeKey(types.NewHeight(0, 1)), []byte("foo")), - types.NewGenesisMetadata(ibctmtypes.ProcessedTimeKey(types.NewHeight(0, 2)), []byte("bar")), - types.NewGenesisMetadata(ibctmtypes.ProcessedTimeKey(types.NewHeight(0, 3)), []byte("baz")), + types.NewGenesisMetadata(ibctm.ProcessedTimeKey(types.NewHeight(0, 1)), []byte("foo")), + types.NewGenesisMetadata(ibctm.ProcessedTimeKey(types.NewHeight(0, 2)), []byte("bar")), + types.NewGenesisMetadata(ibctm.ProcessedTimeKey(types.NewHeight(0, 3)), []byte("baz")), }, ), types.NewIdentifiedGenesisMetadata( "clientB", []types.GenesisMetadata{ - types.NewGenesisMetadata(ibctmtypes.ProcessedTimeKey(types.NewHeight(1, 100)), []byte("val1")), - types.NewGenesisMetadata(ibctmtypes.ProcessedTimeKey(types.NewHeight(2, 300)), []byte("val2")), + types.NewGenesisMetadata(ibctm.ProcessedTimeKey(types.NewHeight(1, 100)), []byte("val1")), + types.NewGenesisMetadata(ibctm.ProcessedTimeKey(types.NewHeight(2, 300)), []byte("val2")), }, ), } genClients := []types.IdentifiedClientState{ - types.NewIdentifiedClientState("07-tendermint-1", &ibctmtypes.ClientState{}), types.NewIdentifiedClientState("clientB", &ibctmtypes.ClientState{}), - types.NewIdentifiedClientState("clientC", &ibctmtypes.ClientState{}), types.NewIdentifiedClientState("clientD", &localhosttypes.ClientState{}), + types.NewIdentifiedClientState("07-tendermint-1", &ibctm.ClientState{}), types.NewIdentifiedClientState("clientB", &ibctm.ClientState{}), } suite.chainA.App.GetIBCKeeper().ClientKeeper.SetAllClientMetadata(suite.chainA.GetContext(), expectedGenMetadata) @@ -325,12 +315,12 @@ func (suite KeeperTestSuite) TestGetConsensusState() { func (suite KeeperTestSuite) TestConsensusStateHelpers() { // initial setup - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) + clientState := ibctm.NewClientState(testChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) suite.keeper.SetClientState(suite.ctx, testClientID, clientState) suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight, suite.consensusState) - nextState := ibctmtypes.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot([]byte("next")), suite.valSetHash) + nextState := ibctm.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot([]byte("next")), suite.valSetHash) testClientHeightPlus5 := types.NewHeight(0, height+5) diff --git a/modules/core/02-client/keeper/proposal.go b/modules/core/02-client/keeper/proposal.go index 95e3544a277..aa0846021cc 100644 --- a/modules/core/02-client/keeper/proposal.go +++ b/modules/core/02-client/keeper/proposal.go @@ -13,16 +13,11 @@ import ( // ClientUpdateProposal will retrieve the subject and substitute client. // A callback will occur to the subject client state with the client // prefixed store being provided for both the subject and the substitute client. -// The localhost client is not allowed to be modified with a proposal. The IBC -// client implementations are responsible for validating the parameters of the +// The IBC client implementations are responsible for validating the parameters of the // subtitute (enusring they match the subject's parameters) as well as copying // the necessary consensus states from the subtitute to the subject client // store. The substitute must be Active and the subject must not be Active. func (k Keeper) ClientUpdateProposal(ctx sdk.Context, p *types.ClientUpdateProposal) error { - if p.SubjectClientId == exported.Localhost || p.SubstituteClientId == exported.Localhost { - return sdkerrors.Wrap(types.ErrInvalidUpdateClientProposal, "cannot update localhost client with proposal") - } - subjectClientState, found := k.GetClientState(ctx, p.SubjectClientId) if !found { return sdkerrors.Wrapf(types.ErrClientNotFound, "subject client with ID %s", p.SubjectClientId) @@ -49,20 +44,18 @@ func (k Keeper) ClientUpdateProposal(ctx sdk.Context, p *types.ClientUpdatePropo return sdkerrors.Wrapf(types.ErrClientNotActive, "substitute client is not Active, status is %s", status) } - clientState, err := subjectClientState.CheckSubstituteAndUpdateState(ctx, k.cdc, subjectClientStore, substituteClientStore, substituteClientState) - if err != nil { + if err := subjectClientState.CheckSubstituteAndUpdateState(ctx, k.cdc, subjectClientStore, substituteClientStore, substituteClientState); err != nil { return err } - k.SetClientState(ctx, p.SubjectClientId, clientState) - k.Logger(ctx).Info("client updated after governance proposal passed", "client-id", p.SubjectClientId, "height", clientState.GetLatestHeight().String()) + k.Logger(ctx).Info("client updated after governance proposal passed", "client-id", p.SubjectClientId) defer func() { telemetry.IncrCounterWithLabels( []string{"ibc", "client", "update"}, 1, []metrics.Label{ - telemetry.NewLabel(types.LabelClientType, clientState.ClientType()), + telemetry.NewLabel(types.LabelClientType, substituteClientState.ClientType()), telemetry.NewLabel(types.LabelClientID, p.SubjectClientId), telemetry.NewLabel(types.LabelUpdateType, "proposal"), }, @@ -70,7 +63,7 @@ func (k Keeper) ClientUpdateProposal(ctx sdk.Context, p *types.ClientUpdatePropo }() // emitting events in the keeper for proposal updates to clients - EmitUpdateClientProposalEvent(ctx, p.SubjectClientId, clientState) + EmitUpdateClientProposalEvent(ctx, p.SubjectClientId, substituteClientState.ClientType()) return nil } diff --git a/modules/core/02-client/keeper/proposal_test.go b/modules/core/02-client/keeper/proposal_test.go index 6123666a7ab..762d41a41ec 100644 --- a/modules/core/02-client/keeper/proposal_test.go +++ b/modules/core/02-client/keeper/proposal_test.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) @@ -30,7 +30,7 @@ func (suite *KeeperTestSuite) TestClientUpdateProposal() { }, { "subject and substitute use different revision numbers", func() { - tmClientState, ok := substituteClientState.(*ibctmtypes.ClientState) + tmClientState, ok := substituteClientState.(*ibctm.ClientState) suite.Require().True(ok) consState, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientConsensusState(suite.chainA.GetContext(), substitute, tmClientState.LatestHeight) suite.Require().True(found) @@ -40,23 +40,13 @@ func (suite *KeeperTestSuite) TestClientUpdateProposal() { suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), substitute, tmClientState.LatestHeight, consState) clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), substitute) - ibctmtypes.SetProcessedTime(clientStore, tmClientState.LatestHeight, 100) - ibctmtypes.SetProcessedHeight(clientStore, tmClientState.LatestHeight, types.NewHeight(0, 1)) + ibctm.SetProcessedTime(clientStore, tmClientState.LatestHeight, 100) + ibctm.SetProcessedHeight(clientStore, tmClientState.LatestHeight, types.NewHeight(0, 1)) suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), substitute, tmClientState) content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, substitute) }, true, }, - { - "cannot use localhost as subject", func() { - content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, exported.Localhost, substitute) - }, false, - }, - { - "cannot use localhost as substitute", func() { - content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, exported.Localhost) - }, false, - }, { "cannot use solomachine as substitute for tendermint client", func() { solomachine := ibctesting.NewSolomachine(suite.T(), suite.cdc, "solo machine", "", 1) @@ -78,7 +68,7 @@ func (suite *KeeperTestSuite) TestClientUpdateProposal() { }, { "subject and substitute have equal latest height", func() { - tmClientState, ok := subjectClientState.(*ibctmtypes.ClientState) + tmClientState, ok := subjectClientState.(*ibctm.ClientState) suite.Require().True(ok) tmClientState.LatestHeight = substituteClientState.GetLatestHeight().(types.Height) suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) @@ -88,7 +78,7 @@ func (suite *KeeperTestSuite) TestClientUpdateProposal() { }, { "update fails, client is not frozen or expired", func() { - tmClientState, ok := subjectClientState.(*ibctmtypes.ClientState) + tmClientState, ok := subjectClientState.(*ibctm.ClientState) suite.Require().True(ok) tmClientState.FrozenHeight = types.ZeroHeight() suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) @@ -98,7 +88,7 @@ func (suite *KeeperTestSuite) TestClientUpdateProposal() { }, { "substitute is frozen", func() { - tmClientState, ok := substituteClientState.(*ibctmtypes.ClientState) + tmClientState, ok := substituteClientState.(*ibctm.ClientState) suite.Require().True(ok) tmClientState.FrozenHeight = types.NewHeight(0, 1) suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), substitute, tmClientState) @@ -128,14 +118,14 @@ func (suite *KeeperTestSuite) TestClientUpdateProposal() { substitutePath.EndpointA.UpdateClient() substituteClientState = suite.chainA.GetClientState(substitute) - tmClientState, ok := subjectClientState.(*ibctmtypes.ClientState) + tmClientState, ok := subjectClientState.(*ibctm.ClientState) suite.Require().True(ok) tmClientState.AllowUpdateAfterMisbehaviour = true tmClientState.AllowUpdateAfterExpiry = true tmClientState.FrozenHeight = tmClientState.LatestHeight suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) - tmClientState, ok = substituteClientState.(*ibctmtypes.ClientState) + tmClientState, ok = substituteClientState.(*ibctm.ClientState) suite.Require().True(ok) tmClientState.AllowUpdateAfterMisbehaviour = true tmClientState.AllowUpdateAfterExpiry = true @@ -158,7 +148,7 @@ func (suite *KeeperTestSuite) TestClientUpdateProposal() { func (suite *KeeperTestSuite) TestHandleUpgradeProposal() { var ( - upgradedClientState *ibctmtypes.ClientState + upgradedClientState *ibctm.ClientState oldPlan, plan upgradetypes.Plan content govtypes.Content err error @@ -188,7 +178,7 @@ func (suite *KeeperTestSuite) TestHandleUpgradeProposal() { }, { "cannot unpack client state", func() { - any, err := types.PackConsensusState(&ibctmtypes.ConsensusState{}) + any, err := types.PackConsensusState(&ibctm.ConsensusState{}) suite.Require().NoError(err) content = &types.UpgradeProposal{ Title: ibctesting.Title, @@ -209,7 +199,7 @@ func (suite *KeeperTestSuite) TestHandleUpgradeProposal() { path := ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(path) - upgradedClientState = suite.chainA.GetClientState(path.EndpointA.ClientID).ZeroCustomFields().(*ibctmtypes.ClientState) + upgradedClientState = suite.chainA.GetClientState(path.EndpointA.ClientID).ZeroCustomFields().(*ibctm.ClientState) // use height 1000 to distinguish from old plan plan = upgradetypes.Plan{ diff --git a/modules/core/02-client/legacy/v100/genesis.go b/modules/core/02-client/legacy/v100/genesis.go index 9442b59b2a4..3a4018ff621 100644 --- a/modules/core/02-client/legacy/v100/genesis.go +++ b/modules/core/02-client/legacy/v100/genesis.go @@ -10,7 +10,7 @@ import ( "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" host "github.com/cosmos/ibc-go/v5/modules/core/24-host" "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ) // MigrateGenesis accepts exported v1.0.0 IBC client genesis file and migrates it to: @@ -67,7 +67,7 @@ func MigrateGenesis(cdc codec.BinaryCodec, clientGenState *types.GenesisState, g case exported.Tendermint: // only add non expired consensus states to new clientsConsensus - tmClientState, ok := client.ClientState.GetCachedValue().(*ibctmtypes.ClientState) + tmClientState, ok := client.ClientState.GetCachedValue().(*ibctm.ClientState) if !ok { return nil, types.ErrInvalidClient } @@ -75,7 +75,7 @@ func MigrateGenesis(cdc codec.BinaryCodec, clientGenState *types.GenesisState, g // collect unexpired consensus states var unexpiredConsensusStates []types.ConsensusStateWithHeight for _, consState := range clientConsensusStates.ConsensusStates { - tmConsState := consState.ConsensusState.GetCachedValue().(*ibctmtypes.ConsensusState) + tmConsState := consState.ConsensusState.GetCachedValue().(*ibctm.ConsensusState) if !tmClientState.IsExpired(tmConsState.Timestamp, genesisBlockTime) { unexpiredConsensusStates = append(unexpiredConsensusStates, consState) } @@ -109,18 +109,18 @@ func MigrateGenesis(cdc codec.BinaryCodec, clientGenState *types.GenesisState, g // the previous version of IBC only contained the processed time metadata // if we find the processed time metadata for an unexpired height, add the // iteration key and processed height keys. - if bytes.Equal(metadata.Key, ibctmtypes.ProcessedTimeKey(height)) { + if bytes.Equal(metadata.Key, ibctm.ProcessedTimeKey(height)) { clientMetadata = append(clientMetadata, // set the processed height using the current self height // this is safe, it may cause delays in packet processing if there // is a non zero connection delay time types.GenesisMetadata{ - Key: ibctmtypes.ProcessedHeightKey(height), + Key: ibctm.ProcessedHeightKey(height), Value: []byte(selfHeight.String()), }, metadata, // processed time types.GenesisMetadata{ - Key: ibctmtypes.IterationKey(height), + Key: ibctm.IterationKey(height), Value: host.ConsensusStateKey(height), }) } diff --git a/modules/core/02-client/legacy/v100/genesis_test.go b/modules/core/02-client/legacy/v100/genesis_test.go index 7235b984261..953643e4ecc 100644 --- a/modules/core/02-client/legacy/v100/genesis_test.go +++ b/modules/core/02-client/legacy/v100/genesis_test.go @@ -14,7 +14,7 @@ import ( "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" host "github.com/cosmos/ibc-go/v5/modules/core/24-host" "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" "github.com/cosmos/ibc-go/v5/testing/simapp" ) @@ -134,7 +134,7 @@ func (suite *LegacyTestSuite) TestMigrateGenesisSolomachine() { var updatedMetadata []types.GenesisMetadata var iterationKeys []types.GenesisMetadata for _, metadata := range clientMetadata.ClientMetadata { - if bytes.HasPrefix(metadata.Key, []byte(ibctmtypes.KeyIterateConsensusStatePrefix)) { + if bytes.HasPrefix(metadata.Key, []byte(ibctm.KeyIterateConsensusStatePrefix)) { iterationKeys = append(iterationKeys, metadata) } else { updatedMetadata = append(updatedMetadata, metadata) @@ -233,7 +233,7 @@ func (suite *LegacyTestSuite) TestMigrateGenesisTendermint() { var updatedMetadata []types.GenesisMetadata var iterationKeys []types.GenesisMetadata for _, metadata := range clientMetadata.ClientMetadata { - if bytes.HasPrefix(metadata.Key, []byte(ibctmtypes.KeyIterateConsensusStatePrefix)) { + if bytes.HasPrefix(metadata.Key, []byte(ibctm.KeyIterateConsensusStatePrefix)) { iterationKeys = append(iterationKeys, metadata) } else { updatedMetadata = append(updatedMetadata, metadata) @@ -258,9 +258,9 @@ func (suite *LegacyTestSuite) TestMigrateGenesisTendermint() { for _, client := range migrated.ClientsMetadata { if client.ClientId == path1.EndpointA.ClientID { for _, metadata := range client.ClientMetadata { - suite.Require().NotEqual(ibctmtypes.ProcessedTimeKey(height), metadata.Key) - suite.Require().NotEqual(ibctmtypes.ProcessedHeightKey(height), metadata.Key) - suite.Require().NotEqual(ibctmtypes.IterationKey(height), metadata.Key) + suite.Require().NotEqual(ibctm.ProcessedTimeKey(height), metadata.Key) + suite.Require().NotEqual(ibctm.ProcessedHeightKey(height), metadata.Key) + suite.Require().NotEqual(ibctm.IterationKey(height), metadata.Key) } } } @@ -278,9 +278,9 @@ func (suite *LegacyTestSuite) TestMigrateGenesisTendermint() { for _, client := range migrated.ClientsMetadata { if client.ClientId == path2.EndpointA.ClientID { for _, metadata := range client.ClientMetadata { - suite.Require().NotEqual(ibctmtypes.ProcessedTimeKey(height), metadata.Key) - suite.Require().NotEqual(ibctmtypes.ProcessedHeightKey(height), metadata.Key) - suite.Require().NotEqual(ibctmtypes.IterationKey(height), metadata.Key) + suite.Require().NotEqual(ibctm.ProcessedTimeKey(height), metadata.Key) + suite.Require().NotEqual(ibctm.ProcessedHeightKey(height), metadata.Key) + suite.Require().NotEqual(ibctm.IterationKey(height), metadata.Key) } } } diff --git a/modules/core/02-client/legacy/v100/solomachine.go b/modules/core/02-client/legacy/v100/solomachine.go index e9121760e5b..d16dad0bfbb 100644 --- a/modules/core/02-client/legacy/v100/solomachine.go +++ b/modules/core/02-client/legacy/v100/solomachine.go @@ -88,16 +88,40 @@ func (cs ClientState) ExportMetadata(_ sdk.KVStore) []exported.GenesisMetadata { panic("legacy solo machine is deprecated!") } +// CheckForMisbehaviour panics! +func (cs ClientState) CheckForMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, msg exported.ClientMessage) bool { + panic("legacy solo machine is deprecated!") +} + +// UpdateStateOnMisbehaviour panics! +func (cs *ClientState) UpdateStateOnMisbehaviour( + _ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, _ exported.ClientMessage, +) { + panic("legacy solo machine is deprecated!") +} + +// VerifyClientMessage panics! +func (cs *ClientState) VerifyClientMessage( + _ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, _ exported.ClientMessage, +) error { + panic("legacy solo machine is deprecated!") +} + +// UpdateState panis! +func (cs *ClientState) UpdateState(_ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, _ exported.ClientMessage) []exported.Height { + panic("legacy solo machine is deprecated!") +} + // CheckHeaderAndUpdateState panics! func (cs *ClientState) CheckHeaderAndUpdateState( - _ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, _ exported.Header, + _ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, _ exported.ClientMessage, ) (exported.ClientState, exported.ConsensusState, error) { panic("legacy solo machine is deprecated!") } // CheckMisbehaviourAndUpdateState panics! func (cs ClientState) CheckMisbehaviourAndUpdateState( - _ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, _ exported.Misbehaviour, + _ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, _ exported.ClientMessage, ) (exported.ClientState, error) { panic("legacy solo machine is deprecated!") } @@ -106,7 +130,7 @@ func (cs ClientState) CheckMisbehaviourAndUpdateState( func (cs ClientState) CheckSubstituteAndUpdateState( ctx sdk.Context, _ codec.BinaryCodec, _, _ sdk.KVStore, _ exported.ClientState, -) (exported.ClientState, error) { +) error { panic("legacy solo machine is deprecated!") } @@ -114,7 +138,7 @@ func (cs ClientState) CheckSubstituteAndUpdateState( func (cs ClientState) VerifyUpgradeAndUpdateState( _ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, _ exported.ClientState, _ exported.ConsensusState, _, _ []byte, -) (exported.ClientState, exported.ConsensusState, error) { +) error { panic("legacy solo machine is deprecated!") } @@ -187,6 +211,42 @@ func (cs ClientState) VerifyNextSequenceRecv( panic("legacy solo machine is deprecated!") } +// GetTimestampAtHeight panics! +func (cs ClientState) GetTimestampAtHeight( + sdk.Context, sdk.KVStore, codec.BinaryCodec, exported.Height, +) (uint64, error) { + panic("legacy solo machine is deprecated!") +} + +// VerifyMembership panics! +func (cs *ClientState) VerifyMembership( + ctx sdk.Context, + clientStore sdk.KVStore, + cdc codec.BinaryCodec, + height exported.Height, + delayTimePeriod uint64, + delayBlockPeriod uint64, + proof []byte, + path []byte, + value []byte, +) error { + panic("legacy solo machine is deprecated!") +} + +// VerifyNonMembership panics! +func (cs *ClientState) VerifyNonMembership( + ctx sdk.Context, + clientStore sdk.KVStore, + cdc codec.BinaryCodec, + height exported.Height, + delayTimePeriod uint64, + delayBlockPeriod uint64, + proof []byte, + path []byte, +) error { + panic("legacy solo machine is deprecated") +} + // ClientType panics! func (ConsensusState) ClientType() string { panic("legacy solo machine is deprecated!") @@ -197,11 +257,6 @@ func (cs ConsensusState) GetTimestamp() uint64 { panic("legacy solo machine is deprecated!") } -// GetRoot panics! -func (cs ConsensusState) GetRoot() exported.Root { - panic("legacy solo machine is deprecated!") -} - // ValidateBasic panics! func (cs ConsensusState) ValidateBasic() error { panic("legacy solo machine is deprecated!") diff --git a/modules/core/02-client/legacy/v100/store.go b/modules/core/02-client/legacy/v100/store.go index f20b24ba2a1..e83b116c956 100644 --- a/modules/core/02-client/legacy/v100/store.go +++ b/modules/core/02-client/legacy/v100/store.go @@ -14,8 +14,8 @@ import ( clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" host "github.com/cosmos/ibc-go/v5/modules/core/24-host" "github.com/cosmos/ibc-go/v5/modules/core/exported" - smtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine/types" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + smtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ) // MigrateStore performs in-place store migrations from SDK v0.40 of the IBC module to v1.0.0 of ibc-go. @@ -88,7 +88,7 @@ func MigrateStore(ctx sdk.Context, storeKey storetypes.StoreKey, cdc codec.Binar return sdkerrors.Wrap(err, "failed to unmarshal client state bytes into tendermint client state") } - tmClientState, ok := clientState.(*ibctmtypes.ClientState) + tmClientState, ok := clientState.(*ibctm.ClientState) if !ok { return sdkerrors.Wrap(clienttypes.ErrInvalidClient, "client state is not tendermint even though client id contains 07-tendermint") } @@ -96,10 +96,7 @@ func MigrateStore(ctx sdk.Context, storeKey storetypes.StoreKey, cdc codec.Binar // add iteration keys so pruning will be successful addConsensusMetadata(ctx, clientStore) - if err = ibctmtypes.PruneAllExpiredConsensusStates(ctx, clientStore, cdc, tmClientState); err != nil { - return err - } - + ibctm.PruneAllExpiredConsensusStates(ctx, clientStore, cdc, tmClientState) default: continue } @@ -170,7 +167,7 @@ func addConsensusMetadata(ctx sdk.Context, clientStore sdk.KVStore) { for _, height := range heights { // set the iteration key and processed height // these keys were not included in the SDK v0.42.0 release - ibctmtypes.SetProcessedHeight(clientStore, height, clienttypes.GetSelfHeight(ctx)) - ibctmtypes.SetIterationKey(clientStore, height) + ibctm.SetProcessedHeight(clientStore, height, clienttypes.GetSelfHeight(ctx)) + ibctm.SetIterationKey(clientStore, height) } } diff --git a/modules/core/02-client/legacy/v100/store_test.go b/modules/core/02-client/legacy/v100/store_test.go index 4cebf0a53cb..69c431fe15f 100644 --- a/modules/core/02-client/legacy/v100/store_test.go +++ b/modules/core/02-client/legacy/v100/store_test.go @@ -10,7 +10,7 @@ import ( "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" host "github.com/cosmos/ibc-go/v5/modules/core/24-host" "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) @@ -146,15 +146,15 @@ func (suite *LegacyTestSuite) TestMigrateStoreTendermint() { ctx := path.EndpointA.Chain.GetContext() clientStore := path.EndpointA.Chain.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) - processedTime, ok := ibctmtypes.GetProcessedTime(clientStore, pruneHeight) + processedTime, ok := ibctm.GetProcessedTime(clientStore, pruneHeight) suite.Require().True(ok) suite.Require().NotNil(processedTime) - processedHeight, ok := ibctmtypes.GetProcessedHeight(clientStore, pruneHeight) + processedHeight, ok := ibctm.GetProcessedHeight(clientStore, pruneHeight) suite.Require().True(ok) suite.Require().NotNil(processedHeight) - expectedConsKey := ibctmtypes.GetIterationKey(clientStore, pruneHeight) + expectedConsKey := ibctm.GetIterationKey(clientStore, pruneHeight) suite.Require().NotNil(expectedConsKey) } pruneHeightMap[path] = pruneHeights @@ -174,8 +174,8 @@ func (suite *LegacyTestSuite) TestMigrateStoreTendermint() { // remove processed height and iteration keys since these were missing from previous version of ibc module clientStore := path.EndpointA.Chain.App.GetIBCKeeper().ClientKeeper.ClientStore(path.EndpointA.Chain.GetContext(), path.EndpointA.ClientID) for _, height := range unexpiredHeights { - clientStore.Delete(ibctmtypes.ProcessedHeightKey(height)) - clientStore.Delete(ibctmtypes.IterationKey(height)) + clientStore.Delete(ibctm.ProcessedHeightKey(height)) + clientStore.Delete(ibctm.IterationKey(height)) } unexpiredHeightMap[path] = unexpiredHeights @@ -198,15 +198,15 @@ func (suite *LegacyTestSuite) TestMigrateStoreTendermint() { suite.Require().False(ok, i) suite.Require().Nil(consState, i) - processedTime, ok := ibctmtypes.GetProcessedTime(clientStore, pruneHeight) + processedTime, ok := ibctm.GetProcessedTime(clientStore, pruneHeight) suite.Require().False(ok, i) suite.Require().Equal(uint64(0), processedTime, i) - processedHeight, ok := ibctmtypes.GetProcessedHeight(clientStore, pruneHeight) + processedHeight, ok := ibctm.GetProcessedHeight(clientStore, pruneHeight) suite.Require().False(ok, i) suite.Require().Nil(processedHeight, i) - expectedConsKey := ibctmtypes.GetIterationKey(clientStore, pruneHeight) + expectedConsKey := ibctm.GetIterationKey(clientStore, pruneHeight) suite.Require().Nil(expectedConsKey, i) } @@ -216,15 +216,15 @@ func (suite *LegacyTestSuite) TestMigrateStoreTendermint() { suite.Require().True(ok) suite.Require().NotNil(consState) - processedTime, ok := ibctmtypes.GetProcessedTime(clientStore, height) + processedTime, ok := ibctm.GetProcessedTime(clientStore, height) suite.Require().True(ok) suite.Require().NotEqual(uint64(0), processedTime) - processedHeight, ok := ibctmtypes.GetProcessedHeight(clientStore, height) + processedHeight, ok := ibctm.GetProcessedHeight(clientStore, height) suite.Require().True(ok) suite.Require().Equal(types.GetSelfHeight(path.EndpointA.Chain.GetContext()), processedHeight) - consKey := ibctmtypes.GetIterationKey(clientStore, height) + consKey := ibctm.GetIterationKey(clientStore, height) suite.Require().Equal(host.ConsensusStateKey(height), consKey) } } diff --git a/modules/light-clients/06-solomachine/types/solomachine.pb.go b/modules/core/02-client/migrations/v6/solomachine.pb.go similarity index 92% rename from modules/light-clients/06-solomachine/types/solomachine.pb.go rename to modules/core/02-client/migrations/v6/solomachine.pb.go index 2a287b9ced7..bbcb1b6a355 100644 --- a/modules/light-clients/06-solomachine/types/solomachine.pb.go +++ b/modules/core/02-client/migrations/v6/solomachine.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: ibc/lightclients/solomachine/v2/solomachine.proto -package types +package v6 import ( fmt "fmt" @@ -823,93 +823,93 @@ func init() { } var fileDescriptor_141333b361aae010 = []byte{ - // 1370 bytes of a gzipped FileDescriptorProto + // 1373 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x5f, 0x8f, 0xdb, 0x44, - 0x10, 0x3f, 0xa7, 0xe9, 0xf5, 0x32, 0xb9, 0xde, 0x05, 0x37, 0x6d, 0x73, 0x6e, 0x95, 0x18, 0x23, - 0xca, 0x81, 0x68, 0xc2, 0x1d, 0x6a, 0x85, 0x2a, 0x04, 0x38, 0x8e, 0x4b, 0xd3, 0xde, 0xf9, 0x82, - 0xe3, 0x03, 0x5a, 0x21, 0x19, 0xc7, 0xd9, 0x4b, 0xac, 0x26, 0xde, 0x34, 0x76, 0x92, 0x06, 0x09, - 0x09, 0xf1, 0x54, 0x22, 0x1e, 0xf8, 0x02, 0x91, 0x10, 0x88, 0xcf, 0xc1, 0x1b, 0xf0, 0xd8, 0x47, - 0x9e, 0x02, 0x6a, 0xbf, 0x41, 0x3e, 0x01, 0xb2, 0x77, 0x13, 0xdb, 0xb9, 0x5e, 0x4e, 0xfc, 0x7b, - 0xdb, 0x9d, 0xdf, 0xcc, 0x6f, 0x66, 0x67, 0xc6, 0xb3, 0x6b, 0xd8, 0xb1, 0x6a, 0x66, 0xa1, 0x65, - 0x35, 0x9a, 0xae, 0xd9, 0xb2, 0x90, 0xed, 0x3a, 0x05, 0x07, 0xb7, 0x70, 0xdb, 0x30, 0x9b, 0x96, - 0x8d, 0x0a, 0xfd, 0xdd, 0xf0, 0x36, 0xdf, 0xe9, 0x62, 0x17, 0xb3, 0x39, 0xab, 0x66, 0xe6, 0xc3, - 0x26, 0xf9, 0xb0, 0x4e, 0x7f, 0x97, 0x7b, 0xcd, 0xe3, 0x34, 0x71, 0x17, 0x15, 0x4c, 0x6c, 0xdb, - 0xc8, 0x74, 0x2d, 0x6c, 0x17, 0xfa, 0x3b, 0xa1, 0x1d, 0x61, 0xe2, 0x5e, 0x0e, 0x14, 0x9b, 0x86, - 0x6d, 0xa3, 0x96, 0xaf, 0x45, 0x96, 0x54, 0x25, 0xdd, 0xc0, 0x0d, 0xec, 0x2f, 0x0b, 0xde, 0x8a, - 0x4a, 0xb7, 0x1a, 0x18, 0x37, 0x5a, 0xa8, 0xe0, 0xef, 0x6a, 0xbd, 0xa3, 0x82, 0x61, 0x0f, 0x09, - 0x24, 0xfc, 0x1c, 0x83, 0xa4, 0xe4, 0xc7, 0x55, 0x75, 0x0d, 0x17, 0xb1, 0x1c, 0xac, 0x39, 0xe8, - 0x51, 0x0f, 0xd9, 0x26, 0xca, 0x30, 0x3c, 0xb3, 0x1d, 0x57, 0xe7, 0x7b, 0x76, 0x07, 0x12, 0x96, - 0xa3, 0x1f, 0x75, 0xf1, 0x17, 0xc8, 0xce, 0xc4, 0x78, 0x66, 0x7b, 0xad, 0x98, 0x9e, 0x4e, 0x72, - 0xa9, 0xa1, 0xd1, 0x6e, 0xdd, 0x12, 0xe6, 0x90, 0xa0, 0xae, 0x59, 0xce, 0x6d, 0x7f, 0xc9, 0xba, - 0xb0, 0x69, 0x62, 0xdb, 0x41, 0xb6, 0xd3, 0x73, 0x74, 0xc7, 0xf3, 0x90, 0x39, 0xc3, 0x33, 0xdb, - 0xc9, 0xdd, 0x42, 0xfe, 0x94, 0xb4, 0xe4, 0xa5, 0x99, 0x9d, 0x1f, 0x58, 0x91, 0x9b, 0x4e, 0x72, - 0x97, 0x88, 0xa7, 0x05, 0x46, 0x41, 0xdd, 0x30, 0x23, 0xba, 0x2c, 0x82, 0x2b, 0x46, 0xab, 0x85, - 0x07, 0x7a, 0xaf, 0x53, 0x37, 0x5c, 0xa4, 0x1b, 0x47, 0x2e, 0xea, 0xea, 0x9d, 0x2e, 0xee, 0x60, - 0xc7, 0x68, 0x65, 0xe2, 0x7e, 0xe8, 0xd7, 0xa6, 0x93, 0x9c, 0x40, 0x08, 0x97, 0x28, 0x0b, 0x6a, - 0xc6, 0x47, 0x0f, 0x7d, 0x50, 0xf4, 0xb0, 0x0a, 0x85, 0x6e, 0xc5, 0x9f, 0x7c, 0x9f, 0x5b, 0x11, - 0x7e, 0x60, 0x60, 0x23, 0x1a, 0x2b, 0x7b, 0x17, 0xa0, 0xd3, 0xab, 0xb5, 0x2c, 0x53, 0x7f, 0x88, - 0x86, 0x7e, 0x1a, 0x93, 0xbb, 0xe9, 0x3c, 0x29, 0x42, 0x7e, 0x56, 0x84, 0xbc, 0x68, 0x0f, 0x8b, - 0x17, 0xa7, 0x93, 0xdc, 0x4b, 0x24, 0x88, 0xc0, 0x42, 0x50, 0x13, 0x64, 0x73, 0x0f, 0x0d, 0x59, - 0x1e, 0x92, 0x75, 0xab, 0x8f, 0xba, 0x8e, 0x75, 0x64, 0xa1, 0xae, 0x9f, 0xf6, 0x84, 0x1a, 0x16, - 0xb1, 0x57, 0x21, 0xe1, 0x5a, 0x6d, 0xe4, 0xb8, 0x46, 0xbb, 0xe3, 0x67, 0x37, 0xae, 0x06, 0x02, - 0x1a, 0xe4, 0xd7, 0x31, 0x58, 0xbd, 0x83, 0x8c, 0x3a, 0xea, 0x2e, 0xad, 0x70, 0x84, 0x2a, 0xb6, - 0x40, 0xe5, 0xa1, 0x8e, 0xd5, 0xb0, 0x0d, 0xb7, 0xd7, 0x25, 0x65, 0x5c, 0x57, 0x03, 0x01, 0x7b, - 0x08, 0x1b, 0x36, 0x1a, 0xe8, 0xa1, 0x83, 0xc7, 0x97, 0x1c, 0x7c, 0x6b, 0x3a, 0xc9, 0x5d, 0x24, - 0x07, 0x8f, 0x5a, 0x09, 0xea, 0xba, 0x8d, 0x06, 0x95, 0xf9, 0xf9, 0x25, 0xd8, 0xf4, 0x14, 0xc2, - 0x39, 0x38, 0xeb, 0xe5, 0x20, 0xdc, 0x10, 0x0b, 0x0a, 0x82, 0xea, 0x45, 0x52, 0x0a, 0x04, 0x34, - 0x09, 0xbf, 0xc6, 0x60, 0x7d, 0xdf, 0x72, 0x6a, 0xa8, 0x69, 0xf4, 0x2d, 0xdc, 0xeb, 0x7a, 0x0d, - 0x4d, 0x9a, 0x4f, 0xb7, 0xea, 0x7e, 0x2e, 0x12, 0xe1, 0x86, 0x9e, 0x43, 0x82, 0xba, 0x46, 0xd6, - 0xe5, 0x7a, 0x24, 0x7b, 0xb1, 0x85, 0xec, 0x75, 0xe0, 0xfc, 0x3c, 0x1d, 0x3a, 0xb6, 0x67, 0xad, - 0xbe, 0x73, 0x6a, 0xab, 0x57, 0x67, 0x56, 0xa2, 0x5d, 0x2f, 0x19, 0xae, 0x51, 0xcc, 0x4c, 0x27, - 0xb9, 0x34, 0x89, 0x22, 0xc2, 0x28, 0xa8, 0xeb, 0xf3, 0xfd, 0x81, 0xbd, 0xe0, 0xd1, 0x1d, 0x60, - 0x9a, 0xf2, 0xff, 0xca, 0xa3, 0x3b, 0xc0, 0x61, 0x8f, 0xda, 0x00, 0xd3, 0x4c, 0xfe, 0xc2, 0x40, - 0x6a, 0x91, 0x22, 0xda, 0x1e, 0xcc, 0x62, 0x7b, 0x7c, 0x06, 0x89, 0xba, 0xe1, 0x1a, 0xba, 0x3b, - 0xec, 0x90, 0xcc, 0x6d, 0xec, 0xbe, 0x7e, 0x6a, 0x98, 0x1e, 0xaf, 0x36, 0xec, 0xa0, 0x70, 0x59, - 0xe6, 0x2c, 0x82, 0xba, 0x56, 0xa7, 0x38, 0xcb, 0x42, 0xdc, 0x5b, 0xd3, 0xae, 0xf4, 0xd7, 0xd1, - 0x66, 0x8e, 0xbf, 0xf8, 0xbb, 0xf8, 0x8a, 0x81, 0x8c, 0x36, 0x93, 0xa1, 0xfa, 0xfc, 0x4c, 0xfe, - 0x81, 0x3e, 0x80, 0x8d, 0x20, 0x17, 0x3e, 0xbd, 0x7f, 0xaa, 0x70, 0xef, 0x46, 0x71, 0x41, 0x0d, - 0xca, 0x51, 0x3a, 0x16, 0x42, 0xec, 0xc5, 0x21, 0xfc, 0xc1, 0x40, 0xc2, 0xf3, 0x5b, 0x1c, 0xba, - 0xc8, 0xf9, 0x17, 0x5f, 0xe7, 0xc2, 0xa0, 0x38, 0x73, 0x7c, 0x50, 0x44, 0x4a, 0x10, 0xff, 0xbf, - 0x4a, 0x70, 0x36, 0x28, 0x01, 0x3d, 0xe1, 0x4f, 0x0c, 0x00, 0x19, 0x3e, 0x7e, 0x52, 0xf6, 0x20, - 0x49, 0x3f, 0xf9, 0x53, 0xc7, 0xe3, 0xa5, 0xe9, 0x24, 0xc7, 0x46, 0xa6, 0x04, 0x9d, 0x8f, 0x64, - 0x44, 0x9c, 0x30, 0x1f, 0x62, 0xff, 0x70, 0x3e, 0x7c, 0x09, 0x9b, 0xa1, 0xab, 0xd0, 0x8f, 0x95, - 0x85, 0x78, 0xc7, 0x70, 0x9b, 0xb4, 0x9d, 0xfd, 0x35, 0x5b, 0x81, 0x75, 0x3a, 0x1a, 0xc8, 0x85, - 0x16, 0x5b, 0x72, 0x80, 0xcb, 0xd3, 0x49, 0xee, 0x42, 0x64, 0x9c, 0xd0, 0x2b, 0x2b, 0x69, 0x06, - 0x9e, 0xa8, 0xfb, 0x6f, 0x18, 0x60, 0xa3, 0x17, 0xc9, 0x89, 0x21, 0xdc, 0x3f, 0x7e, 0xad, 0x2e, - 0x8b, 0xe2, 0x6f, 0xdc, 0x9d, 0x34, 0x96, 0x3e, 0x5c, 0x90, 0xe6, 0xcf, 0x8f, 0xe5, 0xb1, 0xc8, - 0x00, 0xc1, 0x4b, 0x85, 0x86, 0xf1, 0xaa, 0xdf, 0x56, 0xde, 0x53, 0x25, 0x1f, 0x7a, 0xc5, 0xf4, - 0x77, 0xf2, 0x01, 0xa9, 0x6c, 0xd7, 0xd5, 0x90, 0x21, 0xf5, 0x5b, 0x87, 0x94, 0x44, 0x1e, 0x34, - 0xcb, 0x9d, 0xde, 0x84, 0x73, 0xf4, 0xe1, 0x43, 0x3d, 0x5e, 0x0d, 0x79, 0xa4, 0x2f, 0x22, 0xcf, - 0x1d, 0x59, 0xaa, 0x33, 0x65, 0xea, 0xe5, 0x2e, 0xa4, 0x2b, 0x86, 0xf9, 0x10, 0xb9, 0x12, 0x6e, - 0xb7, 0x2d, 0xb7, 0x8d, 0x6c, 0xf7, 0x44, 0x4f, 0x59, 0xef, 0x78, 0x33, 0x2d, 0xdf, 0xd9, 0xba, - 0x1a, 0x92, 0x08, 0xf7, 0x61, 0x8b, 0x70, 0x89, 0xe6, 0x43, 0x1b, 0x0f, 0x5a, 0xa8, 0xde, 0x40, - 0x4b, 0x09, 0xb7, 0x61, 0xd3, 0x88, 0xaa, 0x52, 0xd6, 0x45, 0xb1, 0x90, 0x87, 0x0c, 0xa1, 0x56, - 0x91, 0x89, 0xac, 0x8e, 0x2b, 0xd6, 0x1c, 0x6f, 0x0e, 0x9c, 0xc4, 0x2c, 0x34, 0x21, 0xad, 0xa0, - 0xc7, 0x6e, 0x95, 0xce, 0x0b, 0x15, 0x99, 0xfd, 0x13, 0xa3, 0x78, 0x17, 0xce, 0xdb, 0xe8, 0xb1, - 0xab, 0x3b, 0xe8, 0x91, 0xde, 0x45, 0x66, 0x9f, 0xcc, 0x93, 0xf0, 0x35, 0x10, 0x81, 0x05, 0x35, - 0x69, 0x13, 0x6a, 0x8f, 0xf5, 0x8d, 0x6f, 0xe3, 0xb0, 0x36, 0x1b, 0x0c, 0xec, 0x3b, 0xf0, 0x4a, - 0x49, 0xd4, 0x44, 0x5d, 0xbb, 0x5f, 0x91, 0xf5, 0x43, 0xa5, 0xac, 0x94, 0xb5, 0xb2, 0xb8, 0x57, - 0x7e, 0x20, 0x97, 0xf4, 0x43, 0xa5, 0x5a, 0x91, 0xa5, 0xf2, 0xed, 0xb2, 0x5c, 0x4a, 0xad, 0x70, - 0x9b, 0xa3, 0x31, 0x9f, 0x0c, 0x89, 0xd8, 0x6b, 0x70, 0x29, 0xb0, 0x94, 0xf6, 0xca, 0xb2, 0xa2, - 0xe9, 0x55, 0x4d, 0xd4, 0xe4, 0x14, 0xc3, 0xc1, 0x68, 0xcc, 0xaf, 0x12, 0x19, 0xfb, 0x26, 0x6c, - 0x85, 0xf4, 0x0e, 0x94, 0xaa, 0xac, 0x54, 0x0f, 0xab, 0x54, 0x35, 0xc6, 0x9d, 0x1f, 0x8d, 0xf9, - 0xc4, 0x5c, 0xcc, 0xe6, 0x81, 0x8b, 0x68, 0x2b, 0xb2, 0xa4, 0x95, 0x0f, 0x14, 0xaa, 0x7e, 0x86, - 0xdb, 0x18, 0x8d, 0x79, 0x08, 0xe4, 0xec, 0x36, 0x5c, 0x0e, 0xe9, 0xdf, 0x11, 0x15, 0x45, 0xde, - 0xa3, 0xca, 0x71, 0x2e, 0x39, 0x1a, 0xf3, 0xe7, 0xa8, 0x90, 0xbd, 0x01, 0x57, 0x02, 0xcd, 0x8a, - 0x28, 0xdd, 0x93, 0x35, 0x5d, 0x3a, 0xd8, 0xdf, 0x2f, 0x6b, 0xfb, 0xb2, 0xa2, 0xa5, 0xce, 0x72, - 0xe9, 0xd1, 0x98, 0x4f, 0x11, 0x20, 0x90, 0xb3, 0xef, 0x03, 0x7f, 0xcc, 0x4c, 0x94, 0xee, 0x29, - 0x07, 0x9f, 0xec, 0xc9, 0xa5, 0x0f, 0x65, 0xdf, 0x76, 0x95, 0xdb, 0x1a, 0x8d, 0xf9, 0x8b, 0x04, - 0x5d, 0x00, 0xd9, 0xf7, 0x5e, 0x40, 0xa0, 0xca, 0x92, 0x5c, 0xae, 0x68, 0xba, 0x58, 0xac, 0xca, - 0x8a, 0x24, 0xa7, 0xce, 0x71, 0x99, 0xd1, 0x98, 0x4f, 0x13, 0x94, 0x82, 0x14, 0x63, 0x6f, 0xc2, - 0xd5, 0xc0, 0x5e, 0x91, 0x3f, 0xd5, 0xf4, 0xaa, 0xfc, 0xd1, 0xa1, 0x07, 0x79, 0x34, 0x1f, 0xa7, - 0xd6, 0x48, 0xe0, 0x1e, 0x32, 0x03, 0x3c, 0x39, 0xcb, 0x43, 0x2a, 0xb0, 0xbb, 0x23, 0x8b, 0x25, - 0x59, 0x4d, 0x25, 0x48, 0x65, 0xc8, 0x8e, 0x8b, 0x3f, 0xf9, 0x31, 0xbb, 0x52, 0xfc, 0xfc, 0xb7, - 0x67, 0x59, 0xe6, 0xe9, 0xb3, 0x2c, 0xf3, 0xe7, 0xb3, 0x2c, 0xf3, 0xdd, 0xf3, 0xec, 0xca, 0xd3, - 0xe7, 0xd9, 0x95, 0xdf, 0x9f, 0x67, 0x57, 0x1e, 0xdc, 0x6e, 0x58, 0x6e, 0xb3, 0x57, 0xcb, 0x9b, - 0xb8, 0x5d, 0x30, 0xb1, 0xd3, 0xc6, 0x4e, 0xc1, 0xaa, 0x99, 0xd7, 0x1b, 0xb8, 0xd0, 0xbf, 0x51, - 0x68, 0xe3, 0x7a, 0xaf, 0x85, 0x1c, 0xf2, 0x3f, 0x75, 0x7d, 0xf6, 0x43, 0xf5, 0xd6, 0xcd, 0xeb, - 0xe1, 0x7f, 0x2a, 0xef, 0x9a, 0x71, 0x6a, 0xab, 0xfe, 0x3c, 0x7b, 0xfb, 0xaf, 0x00, 0x00, 0x00, - 0xff, 0xff, 0x32, 0xda, 0xb7, 0x54, 0x80, 0x0d, 0x00, 0x00, + 0x10, 0x3f, 0xa7, 0xe9, 0xf5, 0xb2, 0xb9, 0xde, 0x05, 0x37, 0x6d, 0x73, 0x6e, 0x95, 0x18, 0x23, + 0xca, 0x81, 0x68, 0xcc, 0x1d, 0x6a, 0x85, 0x2a, 0x04, 0x75, 0x1c, 0x97, 0xa6, 0xbd, 0xf3, 0x05, + 0xc7, 0x07, 0xb4, 0x42, 0xb2, 0x1c, 0x7b, 0x2f, 0xb1, 0x9a, 0x78, 0xd3, 0x78, 0x93, 0x34, 0x48, + 0x48, 0x88, 0xa7, 0x12, 0xf1, 0xc0, 0x17, 0x88, 0x84, 0x40, 0x7c, 0x0e, 0xde, 0x80, 0xc7, 0x3e, + 0xf2, 0x14, 0x50, 0xfb, 0x0d, 0xf2, 0x09, 0x90, 0xbd, 0x9b, 0xd8, 0xce, 0xf5, 0x72, 0xe2, 0xdf, + 0xdb, 0xee, 0xfc, 0x66, 0x7e, 0x33, 0x3b, 0x33, 0x9e, 0x5d, 0x83, 0x1d, 0xa7, 0x6e, 0x89, 0x2d, + 0xa7, 0xd1, 0xc4, 0x56, 0xcb, 0x81, 0x2e, 0xf6, 0x44, 0x0f, 0xb5, 0x50, 0xdb, 0xb4, 0x9a, 0x8e, + 0x0b, 0xc5, 0xfe, 0x6e, 0x74, 0x5b, 0xec, 0x74, 0x11, 0x46, 0x6c, 0xc1, 0xa9, 0x5b, 0xc5, 0xa8, + 0x49, 0x31, 0xaa, 0xd3, 0xdf, 0xe5, 0xde, 0xf0, 0x39, 0x2d, 0xd4, 0x85, 0xa2, 0x85, 0x5c, 0x17, + 0x5a, 0xd8, 0x41, 0xae, 0xd8, 0xdf, 0x89, 0xec, 0x08, 0x13, 0xf7, 0x6a, 0xa8, 0xd8, 0x34, 0x5d, + 0x17, 0xb6, 0x02, 0x2d, 0xb2, 0xa4, 0x2a, 0xd9, 0x06, 0x6a, 0xa0, 0x60, 0x29, 0xfa, 0x2b, 0x2a, + 0xdd, 0x6a, 0x20, 0xd4, 0x68, 0x41, 0x31, 0xd8, 0xd5, 0x7b, 0x47, 0xa2, 0xe9, 0x0e, 0x09, 0x24, + 0xfc, 0x9c, 0x00, 0x69, 0x39, 0x88, 0xab, 0x86, 0x4d, 0x0c, 0x59, 0x0e, 0xac, 0x79, 0xf0, 0x71, + 0x0f, 0xba, 0x16, 0xcc, 0x31, 0x3c, 0xb3, 0x9d, 0xd4, 0xe6, 0x7b, 0x76, 0x07, 0xa4, 0x1c, 0xcf, + 0x38, 0xea, 0xa2, 0x2f, 0xa0, 0x9b, 0x4b, 0xf0, 0xcc, 0xf6, 0x5a, 0x29, 0x3b, 0x9d, 0x14, 0x32, + 0x43, 0xb3, 0xdd, 0xba, 0x25, 0xcc, 0x21, 0x41, 0x5b, 0x73, 0xbc, 0x3b, 0xc1, 0x92, 0xc5, 0x60, + 0xd3, 0x42, 0xae, 0x07, 0x5d, 0xaf, 0xe7, 0x19, 0x9e, 0xef, 0x21, 0x77, 0x86, 0x67, 0xb6, 0xd3, + 0xbb, 0x62, 0xf1, 0x94, 0xb4, 0x14, 0xe5, 0x99, 0x5d, 0x10, 0x58, 0x89, 0x9b, 0x4e, 0x0a, 0x97, + 0x88, 0xa7, 0x05, 0x46, 0x41, 0xdb, 0xb0, 0x62, 0xba, 0x2c, 0x04, 0x57, 0xcc, 0x56, 0x0b, 0x0d, + 0x8c, 0x5e, 0xc7, 0x36, 0x31, 0x34, 0xcc, 0x23, 0x0c, 0xbb, 0x46, 0xa7, 0x8b, 0x3a, 0xc8, 0x33, + 0x5b, 0xb9, 0x64, 0x10, 0xfa, 0xb5, 0xe9, 0xa4, 0x20, 0x10, 0xc2, 0x25, 0xca, 0x82, 0x96, 0x0b, + 0xd0, 0xc3, 0x00, 0x94, 0x7c, 0xac, 0x4a, 0xa1, 0x5b, 0xc9, 0xa7, 0xdf, 0x17, 0x56, 0x84, 0x1f, + 0x18, 0xb0, 0x11, 0x8f, 0x95, 0xbd, 0x07, 0x40, 0xa7, 0x57, 0x6f, 0x39, 0x96, 0xf1, 0x08, 0x0e, + 0x83, 0x34, 0xa6, 0x77, 0xb3, 0x45, 0x52, 0x84, 0xe2, 0xac, 0x08, 0x45, 0xc9, 0x1d, 0x96, 0x2e, + 0x4e, 0x27, 0x85, 0x57, 0x48, 0x10, 0xa1, 0x85, 0xa0, 0xa5, 0xc8, 0xe6, 0x3e, 0x1c, 0xb2, 0x3c, + 0x48, 0xdb, 0x4e, 0x1f, 0x76, 0x3d, 0xe7, 0xc8, 0x81, 0xdd, 0x20, 0xed, 0x29, 0x2d, 0x2a, 0x62, + 0xaf, 0x82, 0x14, 0x76, 0xda, 0xd0, 0xc3, 0x66, 0xbb, 0x13, 0x64, 0x37, 0xa9, 0x85, 0x02, 0x1a, + 0xe4, 0xd7, 0x09, 0xb0, 0x7a, 0x17, 0x9a, 0x36, 0xec, 0x2e, 0xad, 0x70, 0x8c, 0x2a, 0xb1, 0x40, + 0xe5, 0xa3, 0x9e, 0xd3, 0x70, 0x4d, 0xdc, 0xeb, 0x92, 0x32, 0xae, 0x6b, 0xa1, 0x80, 0x3d, 0x04, + 0x1b, 0x2e, 0x1c, 0x18, 0x91, 0x83, 0x27, 0x97, 0x1c, 0x7c, 0x6b, 0x3a, 0x29, 0x5c, 0x24, 0x07, + 0x8f, 0x5b, 0x09, 0xda, 0xba, 0x0b, 0x07, 0xd5, 0xf9, 0xf9, 0x65, 0xb0, 0xe9, 0x2b, 0x44, 0x73, + 0x70, 0xd6, 0xcf, 0x41, 0xb4, 0x21, 0x16, 0x14, 0x04, 0xcd, 0x8f, 0xa4, 0x1c, 0x0a, 0x68, 0x12, + 0x7e, 0x4d, 0x80, 0xf5, 0x7d, 0xc7, 0xab, 0xc3, 0xa6, 0xd9, 0x77, 0x50, 0xaf, 0xeb, 0x37, 0x34, + 0x69, 0x3e, 0xc3, 0xb1, 0x83, 0x5c, 0xa4, 0xa2, 0x0d, 0x3d, 0x87, 0x04, 0x6d, 0x8d, 0xac, 0x2b, + 0x76, 0x2c, 0x7b, 0x89, 0x85, 0xec, 0x75, 0xc0, 0xf9, 0x79, 0x3a, 0x0c, 0xe4, 0xce, 0x5a, 0x7d, + 0xe7, 0xd4, 0x56, 0xaf, 0xcd, 0xac, 0x24, 0xd7, 0x2e, 0x9b, 0xd8, 0x2c, 0xe5, 0xa6, 0x93, 0x42, + 0x96, 0x44, 0x11, 0x63, 0x14, 0xb4, 0xf5, 0xf9, 0xfe, 0xc0, 0x5d, 0xf0, 0x88, 0x07, 0x88, 0xa6, + 0xfc, 0xbf, 0xf2, 0x88, 0x07, 0x28, 0xea, 0x51, 0x1f, 0x20, 0x9a, 0xc9, 0x5f, 0x18, 0x90, 0x59, + 0xa4, 0x88, 0xb7, 0x07, 0xb3, 0xd8, 0x1e, 0x9f, 0x83, 0x94, 0x6d, 0x62, 0xd3, 0xc0, 0xc3, 0x0e, + 0xc9, 0xdc, 0xc6, 0xee, 0x9b, 0xa7, 0x86, 0xe9, 0xf3, 0xea, 0xc3, 0x0e, 0x8c, 0x96, 0x65, 0xce, + 0x22, 0x68, 0x6b, 0x36, 0xc5, 0x59, 0x16, 0x24, 0xfd, 0x35, 0xed, 0xca, 0x60, 0x1d, 0x6f, 0xe6, + 0xe4, 0xcb, 0xbf, 0x8b, 0xaf, 0x18, 0x90, 0xd3, 0x67, 0x32, 0x68, 0xcf, 0xcf, 0x14, 0x1c, 0xe8, + 0x36, 0xd8, 0x08, 0x73, 0x11, 0xd0, 0x07, 0xa7, 0x8a, 0xf6, 0x6e, 0x1c, 0x17, 0xb4, 0xb0, 0x1c, + 0xe5, 0x63, 0x21, 0x24, 0x5e, 0x1e, 0xc2, 0x1f, 0x0c, 0x48, 0xf9, 0x7e, 0x4b, 0x43, 0x0c, 0xbd, + 0x7f, 0xf1, 0x75, 0x2e, 0x0c, 0x8a, 0x33, 0xc7, 0x07, 0x45, 0xac, 0x04, 0xc9, 0xff, 0xab, 0x04, + 0x67, 0xc3, 0x12, 0xd0, 0x13, 0xfe, 0xc4, 0x00, 0x40, 0x86, 0x4f, 0x90, 0x94, 0x3d, 0x90, 0xa6, + 0x9f, 0xfc, 0xa9, 0xe3, 0xf1, 0xd2, 0x74, 0x52, 0x60, 0x63, 0x53, 0x82, 0xce, 0x47, 0x32, 0x22, + 0x4e, 0x98, 0x0f, 0x89, 0x7f, 0x38, 0x1f, 0xbe, 0x04, 0x9b, 0x91, 0xab, 0x30, 0x88, 0x95, 0x05, + 0xc9, 0x8e, 0x89, 0x9b, 0xb4, 0x9d, 0x83, 0x35, 0x5b, 0x05, 0xeb, 0x74, 0x34, 0x90, 0x0b, 0x2d, + 0xb1, 0xe4, 0x00, 0x97, 0xa7, 0x93, 0xc2, 0x85, 0xd8, 0x38, 0xa1, 0x57, 0x56, 0xda, 0x0a, 0x3d, + 0x51, 0xf7, 0xdf, 0x30, 0x80, 0x8d, 0x5f, 0x24, 0x27, 0x86, 0xf0, 0xe0, 0xf8, 0xb5, 0xba, 0x2c, + 0x8a, 0xbf, 0x71, 0x77, 0xd2, 0x58, 0xfa, 0xe0, 0x82, 0x3c, 0x7f, 0x7e, 0x2c, 0x8f, 0x45, 0x01, + 0x20, 0x7c, 0xa9, 0xd0, 0x30, 0x5e, 0x0f, 0xda, 0xca, 0x7f, 0xaa, 0x14, 0x23, 0xaf, 0x98, 0xfe, + 0x4e, 0x31, 0x24, 0x55, 0x5c, 0x5b, 0x8b, 0x18, 0x52, 0xbf, 0x36, 0xc8, 0xc8, 0xe4, 0x41, 0xb3, + 0xdc, 0xe9, 0x4d, 0x70, 0x8e, 0x3e, 0x7c, 0xa8, 0xc7, 0xab, 0x11, 0x8f, 0xf4, 0x45, 0xe4, 0xbb, + 0x23, 0x4b, 0x6d, 0xa6, 0x4c, 0xbd, 0xdc, 0x03, 0xd9, 0xaa, 0x69, 0x3d, 0x82, 0x58, 0x46, 0xed, + 0xb6, 0x83, 0xdb, 0xd0, 0xc5, 0x27, 0x7a, 0xca, 0xfb, 0xc7, 0x9b, 0x69, 0x05, 0xce, 0xd6, 0xb5, + 0x88, 0x44, 0x78, 0x00, 0xb6, 0x08, 0x97, 0x64, 0x3d, 0x72, 0xd1, 0xa0, 0x05, 0xed, 0x06, 0x5c, + 0x4a, 0xb8, 0x0d, 0x36, 0xcd, 0xb8, 0x2a, 0x65, 0x5d, 0x14, 0x0b, 0x45, 0x90, 0x23, 0xd4, 0x1a, + 0xb4, 0xa0, 0xd3, 0xc1, 0x52, 0xdd, 0xf3, 0xe7, 0xc0, 0x49, 0xcc, 0x42, 0x13, 0x64, 0x55, 0xf8, + 0x04, 0xd7, 0xe8, 0xbc, 0xd0, 0xa0, 0xd5, 0x3f, 0x31, 0x8a, 0xf7, 0xc1, 0x79, 0x17, 0x3e, 0xc1, + 0x86, 0x07, 0x1f, 0x1b, 0x5d, 0x68, 0xf5, 0xc9, 0x3c, 0x89, 0x5e, 0x03, 0x31, 0x58, 0xd0, 0xd2, + 0x2e, 0xa1, 0xf6, 0x59, 0xdf, 0xfa, 0x36, 0x09, 0xd6, 0x66, 0x83, 0x81, 0x7d, 0x0f, 0xbc, 0x56, + 0x96, 0x74, 0xc9, 0xd0, 0x1f, 0x54, 0x15, 0xe3, 0x50, 0xad, 0xa8, 0x15, 0xbd, 0x22, 0xed, 0x55, + 0x1e, 0x2a, 0x65, 0xe3, 0x50, 0xad, 0x55, 0x15, 0xb9, 0x72, 0xa7, 0xa2, 0x94, 0x33, 0x2b, 0xdc, + 0xe6, 0x68, 0xcc, 0xa7, 0x23, 0x22, 0xf6, 0x1a, 0xb8, 0x14, 0x5a, 0xca, 0x7b, 0x15, 0x45, 0xd5, + 0x8d, 0x9a, 0x2e, 0xe9, 0x4a, 0x86, 0xe1, 0xc0, 0x68, 0xcc, 0xaf, 0x12, 0x19, 0xfb, 0x36, 0xd8, + 0x8a, 0xe8, 0x1d, 0xa8, 0x35, 0x45, 0xad, 0x1d, 0xd6, 0xa8, 0x6a, 0x82, 0x3b, 0x3f, 0x1a, 0xf3, + 0xa9, 0xb9, 0x98, 0x2d, 0x02, 0x2e, 0xa6, 0xad, 0x2a, 0xb2, 0x5e, 0x39, 0x50, 0xa9, 0xfa, 0x19, + 0x6e, 0x63, 0x34, 0xe6, 0x41, 0x28, 0x67, 0xb7, 0xc1, 0xe5, 0x88, 0xfe, 0x5d, 0x49, 0x55, 0x95, + 0x3d, 0xaa, 0x9c, 0xe4, 0xd2, 0xa3, 0x31, 0x7f, 0x8e, 0x0a, 0xd9, 0x1b, 0xe0, 0x4a, 0xa8, 0x59, + 0x95, 0xe4, 0xfb, 0x8a, 0x6e, 0xc8, 0x07, 0xfb, 0xfb, 0x15, 0x7d, 0x5f, 0x51, 0xf5, 0xcc, 0x59, + 0x2e, 0x3b, 0x1a, 0xf3, 0x19, 0x02, 0x84, 0x72, 0xf6, 0x43, 0xc0, 0x1f, 0x33, 0x93, 0xe4, 0xfb, + 0xea, 0xc1, 0xa7, 0x7b, 0x4a, 0xf9, 0x23, 0x25, 0xb0, 0x5d, 0xe5, 0xb6, 0x46, 0x63, 0xfe, 0x22, + 0x41, 0x17, 0x40, 0xf6, 0x83, 0x97, 0x10, 0x68, 0x8a, 0xac, 0x54, 0xaa, 0xba, 0x21, 0x95, 0x6a, + 0x8a, 0x2a, 0x2b, 0x99, 0x73, 0x5c, 0x6e, 0x34, 0xe6, 0xb3, 0x04, 0xa5, 0x20, 0xc5, 0xd8, 0x9b, + 0xe0, 0x6a, 0x68, 0xaf, 0x2a, 0x9f, 0xe9, 0x46, 0x4d, 0xf9, 0xf8, 0xd0, 0x87, 0x7c, 0x9a, 0x4f, + 0x32, 0x6b, 0x24, 0x70, 0x1f, 0x99, 0x01, 0xbe, 0x9c, 0xe5, 0x41, 0x26, 0xb4, 0xbb, 0xab, 0x48, + 0x65, 0x45, 0xcb, 0xa4, 0x48, 0x65, 0xc8, 0x8e, 0x4b, 0x3e, 0xfd, 0x31, 0xbf, 0x52, 0x7a, 0xf8, + 0xdb, 0xf3, 0x3c, 0xf3, 0xec, 0x79, 0x9e, 0xf9, 0xf3, 0x79, 0x9e, 0xf9, 0xee, 0x45, 0x7e, 0xe5, + 0xd9, 0x8b, 0xfc, 0xca, 0xef, 0x2f, 0xf2, 0x2b, 0x0f, 0x6f, 0x37, 0x1c, 0xdc, 0xec, 0xd5, 0x8b, + 0x16, 0x6a, 0x8b, 0x16, 0xf2, 0xda, 0xc8, 0x13, 0x9d, 0xba, 0x75, 0xbd, 0x81, 0xc4, 0xfe, 0x0d, + 0xb1, 0x8d, 0xec, 0x5e, 0x0b, 0x7a, 0xe4, 0x97, 0xe6, 0x9d, 0xdd, 0xeb, 0x64, 0x24, 0x8a, 0x6d, + 0xa7, 0xd1, 0x35, 0xfd, 0x99, 0xe0, 0x89, 0xfd, 0x9b, 0xf5, 0xd5, 0x60, 0x92, 0xbd, 0xfb, 0x57, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x9c, 0xae, 0x69, 0xbe, 0x7a, 0x0d, 0x00, 0x00, } func (m *ClientState) Marshal() (dAtA []byte, err error) { diff --git a/modules/core/02-client/proposal_handler_test.go b/modules/core/02-client/proposal_handler_test.go index 7cbe4de91a5..9c13a1c56f6 100644 --- a/modules/core/02-client/proposal_handler_test.go +++ b/modules/core/02-client/proposal_handler_test.go @@ -7,7 +7,7 @@ import ( client "github.com/cosmos/ibc-go/v5/modules/core/02-client" clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) @@ -38,14 +38,14 @@ func (suite *ClientTestSuite) TestNewClientUpdateProposalHandler() { suite.Require().NoError(err) substituteClientState := suite.chainA.GetClientState(substitutePath.EndpointA.ClientID) - tmClientState, ok := subjectClientState.(*ibctmtypes.ClientState) + tmClientState, ok := subjectClientState.(*ibctm.ClientState) suite.Require().True(ok) tmClientState.AllowUpdateAfterMisbehaviour = true tmClientState.FrozenHeight = tmClientState.LatestHeight suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subjectPath.EndpointA.ClientID, tmClientState) // replicate changes to substitute (they must match) - tmClientState, ok = substituteClientState.(*ibctmtypes.ClientState) + tmClientState, ok = substituteClientState.(*ibctm.ClientState) suite.Require().True(ok) tmClientState.AllowUpdateAfterMisbehaviour = true suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), substitutePath.EndpointA.ClientID, tmClientState) diff --git a/modules/core/02-client/simulation/decoder_test.go b/modules/core/02-client/simulation/decoder_test.go index 6cb7f24811b..40a7c8eea5e 100644 --- a/modules/core/02-client/simulation/decoder_test.go +++ b/modules/core/02-client/simulation/decoder_test.go @@ -11,7 +11,7 @@ import ( "github.com/cosmos/ibc-go/v5/modules/core/02-client/simulation" "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" host "github.com/cosmos/ibc-go/v5/modules/core/24-host" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" "github.com/cosmos/ibc-go/v5/testing/simapp" ) @@ -21,11 +21,11 @@ func TestDecodeStore(t *testing.T) { height := types.NewHeight(0, 10) - clientState := &ibctmtypes.ClientState{ + clientState := &ibctm.ClientState{ FrozenHeight: height, } - consState := &ibctmtypes.ConsensusState{ + consState := &ibctm.ConsensusState{ Timestamp: time.Now().UTC(), } diff --git a/modules/core/02-client/types/codec.go b/modules/core/02-client/types/codec.go index 293b466fd10..247507e8c32 100644 --- a/modules/core/02-client/types/codec.go +++ b/modules/core/02-client/types/codec.go @@ -23,7 +23,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { ) registry.RegisterInterface( "ibc.core.client.v1.Header", - (*exported.Header)(nil), + (*exported.ClientMessage)(nil), ) registry.RegisterInterface( "ibc.core.client.v1.Height", @@ -32,7 +32,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { ) registry.RegisterInterface( "ibc.core.client.v1.Misbehaviour", - (*exported.Misbehaviour)(nil), + (*exported.ClientMessage)(nil), ) registry.RegisterImplementations( (*govtypes.Content)(nil), @@ -124,66 +124,34 @@ func UnpackConsensusState(any *codectypes.Any) (exported.ConsensusState, error) return consensusState, nil } -// PackHeader constructs a new Any packed with the given header value. It returns -// an error if the header can't be casted to a protobuf message or if the concrete +// PackClientMessage constructs a new Any packed with the given value. It returns +// an error if the value can't be casted to a protobuf message or if the concrete // implemention is not registered to the protobuf codec. -func PackHeader(header exported.Header) (*codectypes.Any, error) { - msg, ok := header.(proto.Message) +func PackClientMessage(clientMessage exported.ClientMessage) (*codectypes.Any, error) { + msg, ok := clientMessage.(proto.Message) if !ok { - return nil, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", header) + return nil, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", clientMessage) } - anyHeader, err := codectypes.NewAnyWithValue(msg) + any, err := codectypes.NewAnyWithValue(msg) if err != nil { return nil, sdkerrors.Wrap(sdkerrors.ErrPackAny, err.Error()) } - return anyHeader, nil + return any, nil } -// UnpackHeader unpacks an Any into a Header. It returns an error if the -// consensus state can't be unpacked into a Header. -func UnpackHeader(any *codectypes.Any) (exported.Header, error) { +// UnpackClientMessage unpacks an Any into a ClientMessage. It returns an error if the +// consensus state can't be unpacked into a ClientMessage. +func UnpackClientMessage(any *codectypes.Any) (exported.ClientMessage, error) { if any == nil { return nil, sdkerrors.Wrap(sdkerrors.ErrUnpackAny, "protobuf Any message cannot be nil") } - header, ok := any.GetCachedValue().(exported.Header) + clientMessage, ok := any.GetCachedValue().(exported.ClientMessage) if !ok { return nil, sdkerrors.Wrapf(sdkerrors.ErrUnpackAny, "cannot unpack Any into Header %T", any) } - return header, nil -} - -// PackMisbehaviour constructs a new Any packed with the given misbehaviour value. It returns -// an error if the misbehaviour can't be casted to a protobuf message or if the concrete -// implemention is not registered to the protobuf codec. -func PackMisbehaviour(misbehaviour exported.Misbehaviour) (*codectypes.Any, error) { - msg, ok := misbehaviour.(proto.Message) - if !ok { - return nil, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", misbehaviour) - } - - anyMisbhaviour, err := codectypes.NewAnyWithValue(msg) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrPackAny, err.Error()) - } - - return anyMisbhaviour, nil -} - -// UnpackMisbehaviour unpacks an Any into a Misbehaviour. It returns an error if the -// Any can't be unpacked into a Misbehaviour. -func UnpackMisbehaviour(any *codectypes.Any) (exported.Misbehaviour, error) { - if any == nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrUnpackAny, "protobuf Any message cannot be nil") - } - - misbehaviour, ok := any.GetCachedValue().(exported.Misbehaviour) - if !ok { - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnpackAny, "cannot unpack Any into Misbehaviour %T", any) - } - - return misbehaviour, nil + return clientMessage, nil } diff --git a/modules/core/02-client/types/codec_test.go b/modules/core/02-client/types/codec_test.go index e8bfb0b1beb..cfcd395b0c9 100644 --- a/modules/core/02-client/types/codec_test.go +++ b/modules/core/02-client/types/codec_test.go @@ -6,8 +6,7 @@ import ( "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" - localhosttypes "github.com/cosmos/ibc-go/v5/modules/light-clients/09-localhost/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) @@ -30,12 +29,7 @@ func (suite *TypesTestSuite) TestPackClientState() { }, { "tendermint client", - ibctmtypes.NewClientState(chainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), - true, - }, - { - "localhost client", - localhosttypes.NewClientState(chainID, clientHeight), + ibctm.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), true, }, { @@ -115,15 +109,15 @@ func (suite *TypesTestSuite) TestPackConsensusState() { } } -func (suite *TypesTestSuite) TestPackHeader() { +func (suite *TypesTestSuite) TestPackClientMessage() { testCases := []struct { - name string - header exported.Header - expPass bool + name string + clientMessage exported.ClientMessage + expPass bool }{ { "solo machine header", - ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachine", "", 2).CreateHeader(), + ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachine", "", 2).CreateHeader("solomachine"), true, }, { @@ -141,54 +135,7 @@ func (suite *TypesTestSuite) TestPackHeader() { testCasesAny := []caseAny{} for _, tc := range testCases { - clientAny, err := types.PackHeader(tc.header) - if tc.expPass { - suite.Require().NoError(err, tc.name) - } else { - suite.Require().Error(err, tc.name) - } - - testCasesAny = append(testCasesAny, caseAny{tc.name, clientAny, tc.expPass}) - } - - for i, tc := range testCasesAny { - cs, err := types.UnpackHeader(tc.any) - if tc.expPass { - suite.Require().NoError(err, tc.name) - suite.Require().Equal(testCases[i].header, cs, tc.name) - } else { - suite.Require().Error(err, tc.name) - } - } -} - -func (suite *TypesTestSuite) TestPackMisbehaviour() { - testCases := []struct { - name string - misbehaviour exported.Misbehaviour - expPass bool - }{ - { - "solo machine misbehaviour", - ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachine", "", 2).CreateMisbehaviour(), - true, - }, - { - "tendermint misbehaviour", - ibctmtypes.NewMisbehaviour("tendermint", suite.chainA.LastHeader, suite.chainA.LastHeader), - true, - }, - { - "nil", - nil, - false, - }, - } - - testCasesAny := []caseAny{} - - for _, tc := range testCases { - clientAny, err := types.PackMisbehaviour(tc.misbehaviour) + clientAny, err := types.PackClientMessage(tc.clientMessage) if tc.expPass { suite.Require().NoError(err, tc.name) } else { @@ -199,10 +146,10 @@ func (suite *TypesTestSuite) TestPackMisbehaviour() { } for i, tc := range testCasesAny { - cs, err := types.UnpackMisbehaviour(tc.any) + cs, err := types.UnpackClientMessage(tc.any) if tc.expPass { suite.Require().NoError(err, tc.name) - suite.Require().Equal(testCases[i].misbehaviour, cs, tc.name) + suite.Require().Equal(testCases[i].clientMessage, cs, tc.name) } else { suite.Require().Error(err, tc.name) } diff --git a/modules/core/02-client/types/encoding.go b/modules/core/02-client/types/encoding.go index 90bbbd16965..b974eb8b942 100644 --- a/modules/core/02-client/types/encoding.go +++ b/modules/core/02-client/types/encoding.go @@ -86,29 +86,29 @@ func UnmarshalConsensusState(cdc codec.BinaryCodec, bz []byte) (exported.Consens return consensusState, nil } -// MarshalHeader protobuf serializes a Header interface -func MarshalHeader(cdc codec.BinaryCodec, h exported.Header) ([]byte, error) { - return cdc.MarshalInterface(h) +// MarshalClientMessage protobuf serializes a ClientMessage interface +func MarshalClientMessage(cdc codec.BinaryCodec, clientMessage exported.ClientMessage) ([]byte, error) { + return cdc.MarshalInterface(clientMessage) } -// MustMarshalHeader attempts to encode a Header object and returns the +// MustMarshalClientMessage attempts to encode a ClientMessage object and returns the // raw encoded bytes. It panics on error. -func MustMarshalHeader(cdc codec.BinaryCodec, header exported.Header) []byte { - bz, err := MarshalHeader(cdc, header) +func MustMarshalClientMessage(cdc codec.BinaryCodec, clientMessage exported.ClientMessage) []byte { + bz, err := MarshalClientMessage(cdc, clientMessage) if err != nil { - panic(fmt.Errorf("failed to encode header: %w", err)) + panic(fmt.Errorf("failed to encode ClientMessage: %w", err)) } return bz } -// UnmarshalHeader returns a Header interface from raw proto encoded header bytes. +// UnmarshalClientMessage returns a ClientMessage interface from raw proto encoded header bytes. // An error is returned upon decoding failure. -func UnmarshalHeader(cdc codec.BinaryCodec, bz []byte) (exported.Header, error) { - var header exported.Header - if err := cdc.UnmarshalInterface(bz, &header); err != nil { +func UnmarshalClientMessage(cdc codec.BinaryCodec, bz []byte) (exported.ClientMessage, error) { + var clientMessage exported.ClientMessage + if err := cdc.UnmarshalInterface(bz, &clientMessage); err != nil { return nil, err } - return header, nil + return clientMessage, nil } diff --git a/modules/core/02-client/types/encoding_test.go b/modules/core/02-client/types/encoding_test.go index 3aa01c09708..7142153ff7e 100644 --- a/modules/core/02-client/types/encoding_test.go +++ b/modules/core/02-client/types/encoding_test.go @@ -2,27 +2,27 @@ package types_test import ( "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ) func (suite *TypesTestSuite) TestMarshalHeader() { cdc := suite.chainA.App.AppCodec() - h := &ibctmtypes.Header{ + h := &ibctm.Header{ TrustedHeight: types.NewHeight(4, 100), } // marshal header - bz, err := types.MarshalHeader(cdc, h) + bz, err := types.MarshalClientMessage(cdc, h) suite.Require().NoError(err) // unmarshal header - newHeader, err := types.UnmarshalHeader(cdc, bz) + newHeader, err := types.UnmarshalClientMessage(cdc, bz) suite.Require().NoError(err) suite.Require().Equal(h, newHeader) // use invalid bytes - invalidHeader, err := types.UnmarshalHeader(cdc, []byte("invalid bytes")) + invalidHeader, err := types.UnmarshalClientMessage(cdc, []byte("invalid bytes")) suite.Require().Error(err) suite.Require().Nil(invalidHeader) } diff --git a/modules/core/02-client/types/errors.go b/modules/core/02-client/types/errors.go index c40bae878cc..0c2bd65f339 100644 --- a/modules/core/02-client/types/errors.go +++ b/modules/core/02-client/types/errors.go @@ -33,5 +33,5 @@ var ( ErrInvalidHeight = sdkerrors.Register(SubModuleName, 26, "invalid height") ErrInvalidSubstitute = sdkerrors.Register(SubModuleName, 27, "invalid client state substitute") ErrInvalidUpgradeProposal = sdkerrors.Register(SubModuleName, 28, "invalid upgrade proposal") - ErrClientNotActive = sdkerrors.Register(SubModuleName, 29, "client is not active") + ErrClientNotActive = sdkerrors.Register(SubModuleName, 29, "client state is not active") ) diff --git a/modules/core/02-client/types/events.go b/modules/core/02-client/types/events.go index 78ed0028e65..4e0bd1ba96f 100644 --- a/modules/core/02-client/types/events.go +++ b/modules/core/02-client/types/events.go @@ -12,9 +12,11 @@ const ( AttributeKeySubjectClientID = "subject_client_id" AttributeKeyClientType = "client_type" AttributeKeyConsensusHeight = "consensus_height" + AttributeKeyConsensusHeights = "consensus_heights" AttributeKeyHeader = "header" + AttributeKeyUpgradeStore = "upgrade_store" + AttributeKeyUpgradePlanHeight = "upgrade_plan_height" AttributeKeyUpgradePlanTitle = "title" - AttributeKeyUpgradePlanHeight = "height" ) // IBC client events vars @@ -24,6 +26,7 @@ var ( EventTypeUpgradeClient = "upgrade_client" EventTypeSubmitMisbehaviour = "client_misbehaviour" EventTypeUpdateClientProposal = "update_client_proposal" + EventTypeUpgradeChain = "upgrade_chain" EventTypeUpgradeClientProposal = "upgrade_client_proposal" AttributeValueCategory = fmt.Sprintf("%s_%s", host.ModuleName, SubModuleName) diff --git a/modules/core/02-client/types/genesis.go b/modules/core/02-client/types/genesis.go index 9d12b224765..784bae42f79 100644 --- a/modules/core/02-client/types/genesis.go +++ b/modules/core/02-client/types/genesis.go @@ -200,10 +200,6 @@ func (gs GenesisState) Validate() error { } - if gs.CreateLocalhost && !gs.Params.IsAllowedClient(exported.Localhost) { - return fmt.Errorf("localhost client is not registered on the allowlist") - } - if maxSequence != 0 && maxSequence >= gs.NextClientSequence { return fmt.Errorf("next client identifier sequence %d must be greater than the maximum sequence used in the provided client identifiers %d", gs.NextClientSequence, maxSequence) } diff --git a/modules/core/02-client/types/genesis_test.go b/modules/core/02-client/types/genesis_test.go index 2fba3a19647..08d55606c61 100644 --- a/modules/core/02-client/types/genesis_test.go +++ b/modules/core/02-client/types/genesis_test.go @@ -9,23 +9,23 @@ import ( "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" - localhosttypes "github.com/cosmos/ibc-go/v5/modules/light-clients/09-localhost/types" + solomachinetypes "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ibctestingmock "github.com/cosmos/ibc-go/v5/testing/mock" ) const ( - chainID = "chainID" - tmClientID0 = "07-tendermint-0" - tmClientID1 = "07-tendermint-1" - invalidClientID = "myclient-0" - clientID = tmClientID0 + tmClientID0 = "07-tendermint-0" + tmClientID1 = "07-tendermint-1" + invalidClientID = "myclient-0" + soloMachineClientID = "06-solomachine-0" + clientID = tmClientID0 height = 10 ) -var clientHeight = types.NewHeight(0, 10) +var clientHeight = types.NewHeight(1, 10) func (suite *TypesTestSuite) TestMarshalGenesisState() { cdc := suite.chainA.App.AppCodec() @@ -58,8 +58,8 @@ func (suite *TypesTestSuite) TestValidateGenesis() { signers := make(map[string]tmtypes.PrivValidator) signers[val.Address.String()] = privVal - heightMinus1 := types.NewHeight(0, height-1) - header := suite.chainA.CreateTMClientHeader(chainID, int64(clientHeight.RevisionHeight), heightMinus1, now, valSet, valSet, valSet, signers) + heightMinus1 := types.NewHeight(1, height-1) + header := suite.chainA.CreateTMClientHeader(suite.chainA.ChainID, int64(clientHeight.RevisionHeight), heightMinus1, now, valSet, valSet, valSet, signers) testCases := []struct { name string @@ -76,10 +76,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { genState: types.NewGenesisState( []types.IdentifiedClientState{ types.NewIdentifiedClientState( - tmClientID0, ibctmtypes.NewClientState(chainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), - ), - types.NewIdentifiedClientState( - exported.Localhost+"-1", localhosttypes.NewClientState("chainID", clientHeight), + tmClientID0, ibctm.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), ), }, []types.ClientConsensusStates{ @@ -88,7 +85,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { []types.ConsensusStateWithHeight{ types.NewConsensusStateWithHeight( header.GetHeight().(types.Height), - ibctmtypes.NewConsensusState( + ibctm.NewConsensusState( header.GetTime(), commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), header.Header.NextValidatorsHash, ), ), @@ -104,21 +101,35 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, ), }, - types.NewParams(exported.Tendermint, exported.Localhost), + types.NewParams(exported.Tendermint), false, 2, ), expPass: true, }, { - name: "invalid clientid", + name: "invalid client type", genState: types.NewGenesisState( []types.IdentifiedClientState{ types.NewIdentifiedClientState( - invalidClientID, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), + soloMachineClientID, ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), ), + types.NewIdentifiedClientState(tmClientID0, solomachinetypes.NewClientState(0, &solomachinetypes.ConsensusState{suite.solomachine.ConsensusState().PublicKey, suite.solomachine.Diversifier, suite.solomachine.Time}, false)), + }, + nil, + nil, + types.NewParams(exported.Tendermint), + false, + 0, + ), + expPass: false, + }, + { + name: "invalid clientid", + genState: types.NewGenesisState( + []types.IdentifiedClientState{ types.NewIdentifiedClientState( - exported.Localhost, localhosttypes.NewClientState("chainID", clientHeight), + invalidClientID, ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), ), }, []types.ClientConsensusStates{ @@ -127,7 +138,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { []types.ConsensusStateWithHeight{ types.NewConsensusStateWithHeight( header.GetHeight().(types.Height), - ibctmtypes.NewConsensusState( + ibctm.NewConsensusState( header.GetTime(), commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), header.Header.NextValidatorsHash, ), ), @@ -141,32 +152,12 @@ func (suite *TypesTestSuite) TestValidateGenesis() { ), expPass: false, }, - { - name: "invalid client", - genState: types.NewGenesisState( - []types.IdentifiedClientState{ - types.NewIdentifiedClientState( - tmClientID0, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), - ), - types.NewIdentifiedClientState(exported.Localhost, localhosttypes.NewClientState("chaindID", types.ZeroHeight())), - }, - nil, - nil, - types.NewParams(exported.Tendermint), - false, - 0, - ), - expPass: false, - }, { name: "consensus state client id does not match client id in genesis clients", genState: types.NewGenesisState( []types.IdentifiedClientState{ types.NewIdentifiedClientState( - tmClientID0, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), - ), - types.NewIdentifiedClientState( - exported.Localhost, localhosttypes.NewClientState("chaindID", clientHeight), + tmClientID0, ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), ), }, []types.ClientConsensusStates{ @@ -174,8 +165,8 @@ func (suite *TypesTestSuite) TestValidateGenesis() { tmClientID1, []types.ConsensusStateWithHeight{ types.NewConsensusStateWithHeight( - types.NewHeight(0, 1), - ibctmtypes.NewConsensusState( + types.NewHeight(1, 1), + ibctm.NewConsensusState( header.GetTime(), commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), header.Header.NextValidatorsHash, ), ), @@ -194,10 +185,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { genState: types.NewGenesisState( []types.IdentifiedClientState{ types.NewIdentifiedClientState( - tmClientID0, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), - ), - types.NewIdentifiedClientState( - exported.Localhost, localhosttypes.NewClientState("chaindID", clientHeight), + tmClientID0, ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), ), }, []types.ClientConsensusStates{ @@ -206,7 +194,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { []types.ConsensusStateWithHeight{ types.NewConsensusStateWithHeight( types.ZeroHeight(), - ibctmtypes.NewConsensusState( + ibctm.NewConsensusState( header.GetTime(), commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), header.Header.NextValidatorsHash, ), ), @@ -225,10 +213,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { genState: types.NewGenesisState( []types.IdentifiedClientState{ types.NewIdentifiedClientState( - tmClientID0, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), - ), - types.NewIdentifiedClientState( - exported.Localhost, localhosttypes.NewClientState("chaindID", clientHeight), + tmClientID0, ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), ), }, []types.ClientConsensusStates{ @@ -236,8 +221,8 @@ func (suite *TypesTestSuite) TestValidateGenesis() { tmClientID0, []types.ConsensusStateWithHeight{ types.NewConsensusStateWithHeight( - types.NewHeight(0, 1), - ibctmtypes.NewConsensusState( + types.NewHeight(1, 1), + ibctm.NewConsensusState( time.Time{}, commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), header.Header.NextValidatorsHash, ), ), @@ -256,10 +241,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { genState: types.NewGenesisState( []types.IdentifiedClientState{ types.NewIdentifiedClientState( - tmClientID0, ibctmtypes.NewClientState(chainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), - ), - types.NewIdentifiedClientState( - exported.Localhost, localhosttypes.NewClientState("chainID", clientHeight), + tmClientID0, ibctm.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), ), }, []types.ClientConsensusStates{ @@ -268,7 +250,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { []types.ConsensusStateWithHeight{ types.NewConsensusStateWithHeight( header.GetHeight().(types.Height), - ibctmtypes.NewConsensusState( + ibctm.NewConsensusState( header.GetTime(), commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), header.Header.NextValidatorsHash, ), ), @@ -287,10 +269,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { genState: types.NewGenesisState( []types.IdentifiedClientState{ types.NewIdentifiedClientState( - clientID, ibctmtypes.NewClientState(chainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), - ), - types.NewIdentifiedClientState( - exported.Localhost, localhosttypes.NewClientState("chainID", clientHeight), + clientID, ibctm.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), ), }, []types.ClientConsensusStates{ @@ -299,7 +278,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { []types.ConsensusStateWithHeight{ types.NewConsensusStateWithHeight( header.GetHeight().(types.Height), - ibctmtypes.NewConsensusState( + ibctm.NewConsensusState( header.GetTime(), commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), header.Header.NextValidatorsHash, ), ), @@ -315,7 +294,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, ), }, - types.NewParams(exported.Tendermint, exported.Localhost), + types.NewParams(exported.Tendermint), false, 0, ), @@ -326,7 +305,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { genState: types.NewGenesisState( []types.IdentifiedClientState{ types.NewIdentifiedClientState( - clientID, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), + clientID, ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), ), }, []types.ClientConsensusStates{ @@ -335,7 +314,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { []types.ConsensusStateWithHeight{ types.NewConsensusStateWithHeight( header.GetHeight().(types.Height), - ibctmtypes.NewConsensusState( + ibctm.NewConsensusState( header.GetTime(), commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), header.Header.NextValidatorsHash, ), ), @@ -361,10 +340,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { genState: types.NewGenesisState( []types.IdentifiedClientState{ types.NewIdentifiedClientState( - tmClientID0, ibctmtypes.NewClientState(chainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), - ), - types.NewIdentifiedClientState( - exported.Localhost, localhosttypes.NewClientState("chainID", clientHeight), + tmClientID0, ibctm.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), ), }, []types.ClientConsensusStates{ @@ -373,7 +349,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { []types.ConsensusStateWithHeight{ types.NewConsensusStateWithHeight( header.GetHeight().(types.Height), - ibctmtypes.NewConsensusState( + ibctm.NewConsensusState( header.GetTime(), commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), header.Header.NextValidatorsHash, ), ), @@ -392,10 +368,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { genState: types.NewGenesisState( []types.IdentifiedClientState{ types.NewIdentifiedClientState( - tmClientID0, ibctmtypes.NewClientState(chainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), - ), - types.NewIdentifiedClientState( - exported.Localhost, localhosttypes.NewClientState("chainID", clientHeight), + tmClientID0, ibctm.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), ), }, []types.ClientConsensusStates{ @@ -404,7 +377,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { []types.ConsensusStateWithHeight{ types.NewConsensusStateWithHeight( header.GetHeight().(types.Height), - ibctmtypes.NewConsensusState( + ibctm.NewConsensusState( header.GetTime(), commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), header.Header.NextValidatorsHash, ), ), @@ -413,51 +386,20 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, nil, types.NewParams(" "), - true, + false, 0, ), expPass: false, }, - { - name: "localhost client not registered on allowlist", - genState: types.NewGenesisState( - []types.IdentifiedClientState{ - types.NewIdentifiedClientState( - tmClientID1, ibctmtypes.NewClientState(chainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), - ), - types.NewIdentifiedClientState( - exported.Localhost+"-0", localhosttypes.NewClientState("chainID", clientHeight), - ), - }, - []types.ClientConsensusStates{ - types.NewClientConsensusStates( - tmClientID1, - []types.ConsensusStateWithHeight{ - types.NewConsensusStateWithHeight( - header.GetHeight().(types.Height), - ibctmtypes.NewConsensusState( - header.GetTime(), commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), header.Header.NextValidatorsHash, - ), - ), - }, - ), - }, - nil, - types.NewParams(exported.Tendermint), - true, - 2, - ), - expPass: false, - }, { name: "next sequence too small", genState: types.NewGenesisState( []types.IdentifiedClientState{ types.NewIdentifiedClientState( - tmClientID0, ibctmtypes.NewClientState(chainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), + tmClientID0, ibctm.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), ), types.NewIdentifiedClientState( - exported.Localhost+"-1", localhosttypes.NewClientState("chainID", clientHeight), + tmClientID1, ibctm.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), ), }, []types.ClientConsensusStates{ @@ -466,7 +408,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { []types.ConsensusStateWithHeight{ types.NewConsensusStateWithHeight( header.GetHeight().(types.Height), - ibctmtypes.NewConsensusState( + ibctm.NewConsensusState( header.GetTime(), commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), header.Header.NextValidatorsHash, ), ), @@ -474,7 +416,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { ), }, nil, - types.NewParams(exported.Tendermint, exported.Localhost), + types.NewParams(exported.Tendermint), false, 0, ), @@ -485,10 +427,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { genState: types.NewGenesisState( []types.IdentifiedClientState{ types.NewIdentifiedClientState( - "my-client", ibctmtypes.NewClientState(chainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), - ), - types.NewIdentifiedClientState( - exported.Localhost+"-1", localhosttypes.NewClientState("chainID", clientHeight), + "my-client", ibctm.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), ), }, []types.ClientConsensusStates{ @@ -497,7 +436,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { []types.ConsensusStateWithHeight{ types.NewConsensusStateWithHeight( header.GetHeight().(types.Height), - ibctmtypes.NewConsensusState( + ibctm.NewConsensusState( header.GetTime(), commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), header.Header.NextValidatorsHash, ), ), @@ -505,7 +444,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { ), }, nil, - types.NewParams(exported.Tendermint, exported.Localhost), + types.NewParams(exported.Tendermint), false, 5, ), @@ -514,18 +453,14 @@ func (suite *TypesTestSuite) TestValidateGenesis() { { name: "consensus state different than client state type", genState: types.NewGenesisState( - []types.IdentifiedClientState{ - types.NewIdentifiedClientState( - exported.Localhost+"-1", localhosttypes.NewClientState("chainID", clientHeight), - ), - }, + []types.IdentifiedClientState{}, []types.ClientConsensusStates{ types.NewClientConsensusStates( - exported.Localhost+"-1", + tmClientID0, []types.ConsensusStateWithHeight{ types.NewConsensusStateWithHeight( header.GetHeight().(types.Height), - ibctmtypes.NewConsensusState( + ibctm.NewConsensusState( header.GetTime(), commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), header.Header.NextValidatorsHash, ), ), @@ -533,7 +468,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { ), }, nil, - types.NewParams(exported.Tendermint, exported.Localhost), + types.NewParams(exported.Tendermint), false, 5, ), diff --git a/modules/core/02-client/types/msgs.go b/modules/core/02-client/types/msgs.go index da1ef19275c..8e339199923 100644 --- a/modules/core/02-client/types/msgs.go +++ b/modules/core/02-client/types/msgs.go @@ -65,9 +65,6 @@ func (msg MsgCreateClient) ValidateBasic() error { if err := clientState.Validate(); err != nil { return err } - if clientState.ClientType() == exported.Localhost { - return sdkerrors.Wrap(ErrInvalidClient, "localhost client can only be created on chain initialization") - } consensusState, err := UnpackConsensusState(msg.ConsensusState) if err != nil { return err @@ -105,16 +102,16 @@ func (msg MsgCreateClient) UnpackInterfaces(unpacker codectypes.AnyUnpacker) err // NewMsgUpdateClient creates a new MsgUpdateClient instance // //nolint:interfacer -func NewMsgUpdateClient(id string, header exported.Header, signer string) (*MsgUpdateClient, error) { - anyHeader, err := PackHeader(header) +func NewMsgUpdateClient(id string, clientMsg exported.ClientMessage, signer string) (*MsgUpdateClient, error) { + anyClientMsg, err := PackClientMessage(clientMsg) if err != nil { return nil, err } return &MsgUpdateClient{ - ClientId: id, - Header: anyHeader, - Signer: signer, + ClientId: id, + ClientMessage: anyClientMsg, + Signer: signer, }, nil } @@ -124,16 +121,13 @@ func (msg MsgUpdateClient) ValidateBasic() error { if err != nil { return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err) } - header, err := UnpackHeader(msg.Header) + clientMsg, err := UnpackClientMessage(msg.ClientMessage) if err != nil { return err } - if err := header.ValidateBasic(); err != nil { + if err := clientMsg.ValidateBasic(); err != nil { return err } - if msg.ClientId == exported.Localhost { - return sdkerrors.Wrap(ErrInvalidClient, "localhost client is only updated on ABCI BeginBlock") - } return host.ClientIdentifierValidator(msg.ClientId) } @@ -148,8 +142,8 @@ func (msg MsgUpdateClient) GetSigners() []sdk.AccAddress { // UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces func (msg MsgUpdateClient) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { - var header exported.Header - return unpacker.UnpackAny(msg.Header, &header) + var clientMsg exported.ClientMessage + return unpacker.UnpackAny(msg.ClientMessage, &clientMsg) } // NewMsgUpgradeClient creates a new MsgUpgradeClient instance @@ -233,8 +227,8 @@ func (msg MsgUpgradeClient) UnpackInterfaces(unpacker codectypes.AnyUnpacker) er // NewMsgSubmitMisbehaviour creates a new MsgSubmitMisbehaviour instance. // //nolint:interfacer -func NewMsgSubmitMisbehaviour(clientID string, misbehaviour exported.Misbehaviour, signer string) (*MsgSubmitMisbehaviour, error) { - anyMisbehaviour, err := PackMisbehaviour(misbehaviour) +func NewMsgSubmitMisbehaviour(clientID string, misbehaviour exported.ClientMessage, signer string) (*MsgSubmitMisbehaviour, error) { + anyMisbehaviour, err := PackClientMessage(misbehaviour) if err != nil { return nil, err } @@ -252,20 +246,13 @@ func (msg MsgSubmitMisbehaviour) ValidateBasic() error { if err != nil { return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err) } - misbehaviour, err := UnpackMisbehaviour(msg.Misbehaviour) + misbehaviour, err := UnpackClientMessage(msg.Misbehaviour) if err != nil { return err } if err := misbehaviour.ValidateBasic(); err != nil { return err } - if misbehaviour.GetClientID() != msg.ClientId { - return sdkerrors.Wrapf( - ErrInvalidMisbehaviour, - "misbehaviour client-id doesn't match client-id from message (%s ≠ %s)", - misbehaviour.GetClientID(), msg.ClientId, - ) - } return host.ClientIdentifierValidator(msg.ClientId) } @@ -281,6 +268,6 @@ func (msg MsgSubmitMisbehaviour) GetSigners() []sdk.AccAddress { // UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces func (msg MsgSubmitMisbehaviour) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { - var misbehaviour exported.Misbehaviour + var misbehaviour exported.ClientMessage return unpacker.UnpackAny(msg.Misbehaviour, &misbehaviour) } diff --git a/modules/core/02-client/types/msgs_test.go b/modules/core/02-client/types/msgs_test.go index 3ea81a9d0a7..b42445c030c 100644 --- a/modules/core/02-client/types/msgs_test.go +++ b/modules/core/02-client/types/msgs_test.go @@ -9,9 +9,8 @@ import ( "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v5/modules/core/exported" - solomachinetypes "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine/types" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + solomachinetypes "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) @@ -20,14 +19,16 @@ type TypesTestSuite struct { coordinator *ibctesting.Coordinator - chainA *ibctesting.TestChain - chainB *ibctesting.TestChain + chainA *ibctesting.TestChain + chainB *ibctesting.TestChain + solomachine *ibctesting.Solomachine } func (suite *TypesTestSuite) SetupTest() { suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) + suite.solomachine = ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachinesingle", "testing", 1) } func TestTypesTestSuite(t *testing.T) { @@ -55,7 +56,7 @@ func (suite *TypesTestSuite) TestMarshalMsgCreateClient() { }, { "tendermint client", func() { - tendermintClient := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) + tendermintClient := ibctm.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) msg, err = types.NewMsgCreateClient(tendermintClient, suite.chainA.CurrentTMClientHeader().ConsensusState(), suite.chainA.SenderAccount.GetAddress().String()) suite.Require().NoError(err) }, @@ -100,7 +101,7 @@ func (suite *TypesTestSuite) TestMsgCreateClient_ValidateBasic() { { "valid - tendermint client", func() { - tendermintClient := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) + tendermintClient := ibctm.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) msg, err = types.NewMsgCreateClient(tendermintClient, suite.chainA.CurrentTMClientHeader().ConsensusState(), suite.chainA.SenderAccount.GetAddress().String()) suite.Require().NoError(err) }, @@ -109,7 +110,7 @@ func (suite *TypesTestSuite) TestMsgCreateClient_ValidateBasic() { { "invalid tendermint client", func() { - msg, err = types.NewMsgCreateClient(&ibctmtypes.ClientState{}, suite.chainA.CurrentTMClientHeader().ConsensusState(), suite.chainA.SenderAccount.GetAddress().String()) + msg, err = types.NewMsgCreateClient(&ibctm.ClientState{}, suite.chainA.CurrentTMClientHeader().ConsensusState(), suite.chainA.SenderAccount.GetAddress().String()) suite.Require().NoError(err) }, false, @@ -124,7 +125,7 @@ func (suite *TypesTestSuite) TestMsgCreateClient_ValidateBasic() { { "failed to unpack consensus state", func() { - tendermintClient := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) + tendermintClient := ibctm.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) msg, err = types.NewMsgCreateClient(tendermintClient, suite.chainA.CurrentTMClientHeader().ConsensusState(), suite.chainA.SenderAccount.GetAddress().String()) suite.Require().NoError(err) msg.ConsensusState = nil @@ -168,7 +169,7 @@ func (suite *TypesTestSuite) TestMsgCreateClient_ValidateBasic() { { "invalid - client state and consensus state client types do not match", func() { - tendermintClient := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) + tendermintClient := ibctm.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) soloMachine := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachine", "", 2) msg, err = types.NewMsgCreateClient(tendermintClient, soloMachine.ConsensusState(), suite.chainA.SenderAccount.GetAddress().String()) suite.Require().NoError(err) @@ -203,7 +204,7 @@ func (suite *TypesTestSuite) TestMarshalMsgUpdateClient() { { "solo machine client", func() { soloMachine := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachine", "", 2) - msg, err = types.NewMsgUpdateClient(soloMachine.ClientID, soloMachine.CreateHeader(), suite.chainA.SenderAccount.GetAddress().String()) + msg, err = types.NewMsgUpdateClient(soloMachine.ClientID, soloMachine.CreateHeader(soloMachine.Diversifier), suite.chainA.SenderAccount.GetAddress().String()) suite.Require().NoError(err) }, }, @@ -268,7 +269,7 @@ func (suite *TypesTestSuite) TestMsgUpdateClient_ValidateBasic() { { "invalid tendermint header", func() { - msg, err = types.NewMsgUpdateClient("tendermint", &ibctmtypes.Header{}, suite.chainA.SenderAccount.GetAddress().String()) + msg, err = types.NewMsgUpdateClient("tendermint", &ibctm.Header{}, suite.chainA.SenderAccount.GetAddress().String()) suite.Require().NoError(err) }, false, @@ -276,7 +277,7 @@ func (suite *TypesTestSuite) TestMsgUpdateClient_ValidateBasic() { { "failed to unpack header", func() { - msg.Header = nil + msg.ClientMessage = nil }, false, }, @@ -291,7 +292,8 @@ func (suite *TypesTestSuite) TestMsgUpdateClient_ValidateBasic() { "valid - solomachine header", func() { soloMachine := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachine", "", 2) - msg, err = types.NewMsgUpdateClient(soloMachine.ClientID, soloMachine.CreateHeader(), suite.chainA.SenderAccount.GetAddress().String()) + msg, err = types.NewMsgUpdateClient(soloMachine.ClientID, soloMachine.CreateHeader(soloMachine.Diversifier), suite.chainA.SenderAccount.GetAddress().String()) + suite.Require().NoError(err) }, true, @@ -304,14 +306,6 @@ func (suite *TypesTestSuite) TestMsgUpdateClient_ValidateBasic() { }, false, }, - { - "unsupported - localhost", - func() { - msg, err = types.NewMsgUpdateClient(exported.Localhost, suite.chainA.CurrentTMClientHeader(), suite.chainA.SenderAccount.GetAddress().String()) - suite.Require().NoError(err) - }, - false, - }, } for _, tc := range cases { @@ -338,8 +332,8 @@ func (suite *TypesTestSuite) TestMarshalMsgUpgradeClient() { { "client upgrades to new tendermint client", func() { - tendermintClient := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - tendermintConsState := &ibctmtypes.ConsensusState{NextValidatorsHash: []byte("nextValsHash")} + tendermintClient := ibctm.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) + tendermintConsState := &ibctm.ConsensusState{NextValidatorsHash: []byte("nextValsHash")} msg, err = types.NewMsgUpgradeClient("clientid", tendermintClient, tendermintConsState, []byte("proofUpgradeClient"), []byte("proofUpgradeConsState"), suite.chainA.SenderAccount.GetAddress().String()) suite.Require().NoError(err) }, @@ -451,8 +445,8 @@ func (suite *TypesTestSuite) TestMsgUpgradeClient_ValidateBasic() { for _, tc := range cases { tc := tc - clientState := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - consState := &ibctmtypes.ConsensusState{NextValidatorsHash: []byte("nextValsHash")} + clientState := ibctm.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) + consState := &ibctm.ConsensusState{NextValidatorsHash: []byte("nextValsHash")} msg, err := types.NewMsgUpgradeClient("testclientid", clientState, consState, []byte("proofUpgradeClient"), []byte("proofUpgradeConsState"), suite.chainA.SenderAccount.GetAddress().String()) suite.Require().NoError(err) @@ -492,7 +486,7 @@ func (suite *TypesTestSuite) TestMarshalMsgSubmitMisbehaviour() { header1 := suite.chainA.CreateTMClientHeader(suite.chainA.ChainID, int64(height.RevisionHeight), heightMinus1, suite.chainA.CurrentHeader.Time, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers) header2 := suite.chainA.CreateTMClientHeader(suite.chainA.ChainID, int64(height.RevisionHeight), heightMinus1, suite.chainA.CurrentHeader.Time.Add(time.Minute), suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers) - misbehaviour := ibctmtypes.NewMisbehaviour("tendermint", header1, header2) + misbehaviour := ibctm.NewMisbehaviour("tendermint", header1, header2) msg, err = types.NewMsgSubmitMisbehaviour("tendermint", misbehaviour, suite.chainA.SenderAccount.GetAddress().String()) suite.Require().NoError(err) }, @@ -549,7 +543,7 @@ func (suite *TypesTestSuite) TestMsgSubmitMisbehaviour_ValidateBasic() { header1 := suite.chainA.CreateTMClientHeader(suite.chainA.ChainID, int64(height.RevisionHeight), heightMinus1, suite.chainA.CurrentHeader.Time, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers) header2 := suite.chainA.CreateTMClientHeader(suite.chainA.ChainID, int64(height.RevisionHeight), heightMinus1, suite.chainA.CurrentHeader.Time.Add(time.Minute), suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers) - misbehaviour := ibctmtypes.NewMisbehaviour("tendermint", header1, header2) + misbehaviour := ibctm.NewMisbehaviour("tendermint", header1, header2) msg, err = types.NewMsgSubmitMisbehaviour("tendermint", misbehaviour, suite.chainA.SenderAccount.GetAddress().String()) suite.Require().NoError(err) }, @@ -558,7 +552,7 @@ func (suite *TypesTestSuite) TestMsgSubmitMisbehaviour_ValidateBasic() { { "invalid tendermint misbehaviour", func() { - msg, err = types.NewMsgSubmitMisbehaviour("tendermint", &ibctmtypes.Misbehaviour{}, suite.chainA.SenderAccount.GetAddress().String()) + msg, err = types.NewMsgSubmitMisbehaviour("tendermint", &ibctm.Misbehaviour{}, suite.chainA.SenderAccount.GetAddress().String()) suite.Require().NoError(err) }, false, diff --git a/modules/core/02-client/types/proposal.go b/modules/core/02-client/types/proposal.go index 37b4cee74e2..4bc7a84a810 100644 --- a/modules/core/02-client/types/proposal.go +++ b/modules/core/02-client/types/proposal.go @@ -2,6 +2,7 @@ package types import ( "fmt" + "reflect" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -111,11 +112,15 @@ func (up *UpgradeProposal) ValidateBasic() error { return sdkerrors.Wrap(ErrInvalidUpgradeProposal, "upgraded client state cannot be nil") } - _, err := UnpackClientState(up.UpgradedClientState) + clientState, err := UnpackClientState(up.UpgradedClientState) if err != nil { return sdkerrors.Wrap(err, "failed to unpack upgraded client state") } + if !reflect.DeepEqual(clientState, clientState.ZeroCustomFields()) { + return sdkerrors.Wrap(ErrInvalidUpgradeProposal, "upgraded client state is not zeroed out") + } + return nil } diff --git a/modules/core/02-client/types/proposal_test.go b/modules/core/02-client/types/proposal_test.go index 6b856211901..2b1725248e0 100644 --- a/modules/core/02-client/types/proposal_test.go +++ b/modules/core/02-client/types/proposal_test.go @@ -9,7 +9,7 @@ import ( upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) @@ -109,20 +109,31 @@ func (suite *TypesTestSuite) TestUpgradeProposalValidateBasic() { }{ { "success", func() { - proposal, err = types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, plan, cs) + proposal, err = types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, plan, cs.ZeroCustomFields()) suite.Require().NoError(err) }, true, }, { "fails validate abstract - empty title", func() { - proposal, err = types.NewUpgradeProposal("", ibctesting.Description, plan, cs) + proposal, err = types.NewUpgradeProposal("", ibctesting.Description, plan, cs.ZeroCustomFields()) + suite.Require().NoError(err) + + }, false, + }, + { + "non zeroed fields", func() { + proposal, err = types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, plan, &ibctm.ClientState{ + FrozenHeight: types.Height{ + RevisionHeight: 10, + }, + }) suite.Require().NoError(err) }, false, }, { "plan height is zero", func() { invalidPlan := upgradetypes.Plan{Name: "ibc upgrade", Height: 0} - proposal, err = types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, invalidPlan, cs) + proposal, err = types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, invalidPlan, cs.ZeroCustomFields()) suite.Require().NoError(err) }, false, }, @@ -138,7 +149,7 @@ func (suite *TypesTestSuite) TestUpgradeProposalValidateBasic() { }, { "failed to unpack client state", func() { - any, err := types.PackConsensusState(&ibctmtypes.ConsensusState{}) + any, err := types.PackConsensusState(&ibctm.ConsensusState{}) suite.Require().NoError(err) proposal = &types.UpgradeProposal{ @@ -173,7 +184,7 @@ func (suite *TypesTestSuite) TestMarshalUpgradeProposal() { Name: "upgrade ibc", Height: 1000, } - content, err := types.NewUpgradeProposal("title", "description", plan, &ibctmtypes.ClientState{}) + content, err := types.NewUpgradeProposal("title", "description", plan, &ibctm.ClientState{}) suite.Require().NoError(err) up, ok := content.(*types.UpgradeProposal) @@ -183,7 +194,7 @@ func (suite *TypesTestSuite) TestMarshalUpgradeProposal() { ir := codectypes.NewInterfaceRegistry() types.RegisterInterfaces(ir) govtypes.RegisterInterfaces(ir) - ibctmtypes.RegisterInterfaces(ir) + ibctm.RegisterInterfaces(ir) cdc := codec.NewProtoCodec(ir) // marshal message @@ -207,10 +218,10 @@ func (suite *TypesTestSuite) TestUpgradeString() { Height: 1000, } - proposal, err := types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, plan, &ibctmtypes.ClientState{}) + proposal, err := types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, plan, &ibctm.ClientState{}) suite.Require().NoError(err) - expect := fmt.Sprintf("IBC Upgrade Proposal\n Title: title\n Description: description\n Upgrade Plan\n Name: ibc upgrade\n height: 1000\n Info: https://foo.bar/baz.\n Upgraded IBC Client: %s", &ibctmtypes.ClientState{}) + expect := fmt.Sprintf("IBC Upgrade Proposal\n Title: title\n Description: description\n Upgrade Plan\n Name: ibc upgrade\n height: 1000\n Info: https://foo.bar/baz.\n Upgraded IBC Client: %s", &ibctm.ClientState{}) suite.Require().Equal(expect, proposal.String()) } diff --git a/modules/core/02-client/types/tx.pb.go b/modules/core/02-client/types/tx.pb.go index b2d823567cb..a9cf9917069 100644 --- a/modules/core/02-client/types/tx.pb.go +++ b/modules/core/02-client/types/tx.pb.go @@ -111,12 +111,12 @@ func (m *MsgCreateClientResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgCreateClientResponse proto.InternalMessageInfo // MsgUpdateClient defines an sdk.Msg to update a IBC client state using -// the given header. +// the given client message. type MsgUpdateClient struct { // client unique identifier ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` - // header to update the light client - Header *types.Any `protobuf:"bytes,2,opt,name=header,proto3" json:"header,omitempty"` + // client message to update the light client + ClientMessage *types.Any `protobuf:"bytes,2,opt,name=client_message,json=clientMessage,proto3" json:"client_message,omitempty"` // signer address Signer string `protobuf:"bytes,3,opt,name=signer,proto3" json:"signer,omitempty"` } @@ -281,13 +281,14 @@ var xxx_messageInfo_MsgUpgradeClientResponse proto.InternalMessageInfo // MsgSubmitMisbehaviour defines an sdk.Msg type that submits Evidence for // light client misbehaviour. +// Warning: DEPRECATED type MsgSubmitMisbehaviour struct { // client unique identifier - ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` // Deprecated: Do not use. // misbehaviour used for freezing the light client - Misbehaviour *types.Any `protobuf:"bytes,2,opt,name=misbehaviour,proto3" json:"misbehaviour,omitempty"` + Misbehaviour *types.Any `protobuf:"bytes,2,opt,name=misbehaviour,proto3" json:"misbehaviour,omitempty"` // Deprecated: Do not use. // signer address - Signer string `protobuf:"bytes,3,opt,name=signer,proto3" json:"signer,omitempty"` + Signer string `protobuf:"bytes,3,opt,name=signer,proto3" json:"signer,omitempty"` // Deprecated: Do not use. } func (m *MsgSubmitMisbehaviour) Reset() { *m = MsgSubmitMisbehaviour{} } @@ -375,45 +376,46 @@ func init() { func init() { proto.RegisterFile("ibc/core/client/v1/tx.proto", fileDescriptor_cb5dc4651eb49a04) } var fileDescriptor_cb5dc4651eb49a04 = []byte{ - // 602 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x3f, 0x6f, 0xd3, 0x4e, - 0x18, 0x8e, 0x9b, 0xdf, 0x2f, 0x6a, 0xae, 0x81, 0x56, 0x26, 0xb4, 0xa9, 0xab, 0xda, 0x91, 0xe9, - 0x10, 0x44, 0x7b, 0x47, 0x82, 0x90, 0xaa, 0x6e, 0xa4, 0x13, 0x43, 0x24, 0x70, 0xc5, 0x00, 0x4b, - 0xf0, 0x9f, 0xeb, 0xe5, 0x44, 0xec, 0x8b, 0x7c, 0x76, 0x44, 0xbe, 0x01, 0x23, 0x03, 0x1f, 0xa0, - 0x62, 0xe0, 0xb3, 0x30, 0x76, 0x60, 0x60, 0x8a, 0xaa, 0x64, 0x61, 0xce, 0x27, 0x40, 0xf1, 0x39, - 0x21, 0x76, 0xe3, 0x28, 0xe2, 0xcf, 0xe6, 0xf3, 0xfb, 0xdc, 0xf3, 0xbc, 0x8f, 0x9f, 0xf7, 0x7c, - 0xe0, 0x80, 0x5a, 0x36, 0xb2, 0x99, 0x8f, 0x91, 0xdd, 0xa5, 0xd8, 0x0b, 0x50, 0xbf, 0x8e, 0x82, - 0xf7, 0xb0, 0xe7, 0xb3, 0x80, 0xc9, 0x32, 0xb5, 0x6c, 0x38, 0x2d, 0x42, 0x51, 0x84, 0xfd, 0xba, - 0x52, 0x26, 0x8c, 0xb0, 0xa8, 0x8c, 0xa6, 0x4f, 0x02, 0xa9, 0xec, 0x13, 0xc6, 0x48, 0x17, 0xa3, - 0x68, 0x65, 0x85, 0x97, 0xc8, 0xf4, 0x06, 0xa2, 0xa4, 0xdf, 0x48, 0x60, 0xbb, 0xc5, 0xc9, 0xb9, - 0x8f, 0xcd, 0x00, 0x9f, 0x47, 0x3c, 0xf2, 0x0b, 0x50, 0x12, 0x8c, 0x6d, 0x1e, 0x98, 0x01, 0xae, - 0x48, 0x55, 0xa9, 0xb6, 0xd5, 0x28, 0x43, 0xc1, 0x02, 0x67, 0x2c, 0xf0, 0x99, 0x37, 0x68, 0xee, - 0x4d, 0x86, 0xda, 0xbd, 0x81, 0xe9, 0x76, 0xcf, 0xf4, 0xc5, 0x3d, 0xba, 0xb1, 0x25, 0x96, 0x17, - 0xd3, 0x95, 0xfc, 0x1a, 0x6c, 0xdb, 0xcc, 0xe3, 0xd8, 0xe3, 0x21, 0x8f, 0x49, 0x37, 0x56, 0x90, - 0x2a, 0x93, 0xa1, 0xb6, 0x1b, 0x93, 0x26, 0xb7, 0xe9, 0xc6, 0xdd, 0xf9, 0x1b, 0x41, 0xbd, 0x0b, - 0x0a, 0x9c, 0x12, 0x0f, 0xfb, 0x95, 0x7c, 0x55, 0xaa, 0x15, 0x8d, 0x78, 0x75, 0xb6, 0xf9, 0xe1, - 0x4a, 0xcb, 0xfd, 0xb8, 0xd2, 0x72, 0xfa, 0x3e, 0xd8, 0x4b, 0x39, 0x34, 0x30, 0xef, 0x4d, 0x59, - 0xf4, 0x4f, 0xc2, 0xfd, 0xab, 0x9e, 0xf3, 0xcb, 0x7d, 0x1d, 0x14, 0x63, 0x27, 0xd4, 0x89, 0xac, - 0x17, 0x9b, 0xe5, 0xc9, 0x50, 0xdb, 0x49, 0x98, 0xa4, 0x8e, 0x6e, 0x6c, 0x8a, 0xe7, 0xe7, 0x8e, - 0x7c, 0x0c, 0x0a, 0x1d, 0x6c, 0x3a, 0xd8, 0x5f, 0xe5, 0xca, 0x88, 0x31, 0x6b, 0x77, 0xbc, 0xd8, - 0xd5, 0xbc, 0xe3, 0x6f, 0x79, 0xb0, 0x13, 0xd5, 0x88, 0x6f, 0x3a, 0x7f, 0xd0, 0x72, 0x3a, 0xe3, - 0x8d, 0x7f, 0x91, 0x71, 0xfe, 0x2f, 0x65, 0xfc, 0x12, 0x94, 0x7b, 0x3e, 0x63, 0x97, 0xed, 0x50, - 0xd8, 0x6e, 0x0b, 0xdd, 0xca, 0x7f, 0x55, 0xa9, 0x56, 0x6a, 0x6a, 0x93, 0xa1, 0x76, 0x20, 0x98, - 0x96, 0xa1, 0x74, 0x43, 0x8e, 0x5e, 0x27, 0x3f, 0xd9, 0x3b, 0x70, 0x98, 0x02, 0xa7, 0x7a, 0xff, - 0x3f, 0xe2, 0xae, 0x4d, 0x86, 0xda, 0xd1, 0x52, 0xee, 0x74, 0xcf, 0x4a, 0x42, 0x24, 0x6b, 0x46, - 0x0b, 0x19, 0x89, 0x2b, 0xa0, 0x92, 0x4e, 0x75, 0x1e, 0xf9, 0x17, 0x09, 0xdc, 0x6f, 0x71, 0x72, - 0x11, 0x5a, 0x2e, 0x0d, 0x5a, 0x94, 0x5b, 0xb8, 0x63, 0xf6, 0x29, 0x0b, 0xfd, 0xdf, 0xc9, 0xfd, - 0x14, 0x94, 0xdc, 0x05, 0x8a, 0x95, 0x03, 0x9b, 0x40, 0xae, 0x31, 0xb6, 0x1a, 0x38, 0x5c, 0xda, - 0xe7, 0xcc, 0x49, 0xe3, 0x73, 0x1e, 0xe4, 0x5b, 0x9c, 0xc8, 0x6f, 0x41, 0x29, 0xf1, 0xc3, 0x79, - 0x00, 0x6f, 0xff, 0xca, 0x60, 0xea, 0xcc, 0x2a, 0x8f, 0xd6, 0x00, 0xcd, 0x94, 0xa6, 0x0a, 0x89, - 0x43, 0x9d, 0xa5, 0xb0, 0x08, 0xca, 0x54, 0x58, 0x76, 0x10, 0x65, 0x1b, 0xdc, 0x49, 0x4e, 0xd4, - 0x51, 0xe6, 0xee, 0x05, 0x94, 0x72, 0xbc, 0x0e, 0x6a, 0x2e, 0xe2, 0x03, 0x79, 0x49, 0xec, 0x0f, - 0x33, 0x38, 0x6e, 0x43, 0x95, 0xfa, 0xda, 0xd0, 0x99, 0x66, 0xd3, 0xf8, 0x3a, 0x52, 0xa5, 0xeb, - 0x91, 0x2a, 0xdd, 0x8c, 0x54, 0xe9, 0xe3, 0x58, 0xcd, 0x5d, 0x8f, 0xd5, 0xdc, 0xf7, 0xb1, 0x9a, - 0x7b, 0x73, 0x4a, 0x68, 0xd0, 0x09, 0x2d, 0x68, 0x33, 0x17, 0xd9, 0x8c, 0xbb, 0x8c, 0x23, 0x6a, - 0xd9, 0x27, 0x84, 0xa1, 0xfe, 0x53, 0xe4, 0x32, 0x27, 0xec, 0x62, 0x2e, 0x6e, 0xab, 0xc7, 0x8d, - 0x93, 0xf8, 0xc2, 0x0a, 0x06, 0x3d, 0xcc, 0xad, 0x42, 0x34, 0x57, 0x4f, 0x7e, 0x06, 0x00, 0x00, - 0xff, 0xff, 0xaa, 0xe7, 0x1e, 0x7d, 0xd0, 0x06, 0x00, 0x00, + // 623 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xcd, 0x6e, 0xd3, 0x4c, + 0x14, 0x8d, 0x9b, 0xef, 0x8b, 0x9a, 0x69, 0xfa, 0x23, 0x13, 0x52, 0xd7, 0x55, 0xed, 0xc8, 0x74, + 0x11, 0x04, 0xb5, 0x49, 0x2a, 0x24, 0x54, 0xd8, 0x90, 0xae, 0x58, 0x44, 0x02, 0x57, 0x2c, 0x60, + 0x13, 0xfc, 0x33, 0x9d, 0x8e, 0x88, 0x3d, 0x91, 0xc7, 0x8e, 0xc8, 0x1b, 0xb0, 0xe4, 0x11, 0x2a, + 0x78, 0x01, 0x1e, 0x83, 0x65, 0x17, 0x2c, 0x58, 0x45, 0x55, 0xb2, 0x61, 0x9d, 0x27, 0x40, 0xf1, + 0x38, 0xc1, 0x76, 0xec, 0x28, 0x12, 0xb0, 0xf3, 0xcc, 0x3d, 0x73, 0xce, 0x3d, 0x3e, 0x77, 0x6c, + 0x70, 0x88, 0x4d, 0x4b, 0xb3, 0x88, 0x07, 0x35, 0xab, 0x87, 0xa1, 0xeb, 0x6b, 0x83, 0xa6, 0xe6, + 0x7f, 0x50, 0xfb, 0x1e, 0xf1, 0x09, 0xcf, 0x63, 0xd3, 0x52, 0x67, 0x45, 0x95, 0x15, 0xd5, 0x41, + 0x53, 0xac, 0x22, 0x82, 0x48, 0x58, 0xd6, 0x66, 0x4f, 0x0c, 0x29, 0x1e, 0x20, 0x42, 0x50, 0x0f, + 0x6a, 0xe1, 0xca, 0x0c, 0x2e, 0x35, 0xc3, 0x1d, 0xb2, 0x92, 0x72, 0xcb, 0x81, 0xdd, 0x0e, 0x45, + 0xe7, 0x1e, 0x34, 0x7c, 0x78, 0x1e, 0xf2, 0xf0, 0x2f, 0x41, 0x85, 0x31, 0x76, 0xa9, 0x6f, 0xf8, + 0x50, 0xe0, 0xea, 0x5c, 0x63, 0xab, 0x55, 0x55, 0x19, 0x8b, 0x3a, 0x67, 0x51, 0x9f, 0xbb, 0xc3, + 0xf6, 0xfe, 0x74, 0x24, 0xdf, 0x19, 0x1a, 0x4e, 0xef, 0x4c, 0x89, 0x9f, 0x51, 0xf4, 0x2d, 0xb6, + 0xbc, 0x98, 0xad, 0xf8, 0x37, 0x60, 0xd7, 0x22, 0x2e, 0x85, 0x2e, 0x0d, 0x68, 0x44, 0xba, 0xb1, + 0x82, 0x54, 0x9c, 0x8e, 0xe4, 0x5a, 0x44, 0x9a, 0x3c, 0xa6, 0xe8, 0x3b, 0x8b, 0x1d, 0x46, 0x5d, + 0x03, 0x25, 0x8a, 0x91, 0x0b, 0x3d, 0xa1, 0x58, 0xe7, 0x1a, 0x65, 0x3d, 0x5a, 0x9d, 0x6d, 0x7e, + 0xbc, 0x96, 0x0b, 0x3f, 0xaf, 0xe5, 0x82, 0x72, 0x00, 0xf6, 0x53, 0x0e, 0x75, 0x48, 0xfb, 0x33, + 0x16, 0xe5, 0x0b, 0x73, 0xff, 0xba, 0x6f, 0xff, 0x76, 0xdf, 0x04, 0xe5, 0xc8, 0x09, 0xb6, 0x43, + 0xeb, 0xe5, 0x76, 0x75, 0x3a, 0x92, 0xf7, 0x12, 0x26, 0xb1, 0xad, 0xe8, 0x9b, 0xec, 0xf9, 0x85, + 0xcd, 0x3f, 0x05, 0x3b, 0xd1, 0xbe, 0x03, 0x29, 0x35, 0xd0, 0x4a, 0x77, 0xfa, 0x36, 0xc3, 0x76, + 0x18, 0x74, 0x6d, 0x03, 0xf1, 0x26, 0x17, 0x06, 0xbe, 0x17, 0xc1, 0x5e, 0x58, 0x43, 0x9e, 0x61, + 0xff, 0x81, 0x83, 0x74, 0xe4, 0x1b, 0xff, 0x22, 0xf2, 0xe2, 0x5f, 0x8a, 0xfc, 0x15, 0xa8, 0xf6, + 0x3d, 0x42, 0x2e, 0xbb, 0x01, 0xb3, 0xdd, 0x65, 0xba, 0xc2, 0x7f, 0x75, 0xae, 0x51, 0x69, 0xcb, + 0xd3, 0x91, 0x7c, 0xc8, 0x98, 0xb2, 0x50, 0x8a, 0xce, 0x87, 0xdb, 0xc9, 0x57, 0xf6, 0x1e, 0x1c, + 0xa5, 0xc0, 0xa9, 0xde, 0xff, 0x0f, 0xb9, 0x1b, 0xd3, 0x91, 0x7c, 0x9c, 0xc9, 0x9d, 0xee, 0x59, + 0x4c, 0x88, 0xe4, 0x8d, 0x6c, 0x29, 0x27, 0x71, 0x11, 0x08, 0xe9, 0x54, 0x17, 0x91, 0x7f, 0xe5, + 0xc0, 0xdd, 0x0e, 0x45, 0x17, 0x81, 0xe9, 0x60, 0xbf, 0x83, 0xa9, 0x09, 0xaf, 0x8c, 0x01, 0x26, + 0x81, 0xc7, 0x9f, 0x2e, 0xe7, 0x5e, 0xcb, 0xca, 0x5d, 0xe0, 0x62, 0xc9, 0x3f, 0x03, 0x15, 0x27, + 0x46, 0xb2, 0x32, 0xf9, 0x0d, 0x81, 0xd3, 0x13, 0x68, 0x5e, 0x4c, 0x0e, 0x6f, 0x88, 0x58, 0xb6, + 0x23, 0x83, 0xa3, 0xcc, 0x8e, 0xe7, 0x9e, 0x5a, 0x9f, 0x8b, 0xa0, 0xd8, 0xa1, 0x88, 0x7f, 0x07, + 0x2a, 0x89, 0x2f, 0xd1, 0x3d, 0x75, 0xf9, 0x1b, 0xa7, 0xa6, 0x2e, 0xb3, 0xf8, 0x60, 0x0d, 0xd0, + 0x5c, 0x69, 0xa6, 0x90, 0xb8, 0xed, 0x79, 0x0a, 0x71, 0x50, 0xae, 0x42, 0xd6, 0x95, 0xe4, 0x2d, + 0xb0, 0x9d, 0x9c, 0xad, 0xe3, 0xdc, 0xd3, 0x31, 0x94, 0xf8, 0x70, 0x1d, 0xd4, 0x42, 0xc4, 0x03, + 0x7c, 0xc6, 0x00, 0xdc, 0xcf, 0xe1, 0x58, 0x86, 0x8a, 0xcd, 0xb5, 0xa1, 0x73, 0xcd, 0xb6, 0xfe, + 0x6d, 0x2c, 0x71, 0x37, 0x63, 0x89, 0xbb, 0x1d, 0x4b, 0xdc, 0xa7, 0x89, 0x54, 0xb8, 0x99, 0x48, + 0x85, 0x1f, 0x13, 0xa9, 0xf0, 0xf6, 0x09, 0xc2, 0xfe, 0x55, 0x60, 0xaa, 0x16, 0x71, 0x34, 0x8b, + 0x50, 0x87, 0x50, 0x0d, 0x9b, 0xd6, 0x09, 0x22, 0xda, 0xe0, 0xb1, 0xe6, 0x10, 0x3b, 0xe8, 0x41, + 0xca, 0x7e, 0x63, 0x8f, 0x5a, 0x27, 0xd1, 0x9f, 0xcc, 0x1f, 0xf6, 0x21, 0x35, 0x4b, 0xe1, 0x7c, + 0x9d, 0xfe, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x88, 0x72, 0x43, 0x59, 0xe9, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -716,9 +718,9 @@ func (m *MsgUpdateClient) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x1a } - if m.Header != nil { + if m.ClientMessage != nil { { - size, err := m.Header.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.ClientMessage.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -982,8 +984,8 @@ func (m *MsgUpdateClient) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - if m.Header != nil { - l = m.Header.Size() + if m.ClientMessage != nil { + l = m.ClientMessage.Size() n += 1 + l + sovTx(uint64(l)) } l = len(m.Signer) @@ -1347,7 +1349,7 @@ func (m *MsgUpdateClient) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Header", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ClientMessage", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1374,10 +1376,10 @@ func (m *MsgUpdateClient) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Header == nil { - m.Header = &types.Any{} + if m.ClientMessage == nil { + m.ClientMessage = &types.Any{} } - if err := m.Header.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.ClientMessage.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/modules/core/03-connection/keeper/handshake_test.go b/modules/core/03-connection/keeper/handshake_test.go index 64ef8f8b813..0dfafa5f911 100644 --- a/modules/core/03-connection/keeper/handshake_test.go +++ b/modules/core/03-connection/keeper/handshake_test.go @@ -7,7 +7,7 @@ import ( "github.com/cosmos/ibc-go/v5/modules/core/03-connection/types" host "github.com/cosmos/ibc-go/v5/modules/core/24-host" "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) @@ -125,7 +125,7 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID) // Set an invalid client of chainA on chainB - tmClient, ok := counterpartyClient.(*ibctmtypes.ClientState) + tmClient, ok := counterpartyClient.(*ibctm.ClientState) suite.Require().True(ok) tmClient.ChainId = "wrongchainid" @@ -182,7 +182,7 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID) // modify counterparty client without setting in store so it still passes validate but fails proof verification - tmClient, ok := counterpartyClient.(*ibctmtypes.ClientState) + tmClient, ok := counterpartyClient.(*ibctm.ClientState) suite.Require().True(ok) tmClient.LatestHeight = tmClient.LatestHeight.Increment().(clienttypes.Height) }, false}, @@ -194,7 +194,7 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { consState, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetLatestClientConsensusState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) - tmConsState, ok := consState.(*ibctmtypes.ConsensusState) + tmConsState, ok := consState.(*ibctm.ConsensusState) suite.Require().True(ok) tmConsState.Timestamp = time.Now() @@ -291,7 +291,7 @@ func (suite *KeeperTestSuite) TestConnOpenAck() { counterpartyClient = suite.chainB.GetClientState(path.EndpointB.ClientID) // Set an invalid client of chainA on chainB - tmClient, ok := counterpartyClient.(*ibctmtypes.ClientState) + tmClient, ok := counterpartyClient.(*ibctm.ClientState) suite.Require().True(ok) tmClient.ChainId = "wrongchainid" @@ -431,7 +431,7 @@ func (suite *KeeperTestSuite) TestConnOpenAck() { counterpartyClient = suite.chainB.GetClientState(path.EndpointB.ClientID) // modify counterparty client without setting in store so it still passes validate but fails proof verification - tmClient, ok := counterpartyClient.(*ibctmtypes.ClientState) + tmClient, ok := counterpartyClient.(*ibctm.ClientState) suite.Require().True(ok) tmClient.LatestHeight = tmClient.LatestHeight.Increment().(clienttypes.Height) @@ -449,7 +449,7 @@ func (suite *KeeperTestSuite) TestConnOpenAck() { consState, found := suite.chainB.App.GetIBCKeeper().ClientKeeper.GetLatestClientConsensusState(suite.chainB.GetContext(), path.EndpointB.ClientID) suite.Require().True(found) - tmConsState, ok := consState.(*ibctmtypes.ConsensusState) + tmConsState, ok := consState.(*ibctm.ConsensusState) suite.Require().True(ok) tmConsState.Timestamp = tmConsState.Timestamp.Add(time.Second) diff --git a/modules/core/03-connection/keeper/keeper.go b/modules/core/03-connection/keeper/keeper.go index 9e23503ad50..7995a52c4b3 100644 --- a/modules/core/03-connection/keeper/keeper.go +++ b/modules/core/03-connection/keeper/keeper.go @@ -86,18 +86,19 @@ func (k Keeper) SetConnection(ctx sdk.Context, connectionID string, connection t // GetTimestampAtHeight returns the timestamp in nanoseconds of the consensus state at the // given height. func (k Keeper) GetTimestampAtHeight(ctx sdk.Context, connection types.ConnectionEnd, height exported.Height) (uint64, error) { - consensusState, found := k.clientKeeper.GetClientConsensusState( - ctx, connection.GetClientID(), height, - ) - + clientState, found := k.clientKeeper.GetClientState(ctx, connection.GetClientID()) if !found { return 0, sdkerrors.Wrapf( - clienttypes.ErrConsensusStateNotFound, - "clientID (%s), height (%s)", connection.GetClientID(), height, + clienttypes.ErrClientNotFound, "clientID (%s)", connection.GetClientID(), ) } - return consensusState.GetTimestamp(), nil + timestamp, err := clientState.GetTimestampAtHeight(ctx, k.clientKeeper.ClientStore(ctx, connection.GetClientID()), k.cdc, height) + if err != nil { + return 0, err + } + + return timestamp, nil } // GetClientConnectionPaths returns all the connection paths stored under a diff --git a/modules/core/03-connection/keeper/keeper_test.go b/modules/core/03-connection/keeper/keeper_test.go index df1a6131d3e..2062105dac9 100644 --- a/modules/core/03-connection/keeper/keeper_test.go +++ b/modules/core/03-connection/keeper/keeper_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/cosmos/ibc-go/v5/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v5/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) @@ -111,7 +112,10 @@ func (suite KeeperTestSuite) TestGetAllClientConnectionPaths() { // TestGetTimestampAtHeight verifies if the clients on each chain return the // correct timestamp for the other chain. func (suite *KeeperTestSuite) TestGetTimestampAtHeight() { - var connection types.ConnectionEnd + var ( + connection types.ConnectionEnd + height exported.Height + ) cases := []struct { msg string @@ -122,10 +126,14 @@ func (suite *KeeperTestSuite) TestGetTimestampAtHeight() { path := ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) connection = path.EndpointA.GetConnection() + height = suite.chainB.LastHeader.GetHeight() }, true}, + {"client state not found", func() {}, false}, {"consensus state not found", func() { - // any non-nil value of connection is valid - suite.Require().NotNil(connection) + path := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + connection = path.EndpointA.GetConnection() + height = suite.chainB.LastHeader.GetHeight().Increment() }, false}, } @@ -136,7 +144,7 @@ func (suite *KeeperTestSuite) TestGetTimestampAtHeight() { tc.malleate() actualTimestamp, err := suite.chainA.App.GetIBCKeeper().ConnectionKeeper.GetTimestampAtHeight( - suite.chainA.GetContext(), connection, suite.chainB.LastHeader.GetHeight(), + suite.chainA.GetContext(), connection, height, ) if tc.expPass { diff --git a/modules/core/03-connection/keeper/verify.go b/modules/core/03-connection/keeper/verify.go index 3471cdcb7ac..bafea2bd190 100644 --- a/modules/core/03-connection/keeper/verify.go +++ b/modules/core/03-connection/keeper/verify.go @@ -7,6 +7,10 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v5/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v5/modules/core/24-host" "github.com/cosmos/ibc-go/v5/modules/core/exported" ) @@ -31,9 +35,27 @@ func (k Keeper) VerifyClientState( return sdkerrors.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - if err := targetClient.VerifyClientState( - clientStore, k.cdc, height, - connection.GetCounterparty().GetPrefix(), connection.GetCounterparty().GetClientID(), proof, clientState); err != nil { + merklePath := commitmenttypes.NewMerklePath(host.FullClientStatePath(connection.GetCounterparty().GetClientID())) + merklePath, err := commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) + if err != nil { + return err + } + + path, err := k.cdc.Marshal(&merklePath) + if err != nil { + return err + } + + bz, err := k.cdc.MarshalInterface(clientState) + if err != nil { + return err + } + + if err := targetClient.VerifyMembership( + ctx, clientStore, k.cdc, height, + 0, 0, // skip delay period checks for non-packet processing verification + proof, path, bz, + ); err != nil { return sdkerrors.Wrapf(err, "failed client state verification for target client: %s", clientID) } @@ -62,9 +84,26 @@ func (k Keeper) VerifyClientConsensusState( return sdkerrors.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - if err := clientState.VerifyClientConsensusState( - clientStore, k.cdc, height, - connection.GetCounterparty().GetClientID(), consensusHeight, connection.GetCounterparty().GetPrefix(), proof, consensusState, + merklePath := commitmenttypes.NewMerklePath(host.FullConsensusStatePath(connection.GetCounterparty().GetClientID(), consensusHeight)) + merklePath, err := commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) + if err != nil { + return err + } + + path, err := k.cdc.Marshal(&merklePath) + if err != nil { + return err + } + + bz, err := k.cdc.MarshalInterface(consensusState) + 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, path, bz, ); err != nil { return sdkerrors.Wrapf(err, "failed consensus state verification for client (%s)", clientID) } @@ -80,7 +119,7 @@ func (k Keeper) VerifyConnectionState( height exported.Height, proof []byte, connectionID string, - connectionEnd exported.ConnectionI, // opposite connection + counterpartyConnection exported.ConnectionI, // opposite connection ) error { clientID := connection.GetClientID() clientStore := k.clientKeeper.ClientStore(ctx, clientID) @@ -94,9 +133,31 @@ func (k Keeper) VerifyConnectionState( return sdkerrors.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - if err := clientState.VerifyConnectionState( - clientStore, k.cdc, height, - connection.GetCounterparty().GetPrefix(), proof, connectionID, connectionEnd, + merklePath := commitmenttypes.NewMerklePath(host.ConnectionPath(connectionID)) + merklePath, err := commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) + if err != nil { + return err + } + + path, err := k.cdc.Marshal(&merklePath) + if err != nil { + return err + } + + connectionEnd, ok := counterpartyConnection.(connectiontypes.ConnectionEnd) + if !ok { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "invalid connection type %T", counterpartyConnection) + } + + bz, err := k.cdc.Marshal(&connectionEnd) + 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, path, bz, ); err != nil { return sdkerrors.Wrapf(err, "failed connection state verification for client (%s)", clientID) } @@ -127,10 +188,31 @@ func (k Keeper) VerifyChannelState( return sdkerrors.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - if err := clientState.VerifyChannelState( - clientStore, k.cdc, height, - connection.GetCounterparty().GetPrefix(), proof, - portID, channelID, channel, + merklePath := commitmenttypes.NewMerklePath(host.ChannelPath(portID, channelID)) + merklePath, err := commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) + if err != nil { + return err + } + + path, err := k.cdc.Marshal(&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, path, bz, ); err != nil { return sdkerrors.Wrapf(err, "failed channel state verification for client (%s)", clientID) } @@ -166,11 +248,21 @@ func (k Keeper) VerifyPacketCommitment( timeDelay := connection.GetDelayPeriod() blockDelay := k.getBlockDelay(ctx, connection) - if err := clientState.VerifyPacketCommitment( + merklePath := commitmenttypes.NewMerklePath(host.PacketCommitmentPath(portID, channelID, sequence)) + merklePath, err := commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) + if err != nil { + return err + } + + path, err := k.cdc.Marshal(&merklePath) + if err != nil { + return err + } + + if err := clientState.VerifyMembership( ctx, clientStore, k.cdc, height, timeDelay, blockDelay, - connection.GetCounterparty().GetPrefix(), proof, portID, channelID, - sequence, commitmentBytes, + proof, path, commitmentBytes, ); err != nil { return sdkerrors.Wrapf(err, "failed packet commitment verification for client (%s)", clientID) } @@ -206,11 +298,21 @@ func (k Keeper) VerifyPacketAcknowledgement( timeDelay := connection.GetDelayPeriod() blockDelay := k.getBlockDelay(ctx, connection) - if err := clientState.VerifyPacketAcknowledgement( + merklePath := commitmenttypes.NewMerklePath(host.PacketAcknowledgementPath(portID, channelID, sequence)) + merklePath, err := commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) + if err != nil { + return err + } + + path, err := k.cdc.Marshal(&merklePath) + if err != nil { + return err + } + + if err := clientState.VerifyMembership( ctx, clientStore, k.cdc, height, timeDelay, blockDelay, - connection.GetCounterparty().GetPrefix(), proof, portID, channelID, - sequence, acknowledgement, + proof, path, channeltypes.CommitAcknowledgement(acknowledgement), ); err != nil { return sdkerrors.Wrapf(err, "failed packet acknowledgement verification for client (%s)", clientID) } @@ -246,11 +348,21 @@ func (k Keeper) VerifyPacketReceiptAbsence( timeDelay := connection.GetDelayPeriod() blockDelay := k.getBlockDelay(ctx, connection) - if err := clientState.VerifyPacketReceiptAbsence( + merklePath := commitmenttypes.NewMerklePath(host.PacketReceiptPath(portID, channelID, sequence)) + merklePath, err := commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) + if err != nil { + return err + } + + path, err := k.cdc.Marshal(&merklePath) + if err != nil { + return err + } + + if err := clientState.VerifyNonMembership( ctx, clientStore, k.cdc, height, timeDelay, blockDelay, - connection.GetCounterparty().GetPrefix(), proof, portID, channelID, - sequence, + proof, path, ); err != nil { return sdkerrors.Wrapf(err, "failed packet receipt absence verification for client (%s)", clientID) } @@ -285,11 +397,21 @@ func (k Keeper) VerifyNextSequenceRecv( timeDelay := connection.GetDelayPeriod() blockDelay := k.getBlockDelay(ctx, connection) - if err := clientState.VerifyNextSequenceRecv( + merklePath := commitmenttypes.NewMerklePath(host.NextSequenceRecvPath(portID, channelID)) + merklePath, err := commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) + if err != nil { + return err + } + + path, err := k.cdc.Marshal(&merklePath) + if err != nil { + return err + } + + if err := clientState.VerifyMembership( ctx, clientStore, k.cdc, height, timeDelay, blockDelay, - connection.GetCounterparty().GetPrefix(), proof, portID, channelID, - nextSequenceRecv, + proof, path, sdk.Uint64ToBigEndian(nextSequenceRecv), ); err != nil { return sdkerrors.Wrapf(err, "failed next sequence receive verification for client (%s)", clientID) } diff --git a/modules/core/03-connection/keeper/verify_test.go b/modules/core/03-connection/keeper/verify_test.go index b5592362936..3ad64e9b285 100644 --- a/modules/core/03-connection/keeper/verify_test.go +++ b/modules/core/03-connection/keeper/verify_test.go @@ -9,12 +9,12 @@ import ( channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v5/modules/core/24-host" "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ibcmock "github.com/cosmos/ibc-go/v5/testing/mock" ) -var defaultTimeoutHeight = clienttypes.NewHeight(0, 100000) +var defaultTimeoutHeight = clienttypes.NewHeight(1, 100000) // TestVerifyClientState verifies a client state of chainA // stored on path.EndpointB (which is on chainB) @@ -38,12 +38,12 @@ func (suite *KeeperTestSuite) TestVerifyClientState() { heightDiff = 5 }, false}, {"verification failed", func() { - counterpartyClient := path.EndpointB.GetClientState().(*ibctmtypes.ClientState) + counterpartyClient := path.EndpointB.GetClientState().(*ibctm.ClientState) counterpartyClient.ChainId = "wrongChainID" path.EndpointB.SetClientState(counterpartyClient) }, false}, {"client status is not active - client is expired", func() { - clientState := path.EndpointA.GetClientState().(*ibctmtypes.ClientState) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) clientState.FrozenHeight = clienttypes.NewHeight(0, 1) path.EndpointA.SetClientState(clientState) }, false}, @@ -62,7 +62,7 @@ func (suite *KeeperTestSuite) TestVerifyClientState() { tc.malleate() counterpartyClient, clientProof := path.EndpointB.QueryClientStateProof() - proofHeight := clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()-1)) + proofHeight := clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()-1)) connection := path.EndpointA.GetConnection() @@ -109,7 +109,7 @@ func (suite *KeeperTestSuite) TestVerifyClientConsensusState() { consState, found := suite.chainB.App.GetIBCKeeper().ClientKeeper.GetLatestClientConsensusState(suite.chainB.GetContext(), path.EndpointB.ClientID) suite.Require().True(found) - tmConsState, ok := consState.(*ibctmtypes.ConsensusState) + tmConsState, ok := consState.(*ibctm.ConsensusState) suite.Require().True(ok) tmConsState.Timestamp = time.Now() @@ -118,7 +118,7 @@ func (suite *KeeperTestSuite) TestVerifyClientConsensusState() { suite.coordinator.CommitBlock(suite.chainB) }, false}, {"client status is not active - client is expired", func() { - clientState := path.EndpointA.GetClientState().(*ibctmtypes.ClientState) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) clientState.FrozenHeight = clienttypes.NewHeight(0, 1) path.EndpointA.SetClientState(clientState) }, false}, @@ -138,7 +138,7 @@ func (suite *KeeperTestSuite) TestVerifyClientConsensusState() { connection := path.EndpointA.GetConnection() proof, consensusHeight := suite.chainB.QueryConsensusStateProof(path.EndpointB.ClientID) - proofHeight := clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()-1)) + proofHeight := clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()-1)) consensusState, err := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetSelfConsensusState(suite.chainA.GetContext(), consensusHeight) suite.Require().NoError(err) @@ -183,7 +183,7 @@ func (suite *KeeperTestSuite) TestVerifyConnectionState() { path.EndpointA.SetConnection(connection) }, false}, {"client status is not active - client is expired", func() { - clientState := path.EndpointA.GetClientState().(*ibctmtypes.ClientState) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) clientState.FrozenHeight = clienttypes.NewHeight(0, 1) path.EndpointA.SetClientState(clientState) }, false}, @@ -248,7 +248,7 @@ func (suite *KeeperTestSuite) TestVerifyChannelState() { path.EndpointA.SetChannel(channel) }, false}, {"client status is not active - client is expired", func() { - clientState := path.EndpointA.GetClientState().(*ibctmtypes.ClientState) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) clientState.FrozenHeight = clienttypes.NewHeight(0, 1) path.EndpointA.SetClientState(clientState) }, false}, @@ -326,7 +326,7 @@ func (suite *KeeperTestSuite) TestVerifyPacketCommitment() { packet.Data = []byte(ibctesting.InvalidID) }, false}, {"client status is not active - client is expired", func() { - clientState := path.EndpointB.GetClientState().(*ibctmtypes.ClientState) + clientState := path.EndpointB.GetClientState().(*ibctm.ClientState) clientState.FrozenHeight = clienttypes.NewHeight(0, 1) path.EndpointB.SetClientState(clientState) }, false}, @@ -418,7 +418,7 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() { ack = ibcmock.MockFailAcknowledgement }, false}, {"client status is not active - client is expired", func() { - clientState := path.EndpointA.GetClientState().(*ibctmtypes.ClientState) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) clientState.FrozenHeight = clienttypes.NewHeight(0, 1) path.EndpointA.SetClientState(clientState) }, false}, @@ -524,7 +524,7 @@ func (suite *KeeperTestSuite) TestVerifyPacketReceiptAbsence() { suite.Require().NoError(err) }, false}, {"client status is not active - client is expired", func() { - clientState := path.EndpointA.GetClientState().(*ibctmtypes.ClientState) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) clientState.FrozenHeight = clienttypes.NewHeight(0, 1) path.EndpointA.SetClientState(clientState) }, false}, @@ -553,7 +553,7 @@ func (suite *KeeperTestSuite) TestVerifyPacketReceiptAbsence() { connection := path.EndpointA.GetConnection() connection.DelayPeriod = delayTimePeriod - clientState := path.EndpointA.GetClientState().(*ibctmtypes.ClientState) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) if clientState.FrozenHeight.IsZero() { // need to update height to prove absence or receipt suite.coordinator.CommitBlock(suite.chainA, suite.chainB) @@ -624,7 +624,7 @@ func (suite *KeeperTestSuite) TestVerifyNextSequenceRecv() { offsetSeq = 1 }, false}, {"client status is not active - client is expired", func() { - clientState := path.EndpointA.GetClientState().(*ibctmtypes.ClientState) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) clientState.FrozenHeight = clienttypes.NewHeight(0, 1) path.EndpointA.SetClientState(clientState) }, false}, diff --git a/modules/core/03-connection/types/msgs_test.go b/modules/core/03-connection/types/msgs_test.go index 58c02063378..5d8d4bcc99c 100644 --- a/modules/core/03-connection/types/msgs_test.go +++ b/modules/core/03-connection/types/msgs_test.go @@ -16,7 +16,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" "github.com/cosmos/ibc-go/v5/modules/core/03-connection/types" commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" "github.com/cosmos/ibc-go/v5/testing/simapp" ) @@ -109,22 +109,22 @@ func (suite *MsgTestSuite) TestNewMsgConnectionOpenInit() { func (suite *MsgTestSuite) TestNewMsgConnectionOpenTry() { prefix := commitmenttypes.NewMerklePrefix([]byte("storePrefixKey")) - clientState := ibctmtypes.NewClientState( - chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false, + clientState := ibctm.NewClientState( + chainID, ibctm.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false, ) any, err := clienttypes.PackClientState(clientState) suite.Require().NoError(err) // Pack consensus state into any to test unpacking error - consState := ibctmtypes.NewConsensusState( + consState := ibctm.NewConsensusState( time.Now(), commitmenttypes.NewMerkleRoot([]byte("root")), []byte("nextValsHash"), ) invalidAny := clienttypes.MustPackConsensusState(consState) counterparty := types.NewCounterparty("connectiontotest", "clienttotest", prefix) // invalidClientState fails validateBasic - invalidClient := ibctmtypes.NewClientState( - chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clienttypes.ZeroHeight(), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false, + invalidClient := ibctm.NewClientState( + chainID, ibctm.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clienttypes.ZeroHeight(), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false, ) testCases := []struct { @@ -162,19 +162,19 @@ func (suite *MsgTestSuite) TestNewMsgConnectionOpenTry() { } func (suite *MsgTestSuite) TestNewMsgConnectionOpenAck() { - clientState := ibctmtypes.NewClientState( - chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false, + clientState := ibctm.NewClientState( + chainID, ibctm.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false, ) // Pack consensus state into any to test unpacking error - consState := ibctmtypes.NewConsensusState( + consState := ibctm.NewConsensusState( time.Now(), commitmenttypes.NewMerkleRoot([]byte("root")), []byte("nextValsHash"), ) invalidAny := clienttypes.MustPackConsensusState(consState) // invalidClientState fails validateBasic - invalidClient := ibctmtypes.NewClientState( - chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clienttypes.ZeroHeight(), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false, + invalidClient := ibctm.NewClientState( + chainID, ibctm.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clienttypes.ZeroHeight(), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false, ) connectionID := "connection-0" diff --git a/modules/core/04-channel/keeper/packet.go b/modules/core/04-channel/keeper/packet.go index ad160bd8a0e..3fa66a6e989 100644 --- a/modules/core/04-channel/keeper/packet.go +++ b/modules/core/04-channel/keeper/packet.go @@ -84,25 +84,16 @@ func (k Keeper) SendPacket( ) } - clientType, _, err := clienttypes.ParseClientIdentifier(connectionEnd.GetClientID()) + latestTimestamp, err := k.connectionKeeper.GetTimestampAtHeight(ctx, connectionEnd, latestHeight) if err != nil { return err } - // NOTE: this is a temporary fix. Solo machine does not support usage of 'GetTimestampAtHeight' - // A future change should move this function to be a ClientState callback. - if clientType != exported.Solomachine { - latestTimestamp, err := k.connectionKeeper.GetTimestampAtHeight(ctx, connectionEnd, latestHeight) - if err != nil { - return err - } - - if packet.GetTimeoutTimestamp() != 0 && latestTimestamp >= packet.GetTimeoutTimestamp() { - return sdkerrors.Wrapf( - types.ErrPacketTimeout, - "receiving chain block timestamp >= packet timeout timestamp (%s >= %s)", time.Unix(0, int64(latestTimestamp)), time.Unix(0, int64(packet.GetTimeoutTimestamp())), - ) - } + if packet.GetTimeoutTimestamp() != 0 && latestTimestamp >= packet.GetTimeoutTimestamp() { + return sdkerrors.Wrapf( + types.ErrPacketTimeout, + "receiving chain block timestamp >= packet timeout timestamp (%s >= %s)", time.Unix(0, int64(latestTimestamp)), time.Unix(0, int64(packet.GetTimeoutTimestamp())), + ) } nextSequenceSend, found := k.GetNextSequenceSend(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) diff --git a/modules/core/04-channel/keeper/packet_test.go b/modules/core/04-channel/keeper/packet_test.go index 1080b1ebb73..8614f369bbd 100644 --- a/modules/core/04-channel/keeper/packet_test.go +++ b/modules/core/04-channel/keeper/packet_test.go @@ -12,7 +12,7 @@ import ( "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v5/modules/core/24-host" "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ibcmock "github.com/cosmos/ibc-go/v5/testing/mock" ) @@ -20,7 +20,7 @@ import ( var ( disabledTimeoutTimestamp = uint64(0) disabledTimeoutHeight = clienttypes.ZeroHeight() - timeoutHeight = clienttypes.NewHeight(0, 100) + timeoutHeight = clienttypes.NewHeight(1, 100) // for when the testing package cannot be used clientIDA = "clientA" @@ -148,7 +148,7 @@ func (suite *KeeperTestSuite) TestSendPacket() { connection := path.EndpointA.GetConnection() clientState := path.EndpointA.GetClientState() - cs, ok := clientState.(*ibctmtypes.ClientState) + cs, ok := clientState.(*ibctm.ClientState) suite.Require().True(ok) // freeze client @@ -177,6 +177,23 @@ func (suite *KeeperTestSuite) TestSendPacket() { packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, disabledTimeoutHeight, timestamp) channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, + {"timeout timestamp passed with solomachine", func() { + suite.coordinator.Setup(path) + // swap client with solomachine + solomachine := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachinesingle", "testing", 1) + path.EndpointA.ClientID = clienttypes.FormatClientIdentifier(exported.Solomachine, 10) + path.EndpointA.SetClientState(solomachine.ClientState()) + connection := path.EndpointA.GetConnection() + connection.ClientId = path.EndpointA.ClientID + path.EndpointA.SetConnection(connection) + + clientState := path.EndpointA.GetClientState() + timestamp, err := suite.chainA.App.GetIBCKeeper().ConnectionKeeper.GetTimestampAtHeight(suite.chainA.GetContext(), connection, clientState.GetLatestHeight()) + suite.Require().NoError(err) + + packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, disabledTimeoutHeight, timestamp) + channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + }, false}, {"next sequence send not found", func() { path := ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) diff --git a/modules/core/ante/ante_test.go b/modules/core/ante/ante_test.go index 3d074429a66..363ea28e398 100644 --- a/modules/core/ante/ante_test.go +++ b/modules/core/ante/ante_test.go @@ -49,7 +49,7 @@ func (suite *AnteTestSuite) createRecvPacketMessage(sequenceNumber uint64, isRed packet := channeltypes.NewPacket(ibctesting.MockPacketData, sequenceNumber, suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - clienttypes.NewHeight(1, 0), 0) + clienttypes.NewHeight(2, 0), 0) err := suite.path.EndpointA.SendPacket(packet) suite.Require().NoError(err) @@ -73,7 +73,7 @@ func (suite *AnteTestSuite) createAcknowledgementMessage(sequenceNumber uint64, packet := channeltypes.NewPacket(ibctesting.MockPacketData, sequenceNumber, suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - clienttypes.NewHeight(1, 0), 0) + clienttypes.NewHeight(2, 0), 0) err := suite.path.EndpointB.SendPacket(packet) suite.Require().NoError(err) @@ -153,7 +153,7 @@ func (suite *AnteTestSuite) createUpdateClientMessage() sdk.Msg { // ensure counterparty has committed state endpoint.Chain.Coordinator.CommitBlock(endpoint.Counterparty.Chain) - var header exported.Header + var header exported.ClientMessage switch endpoint.ClientConfig.GetClientType() { case exported.Tendermint: @@ -415,11 +415,11 @@ func (suite *AnteTestSuite) TestAnteDecorator() { packet := channeltypes.NewPacket(ibctesting.MockPacketData, 2, suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - clienttypes.NewHeight(1, 0), 0) + clienttypes.NewHeight(2, 0), 0) return []sdk.Msg{ suite.createRecvPacketMessage(uint64(1), false), - channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer"), + channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(1, 1), "signer"), } }, false, diff --git a/modules/core/exported/client.go b/modules/core/exported/client.go index 4dce203bea4..ac76a647dc5 100644 --- a/modules/core/exported/client.go +++ b/modules/core/exported/client.go @@ -19,10 +19,6 @@ const ( // Tendermint is used to indicate that the client uses the Tendermint Consensus Algorithm. Tendermint string = "07-tendermint" - // Localhost is the client type for a localhost client. It is also used as the clientID - // for the localhost client. - Localhost string = "09-localhost" - // Active is a status type of a client. An active client is allowed to be used. Active Status = "Active" @@ -44,137 +40,93 @@ type ClientState interface { GetLatestHeight() Height Validate() error - // Initialization function - // Clients must validate the initial consensus state, and may store any client-specific metadata - // necessary for correct light client operation - Initialize(sdk.Context, codec.BinaryCodec, sdk.KVStore, ConsensusState) error - - // Status function - // Clients must return their status. Only Active clients are allowed to process packets. + // Status must return the status of the client. Only Active clients are allowed to process packets. Status(ctx sdk.Context, clientStore sdk.KVStore, cdc codec.BinaryCodec) Status - // Genesis function - ExportMetadata(sdk.KVStore) []GenesisMetadata - - // Update and Misbehaviour functions + // ExportMetadata must export metadata stored within the clientStore for genesis export + ExportMetadata(clientStore sdk.KVStore) []GenesisMetadata - CheckHeaderAndUpdateState(sdk.Context, codec.BinaryCodec, sdk.KVStore, Header) (ClientState, ConsensusState, error) - CheckMisbehaviourAndUpdateState(sdk.Context, codec.BinaryCodec, sdk.KVStore, Misbehaviour) (ClientState, error) - CheckSubstituteAndUpdateState(ctx sdk.Context, cdc codec.BinaryCodec, subjectClientStore, substituteClientStore sdk.KVStore, substituteClient ClientState) (ClientState, error) - - // 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, - ) (ClientState, ConsensusState, error) - // Utility function that zeroes out any client customizable fields in client state + // ZeroCustomFields 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 - // State verification functions - - VerifyClientState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height Height, - prefix Prefix, - counterpartyClientIdentifier string, - proof []byte, - clientState ClientState, - ) error - VerifyClientConsensusState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height Height, - counterpartyClientIdentifier string, - consensusHeight Height, - prefix Prefix, - proof []byte, - consensusState ConsensusState, - ) error - VerifyConnectionState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height Height, - prefix Prefix, - proof []byte, - connectionID string, - connectionEnd ConnectionI, - ) error - VerifyChannelState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height Height, - prefix Prefix, - proof []byte, - portID, - channelID string, - channel ChannelI, - ) error - VerifyPacketCommitment( + // GetTimestampAtHeight must return the timestamp for the consensus state associated with the provided height. + GetTimestampAtHeight( ctx sdk.Context, - store sdk.KVStore, + clientStore sdk.KVStore, cdc codec.BinaryCodec, height Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - prefix Prefix, - proof []byte, - portID, - channelID string, - sequence uint64, - commitmentBytes []byte, - ) error - VerifyPacketAcknowledgement( + ) (uint64, error) + + // Initialization function + // Clients must validate the initial consensus state, and may store any client-specific metadata + // necessary for correct light client operation + Initialize(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, consensusState ConsensusState) error + + // VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. + // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). + VerifyMembership( ctx sdk.Context, - store sdk.KVStore, + clientStore sdk.KVStore, cdc codec.BinaryCodec, height Height, delayTimePeriod uint64, delayBlockPeriod uint64, - prefix Prefix, proof []byte, - portID, - channelID string, - sequence uint64, - acknowledgement []byte, + path []byte, + value []byte, ) error - VerifyPacketReceiptAbsence( + + // 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, - store sdk.KVStore, + clientStore sdk.KVStore, cdc codec.BinaryCodec, height Height, delayTimePeriod uint64, delayBlockPeriod uint64, - prefix Prefix, proof []byte, - portID, - channelID string, - sequence uint64, + path []byte, ) error - VerifyNextSequenceRecv( + + // 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. + VerifyClientMessage(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg ClientMessage) error + + // Checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage + // has already been verified. + CheckForMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg ClientMessage) bool + + // UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified + UpdateStateOnMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg ClientMessage) + + // 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(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg ClientMessage) []Height + + // 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 + + // 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. + // If the upgrade is verified, the upgraded client and consensus states must be set in the client store. + VerifyUpgradeAndUpdateState( ctx sdk.Context, - store sdk.KVStore, cdc codec.BinaryCodec, - height Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - prefix Prefix, - proof []byte, - portID, - channelID string, - nextSequenceRecv uint64, + store sdk.KVStore, + newClient ClientState, + newConsState ConsensusState, + proofUpgradeClient, + proofUpgradeConsState []byte, ) error } @@ -184,31 +136,19 @@ type ConsensusState interface { ClientType() string // Consensus kind - // GetRoot returns the commitment root of the consensus state, - // which is used for key-value pair verification. - GetRoot() Root - // GetTimestamp returns the timestamp (in nanoseconds) of the consensus state GetTimestamp() uint64 ValidateBasic() error } -// Misbehaviour defines counterparty misbehaviour for a specific consensus type -type Misbehaviour interface { - proto.Message - - ClientType() string - GetClientID() string - ValidateBasic() error -} - -// Header is the consensus state update information -type Header interface { +// 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 - GetHeight() Height ValidateBasic() error } diff --git a/modules/core/genesis.go b/modules/core/genesis.go index 363b9a07717..e7875770dac 100644 --- a/modules/core/genesis.go +++ b/modules/core/genesis.go @@ -12,7 +12,7 @@ import ( // InitGenesis initializes the ibc state from a provided genesis // state. -func InitGenesis(ctx sdk.Context, k keeper.Keeper, createLocalhost bool, gs *types.GenesisState) { +func InitGenesis(ctx sdk.Context, k keeper.Keeper, gs *types.GenesisState) { client.InitGenesis(ctx, k.ClientKeeper, gs.ClientGenesis) connection.InitGenesis(ctx, k.ConnectionKeeper, gs.ConnectionGenesis) channel.InitGenesis(ctx, k.ChannelKeeper, gs.ChannelGenesis) diff --git a/modules/core/genesis_test.go b/modules/core/genesis_test.go index 0a4fa2e1fe4..c433e834de1 100644 --- a/modules/core/genesis_test.go +++ b/modules/core/genesis_test.go @@ -15,8 +15,7 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" "github.com/cosmos/ibc-go/v5/modules/core/exported" "github.com/cosmos/ibc-go/v5/modules/core/types" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" - localhosttypes "github.com/cosmos/ibc-go/v5/modules/light-clients/09-localhost/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" "github.com/cosmos/ibc-go/v5/testing/simapp" ) @@ -25,8 +24,7 @@ const ( connectionID = "connection-0" clientID = "07-tendermint-0" connectionID2 = "connection-1" - clientID2 = "07-tendermin-1" - localhostID = exported.Localhost + "-1" + clientID2 = "07-tendermint-1" port1 = "firstport" port2 = "secondport" @@ -35,7 +33,7 @@ const ( channel2 = "channel-1" ) -var clientHeight = clienttypes.NewHeight(0, 10) +var clientHeight = clienttypes.NewHeight(1, 10) type IBCTestSuite struct { suite.Suite @@ -77,10 +75,7 @@ func (suite *IBCTestSuite) TestValidateGenesis() { ClientGenesis: clienttypes.NewGenesisState( []clienttypes.IdentifiedClientState{ clienttypes.NewIdentifiedClientState( - clientID, ibctmtypes.NewClientState(suite.chainA.ChainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), - ), - clienttypes.NewIdentifiedClientState( - localhostID, localhosttypes.NewClientState("chaindID", clientHeight), + clientID, ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), ), }, []clienttypes.ClientConsensusStates{ @@ -89,7 +84,7 @@ func (suite *IBCTestSuite) TestValidateGenesis() { []clienttypes.ConsensusStateWithHeight{ clienttypes.NewConsensusStateWithHeight( header.GetHeight().(clienttypes.Height), - ibctmtypes.NewConsensusState( + ibctm.NewConsensusState( header.GetTime(), commitmenttypes.NewMerkleRoot(header.Header.AppHash), header.Header.NextValidatorsHash, ), ), @@ -105,8 +100,8 @@ func (suite *IBCTestSuite) TestValidateGenesis() { }, ), }, - clienttypes.NewParams(exported.Tendermint, exported.Localhost), - true, + clienttypes.NewParams(exported.Tendermint), + false, 2, ), ConnectionGenesis: connectiontypes.NewGenesisState( @@ -157,10 +152,7 @@ func (suite *IBCTestSuite) TestValidateGenesis() { ClientGenesis: clienttypes.NewGenesisState( []clienttypes.IdentifiedClientState{ clienttypes.NewIdentifiedClientState( - clientID, ibctmtypes.NewClientState(suite.chainA.ChainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), - ), - clienttypes.NewIdentifiedClientState( - localhostID, localhosttypes.NewClientState("(chaindID)", clienttypes.ZeroHeight()), + clientID, ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), ), }, nil, @@ -241,10 +233,7 @@ func (suite *IBCTestSuite) TestInitGenesis() { ClientGenesis: clienttypes.NewGenesisState( []clienttypes.IdentifiedClientState{ clienttypes.NewIdentifiedClientState( - clientID, ibctmtypes.NewClientState(suite.chainA.ChainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), - ), - clienttypes.NewIdentifiedClientState( - exported.Localhost, localhosttypes.NewClientState("chaindID", clientHeight), + clientID, ibctm.NewClientState(suite.chainA.ChainID, ibctm.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), ), }, []clienttypes.ClientConsensusStates{ @@ -253,7 +242,7 @@ func (suite *IBCTestSuite) TestInitGenesis() { []clienttypes.ConsensusStateWithHeight{ clienttypes.NewConsensusStateWithHeight( header.GetHeight().(clienttypes.Height), - ibctmtypes.NewConsensusState( + ibctm.NewConsensusState( header.GetTime(), commitmenttypes.NewMerkleRoot(header.Header.AppHash), header.Header.NextValidatorsHash, ), ), @@ -269,8 +258,8 @@ func (suite *IBCTestSuite) TestInitGenesis() { }, ), }, - clienttypes.NewParams(exported.Tendermint, exported.Localhost), - true, + clienttypes.NewParams(exported.Tendermint), + false, 0, ), ConnectionGenesis: connectiontypes.NewGenesisState( @@ -320,7 +309,7 @@ func (suite *IBCTestSuite) TestInitGenesis() { app := simapp.Setup(false) suite.NotPanics(func() { - ibc.InitGenesis(app.BaseApp.NewContext(false, tmproto.Header{Height: 1}), *app.IBCKeeper, true, tc.genState) + ibc.InitGenesis(app.BaseApp.NewContext(false, tmproto.Header{Height: 1}), *app.IBCKeeper, tc.genState) }) } } @@ -355,7 +344,7 @@ func (suite *IBCTestSuite) TestExportGenesis() { // init genesis based on export suite.NotPanics(func() { - ibc.InitGenesis(suite.chainA.GetContext(), *suite.chainA.App.GetIBCKeeper(), true, gs) + ibc.InitGenesis(suite.chainA.GetContext(), *suite.chainA.App.GetIBCKeeper(), gs) }) suite.NotPanics(func() { @@ -366,7 +355,7 @@ func (suite *IBCTestSuite) TestExportGenesis() { // init genesis based on marshal and unmarshal suite.NotPanics(func() { - ibc.InitGenesis(suite.chainA.GetContext(), *suite.chainA.App.GetIBCKeeper(), true, gs) + ibc.InitGenesis(suite.chainA.GetContext(), *suite.chainA.App.GetIBCKeeper(), gs) }) }) } diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 500d1dd8cf7..5f6c77a3981 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -46,12 +46,12 @@ func (k Keeper) CreateClient(goCtx context.Context, msg *clienttypes.MsgCreateCl func (k Keeper) UpdateClient(goCtx context.Context, msg *clienttypes.MsgUpdateClient) (*clienttypes.MsgUpdateClientResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - header, err := clienttypes.UnpackHeader(msg.Header) + clientMsg, err := clienttypes.UnpackClientMessage(msg.ClientMessage) if err != nil { return nil, err } - if err = k.ClientKeeper.UpdateClient(ctx, msg.ClientId, header); err != nil { + if err = k.ClientKeeper.UpdateClient(ctx, msg.ClientId, clientMsg); err != nil { return nil, err } @@ -80,16 +80,18 @@ func (k Keeper) UpgradeClient(goCtx context.Context, msg *clienttypes.MsgUpgrade } // SubmitMisbehaviour defines a rpc handler method for MsgSubmitMisbehaviour. +// Warning: DEPRECATED +// This handler is redudant as `MsgUpdateClient` is now capable of handling both a Header and a Misbehaviour func (k Keeper) SubmitMisbehaviour(goCtx context.Context, msg *clienttypes.MsgSubmitMisbehaviour) (*clienttypes.MsgSubmitMisbehaviourResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - misbehaviour, err := clienttypes.UnpackMisbehaviour(msg.Misbehaviour) + misbehaviour, err := clienttypes.UnpackClientMessage(msg.Misbehaviour) if err != nil { return nil, err } - if err := k.ClientKeeper.CheckMisbehaviourAndUpdateState(ctx, misbehaviour); err != nil { - return nil, sdkerrors.Wrap(err, "failed to process misbehaviour for IBC client") + if err = k.ClientKeeper.UpdateClient(ctx, msg.ClientId, misbehaviour); err != nil { + return nil, err } return &clienttypes.MsgSubmitMisbehaviourResponse{}, nil diff --git a/modules/core/keeper/msg_server_test.go b/modules/core/keeper/msg_server_test.go index 420e8c429e6..1fd6a73ad87 100644 --- a/modules/core/keeper/msg_server_test.go +++ b/modules/core/keeper/msg_server_test.go @@ -10,13 +10,13 @@ import ( host "github.com/cosmos/ibc-go/v5/modules/core/24-host" "github.com/cosmos/ibc-go/v5/modules/core/exported" "github.com/cosmos/ibc-go/v5/modules/core/keeper" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ibcmock "github.com/cosmos/ibc-go/v5/testing/mock" ) var ( - timeoutHeight = clienttypes.NewHeight(0, 10000) + timeoutHeight = clienttypes.NewHeight(1, 10000) maxSequence = uint64(10) ) @@ -627,15 +627,13 @@ func (suite *KeeperTestSuite) TestHandleTimeoutOnClosePacket() { func (suite *KeeperTestSuite) TestUpgradeClient() { var ( path *ibctesting.Path + newChainID string + newClientHeight clienttypes.Height upgradedClient exported.ClientState upgradedConsState exported.ConsensusState lastHeight exported.Height msg *clienttypes.MsgUpgradeClient ) - - newClientHeight := clienttypes.NewHeight(1, 1) - newChainId := "newChainId-1" - cases := []struct { name string setup func() @@ -644,11 +642,11 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { { name: "successful upgrade", setup: func() { - upgradedClient = ibctmtypes.NewClientState(newChainId, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod+ibctesting.TrustingPeriod, ibctesting.MaxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) + upgradedClient = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod+ibctesting.TrustingPeriod, ibctesting.MaxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) // Call ZeroCustomFields on upgraded clients to clear any client-chosen parameters in test-case upgradedClient upgradedClient = upgradedClient.ZeroCustomFields() - upgradedConsState = &ibctmtypes.ConsensusState{ + upgradedConsState = &ibctm.ConsensusState{ NextValidatorsHash: []byte("nextValsHash"), } @@ -684,11 +682,11 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { { name: "VerifyUpgrade fails", setup: func() { - upgradedClient = ibctmtypes.NewClientState(newChainId, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod+ibctesting.TrustingPeriod, ibctesting.MaxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) + upgradedClient = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod+ibctesting.TrustingPeriod, ibctesting.MaxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) // Call ZeroCustomFields on upgraded clients to clear any client-chosen parameters in test-case upgradedClient upgradedClient = upgradedClient.ZeroCustomFields() - upgradedConsState = &ibctmtypes.ConsensusState{ + upgradedConsState = &ibctm.ConsensusState{ NextValidatorsHash: []byte("nextValsHash"), } @@ -721,9 +719,18 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { path = ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(path) + var err error + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) + revisionNumber := clienttypes.ParseChainID(clientState.ChainId) + + newChainID, err = clienttypes.SetRevisionNumber(clientState.ChainId, revisionNumber+1) + suite.Require().NoError(err) + + newClientHeight = clienttypes.NewHeight(revisionNumber+1, clientState.GetLatestHeight().GetRevisionHeight()+1) + tc.setup() - _, err := keeper.Keeper.UpgradeClient(*suite.chainA.App.GetIBCKeeper(), sdk.WrapSDKContext(suite.chainA.GetContext()), msg) + _, err = keeper.Keeper.UpgradeClient(*suite.chainA.App.GetIBCKeeper(), sdk.WrapSDKContext(suite.chainA.GetContext()), msg) if tc.expPass { suite.Require().NoError(err, "upgrade handler failed on valid case: %s", tc.name) diff --git a/modules/core/legacy/v100/genesis_test.go b/modules/core/legacy/v100/genesis_test.go index fa06a137756..b50a802b935 100644 --- a/modules/core/legacy/v100/genesis_test.go +++ b/modules/core/legacy/v100/genesis_test.go @@ -14,7 +14,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v5/modules/core/03-connection/types" host "github.com/cosmos/ibc-go/v5/modules/core/24-host" - v100 "github.com/cosmos/ibc-go/v5/modules/core/legacy/v100" + "github.com/cosmos/ibc-go/v5/modules/core/legacy/v100" "github.com/cosmos/ibc-go/v5/modules/core/types" ibctesting "github.com/cosmos/ibc-go/v5/testing" "github.com/cosmos/ibc-go/v5/testing/simapp" diff --git a/modules/core/migrations/v5/migrations.go b/modules/core/migrations/v5/migrations.go new file mode 100644 index 00000000000..dec7eb79d80 --- /dev/null +++ b/modules/core/migrations/v5/migrations.go @@ -0,0 +1,44 @@ +package v5 + +import ( + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + + clientkeeper "github.com/cosmos/ibc-go/v5/modules/core/02-client/keeper" + clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v5/modules/core/24-host" + "github.com/cosmos/ibc-go/v5/modules/core/exported" +) + +// Localhost is the client type for a localhost client. It is also used as the clientID +// for the localhost client. +const Localhost string = "09-localhost" + +// MigrateToV5 prunes the 09-Localhost client and associated consensus states from the ibc store +func MigrateToV5(ctx sdk.Context, clientKeeper clientkeeper.Keeper) { + clientStore := clientKeeper.ClientStore(ctx, Localhost) + + iterator := sdk.KVStorePrefixIterator(clientStore, []byte(host.KeyConsensusStatePrefix)) + var heights []exported.Height + + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + keySplit := strings.Split(string(iterator.Key()), "/") + // key is in the format "consensusStates/" + if len(keySplit) != 2 || keySplit[0] != string(host.KeyConsensusStatePrefix) { + continue + } + + // collect consensus states to be pruned + heights = append(heights, clienttypes.MustParseHeight(keySplit[1])) + } + + // delete all consensus states + for _, height := range heights { + clientStore.Delete(host.ConsensusStateKey(height)) + } + + // delete the client state + clientStore.Delete(host.ClientStateKey()) +} diff --git a/modules/core/migrations/v5/migrations_test.go b/modules/core/migrations/v5/migrations_test.go new file mode 100644 index 00000000000..2e70ede1cae --- /dev/null +++ b/modules/core/migrations/v5/migrations_test.go @@ -0,0 +1,116 @@ +package v5_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/suite" + + clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v5/modules/core/24-host" + "github.com/cosmos/ibc-go/v5/modules/core/exported" + v5 "github.com/cosmos/ibc-go/v5/modules/core/migrations/v5" + ibctesting "github.com/cosmos/ibc-go/v5/testing" +) + +type MigrationsV5TestSuite struct { + suite.Suite + + coordinator *ibctesting.Coordinator + + chainA *ibctesting.TestChain + chainB *ibctesting.TestChain +} + +func (suite *MigrationsV5TestSuite) SetupTest() { + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) + + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) + suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) +} + +func TestIBCTestSuite(t *testing.T) { + suite.Run(t, new(MigrationsV5TestSuite)) +} + +func (suite *MigrationsV5TestSuite) TestMigrateToV5() { + var clientStore sdk.KVStore + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success: prune localhost client state", + func() { + clientStore.Set(host.ClientStateKey(), []byte("clientState")) + }, + true, + }, + { + "success: prune localhost client state and consensus states", + func() { + clientStore.Set(host.ClientStateKey(), []byte("clientState")) + + for i := 0; i < 10; i++ { + clientStore.Set(host.ConsensusStateKey(clienttypes.NewHeight(1, uint64(i))), []byte("consensusState")) + } + }, + true, + }, + { + "07-tendermint client state and consensus states remain in client store", + func() { + clientStore = suite.chainA.GetSimApp().IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clienttypes.FormatClientIdentifier(exported.Tendermint, 0)) + clientStore.Set(host.ClientStateKey(), []byte("clientState")) + + for i := 0; i < 10; i++ { + clientStore.Set(host.ConsensusStateKey(clienttypes.NewHeight(1, uint64(i))), []byte("consensusState")) + } + }, + false, + }, + { + "06-solomachine client state and consensus states remain in client store", + func() { + clientStore = suite.chainA.GetSimApp().IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clienttypes.FormatClientIdentifier(exported.Solomachine, 0)) + clientStore.Set(host.ClientStateKey(), []byte("clientState")) + + for i := 0; i < 10; i++ { + clientStore.Set(host.ConsensusStateKey(clienttypes.NewHeight(1, uint64(i))), []byte("consensusState")) + } + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + ctx := suite.chainA.GetContext() + clientStore = suite.chainA.GetSimApp().IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), v5.Localhost) + + tc.malleate() + + v5.MigrateToV5(ctx, suite.chainA.GetSimApp().IBCKeeper.ClientKeeper) + + if tc.expPass { + suite.Require().False(clientStore.Has(host.ClientStateKey())) + + for i := 0; i < 10; i++ { + suite.Require().False(clientStore.Has(host.ConsensusStateKey(clienttypes.NewHeight(1, uint64(i))))) + } + } else { + suite.Require().True(clientStore.Has(host.ClientStateKey())) + + for i := 0; i < 10; i++ { + suite.Require().True(clientStore.Has(host.ConsensusStateKey(clienttypes.NewHeight(1, uint64(i))))) + } + } + }) + } +} diff --git a/modules/core/module.go b/modules/core/module.go index 19b5d445fb7..a2888a6d6bf 100644 --- a/modules/core/module.go +++ b/modules/core/module.go @@ -98,9 +98,6 @@ func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) type AppModule struct { AppModuleBasic keeper *keeper.Keeper - - // create localhost by default - createLocalhost bool } // NewAppModule creates a new AppModule object @@ -157,7 +154,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, bz json.Ra if err != nil { panic(fmt.Sprintf("failed to unmarshal %s genesis state: %s", host.ModuleName, err)) } - InitGenesis(ctx, *am.keeper, am.createLocalhost, &gs) + InitGenesis(ctx, *am.keeper, &gs) return []abci.ValidatorUpdate{} } diff --git a/modules/core/simulation/decoder_test.go b/modules/core/simulation/decoder_test.go index c9575ccbe31..6701dca6b6f 100644 --- a/modules/core/simulation/decoder_test.go +++ b/modules/core/simulation/decoder_test.go @@ -12,7 +12,7 @@ import ( channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v5/modules/core/24-host" "github.com/cosmos/ibc-go/v5/modules/core/simulation" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" "github.com/cosmos/ibc-go/v5/testing/simapp" ) @@ -25,7 +25,7 @@ func TestDecodeStore(t *testing.T) { channelID := "channelidone" portID := "portidone" - clientState := &ibctmtypes.ClientState{ + clientState := &ibctm.ClientState{ FrozenHeight: clienttypes.NewHeight(0, 10), } connection := connectiontypes.ConnectionEnd{ diff --git a/modules/core/types/codec.go b/modules/core/types/codec.go index d597141005f..5911d6d7215 100644 --- a/modules/core/types/codec.go +++ b/modules/core/types/codec.go @@ -7,9 +7,8 @@ import ( connectiontypes "github.com/cosmos/ibc-go/v5/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" - solomachinetypes "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine/types" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" - localhosttypes "github.com/cosmos/ibc-go/v5/modules/light-clients/09-localhost/types" + solomachinetypes "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ) // RegisterInterfaces registers x/ibc interfaces into protobuf Any. @@ -18,7 +17,6 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { connectiontypes.RegisterInterfaces(registry) channeltypes.RegisterInterfaces(registry) solomachinetypes.RegisterInterfaces(registry) - ibctmtypes.RegisterInterfaces(registry) - localhosttypes.RegisterInterfaces(registry) + ibctm.RegisterInterfaces(registry) commitmenttypes.RegisterInterfaces(registry) } diff --git a/modules/light-clients/06-solomachine/client_state.go b/modules/light-clients/06-solomachine/client_state.go new file mode 100644 index 00000000000..29474f0d32b --- /dev/null +++ b/modules/light-clients/06-solomachine/client_state.go @@ -0,0 +1,260 @@ +package solomachine + +import ( + "reflect" + + "github.com/cosmos/cosmos-sdk/codec" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + + clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v5/modules/core/24-host" + "github.com/cosmos/ibc-go/v5/modules/core/exported" +) + +var _ exported.ClientState = (*ClientState)(nil) + +// NewClientState creates a new ClientState instance. +func NewClientState(latestSequence uint64, consensusState *ConsensusState, allowUpdateAfterProposal bool) *ClientState { + return &ClientState{ + Sequence: latestSequence, + IsFrozen: false, + ConsensusState: consensusState, + AllowUpdateAfterProposal: allowUpdateAfterProposal, + } +} + +// ClientType is Solo Machine. +func (cs ClientState) ClientType() string { + return exported.Solomachine +} + +// GetLatestHeight returns the latest sequence number. +// Return exported.Height to satisfy ClientState interface +// Revision number is always 0 for a solo-machine. +func (cs ClientState) GetLatestHeight() exported.Height { + return clienttypes.NewHeight(0, cs.Sequence) +} + +// GetTimestampAtHeight returns the timestamp in nanoseconds of the consensus state at the given height. +func (cs ClientState) GetTimestampAtHeight( + _ sdk.Context, + clientStore sdk.KVStore, + cdc codec.BinaryCodec, + height exported.Height, +) (uint64, error) { + if !cs.GetLatestHeight().EQ(height) { + return 0, sdkerrors.Wrapf(ErrInvalidSequence, "not latest height (%s)", height) + } + return cs.ConsensusState.Timestamp, nil +} + +// Status returns the status of the solo machine client. +// The client may be: +// - Active: if frozen sequence is 0 +// - Frozen: otherwise solo machine is frozen +func (cs ClientState) Status(_ sdk.Context, _ sdk.KVStore, _ codec.BinaryCodec) exported.Status { + if cs.IsFrozen { + return exported.Frozen + } + + return exported.Active +} + +// Validate performs basic validation of the client state fields. +func (cs ClientState) Validate() error { + if cs.Sequence == 0 { + return sdkerrors.Wrap(clienttypes.ErrInvalidClient, "sequence cannot be 0") + } + if cs.ConsensusState == nil { + return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "consensus state cannot be nil") + } + return cs.ConsensusState.ValidateBasic() +} + +// ZeroCustomFields returns solomachine client state with client-specific fields FrozenSequence, +// and AllowUpdateAfterProposal zeroed out +func (cs ClientState) ZeroCustomFields() exported.ClientState { + return NewClientState( + cs.Sequence, cs.ConsensusState, false, + ) +} + +// Initialize will check that initial consensus state is equal to the latest consensus state of the initial client. +func (cs ClientState) Initialize(_ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, consState exported.ConsensusState) error { + if !reflect.DeepEqual(cs.ConsensusState, consState) { + return sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "consensus state in initial client does not equal initial consensus state. expected: %s, got: %s", + cs.ConsensusState, consState) + } + return nil +} + +// ExportMetadata is a no-op since solomachine does not store any metadata in client store +func (cs ClientState) ExportMetadata(_ sdk.KVStore) []exported.GenesisMetadata { + return nil +} + +// VerifyUpgradeAndUpdateState returns an error since solomachine client does not support upgrades +func (cs ClientState) VerifyUpgradeAndUpdateState( + _ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, + _ exported.ClientState, _ exported.ConsensusState, _, _ []byte, +) error { + return sdkerrors.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade solomachine client") +} + +// VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. +// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +func (cs *ClientState) VerifyMembership( + ctx sdk.Context, + clientStore sdk.KVStore, + cdc codec.BinaryCodec, + height exported.Height, + delayTimePeriod uint64, + delayBlockPeriod uint64, + proof []byte, + path []byte, + value []byte, +) error { + publicKey, sigData, timestamp, sequence, err := produceVerificationArgs(cdc, cs, height, proof) + if err != nil { + return err + } + + var merklePath commitmenttypes.MerklePath + if err := cdc.Unmarshal(path, &merklePath); err != nil { + return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "failed to unmarshal path into ICS 23 commitment merkle path") + } + + signBytes := &SignBytes{ + Sequence: sequence, + Timestamp: timestamp, + Diversifier: cs.ConsensusState.Diversifier, + Path: []byte(merklePath.String()), + Data: value, + } + + signBz, err := cdc.Marshal(signBytes) + if err != nil { + return err + } + + if err := VerifySignature(publicKey, signBz, sigData); err != nil { + return err + } + + cs.Sequence++ + cs.ConsensusState.Timestamp = timestamp + setClientState(clientStore, cdc, cs) + + return nil +} + +// 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). +func (cs *ClientState) VerifyNonMembership( + ctx sdk.Context, + clientStore sdk.KVStore, + cdc codec.BinaryCodec, + height exported.Height, + delayTimePeriod uint64, + delayBlockPeriod uint64, + proof []byte, + path []byte, +) error { + publicKey, sigData, timestamp, sequence, err := produceVerificationArgs(cdc, cs, height, proof) + if err != nil { + return err + } + + var merklePath commitmenttypes.MerklePath + if err := cdc.Unmarshal(path, &merklePath); err != nil { + return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "failed to unmarshal path into ICS 23 commitment merkle path") + } + + signBytes := &SignBytes{ + Sequence: sequence, + Timestamp: timestamp, + Diversifier: cs.ConsensusState.Diversifier, + Path: []byte(merklePath.String()), + Data: nil, + } + + signBz, err := cdc.Marshal(signBytes) + if err != nil { + return err + } + + if err := VerifySignature(publicKey, signBz, sigData); err != nil { + return err + } + + cs.Sequence++ + cs.ConsensusState.Timestamp = timestamp + setClientState(clientStore, cdc, cs) + + return nil +} + +// produceVerificationArgs perfoms the basic checks on the arguments that are +// shared between the verification functions and returns the public key of the +// consensus state, the unmarshalled proof representing the signature and timestamp +// along with the solo-machine sequence encoded in the proofHeight. +func produceVerificationArgs( + cdc codec.BinaryCodec, + cs *ClientState, + height exported.Height, + proof []byte, +) (cryptotypes.PubKey, signing.SignatureData, uint64, uint64, error) { + if revision := height.GetRevisionNumber(); revision != 0 { + return nil, nil, 0, 0, sdkerrors.Wrapf(sdkerrors.ErrInvalidHeight, "revision must be 0 for solomachine, got revision-number: %d", revision) + } + + if proof == nil { + return nil, nil, 0, 0, sdkerrors.Wrap(ErrInvalidProof, "proof cannot be empty") + } + + var timestampedSigData TimestampedSignatureData + if err := cdc.Unmarshal(proof, ×tampedSigData); err != nil { + return nil, nil, 0, 0, sdkerrors.Wrapf(err, "failed to unmarshal proof into type %T", timestampedSigData) + } + + timestamp := timestampedSigData.Timestamp + if len(timestampedSigData.SignatureData) == 0 { + return nil, nil, 0, 0, sdkerrors.Wrap(ErrInvalidProof, "signature data cannot be empty") + } + + sigData, err := UnmarshalSignatureData(cdc, timestampedSigData.SignatureData) + if err != nil { + return nil, nil, 0, 0, err + } + + // sequence is encoded in the revision height of height struct + sequence := height.GetRevisionHeight() + latestSequence := cs.GetLatestHeight().GetRevisionHeight() + if latestSequence != sequence { + return nil, nil, 0, 0, sdkerrors.Wrapf( + sdkerrors.ErrInvalidHeight, + "client state sequence != proof sequence (%d != %d)", latestSequence, sequence, + ) + } + + if cs.ConsensusState.GetTimestamp() > timestamp { + return nil, nil, 0, 0, sdkerrors.Wrapf(ErrInvalidProof, "the consensus state timestamp is greater than the signature timestamp (%d >= %d)", cs.ConsensusState.GetTimestamp(), timestamp) + } + + publicKey, err := cs.ConsensusState.GetPubKey() + if err != nil { + return nil, nil, 0, 0, err + } + + return publicKey, sigData, timestamp, sequence, nil +} + +// sets the client state to the store +func setClientState(store sdk.KVStore, cdc codec.BinaryCodec, clientState exported.ClientState) { + bz := clienttypes.MustMarshalClientState(cdc, clientState) + store.Set([]byte(host.KeyClientState), bz) +} diff --git a/modules/light-clients/06-solomachine/client_state_test.go b/modules/light-clients/06-solomachine/client_state_test.go new file mode 100644 index 00000000000..68bf15cace9 --- /dev/null +++ b/modules/light-clients/06-solomachine/client_state_test.go @@ -0,0 +1,875 @@ +package solomachine_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v5/modules/core/exported" + solomachine "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v5/testing" +) + +const ( + counterpartyClientIdentifier = "chainA" + testConnectionID = "connectionid" + testChannelID = "testchannelid" + testPortID = "testportid" +) + +func (suite *SoloMachineTestSuite) TestStatus() { + clientState := suite.solomachine.ClientState() + // solo machine discards arguments + status := clientState.Status(suite.chainA.GetContext(), nil, nil) + suite.Require().Equal(exported.Active, status) + + // freeze solo machine + clientState.IsFrozen = true + status = clientState.Status(suite.chainA.GetContext(), nil, nil) + suite.Require().Equal(exported.Frozen, status) +} + +func (suite *SoloMachineTestSuite) TestClientStateValidateBasic() { + // test singlesig and multisig public keys + for _, sm := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { + + testCases := []struct { + name string + clientState *solomachine.ClientState + expPass bool + }{ + { + "valid client state", + sm.ClientState(), + true, + }, + { + "empty ClientState", + &solomachine.ClientState{}, + false, + }, + { + "sequence is zero", + solomachine.NewClientState(0, &solomachine.ConsensusState{sm.ConsensusState().PublicKey, sm.Diversifier, sm.Time}, false), + false, + }, + { + "timestamp is zero", + solomachine.NewClientState(1, &solomachine.ConsensusState{sm.ConsensusState().PublicKey, sm.Diversifier, 0}, false), + false, + }, + { + "diversifier is blank", + solomachine.NewClientState(1, &solomachine.ConsensusState{sm.ConsensusState().PublicKey, " ", 1}, false), + false, + }, + { + "pubkey is empty", + solomachine.NewClientState(1, &solomachine.ConsensusState{nil, sm.Diversifier, sm.Time}, false), + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + + err := tc.clientState.Validate() + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } + } +} + +func (suite *SoloMachineTestSuite) TestInitialize() { + // test singlesig and multisig public keys + for _, sm := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { + malleatedConsensus := sm.ClientState().ConsensusState + malleatedConsensus.Timestamp = malleatedConsensus.Timestamp + 10 + + testCases := []struct { + name string + consState exported.ConsensusState + expPass bool + }{ + { + "valid consensus state", + sm.ConsensusState(), + true, + }, + { + "nil consensus state", + nil, + false, + }, + { + "invalid consensus state: Tendermint consensus state", + &ibctm.ConsensusState{}, + false, + }, + { + "invalid consensus state: consensus state does not match consensus state in client", + malleatedConsensus, + false, + }, + } + + for _, tc := range testCases { + err := sm.ClientState().Initialize( + suite.chainA.GetContext(), suite.chainA.Codec, + suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "solomachine"), + tc.consState, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid testcase: %s failed", tc.name) + } else { + suite.Require().Error(err, "invalid testcase: %s passed", tc.name) + } + } + } +} + +func (suite *SoloMachineTestSuite) TestVerifyMembership() { + // test singlesig and multisig public keys + for _, sm := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { + + var ( + clientState *solomachine.ClientState + err error + height clienttypes.Height + path []byte + proof []byte + testingPath *ibctesting.Path + signBytes solomachine.SignBytes + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "success: client state verification", + func() { + clientState = sm.ClientState() + clientStateBz, err := suite.chainA.Codec.Marshal(clientState) + suite.Require().NoError(err) + + merklePath := suite.solomachine.GetClientStatePath(counterpartyClientIdentifier) + signBytes = solomachine.SignBytes{ + Sequence: sm.GetHeight().GetRevisionHeight(), + Timestamp: sm.Time, + Diversifier: sm.Diversifier, + Path: []byte(merklePath.String()), + Data: clientStateBz, + } + + signBz, err := suite.chainA.Codec.Marshal(&signBytes) + suite.Require().NoError(err) + + sig := sm.GenerateSignature(signBz) + + signatureDoc := &solomachine.TimestampedSignatureData{ + SignatureData: sig, + Timestamp: sm.Time, + } + + path, err = suite.chainA.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, err = suite.chainA.Codec.Marshal(signatureDoc) + suite.Require().NoError(err) + + }, + true, + }, + { + "success: consensus state verification", + func() { + clientState = sm.ClientState() + consensusState := clientState.ConsensusState + consensusStateBz, err := suite.chainA.Codec.Marshal(consensusState) + suite.Require().NoError(err) + + merklePath := sm.GetConsensusStatePath(counterpartyClientIdentifier, height) + signBytes = solomachine.SignBytes{ + Sequence: sm.Sequence, + Timestamp: sm.Time, + Diversifier: sm.Diversifier, + Path: []byte(merklePath.String()), + Data: consensusStateBz, + } + + signBz, err := suite.chainA.Codec.Marshal(&signBytes) + suite.Require().NoError(err) + + sig := sm.GenerateSignature(signBz) + + signatureDoc := &solomachine.TimestampedSignatureData{ + SignatureData: sig, + Timestamp: sm.Time, + } + + path, err = suite.chainA.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, err = suite.chainA.Codec.Marshal(signatureDoc) + suite.Require().NoError(err) + }, + true, + }, + { + "success: connection state verification", + func() { + suite.coordinator.SetupConnections(testingPath) + + connectionEnd, found := suite.chainA.GetSimApp().IBCKeeper.ConnectionKeeper.GetConnection(suite.chainA.GetContext(), ibctesting.FirstConnectionID) + suite.Require().True(found) + + connectionEndBz, err := suite.chainA.Codec.Marshal(&connectionEnd) + suite.Require().NoError(err) + + merklePath := sm.GetConnectionStatePath(ibctesting.FirstConnectionID) + signBytes = solomachine.SignBytes{ + Sequence: sm.Sequence, + Timestamp: sm.Time, + Diversifier: sm.Diversifier, + Path: []byte(merklePath.String()), + Data: connectionEndBz, + } + + signBz, err := suite.chainA.Codec.Marshal(&signBytes) + suite.Require().NoError(err) + + sig := sm.GenerateSignature(signBz) + + signatureDoc := &solomachine.TimestampedSignatureData{ + SignatureData: sig, + Timestamp: sm.Time, + } + + path, err = suite.chainA.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, err = suite.chainA.Codec.Marshal(signatureDoc) + suite.Require().NoError(err) + }, + true, + }, + { + "success: channel state verification", + func() { + suite.coordinator.SetupConnections(testingPath) + suite.coordinator.CreateMockChannels(testingPath) + + channelEnd, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetChannel(suite.chainA.GetContext(), ibctesting.MockPort, ibctesting.FirstChannelID) + suite.Require().True(found) + + channelEndBz, err := suite.chainA.Codec.Marshal(&channelEnd) + suite.Require().NoError(err) + + merklePath := sm.GetChannelStatePath(ibctesting.MockPort, ibctesting.FirstChannelID) + signBytes = solomachine.SignBytes{ + Sequence: sm.Sequence, + Timestamp: sm.Time, + Diversifier: sm.Diversifier, + Path: []byte(merklePath.String()), + Data: channelEndBz, + } + + signBz, err := suite.chainA.Codec.Marshal(&signBytes) + suite.Require().NoError(err) + + sig := sm.GenerateSignature(signBz) + + signatureDoc := &solomachine.TimestampedSignatureData{ + SignatureData: sig, + Timestamp: sm.Time, + } + + path, err = suite.chainA.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, err = suite.chainA.Codec.Marshal(signatureDoc) + suite.Require().NoError(err) + }, + true, + }, + { + "success: next sequence recv verification", + func() { + suite.coordinator.SetupConnections(testingPath) + suite.coordinator.CreateMockChannels(testingPath) + + nextSeqRecv, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.GetNextSequenceRecv(suite.chainA.GetContext(), ibctesting.MockPort, ibctesting.FirstChannelID) + suite.Require().True(found) + + merklePath := sm.GetNextSequenceRecvPath(ibctesting.MockPort, ibctesting.FirstChannelID) + signBytes = solomachine.SignBytes{ + Sequence: sm.Sequence, + Timestamp: sm.Time, + Diversifier: sm.Diversifier, + Path: []byte(merklePath.String()), + Data: sdk.Uint64ToBigEndian(nextSeqRecv), + } + + signBz, err := suite.chainA.Codec.Marshal(&signBytes) + suite.Require().NoError(err) + + sig := sm.GenerateSignature(signBz) + + signatureDoc := &solomachine.TimestampedSignatureData{ + SignatureData: sig, + Timestamp: sm.Time, + } + + path, err = suite.chainA.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, err = suite.chainA.Codec.Marshal(signatureDoc) + suite.Require().NoError(err) + }, + true, + }, + { + "success: packet commitment verification", + func() { + packet := channeltypes.NewPacket( + ibctesting.MockPacketData, + 1, + ibctesting.MockPort, + ibctesting.FirstChannelID, + ibctesting.MockPort, + ibctesting.FirstChannelID, + clienttypes.NewHeight(0, 10), + 0, + ) + + commitmentBz := channeltypes.CommitPacket(suite.chainA.Codec, packet) + merklePath := sm.GetPacketCommitmentPath(ibctesting.MockPort, ibctesting.FirstChannelID) + signBytes = solomachine.SignBytes{ + Sequence: sm.Sequence, + Timestamp: sm.Time, + Diversifier: sm.Diversifier, + Path: []byte(merklePath.String()), + Data: commitmentBz, + } + + signBz, err := suite.chainA.Codec.Marshal(&signBytes) + suite.Require().NoError(err) + + sig := sm.GenerateSignature(signBz) + + signatureDoc := &solomachine.TimestampedSignatureData{ + SignatureData: sig, + Timestamp: sm.Time, + } + + path, err = suite.chainA.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, err = suite.chainA.Codec.Marshal(signatureDoc) + suite.Require().NoError(err) + }, + true, + }, + { + "success: packet acknowledgement verification", + func() { + merklePath := sm.GetPacketAcknowledgementPath(ibctesting.MockPort, ibctesting.FirstChannelID) + signBytes = solomachine.SignBytes{ + Sequence: sm.Sequence, + Timestamp: sm.Time, + Diversifier: sm.Diversifier, + Path: []byte(merklePath.String()), + Data: ibctesting.MockAcknowledgement, + } + + signBz, err := suite.chainA.Codec.Marshal(&signBytes) + suite.Require().NoError(err) + + sig := sm.GenerateSignature(signBz) + + signatureDoc := &solomachine.TimestampedSignatureData{ + SignatureData: sig, + Timestamp: sm.Time, + } + + path, err = suite.chainA.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, err = suite.chainA.Codec.Marshal(signatureDoc) + suite.Require().NoError(err) + }, + true, + }, + { + "success: packet receipt verification", + func() { + merklePath := sm.GetPacketReceiptPath(ibctesting.MockPort, ibctesting.FirstChannelID) + signBytes = solomachine.SignBytes{ + Sequence: sm.Sequence, + Timestamp: sm.Time, + Diversifier: sm.Diversifier, + Path: []byte(merklePath.String()), + Data: []byte{byte(1)}, // packet receipt is stored as a single byte + } + + signBz, err := suite.chainA.Codec.Marshal(&signBytes) + suite.Require().NoError(err) + + sig := sm.GenerateSignature(signBz) + + signatureDoc := &solomachine.TimestampedSignatureData{ + SignatureData: sig, + Timestamp: sm.Time, + } + + path, err = suite.chainA.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, err = suite.chainA.Codec.Marshal(signatureDoc) + suite.Require().NoError(err) + }, + true, + }, + { + "client state latest height is less than sequence", + func() { + consensusState := &solomachine.ConsensusState{ + Timestamp: sm.Time, + PublicKey: sm.ConsensusState().PublicKey, + } + + clientState = solomachine.NewClientState(sm.Sequence-1, consensusState, false) + }, + false, + }, + { + "height revision number is not zero", + func() { + height = clienttypes.NewHeight(1, sm.GetHeight().GetRevisionHeight()) + }, + false, + }, + { + "malformed merkle path fails to unmarshal", + func() { + path = []byte("invalid path") + }, + false, + }, + { + "malformed proof fails to unmarshal", + func() { + merklePath := suite.solomachine.GetClientStatePath(counterpartyClientIdentifier) + path, err = suite.chainA.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof = []byte("invalid proof") + }, + false, + }, + { + "consensus state timestamp is greater than signature", + func() { + consensusState := &solomachine.ConsensusState{ + Timestamp: sm.Time + 1, + PublicKey: sm.ConsensusState().PublicKey, + } + + clientState = solomachine.NewClientState(sm.Sequence, consensusState, false) + }, + false, + }, + { + "signature data is nil", + func() { + signatureDoc := &solomachine.TimestampedSignatureData{ + SignatureData: nil, + Timestamp: sm.Time, + } + + proof, err = suite.chainA.Codec.Marshal(signatureDoc) + suite.Require().NoError(err) + }, + false, + }, + { + "consensus state public key is nil", + func() { + clientState.ConsensusState.PublicKey = nil + }, + false, + }, + { + "malformed signature data fails to unmarshal", + func() { + signatureDoc := &solomachine.TimestampedSignatureData{ + SignatureData: []byte("invalid signature data"), + Timestamp: sm.Time, + } + + proof, err = suite.chainA.Codec.Marshal(signatureDoc) + suite.Require().NoError(err) + }, + false, + }, + { + "proof is nil", + func() { + proof = nil + }, + false, + }, + { + "proof verification failed", + func() { + signBytes.Data = []byte("invalid membership data value") + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() + testingPath = ibctesting.NewPath(suite.chainA, suite.chainB) + + clientState = sm.ClientState() + height = clienttypes.NewHeight(sm.GetHeight().GetRevisionNumber(), sm.GetHeight().GetRevisionHeight()) + + merklePath := commitmenttypes.NewMerklePath("ibc", "solomachine") + signBytes = solomachine.SignBytes{ + Sequence: sm.GetHeight().GetRevisionHeight(), + Timestamp: sm.Time, + Diversifier: sm.Diversifier, + Path: []byte(merklePath.String()), + Data: []byte("solomachine"), + } + + signBz, err := suite.chainA.Codec.Marshal(&signBytes) + suite.Require().NoError(err) + + sig := sm.GenerateSignature(signBz) + + signatureDoc := &solomachine.TimestampedSignatureData{ + SignatureData: sig, + Timestamp: sm.Time, + } + + path, err = suite.chainA.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, err = suite.chainA.Codec.Marshal(signatureDoc) + suite.Require().NoError(err) + + tc.malleate() + + var expSeq uint64 + if clientState.ConsensusState != nil { + expSeq = clientState.Sequence + 1 + } + + err = clientState.VerifyMembership( + suite.chainA.GetContext(), suite.store, suite.chainA.Codec, + height, 0, 0, // solomachine does not check delay periods + proof, path, signBytes.Data, + ) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(expSeq, clientState.Sequence) + suite.Require().Equal(expSeq, suite.GetSequenceFromStore(), "sequence not updated in the store (%d) on valid test case %s", suite.GetSequenceFromStore(), tc.name) + } else { + suite.Require().Error(err) + } + }) + } + } +} + +func (suite *SoloMachineTestSuite) TestVerifyNonMembership() { + // test singlesig and multisig public keys + for _, sm := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { + + var ( + clientState *solomachine.ClientState + err error + height clienttypes.Height + path []byte + proof []byte + signBytes solomachine.SignBytes + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "success: packet receipt absence verification", + func() { + merklePath := suite.solomachine.GetPacketReceiptPath(ibctesting.MockPort, ibctesting.FirstChannelID) + signBytes = solomachine.SignBytes{ + Sequence: sm.GetHeight().GetRevisionHeight(), + Timestamp: sm.Time, + Diversifier: sm.Diversifier, + Path: []byte(merklePath.String()), + Data: nil, + } + + signBz, err := suite.chainA.Codec.Marshal(&signBytes) + suite.Require().NoError(err) + + sig := sm.GenerateSignature(signBz) + + signatureDoc := &solomachine.TimestampedSignatureData{ + SignatureData: sig, + Timestamp: sm.Time, + } + + path, err = suite.chainA.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, err = suite.chainA.Codec.Marshal(signatureDoc) + suite.Require().NoError(err) + }, + true, + }, + { + "client state latest height is less than sequence", + func() { + consensusState := &solomachine.ConsensusState{ + Timestamp: sm.Time, + PublicKey: sm.ConsensusState().PublicKey, + } + + clientState = solomachine.NewClientState(sm.Sequence-1, consensusState, false) + }, + false, + }, + { + "height revision number is not zero", + func() { + height = clienttypes.NewHeight(1, sm.GetHeight().GetRevisionHeight()) + }, + false, + }, + { + "malformed merkle path fails to unmarshal", + func() { + path = []byte("invalid path") + }, + false, + }, + { + "malformed proof fails to unmarshal", + func() { + merklePath := suite.solomachine.GetClientStatePath(counterpartyClientIdentifier) + path, err = suite.chainA.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof = []byte("invalid proof") + }, + false, + }, + { + "consensus state timestamp is greater than signature", + func() { + consensusState := &solomachine.ConsensusState{ + Timestamp: sm.Time + 1, + PublicKey: sm.ConsensusState().PublicKey, + } + + clientState = solomachine.NewClientState(sm.Sequence, consensusState, false) + }, + false, + }, + { + "signature data is nil", + func() { + signatureDoc := &solomachine.TimestampedSignatureData{ + SignatureData: nil, + Timestamp: sm.Time, + } + + proof, err = suite.chainA.Codec.Marshal(signatureDoc) + suite.Require().NoError(err) + }, + false, + }, + { + "consensus state public key is nil", + func() { + clientState.ConsensusState.PublicKey = nil + }, + false, + }, + { + "malformed signature data fails to unmarshal", + func() { + signatureDoc := &solomachine.TimestampedSignatureData{ + SignatureData: []byte("invalid signature data"), + Timestamp: sm.Time, + } + + proof, err = suite.chainA.Codec.Marshal(signatureDoc) + suite.Require().NoError(err) + }, + false, + }, + { + "proof is nil", + func() { + proof = nil + }, + false, + }, + { + "proof verification failed", + func() { + signBytes.Data = []byte("invalid non-membership data value") + + signBz, err := suite.chainA.Codec.Marshal(&signBytes) + suite.Require().NoError(err) + + sig := sm.GenerateSignature(signBz) + + signatureDoc := &solomachine.TimestampedSignatureData{ + SignatureData: sig, + Timestamp: sm.Time, + } + + proof, err = suite.chainA.Codec.Marshal(signatureDoc) + suite.Require().NoError(err) + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + clientState = sm.ClientState() + height = clienttypes.NewHeight(sm.GetHeight().GetRevisionNumber(), sm.GetHeight().GetRevisionHeight()) + + merklePath := commitmenttypes.NewMerklePath("ibc", "solomachine") + signBytes = solomachine.SignBytes{ + Sequence: sm.GetHeight().GetRevisionHeight(), + Timestamp: sm.Time, + Diversifier: sm.Diversifier, + Path: []byte(merklePath.String()), + Data: nil, + } + + signBz, err := suite.chainA.Codec.Marshal(&signBytes) + suite.Require().NoError(err) + + sig := sm.GenerateSignature(signBz) + + signatureDoc := &solomachine.TimestampedSignatureData{ + SignatureData: sig, + Timestamp: sm.Time, + } + + path, err = suite.chainA.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, err = suite.chainA.Codec.Marshal(signatureDoc) + suite.Require().NoError(err) + + tc.malleate() + + var expSeq uint64 + if clientState.ConsensusState != nil { + expSeq = clientState.Sequence + 1 + } + + err = clientState.VerifyNonMembership( + suite.chainA.GetContext(), suite.store, suite.chainA.Codec, + height, 0, 0, // solomachine does not check delay periods + proof, path, + ) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(expSeq, clientState.Sequence) + suite.Require().Equal(expSeq, suite.GetSequenceFromStore(), "sequence not updated in the store (%d) on valid test case %s", suite.GetSequenceFromStore(), tc.name) + } else { + suite.Require().Error(err) + } + }) + } + } +} + +func (suite *SoloMachineTestSuite) TestGetTimestampAtHeight() { + tmPath := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupClients(tmPath) + // Single setup for all test cases. + suite.SetupTest() + + testCases := []struct { + name string + clientState *solomachine.ClientState + height exported.Height + expValue uint64 + expPass bool + }{ + { + name: "get timestamp at height exists", + clientState: suite.solomachine.ClientState(), + height: suite.solomachine.ClientState().GetLatestHeight(), + expValue: suite.solomachine.ClientState().ConsensusState.Timestamp, + expPass: true, + }, + { + name: "get timestamp at height not exists", + clientState: suite.solomachine.ClientState(), + height: suite.solomachine.ClientState().GetLatestHeight().Increment(), + }, + } + + for i, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + ctx := suite.chainA.GetContext() + + ts, err := tc.clientState.GetTimestampAtHeight( + ctx, suite.store, suite.chainA.Codec, tc.height, + ) + + suite.Require().Equal(tc.expValue, ts) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) + } + }) + } +} diff --git a/modules/light-clients/06-solomachine/codec.go b/modules/light-clients/06-solomachine/codec.go new file mode 100644 index 00000000000..2792e19c759 --- /dev/null +++ b/modules/light-clients/06-solomachine/codec.go @@ -0,0 +1,42 @@ +package solomachine + +import ( + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + + "github.com/cosmos/ibc-go/v5/modules/core/exported" +) + +// RegisterInterfaces register the ibc channel submodule interfaces to protobuf +// Any. +func RegisterInterfaces(registry codectypes.InterfaceRegistry) { + registry.RegisterImplementations( + (*exported.ClientState)(nil), + &ClientState{}, + ) + registry.RegisterImplementations( + (*exported.ConsensusState)(nil), + &ConsensusState{}, + ) + registry.RegisterImplementations( + (*exported.ClientMessage)(nil), + &Header{}, + ) + registry.RegisterImplementations( + (*exported.ClientMessage)(nil), + &Misbehaviour{}, + ) +} + +func UnmarshalSignatureData(cdc codec.BinaryCodec, data []byte) (signing.SignatureData, error) { + protoSigData := &signing.SignatureDescriptor_Data{} + if err := cdc.Unmarshal(data, protoSigData); err != nil { + return nil, sdkerrors.Wrapf(err, "failed to unmarshal proof into type %T", protoSigData) + } + + sigData := signing.SignatureDataFromProto(protoSigData) + + return sigData, nil +} diff --git a/modules/light-clients/06-solomachine/types/consensus_state.go b/modules/light-clients/06-solomachine/consensus_state.go similarity index 92% rename from modules/light-clients/06-solomachine/types/consensus_state.go rename to modules/light-clients/06-solomachine/consensus_state.go index 76a034b2760..1f63823663f 100644 --- a/modules/light-clients/06-solomachine/types/consensus_state.go +++ b/modules/light-clients/06-solomachine/consensus_state.go @@ -1,4 +1,4 @@ -package types +package solomachine import ( "strings" @@ -22,11 +22,6 @@ func (cs ConsensusState) GetTimestamp() uint64 { return cs.Timestamp } -// GetRoot returns nil since solo machines do not have roots. -func (cs ConsensusState) GetRoot() exported.Root { - return nil -} - // GetPubKey unmarshals the public key into a cryptotypes.PubKey type. // An error is returned if the public key is nil or the cached value // is not a PubKey. diff --git a/modules/light-clients/06-solomachine/types/consensus_state_test.go b/modules/light-clients/06-solomachine/consensus_state_test.go similarity index 62% rename from modules/light-clients/06-solomachine/types/consensus_state_test.go rename to modules/light-clients/06-solomachine/consensus_state_test.go index 5a2f519af1e..6319c418931 100644 --- a/modules/light-clients/06-solomachine/types/consensus_state_test.go +++ b/modules/light-clients/06-solomachine/consensus_state_test.go @@ -1,8 +1,8 @@ -package types_test +package solomachine_test import ( "github.com/cosmos/ibc-go/v5/modules/core/exported" - "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine/types" + solomachine "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) @@ -11,46 +11,45 @@ func (suite *SoloMachineTestSuite) TestConsensusState() { suite.Require().Equal(exported.Solomachine, consensusState.ClientType()) suite.Require().Equal(suite.solomachine.Time, consensusState.GetTimestamp()) - suite.Require().Nil(consensusState.GetRoot()) } func (suite *SoloMachineTestSuite) TestConsensusStateValidateBasic() { // test singlesig and multisig public keys - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { + for _, sm := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { testCases := []struct { name string - consensusState *types.ConsensusState + consensusState *solomachine.ConsensusState expPass bool }{ { "valid consensus state", - solomachine.ConsensusState(), + sm.ConsensusState(), true, }, { "timestamp is zero", - &types.ConsensusState{ - PublicKey: solomachine.ConsensusState().PublicKey, + &solomachine.ConsensusState{ + PublicKey: sm.ConsensusState().PublicKey, Timestamp: 0, - Diversifier: solomachine.Diversifier, + Diversifier: sm.Diversifier, }, false, }, { "diversifier is blank", - &types.ConsensusState{ - PublicKey: solomachine.ConsensusState().PublicKey, - Timestamp: solomachine.Time, + &solomachine.ConsensusState{ + PublicKey: sm.ConsensusState().PublicKey, + Timestamp: sm.Time, Diversifier: " ", }, false, }, { "pubkey is nil", - &types.ConsensusState{ - Timestamp: solomachine.Time, - Diversifier: solomachine.Diversifier, + &solomachine.ConsensusState{ + Timestamp: sm.Time, + Diversifier: sm.Diversifier, PublicKey: nil, }, false, diff --git a/modules/light-clients/06-solomachine/types/errors.go b/modules/light-clients/06-solomachine/errors.go similarity index 85% rename from modules/light-clients/06-solomachine/types/errors.go rename to modules/light-clients/06-solomachine/errors.go index 3e27f60732a..7f41349337d 100644 --- a/modules/light-clients/06-solomachine/types/errors.go +++ b/modules/light-clients/06-solomachine/errors.go @@ -1,4 +1,4 @@ -package types +package solomachine import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -14,5 +14,4 @@ var ( ErrInvalidSignatureAndData = sdkerrors.Register(SubModuleName, 4, "invalid signature and data") ErrSignatureVerificationFailed = sdkerrors.Register(SubModuleName, 5, "signature verification failed") ErrInvalidProof = sdkerrors.Register(SubModuleName, 6, "invalid solo machine proof") - ErrInvalidDataType = sdkerrors.Register(SubModuleName, 7, "invalid data type") ) diff --git a/modules/light-clients/06-solomachine/types/header.go b/modules/light-clients/06-solomachine/header.go similarity index 85% rename from modules/light-clients/06-solomachine/types/header.go rename to modules/light-clients/06-solomachine/header.go index e22d0d605a9..b5bfe11f28d 100644 --- a/modules/light-clients/06-solomachine/types/header.go +++ b/modules/light-clients/06-solomachine/header.go @@ -1,4 +1,4 @@ -package types +package solomachine import ( "strings" @@ -10,20 +10,13 @@ import ( "github.com/cosmos/ibc-go/v5/modules/core/exported" ) -var _ exported.Header = &Header{} +var _ exported.ClientMessage = &Header{} // ClientType defines that the Header is a Solo Machine. func (Header) ClientType() string { return exported.Solomachine } -// GetHeight returns the current sequence number as the height. -// Return clientexported.Height to satisfy interface -// Revision number is always 0 for a solo-machine -func (h Header) GetHeight() exported.Height { - return clienttypes.NewHeight(0, h.Sequence) -} - // GetPubKey unmarshals the new public key into a cryptotypes.PubKey type. // An error is returned if the new public key is nil or the cached value // is not a PubKey. diff --git a/modules/light-clients/06-solomachine/types/header_test.go b/modules/light-clients/06-solomachine/header_test.go similarity index 82% rename from modules/light-clients/06-solomachine/types/header_test.go rename to modules/light-clients/06-solomachine/header_test.go index fb771b4c684..1a0ce46ee33 100644 --- a/modules/light-clients/06-solomachine/types/header_test.go +++ b/modules/light-clients/06-solomachine/header_test.go @@ -1,20 +1,20 @@ -package types_test +package solomachine_test import ( "github.com/cosmos/ibc-go/v5/modules/core/exported" - "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine/types" + solomachine "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) func (suite *SoloMachineTestSuite) TestHeaderValidateBasic() { // test singlesig and multisig public keys - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { + for _, sm := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { - header := solomachine.CreateHeader() + header := sm.CreateHeader(sm.Diversifier) cases := []struct { name string - header *types.Header + header *solomachine.Header expPass bool }{ { @@ -24,7 +24,7 @@ func (suite *SoloMachineTestSuite) TestHeaderValidateBasic() { }, { "sequence is zero", - &types.Header{ + &solomachine.Header{ Sequence: 0, Timestamp: header.Timestamp, Signature: header.Signature, @@ -35,7 +35,7 @@ func (suite *SoloMachineTestSuite) TestHeaderValidateBasic() { }, { "timestamp is zero", - &types.Header{ + &solomachine.Header{ Sequence: header.Sequence, Timestamp: 0, Signature: header.Signature, @@ -46,7 +46,7 @@ func (suite *SoloMachineTestSuite) TestHeaderValidateBasic() { }, { "signature is empty", - &types.Header{ + &solomachine.Header{ Sequence: header.Sequence, Timestamp: header.Timestamp, Signature: []byte{}, @@ -57,7 +57,7 @@ func (suite *SoloMachineTestSuite) TestHeaderValidateBasic() { }, { "diversifier contains only spaces", - &types.Header{ + &solomachine.Header{ Sequence: header.Sequence, Timestamp: header.Timestamp, Signature: header.Signature, @@ -68,7 +68,7 @@ func (suite *SoloMachineTestSuite) TestHeaderValidateBasic() { }, { "public key is nil", - &types.Header{ + &solomachine.Header{ Sequence: header.Sequence, Timestamp: header.Timestamp, Signature: header.Signature, diff --git a/modules/light-clients/06-solomachine/types/misbehaviour.go b/modules/light-clients/06-solomachine/misbehaviour.go similarity index 83% rename from modules/light-clients/06-solomachine/types/misbehaviour.go rename to modules/light-clients/06-solomachine/misbehaviour.go index d13b1407be8..526fc76e839 100644 --- a/modules/light-clients/06-solomachine/types/misbehaviour.go +++ b/modules/light-clients/06-solomachine/misbehaviour.go @@ -1,4 +1,4 @@ -package types +package solomachine import ( "bytes" @@ -10,24 +10,19 @@ import ( "github.com/cosmos/ibc-go/v5/modules/core/exported" ) -var _ exported.Misbehaviour = &Misbehaviour{} +var _ exported.ClientMessage = &Misbehaviour{} // ClientType is a Solo Machine light client. func (misbehaviour Misbehaviour) ClientType() string { return exported.Solomachine } -// GetClientID returns the ID of the client that committed a misbehaviour. -func (misbehaviour Misbehaviour) GetClientID() string { - return misbehaviour.ClientId -} - -// Type implements Evidence interface. +// Type implements Misbehaviour interface. func (misbehaviour Misbehaviour) Type() string { return exported.TypeClientMisbehaviour } -// ValidateBasic implements Evidence interface. +// ValidateBasic implements Misbehaviour interface. func (misbehaviour Misbehaviour) ValidateBasic() error { if err := host.ClientIdentifierValidator(misbehaviour.ClientId); err != nil { return sdkerrors.Wrap(err, "invalid client identifier for solo machine") @@ -66,8 +61,8 @@ func (sd SignatureAndData) ValidateBasic() error { if len(sd.Data) == 0 { return sdkerrors.Wrap(ErrInvalidSignatureAndData, "data for signature cannot be empty") } - if sd.DataType == UNSPECIFIED { - return sdkerrors.Wrap(ErrInvalidSignatureAndData, "data type cannot be UNSPECIFIED") + if len(sd.Path) == 0 { + return sdkerrors.Wrap(ErrInvalidSignatureAndData, "path for signature cannot be empty") } if sd.Timestamp == 0 { return sdkerrors.Wrap(ErrInvalidSignatureAndData, "timestamp cannot be 0") diff --git a/modules/light-clients/06-solomachine/misbehaviour_handle.go b/modules/light-clients/06-solomachine/misbehaviour_handle.go new file mode 100644 index 00000000000..e108931b7ea --- /dev/null +++ b/modules/light-clients/06-solomachine/misbehaviour_handle.go @@ -0,0 +1,46 @@ +package solomachine + +import ( + "github.com/cosmos/cosmos-sdk/codec" + + commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" +) + +// verifySignatureAndData verifies that the currently registered public key has signed +// over the provided data and that the data is valid. The data is valid if it can be +// unmarshaled into the specified data type. +func (cs ClientState) verifySignatureAndData(cdc codec.BinaryCodec, misbehaviour *Misbehaviour, sigAndData *SignatureAndData) error { + // do not check misbehaviour timestamp since we want to allow processing of past misbehaviour + if err := cdc.Unmarshal(sigAndData.Path, new(commitmenttypes.MerklePath)); err != nil { + return err + } + + signBytes := SignBytes{ + Sequence: misbehaviour.Sequence, + Timestamp: sigAndData.Timestamp, + Diversifier: cs.ConsensusState.Diversifier, + Path: sigAndData.Path, + Data: sigAndData.Data, + } + + data, err := cdc.Marshal(&signBytes) + if err != nil { + return err + } + + sigData, err := UnmarshalSignatureData(cdc, sigAndData.Signature) + if err != nil { + return err + } + + publicKey, err := cs.ConsensusState.GetPubKey() + if err != nil { + return err + } + + if err := VerifySignature(publicKey, data, sigData); err != nil { + return err + } + + return nil +} diff --git a/modules/light-clients/06-solomachine/types/misbehaviour_test.go b/modules/light-clients/06-solomachine/misbehaviour_test.go similarity index 63% rename from modules/light-clients/06-solomachine/types/misbehaviour_test.go rename to modules/light-clients/06-solomachine/misbehaviour_test.go index bdcdc664504..2e6044b67d1 100644 --- a/modules/light-clients/06-solomachine/types/misbehaviour_test.go +++ b/modules/light-clients/06-solomachine/misbehaviour_test.go @@ -1,8 +1,8 @@ -package types_test +package solomachine_test import ( "github.com/cosmos/ibc-go/v5/modules/core/exported" - "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine/types" + solomachine "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) @@ -10,100 +10,99 @@ func (suite *SoloMachineTestSuite) TestMisbehaviour() { misbehaviour := suite.solomachine.CreateMisbehaviour() suite.Require().Equal(exported.Solomachine, misbehaviour.ClientType()) - suite.Require().Equal(suite.solomachine.ClientID, misbehaviour.GetClientID()) } func (suite *SoloMachineTestSuite) TestMisbehaviourValidateBasic() { // test singlesig and multisig public keys - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { + for _, sm := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { testCases := []struct { name string - malleateMisbehaviour func(misbehaviour *types.Misbehaviour) + malleateMisbehaviour func(misbehaviour *solomachine.Misbehaviour) expPass bool }{ { "valid misbehaviour", - func(*types.Misbehaviour) {}, + func(*solomachine.Misbehaviour) {}, true, }, { "invalid client ID", - func(misbehaviour *types.Misbehaviour) { + func(misbehaviour *solomachine.Misbehaviour) { misbehaviour.ClientId = "(badclientid)" }, false, }, { "sequence is zero", - func(misbehaviour *types.Misbehaviour) { + func(misbehaviour *solomachine.Misbehaviour) { misbehaviour.Sequence = 0 }, false, }, { "signature one sig is empty", - func(misbehaviour *types.Misbehaviour) { + func(misbehaviour *solomachine.Misbehaviour) { misbehaviour.SignatureOne.Signature = []byte{} }, false, }, { "signature two sig is empty", - func(misbehaviour *types.Misbehaviour) { + func(misbehaviour *solomachine.Misbehaviour) { misbehaviour.SignatureTwo.Signature = []byte{} }, false, }, { "signature one data is empty", - func(misbehaviour *types.Misbehaviour) { + func(misbehaviour *solomachine.Misbehaviour) { misbehaviour.SignatureOne.Data = nil }, false, }, { "signature two data is empty", - func(misbehaviour *types.Misbehaviour) { + func(misbehaviour *solomachine.Misbehaviour) { misbehaviour.SignatureTwo.Data = []byte{} }, false, }, { "signatures are identical", - func(misbehaviour *types.Misbehaviour) { + func(misbehaviour *solomachine.Misbehaviour) { misbehaviour.SignatureTwo.Signature = misbehaviour.SignatureOne.Signature }, false, }, { "data signed is identical", - func(misbehaviour *types.Misbehaviour) { + func(misbehaviour *solomachine.Misbehaviour) { misbehaviour.SignatureTwo.Data = misbehaviour.SignatureOne.Data }, false, }, { - "data type for SignatureOne is unspecified", - func(misbehaviour *types.Misbehaviour) { - misbehaviour.SignatureOne.DataType = types.UNSPECIFIED + "data path for SignatureOne is unspecified", + func(misbehaviour *solomachine.Misbehaviour) { + misbehaviour.SignatureOne.Path = []byte{} }, false, }, { - "data type for SignatureTwo is unspecified", - func(misbehaviour *types.Misbehaviour) { - misbehaviour.SignatureTwo.DataType = types.UNSPECIFIED + "data path for SignatureTwo is unspecified", + func(misbehaviour *solomachine.Misbehaviour) { + misbehaviour.SignatureTwo.Path = []byte{} }, false, }, { "timestamp for SignatureOne is zero", - func(misbehaviour *types.Misbehaviour) { + func(misbehaviour *solomachine.Misbehaviour) { misbehaviour.SignatureOne.Timestamp = 0 }, false, }, { "timestamp for SignatureTwo is zero", - func(misbehaviour *types.Misbehaviour) { + func(misbehaviour *solomachine.Misbehaviour) { misbehaviour.SignatureTwo.Timestamp = 0 }, false, }, @@ -113,7 +112,8 @@ func (suite *SoloMachineTestSuite) TestMisbehaviourValidateBasic() { tc := tc suite.Run(tc.name, func() { - misbehaviour := solomachine.CreateMisbehaviour() + + misbehaviour := sm.CreateMisbehaviour() tc.malleateMisbehaviour(misbehaviour) err := misbehaviour.ValidateBasic() diff --git a/modules/light-clients/06-solomachine/module.go b/modules/light-clients/06-solomachine/module.go index 4acbc3d7a25..d66b482541c 100644 --- a/modules/light-clients/06-solomachine/module.go +++ b/modules/light-clients/06-solomachine/module.go @@ -1,10 +1,6 @@ package solomachine -import ( - "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine/types" -) - // Name returns the solo machine client name. func Name() string { - return types.SubModuleName + return SubModuleName } diff --git a/modules/light-clients/06-solomachine/proof.go b/modules/light-clients/06-solomachine/proof.go new file mode 100644 index 00000000000..386830340cf --- /dev/null +++ b/modules/light-clients/06-solomachine/proof.go @@ -0,0 +1,43 @@ +package solomachine + +import ( + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/crypto/types/multisig" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/tx/signing" +) + +// VerifySignature verifies if the the provided public key generated the signature +// over the given data. Single and Multi signature public keys are supported. +// The signature data type must correspond to the public key type. An error is +// returned if signature verification fails or an invalid SignatureData type is +// provided. +func VerifySignature(pubKey cryptotypes.PubKey, signBytes []byte, sigData signing.SignatureData) error { + switch pubKey := pubKey.(type) { + case multisig.PubKey: + data, ok := sigData.(*signing.MultiSignatureData) + if !ok { + return sdkerrors.Wrapf(ErrSignatureVerificationFailed, "invalid signature data type, expected %T, got %T", (*signing.MultiSignatureData)(nil), data) + } + + // The function supplied fulfills the VerifyMultisignature interface. No special + // adjustments need to be made to the sign bytes based on the sign mode. + if err := pubKey.VerifyMultisignature(func(signing.SignMode) ([]byte, error) { + return signBytes, nil + }, data); err != nil { + return err + } + + default: + data, ok := sigData.(*signing.SingleSignatureData) + if !ok { + return sdkerrors.Wrapf(ErrSignatureVerificationFailed, "invalid signature data type, expected %T, got %T", (*signing.SingleSignatureData)(nil), data) + } + + if !pubKey.VerifySignature(signBytes, data.Signature) { + return ErrSignatureVerificationFailed + } + } + + return nil +} diff --git a/modules/light-clients/06-solomachine/proof_test.go b/modules/light-clients/06-solomachine/proof_test.go new file mode 100644 index 00000000000..2fa853d46a5 --- /dev/null +++ b/modules/light-clients/06-solomachine/proof_test.go @@ -0,0 +1,67 @@ +package solomachine_test + +import ( + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + + solomachine "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine" +) + +func (suite *SoloMachineTestSuite) TestVerifySignature() { + cdc := suite.chainA.App.AppCodec() + signBytes := []byte("sign bytes") + + singleSignature := suite.solomachine.GenerateSignature(signBytes) + singleSigData, err := solomachine.UnmarshalSignatureData(cdc, singleSignature) + suite.Require().NoError(err) + + multiSignature := suite.solomachineMulti.GenerateSignature(signBytes) + multiSigData, err := solomachine.UnmarshalSignatureData(cdc, multiSignature) + suite.Require().NoError(err) + + testCases := []struct { + name string + publicKey cryptotypes.PubKey + sigData signing.SignatureData + expPass bool + }{ + { + "single signature with regular public key", + suite.solomachine.PublicKey, + singleSigData, + true, + }, + { + "multi signature with multisig public key", + suite.solomachineMulti.PublicKey, + multiSigData, + true, + }, + { + "single signature with multisig public key", + suite.solomachineMulti.PublicKey, + singleSigData, + false, + }, + { + "multi signature with regular public key", + suite.solomachine.PublicKey, + multiSigData, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + err := solomachine.VerifySignature(tc.publicKey, signBytes, tc.sigData) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/modules/light-clients/06-solomachine/types/proposal_handle.go b/modules/light-clients/06-solomachine/proposal_handle.go similarity index 62% rename from modules/light-clients/06-solomachine/types/proposal_handle.go rename to modules/light-clients/06-solomachine/proposal_handle.go index 6cbcb2b3627..bef2db14299 100644 --- a/modules/light-clients/06-solomachine/types/proposal_handle.go +++ b/modules/light-clients/06-solomachine/proposal_handle.go @@ -1,4 +1,4 @@ -package types +package solomachine import ( "reflect" @@ -21,43 +21,36 @@ import ( func (cs ClientState) CheckSubstituteAndUpdateState( ctx sdk.Context, cdc codec.BinaryCodec, subjectClientStore, _ sdk.KVStore, substituteClient exported.ClientState, -) (exported.ClientState, error) { +) error { if !cs.AllowUpdateAfterProposal { - return nil, sdkerrors.Wrapf( - clienttypes.ErrUpdateClientFailed, - "solo machine client is not allowed to updated with a proposal", - ) + return sdkerrors.Wrapf(clienttypes.ErrUpdateClientFailed, "solo machine client is not allowed to updated with a proposal") } substituteClientState, ok := substituteClient.(*ClientState) if !ok { - return nil, sdkerrors.Wrapf( - clienttypes.ErrInvalidClientType, "substitute client state type %T, expected %T", substituteClient, &ClientState{}, - ) + return sdkerrors.Wrapf(clienttypes.ErrInvalidClientType, "substitute client state type %T, expected %T", substituteClient, &ClientState{}) } subjectPublicKey, err := cs.ConsensusState.GetPubKey() if err != nil { - return nil, sdkerrors.Wrap(err, "failed to get consensus public key") + return sdkerrors.Wrap(err, "failed to get consensus public key") } substitutePublicKey, err := substituteClientState.ConsensusState.GetPubKey() if err != nil { - return nil, sdkerrors.Wrap(err, "failed to get substitute client public key") + return sdkerrors.Wrap(err, "failed to get substitute client public key") } if reflect.DeepEqual(subjectPublicKey, substitutePublicKey) { - return nil, sdkerrors.Wrapf( - clienttypes.ErrInvalidHeader, "subject and substitute have the same public key", - ) + return sdkerrors.Wrapf(clienttypes.ErrInvalidHeader, "subject and substitute have the same public key") } - clientState := &cs - // update to substitute parameters - clientState.Sequence = substituteClientState.Sequence - clientState.ConsensusState = substituteClientState.ConsensusState - clientState.IsFrozen = false + cs.Sequence = substituteClientState.Sequence + cs.ConsensusState = substituteClientState.ConsensusState + cs.IsFrozen = false + + setClientState(subjectClientStore, cdc, &cs) - return clientState, nil + return nil } diff --git a/modules/light-clients/06-solomachine/types/proposal_handle_test.go b/modules/light-clients/06-solomachine/proposal_handle_test.go similarity index 51% rename from modules/light-clients/06-solomachine/types/proposal_handle_test.go rename to modules/light-clients/06-solomachine/proposal_handle_test.go index 800f563f0b9..21a28564320 100644 --- a/modules/light-clients/06-solomachine/types/proposal_handle_test.go +++ b/modules/light-clients/06-solomachine/proposal_handle_test.go @@ -1,20 +1,22 @@ -package types_test +package solomachine_test import ( + clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v5/modules/core/24-host" "github.com/cosmos/ibc-go/v5/modules/core/exported" - "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine/types" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + solomachine "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) func (suite *SoloMachineTestSuite) TestCheckSubstituteAndUpdateState() { var ( - subjectClientState *types.ClientState + subjectClientState *solomachine.ClientState substituteClientState exported.ClientState ) // test singlesig and multisig public keys - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { + for _, sm := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { testCases := []struct { name string @@ -33,7 +35,7 @@ func (suite *SoloMachineTestSuite) TestCheckSubstituteAndUpdateState() { }, { "substitute is not the solo machine", func() { - substituteClientState = &ibctmtypes.ClientState{} + substituteClientState = &ibctm.ClientState{} }, false, }, { @@ -44,12 +46,12 @@ func (suite *SoloMachineTestSuite) TestCheckSubstituteAndUpdateState() { { "substitute public key is nil", func() { - substituteClientState.(*types.ClientState).ConsensusState.PublicKey = nil + substituteClientState.(*solomachine.ClientState).ConsensusState.PublicKey = nil }, false, }, { "subject and substitute use the same public key", func() { - substituteClientState.(*types.ClientState).ConsensusState.PublicKey = subjectClientState.ConsensusState.PublicKey + substituteClientState.(*solomachine.ClientState).ConsensusState.PublicKey = subjectClientState.ConsensusState.PublicKey }, false, }, } @@ -60,27 +62,31 @@ func (suite *SoloMachineTestSuite) TestCheckSubstituteAndUpdateState() { suite.Run(tc.name, func() { suite.SetupTest() - subjectClientState = solomachine.ClientState() + subjectClientState = sm.ClientState() subjectClientState.AllowUpdateAfterProposal = true substitute := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "substitute", "testing", 5) substituteClientState = substitute.ClientState() tc.malleate() - subjectClientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), solomachine.ClientID) + subjectClientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), sm.ClientID) substituteClientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), substitute.ClientID) - updatedClient, err := subjectClientState.CheckSubstituteAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), subjectClientStore, substituteClientStore, substituteClientState) + err := subjectClientState.CheckSubstituteAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), subjectClientStore, substituteClientStore, substituteClientState) if tc.expPass { suite.Require().NoError(err) - suite.Require().Equal(substituteClientState.(*types.ClientState).ConsensusState, updatedClient.(*types.ClientState).ConsensusState) - suite.Require().Equal(substituteClientState.(*types.ClientState).Sequence, updatedClient.(*types.ClientState).Sequence) - suite.Require().Equal(false, updatedClient.(*types.ClientState).IsFrozen) + // ensure updated client state is set in store + bz := subjectClientStore.Get(host.ClientStateKey()) + updatedClient := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), bz).(*solomachine.ClientState) + + suite.Require().Equal(substituteClientState.(*solomachine.ClientState).ConsensusState, updatedClient.ConsensusState) + suite.Require().Equal(substituteClientState.(*solomachine.ClientState).Sequence, updatedClient.Sequence) + suite.Require().Equal(false, updatedClient.IsFrozen) + } else { suite.Require().Error(err) - suite.Require().Nil(updatedClient) } }) } diff --git a/modules/light-clients/06-solomachine/types/solomachine.go b/modules/light-clients/06-solomachine/solomachine.go similarity index 69% rename from modules/light-clients/06-solomachine/types/solomachine.go rename to modules/light-clients/06-solomachine/solomachine.go index 2e7fc46307e..41511910bf4 100644 --- a/modules/light-clients/06-solomachine/types/solomachine.go +++ b/modules/light-clients/06-solomachine/solomachine.go @@ -1,10 +1,8 @@ -package types +package solomachine import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - - "github.com/cosmos/ibc-go/v5/modules/core/exported" ) // Interface implementation checks. @@ -32,13 +30,3 @@ func (h Header) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { func (hd HeaderData) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { return unpacker.UnpackAny(hd.NewPubKey, new(cryptotypes.PubKey)) } - -// UnpackInterfaces implements the UnpackInterfaceMessages.UnpackInterfaces method -func (csd ClientStateData) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { - return unpacker.UnpackAny(csd.ClientState, new(exported.ClientState)) -} - -// UnpackInterfaces implements the UnpackInterfaceMessages.UnpackInterfaces method -func (csd ConsensusStateData) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { - return unpacker.UnpackAny(csd.ConsensusState, new(exported.ConsensusState)) -} diff --git a/modules/light-clients/06-solomachine/solomachine.pb.go b/modules/light-clients/06-solomachine/solomachine.pb.go new file mode 100644 index 00000000000..4714f24f568 --- /dev/null +++ b/modules/light-clients/06-solomachine/solomachine.pb.go @@ -0,0 +1,2350 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/lightclients/solomachine/v3/solomachine.proto + +package solomachine + +import ( + fmt "fmt" + types "github.com/cosmos/cosmos-sdk/codec/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/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 + +// ClientState defines a solo machine client that tracks the current consensus +// state and if the client is frozen. +type ClientState struct { + // latest sequence of the client state + Sequence uint64 `protobuf:"varint,1,opt,name=sequence,proto3" json:"sequence,omitempty"` + // frozen sequence of the solo machine + IsFrozen bool `protobuf:"varint,2,opt,name=is_frozen,json=isFrozen,proto3" json:"is_frozen,omitempty" yaml:"is_frozen"` + ConsensusState *ConsensusState `protobuf:"bytes,3,opt,name=consensus_state,json=consensusState,proto3" json:"consensus_state,omitempty" yaml:"consensus_state"` + // when set to true, will allow governance to update a solo machine client. + // The client will be unfrozen if it is frozen. + AllowUpdateAfterProposal bool `protobuf:"varint,4,opt,name=allow_update_after_proposal,json=allowUpdateAfterProposal,proto3" json:"allow_update_after_proposal,omitempty" yaml:"allow_update_after_proposal"` +} + +func (m *ClientState) Reset() { *m = ClientState{} } +func (m *ClientState) String() string { return proto.CompactTextString(m) } +func (*ClientState) ProtoMessage() {} +func (*ClientState) Descriptor() ([]byte, []int) { + return fileDescriptor_264187157b9220a4, []int{0} +} +func (m *ClientState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ClientState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ClientState.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 *ClientState) XXX_Merge(src proto.Message) { + xxx_messageInfo_ClientState.Merge(m, src) +} +func (m *ClientState) XXX_Size() int { + return m.Size() +} +func (m *ClientState) XXX_DiscardUnknown() { + xxx_messageInfo_ClientState.DiscardUnknown(m) +} + +var xxx_messageInfo_ClientState proto.InternalMessageInfo + +// ConsensusState defines a solo machine consensus state. The sequence of a +// consensus state is contained in the "height" key used in storing the +// consensus state. +type ConsensusState struct { + // public key of the solo machine + PublicKey *types.Any `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty" yaml:"public_key"` + // diversifier allows the same public key to be re-used across different solo + // machine clients (potentially on different chains) without being considered + // misbehaviour. + Diversifier string `protobuf:"bytes,2,opt,name=diversifier,proto3" json:"diversifier,omitempty"` + Timestamp uint64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` +} + +func (m *ConsensusState) Reset() { *m = ConsensusState{} } +func (m *ConsensusState) String() string { return proto.CompactTextString(m) } +func (*ConsensusState) ProtoMessage() {} +func (*ConsensusState) Descriptor() ([]byte, []int) { + return fileDescriptor_264187157b9220a4, []int{1} +} +func (m *ConsensusState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ConsensusState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ConsensusState.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 *ConsensusState) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConsensusState.Merge(m, src) +} +func (m *ConsensusState) XXX_Size() int { + return m.Size() +} +func (m *ConsensusState) XXX_DiscardUnknown() { + xxx_messageInfo_ConsensusState.DiscardUnknown(m) +} + +var xxx_messageInfo_ConsensusState proto.InternalMessageInfo + +// Header defines a solo machine consensus header +type Header struct { + // sequence to update solo machine public key at + Sequence uint64 `protobuf:"varint,1,opt,name=sequence,proto3" json:"sequence,omitempty"` + Timestamp uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Signature []byte `protobuf:"bytes,3,opt,name=signature,proto3" json:"signature,omitempty"` + NewPublicKey *types.Any `protobuf:"bytes,4,opt,name=new_public_key,json=newPublicKey,proto3" json:"new_public_key,omitempty" yaml:"new_public_key"` + NewDiversifier string `protobuf:"bytes,5,opt,name=new_diversifier,json=newDiversifier,proto3" json:"new_diversifier,omitempty" yaml:"new_diversifier"` +} + +func (m *Header) Reset() { *m = Header{} } +func (m *Header) String() string { return proto.CompactTextString(m) } +func (*Header) ProtoMessage() {} +func (*Header) Descriptor() ([]byte, []int) { + return fileDescriptor_264187157b9220a4, []int{2} +} +func (m *Header) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Header) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Header.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 *Header) XXX_Merge(src proto.Message) { + xxx_messageInfo_Header.Merge(m, src) +} +func (m *Header) XXX_Size() int { + return m.Size() +} +func (m *Header) XXX_DiscardUnknown() { + xxx_messageInfo_Header.DiscardUnknown(m) +} + +var xxx_messageInfo_Header proto.InternalMessageInfo + +// Misbehaviour defines misbehaviour for a solo machine which consists +// of a sequence and two signatures over different messages at that sequence. +type Misbehaviour struct { + // ClientID is deprecated + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` // Deprecated: Do not use. + Sequence uint64 `protobuf:"varint,2,opt,name=sequence,proto3" json:"sequence,omitempty"` + SignatureOne *SignatureAndData `protobuf:"bytes,3,opt,name=signature_one,json=signatureOne,proto3" json:"signature_one,omitempty" yaml:"signature_one"` + SignatureTwo *SignatureAndData `protobuf:"bytes,4,opt,name=signature_two,json=signatureTwo,proto3" json:"signature_two,omitempty" yaml:"signature_two"` +} + +func (m *Misbehaviour) Reset() { *m = Misbehaviour{} } +func (m *Misbehaviour) String() string { return proto.CompactTextString(m) } +func (*Misbehaviour) ProtoMessage() {} +func (*Misbehaviour) Descriptor() ([]byte, []int) { + return fileDescriptor_264187157b9220a4, []int{3} +} +func (m *Misbehaviour) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Misbehaviour) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Misbehaviour.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 *Misbehaviour) XXX_Merge(src proto.Message) { + xxx_messageInfo_Misbehaviour.Merge(m, src) +} +func (m *Misbehaviour) XXX_Size() int { + return m.Size() +} +func (m *Misbehaviour) XXX_DiscardUnknown() { + xxx_messageInfo_Misbehaviour.DiscardUnknown(m) +} + +var xxx_messageInfo_Misbehaviour proto.InternalMessageInfo + +// SignatureAndData contains a signature and the data signed over to create that +// signature. +type SignatureAndData struct { + Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"` + Path []byte `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` + Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` + Timestamp uint64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` +} + +func (m *SignatureAndData) Reset() { *m = SignatureAndData{} } +func (m *SignatureAndData) String() string { return proto.CompactTextString(m) } +func (*SignatureAndData) ProtoMessage() {} +func (*SignatureAndData) Descriptor() ([]byte, []int) { + return fileDescriptor_264187157b9220a4, []int{4} +} +func (m *SignatureAndData) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SignatureAndData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SignatureAndData.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 *SignatureAndData) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignatureAndData.Merge(m, src) +} +func (m *SignatureAndData) XXX_Size() int { + return m.Size() +} +func (m *SignatureAndData) XXX_DiscardUnknown() { + xxx_messageInfo_SignatureAndData.DiscardUnknown(m) +} + +var xxx_messageInfo_SignatureAndData proto.InternalMessageInfo + +// TimestampedSignatureData contains the signature data and the timestamp of the +// signature. +type TimestampedSignatureData struct { + SignatureData []byte `protobuf:"bytes,1,opt,name=signature_data,json=signatureData,proto3" json:"signature_data,omitempty" yaml:"signature_data"` + Timestamp uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` +} + +func (m *TimestampedSignatureData) Reset() { *m = TimestampedSignatureData{} } +func (m *TimestampedSignatureData) String() string { return proto.CompactTextString(m) } +func (*TimestampedSignatureData) ProtoMessage() {} +func (*TimestampedSignatureData) Descriptor() ([]byte, []int) { + return fileDescriptor_264187157b9220a4, []int{5} +} +func (m *TimestampedSignatureData) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TimestampedSignatureData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TimestampedSignatureData.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 *TimestampedSignatureData) XXX_Merge(src proto.Message) { + xxx_messageInfo_TimestampedSignatureData.Merge(m, src) +} +func (m *TimestampedSignatureData) XXX_Size() int { + return m.Size() +} +func (m *TimestampedSignatureData) XXX_DiscardUnknown() { + xxx_messageInfo_TimestampedSignatureData.DiscardUnknown(m) +} + +var xxx_messageInfo_TimestampedSignatureData proto.InternalMessageInfo + +// SignBytes defines the signed bytes used for signature verification. +type SignBytes struct { + // the sequence number + Sequence uint64 `protobuf:"varint,1,opt,name=sequence,proto3" json:"sequence,omitempty"` + // the proof timestamp + Timestamp uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + // the public key diversifier + Diversifier string `protobuf:"bytes,3,opt,name=diversifier,proto3" json:"diversifier,omitempty"` + // the standardised path bytes + Path []byte `protobuf:"bytes,4,opt,name=path,proto3" json:"path,omitempty"` + // the marshaled data bytes + Data []byte `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *SignBytes) Reset() { *m = SignBytes{} } +func (m *SignBytes) String() string { return proto.CompactTextString(m) } +func (*SignBytes) ProtoMessage() {} +func (*SignBytes) Descriptor() ([]byte, []int) { + return fileDescriptor_264187157b9220a4, []int{6} +} +func (m *SignBytes) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SignBytes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SignBytes.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 *SignBytes) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignBytes.Merge(m, src) +} +func (m *SignBytes) XXX_Size() int { + return m.Size() +} +func (m *SignBytes) XXX_DiscardUnknown() { + xxx_messageInfo_SignBytes.DiscardUnknown(m) +} + +var xxx_messageInfo_SignBytes proto.InternalMessageInfo + +// HeaderData returns the SignBytes data for update verification. +type HeaderData struct { + // header public key + NewPubKey *types.Any `protobuf:"bytes,1,opt,name=new_pub_key,json=newPubKey,proto3" json:"new_pub_key,omitempty" yaml:"new_pub_key"` + // header diversifier + NewDiversifier string `protobuf:"bytes,2,opt,name=new_diversifier,json=newDiversifier,proto3" json:"new_diversifier,omitempty" yaml:"new_diversifier"` +} + +func (m *HeaderData) Reset() { *m = HeaderData{} } +func (m *HeaderData) String() string { return proto.CompactTextString(m) } +func (*HeaderData) ProtoMessage() {} +func (*HeaderData) Descriptor() ([]byte, []int) { + return fileDescriptor_264187157b9220a4, []int{7} +} +func (m *HeaderData) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *HeaderData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_HeaderData.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 *HeaderData) XXX_Merge(src proto.Message) { + xxx_messageInfo_HeaderData.Merge(m, src) +} +func (m *HeaderData) XXX_Size() int { + return m.Size() +} +func (m *HeaderData) XXX_DiscardUnknown() { + xxx_messageInfo_HeaderData.DiscardUnknown(m) +} + +var xxx_messageInfo_HeaderData proto.InternalMessageInfo + +func init() { + proto.RegisterType((*ClientState)(nil), "ibc.lightclients.solomachine.v3.ClientState") + proto.RegisterType((*ConsensusState)(nil), "ibc.lightclients.solomachine.v3.ConsensusState") + proto.RegisterType((*Header)(nil), "ibc.lightclients.solomachine.v3.Header") + proto.RegisterType((*Misbehaviour)(nil), "ibc.lightclients.solomachine.v3.Misbehaviour") + proto.RegisterType((*SignatureAndData)(nil), "ibc.lightclients.solomachine.v3.SignatureAndData") + proto.RegisterType((*TimestampedSignatureData)(nil), "ibc.lightclients.solomachine.v3.TimestampedSignatureData") + proto.RegisterType((*SignBytes)(nil), "ibc.lightclients.solomachine.v3.SignBytes") + proto.RegisterType((*HeaderData)(nil), "ibc.lightclients.solomachine.v3.HeaderData") +} + +func init() { + proto.RegisterFile("ibc/lightclients/solomachine/v3/solomachine.proto", fileDescriptor_264187157b9220a4) +} + +var fileDescriptor_264187157b9220a4 = []byte{ + // 784 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x4d, 0x6f, 0xe3, 0x44, + 0x18, 0x8e, 0x5d, 0xb7, 0x4a, 0x26, 0x21, 0x2d, 0x56, 0x5a, 0xb9, 0x01, 0xc5, 0x91, 0x0f, 0xa8, + 0x97, 0xda, 0xb4, 0x11, 0x1c, 0xca, 0x85, 0xa6, 0x15, 0xe2, 0xa3, 0x88, 0xca, 0x6d, 0x2f, 0x5c, + 0xac, 0xb1, 0x3d, 0x71, 0x46, 0x38, 0x1e, 0xe3, 0x19, 0x27, 0x0a, 0xe2, 0x80, 0x38, 0x71, 0xe4, + 0xc2, 0x1d, 0x21, 0xf1, 0x3b, 0xb8, 0xb2, 0xb7, 0x1e, 0xf7, 0x14, 0xad, 0xda, 0x7f, 0x90, 0x5f, + 0xb0, 0xf2, 0xd8, 0x89, 0x3f, 0xda, 0x6d, 0xa5, 0xdd, 0xbd, 0xcd, 0xbc, 0x9f, 0xcf, 0xfb, 0xcc, + 0xf3, 0xda, 0xe0, 0x08, 0xdb, 0x8e, 0xe1, 0x63, 0x6f, 0xcc, 0x1c, 0x1f, 0xa3, 0x80, 0x51, 0x83, + 0x12, 0x9f, 0x4c, 0xa0, 0x33, 0xc6, 0x01, 0x32, 0xa6, 0x83, 0xe2, 0x55, 0x0f, 0x23, 0xc2, 0x88, + 0xac, 0x62, 0xdb, 0xd1, 0x8b, 0x29, 0x7a, 0x31, 0x66, 0x3a, 0xe8, 0x76, 0x3c, 0xe2, 0x11, 0x1e, + 0x6b, 0x24, 0xa7, 0x34, 0xad, 0xbb, 0xef, 0x11, 0xe2, 0xf9, 0xc8, 0xe0, 0x37, 0x3b, 0x1e, 0x19, + 0x30, 0x98, 0xa7, 0x2e, 0xed, 0x3f, 0x11, 0x34, 0xcf, 0x78, 0xad, 0x2b, 0x06, 0x19, 0x92, 0xbb, + 0xa0, 0x4e, 0xd1, 0xcf, 0x31, 0x0a, 0x1c, 0xa4, 0x08, 0x7d, 0xe1, 0x40, 0x32, 0xd7, 0x77, 0xf9, + 0x08, 0x34, 0x30, 0xb5, 0x46, 0x11, 0xf9, 0x05, 0x05, 0x8a, 0xd8, 0x17, 0x0e, 0xea, 0xc3, 0xce, + 0x72, 0xa1, 0xee, 0xcc, 0xe1, 0xc4, 0x3f, 0xd1, 0xd6, 0x2e, 0xcd, 0xac, 0x63, 0xfa, 0x15, 0x3f, + 0xca, 0x0c, 0x6c, 0x3b, 0x24, 0xa0, 0x28, 0xa0, 0x31, 0xb5, 0x68, 0xd2, 0x41, 0xd9, 0xe8, 0x0b, + 0x07, 0xcd, 0x63, 0x43, 0x7f, 0x66, 0x14, 0xfd, 0x6c, 0x95, 0xc7, 0x81, 0x0d, 0xbb, 0xcb, 0x85, + 0xba, 0x97, 0x76, 0xaa, 0x54, 0xd4, 0xcc, 0xb6, 0x53, 0x8a, 0x95, 0x11, 0xf8, 0x08, 0xfa, 0x3e, + 0x99, 0x59, 0x71, 0xe8, 0x42, 0x86, 0x2c, 0x38, 0x62, 0x28, 0xb2, 0xc2, 0x88, 0x84, 0x84, 0x42, + 0x5f, 0x91, 0x38, 0xf4, 0x4f, 0x96, 0x0b, 0x55, 0x4b, 0x0b, 0x3e, 0x11, 0xac, 0x99, 0x0a, 0xf7, + 0xde, 0x70, 0xe7, 0x69, 0xe2, 0xbb, 0xcc, 0x5c, 0x27, 0xd2, 0x1f, 0x7f, 0xab, 0x35, 0xed, 0x1f, + 0x01, 0xb4, 0xcb, 0x58, 0xe5, 0x6f, 0x01, 0x08, 0x63, 0xdb, 0xc7, 0x8e, 0xf5, 0x13, 0x9a, 0x73, + 0x1a, 0x9b, 0xc7, 0x1d, 0x3d, 0x7d, 0x04, 0x7d, 0xf5, 0x08, 0xfa, 0x69, 0x30, 0x1f, 0xee, 0x2e, + 0x17, 0xea, 0x87, 0x29, 0x88, 0x3c, 0x43, 0x33, 0x1b, 0xe9, 0xe5, 0x3b, 0x34, 0x97, 0xfb, 0xa0, + 0xe9, 0xe2, 0x29, 0x8a, 0x28, 0x1e, 0x61, 0x14, 0x71, 0xda, 0x1b, 0x66, 0xd1, 0x24, 0x7f, 0x0c, + 0x1a, 0x0c, 0x4f, 0x10, 0x65, 0x70, 0x12, 0x72, 0x76, 0x25, 0x33, 0x37, 0x64, 0x20, 0x7f, 0x17, + 0xc1, 0xd6, 0xd7, 0x08, 0xba, 0x28, 0x7a, 0xf2, 0x85, 0x4b, 0xa5, 0xc4, 0x4a, 0xa9, 0xc4, 0x4b, + 0xb1, 0x17, 0x40, 0x16, 0x47, 0xe9, 0x33, 0xb6, 0xcc, 0xdc, 0x20, 0xdf, 0x80, 0x76, 0x80, 0x66, + 0x56, 0x61, 0x70, 0xe9, 0x89, 0xc1, 0xf7, 0x97, 0x0b, 0x75, 0x37, 0x1d, 0xbc, 0x9c, 0xa5, 0x99, + 0xad, 0x00, 0xcd, 0x2e, 0xd7, 0xf3, 0x9f, 0x81, 0xed, 0x24, 0xa0, 0xc8, 0xc1, 0x66, 0xc2, 0x41, + 0x51, 0x10, 0x95, 0x00, 0xcd, 0x4c, 0x90, 0x9c, 0xe7, 0x86, 0x8c, 0x84, 0x17, 0x22, 0x68, 0x7d, + 0x8f, 0xa9, 0x8d, 0xc6, 0x70, 0x8a, 0x49, 0x1c, 0xc9, 0x03, 0xd0, 0x48, 0xc5, 0x67, 0x61, 0x97, + 0x73, 0xd1, 0x18, 0xee, 0xe5, 0x82, 0x5e, 0xbb, 0x34, 0x45, 0x30, 0xeb, 0xe9, 0xed, 0x1b, 0xb7, + 0xc4, 0x9f, 0x58, 0xe1, 0x2f, 0x04, 0x1f, 0xac, 0x09, 0xb1, 0x48, 0xb0, 0x12, 0xfb, 0xd1, 0xb3, + 0x62, 0xbf, 0x5a, 0x65, 0x9d, 0x06, 0xee, 0x39, 0x64, 0x70, 0xa8, 0x2c, 0x17, 0x6a, 0x27, 0xc5, + 0x51, 0xaa, 0xa8, 0x99, 0xad, 0xf5, 0xfd, 0x87, 0xa0, 0xd2, 0x91, 0xcd, 0x48, 0x46, 0xfa, 0xfb, + 0xea, 0xc8, 0x66, 0xa4, 0xd8, 0xf1, 0x7a, 0x46, 0x32, 0x2e, 0x7f, 0x05, 0x3b, 0xd5, 0x0a, 0x65, + 0x7d, 0x08, 0x55, 0x7d, 0xc8, 0x40, 0x0a, 0x21, 0x1b, 0x73, 0xce, 0x5a, 0x26, 0x3f, 0x27, 0x36, + 0x17, 0x32, 0x98, 0x89, 0x89, 0x9f, 0xcb, 0x1a, 0x94, 0x1e, 0x97, 0xf3, 0x6f, 0x02, 0x50, 0xae, + 0x57, 0x36, 0xe4, 0xae, 0x91, 0x70, 0x18, 0x5f, 0x82, 0x76, 0x3e, 0x00, 0x2f, 0xcf, 0xb1, 0x14, + 0x25, 0x57, 0xf6, 0x6b, 0x66, 0xce, 0xe1, 0xf9, 0x03, 0x08, 0xe2, 0xe3, 0x10, 0xfe, 0x12, 0x40, + 0x23, 0xe9, 0x3b, 0x9c, 0x33, 0x44, 0xdf, 0x61, 0xa9, 0x2a, 0xfb, 0xbd, 0xf1, 0x70, 0xbf, 0x57, + 0xc4, 0x49, 0x8f, 0x10, 0xb7, 0x99, 0x13, 0x97, 0xe1, 0xfa, 0x57, 0x00, 0x20, 0xdd, 0x74, 0x3e, + 0xca, 0x05, 0x68, 0x66, 0xfb, 0xf5, 0xec, 0xb7, 0x28, 0x91, 0xbe, 0x5c, 0x5a, 0xc9, 0xec, 0x63, + 0x94, 0xee, 0xe3, 0x1b, 0x96, 0x51, 0x7c, 0xbb, 0x65, 0x1c, 0x8e, 0xfe, 0xbf, 0xeb, 0x09, 0xb7, + 0x77, 0x3d, 0xe1, 0xd5, 0x5d, 0x4f, 0xf8, 0xf3, 0xbe, 0x57, 0xbb, 0xbd, 0xef, 0xd5, 0x5e, 0xde, + 0xf7, 0x6a, 0x3f, 0x5e, 0x78, 0x98, 0x8d, 0x63, 0x5b, 0x77, 0xc8, 0xc4, 0x70, 0x08, 0x9d, 0x10, + 0x6a, 0x60, 0xdb, 0x39, 0xf4, 0x88, 0x31, 0xfd, 0xcc, 0x98, 0x10, 0x37, 0xf6, 0x11, 0x4d, 0xff, + 0x9b, 0x87, 0xab, 0x1f, 0xe7, 0xa7, 0x9f, 0x1f, 0x16, 0xe4, 0xfd, 0x45, 0xe1, 0x6c, 0x6f, 0xf1, + 0x19, 0x07, 0xaf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x62, 0x3e, 0x62, 0x81, 0x6e, 0x07, 0x00, 0x00, +} + +func (m *ClientState) 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 *ClientState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ClientState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.AllowUpdateAfterProposal { + i-- + if m.AllowUpdateAfterProposal { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } + if m.ConsensusState != nil { + { + size, err := m.ConsensusState.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSolomachine(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.IsFrozen { + i-- + if m.IsFrozen { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if m.Sequence != 0 { + i = encodeVarintSolomachine(dAtA, i, uint64(m.Sequence)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *ConsensusState) 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 *ConsensusState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ConsensusState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Timestamp != 0 { + i = encodeVarintSolomachine(dAtA, i, uint64(m.Timestamp)) + i-- + dAtA[i] = 0x18 + } + if len(m.Diversifier) > 0 { + i -= len(m.Diversifier) + copy(dAtA[i:], m.Diversifier) + i = encodeVarintSolomachine(dAtA, i, uint64(len(m.Diversifier))) + i-- + dAtA[i] = 0x12 + } + if m.PublicKey != nil { + { + size, err := m.PublicKey.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSolomachine(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Header) 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 *Header) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Header) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.NewDiversifier) > 0 { + i -= len(m.NewDiversifier) + copy(dAtA[i:], m.NewDiversifier) + i = encodeVarintSolomachine(dAtA, i, uint64(len(m.NewDiversifier))) + i-- + dAtA[i] = 0x2a + } + if m.NewPublicKey != nil { + { + size, err := m.NewPublicKey.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSolomachine(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if len(m.Signature) > 0 { + i -= len(m.Signature) + copy(dAtA[i:], m.Signature) + i = encodeVarintSolomachine(dAtA, i, uint64(len(m.Signature))) + i-- + dAtA[i] = 0x1a + } + if m.Timestamp != 0 { + i = encodeVarintSolomachine(dAtA, i, uint64(m.Timestamp)) + i-- + dAtA[i] = 0x10 + } + if m.Sequence != 0 { + i = encodeVarintSolomachine(dAtA, i, uint64(m.Sequence)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Misbehaviour) 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 *Misbehaviour) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Misbehaviour) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.SignatureTwo != nil { + { + size, err := m.SignatureTwo.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSolomachine(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if m.SignatureOne != nil { + { + size, err := m.SignatureOne.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSolomachine(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.Sequence != 0 { + i = encodeVarintSolomachine(dAtA, i, uint64(m.Sequence)) + i-- + dAtA[i] = 0x10 + } + if len(m.ClientId) > 0 { + i -= len(m.ClientId) + copy(dAtA[i:], m.ClientId) + i = encodeVarintSolomachine(dAtA, i, uint64(len(m.ClientId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *SignatureAndData) 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 *SignatureAndData) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SignatureAndData) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Timestamp != 0 { + i = encodeVarintSolomachine(dAtA, i, uint64(m.Timestamp)) + i-- + dAtA[i] = 0x20 + } + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintSolomachine(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x1a + } + if len(m.Path) > 0 { + i -= len(m.Path) + copy(dAtA[i:], m.Path) + i = encodeVarintSolomachine(dAtA, i, uint64(len(m.Path))) + i-- + dAtA[i] = 0x12 + } + if len(m.Signature) > 0 { + i -= len(m.Signature) + copy(dAtA[i:], m.Signature) + i = encodeVarintSolomachine(dAtA, i, uint64(len(m.Signature))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *TimestampedSignatureData) 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 *TimestampedSignatureData) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TimestampedSignatureData) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Timestamp != 0 { + i = encodeVarintSolomachine(dAtA, i, uint64(m.Timestamp)) + i-- + dAtA[i] = 0x10 + } + if len(m.SignatureData) > 0 { + i -= len(m.SignatureData) + copy(dAtA[i:], m.SignatureData) + i = encodeVarintSolomachine(dAtA, i, uint64(len(m.SignatureData))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *SignBytes) 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 *SignBytes) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SignBytes) 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 = encodeVarintSolomachine(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x2a + } + if len(m.Path) > 0 { + i -= len(m.Path) + copy(dAtA[i:], m.Path) + i = encodeVarintSolomachine(dAtA, i, uint64(len(m.Path))) + i-- + dAtA[i] = 0x22 + } + if len(m.Diversifier) > 0 { + i -= len(m.Diversifier) + copy(dAtA[i:], m.Diversifier) + i = encodeVarintSolomachine(dAtA, i, uint64(len(m.Diversifier))) + i-- + dAtA[i] = 0x1a + } + if m.Timestamp != 0 { + i = encodeVarintSolomachine(dAtA, i, uint64(m.Timestamp)) + i-- + dAtA[i] = 0x10 + } + if m.Sequence != 0 { + i = encodeVarintSolomachine(dAtA, i, uint64(m.Sequence)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *HeaderData) 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 *HeaderData) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *HeaderData) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.NewDiversifier) > 0 { + i -= len(m.NewDiversifier) + copy(dAtA[i:], m.NewDiversifier) + i = encodeVarintSolomachine(dAtA, i, uint64(len(m.NewDiversifier))) + i-- + dAtA[i] = 0x12 + } + if m.NewPubKey != nil { + { + size, err := m.NewPubKey.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSolomachine(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintSolomachine(dAtA []byte, offset int, v uint64) int { + offset -= sovSolomachine(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ClientState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sequence != 0 { + n += 1 + sovSolomachine(uint64(m.Sequence)) + } + if m.IsFrozen { + n += 2 + } + if m.ConsensusState != nil { + l = m.ConsensusState.Size() + n += 1 + l + sovSolomachine(uint64(l)) + } + if m.AllowUpdateAfterProposal { + n += 2 + } + return n +} + +func (m *ConsensusState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PublicKey != nil { + l = m.PublicKey.Size() + n += 1 + l + sovSolomachine(uint64(l)) + } + l = len(m.Diversifier) + if l > 0 { + n += 1 + l + sovSolomachine(uint64(l)) + } + if m.Timestamp != 0 { + n += 1 + sovSolomachine(uint64(m.Timestamp)) + } + return n +} + +func (m *Header) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sequence != 0 { + n += 1 + sovSolomachine(uint64(m.Sequence)) + } + if m.Timestamp != 0 { + n += 1 + sovSolomachine(uint64(m.Timestamp)) + } + l = len(m.Signature) + if l > 0 { + n += 1 + l + sovSolomachine(uint64(l)) + } + if m.NewPublicKey != nil { + l = m.NewPublicKey.Size() + n += 1 + l + sovSolomachine(uint64(l)) + } + l = len(m.NewDiversifier) + if l > 0 { + n += 1 + l + sovSolomachine(uint64(l)) + } + return n +} + +func (m *Misbehaviour) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ClientId) + if l > 0 { + n += 1 + l + sovSolomachine(uint64(l)) + } + if m.Sequence != 0 { + n += 1 + sovSolomachine(uint64(m.Sequence)) + } + if m.SignatureOne != nil { + l = m.SignatureOne.Size() + n += 1 + l + sovSolomachine(uint64(l)) + } + if m.SignatureTwo != nil { + l = m.SignatureTwo.Size() + n += 1 + l + sovSolomachine(uint64(l)) + } + return n +} + +func (m *SignatureAndData) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Signature) + if l > 0 { + n += 1 + l + sovSolomachine(uint64(l)) + } + l = len(m.Path) + if l > 0 { + n += 1 + l + sovSolomachine(uint64(l)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovSolomachine(uint64(l)) + } + if m.Timestamp != 0 { + n += 1 + sovSolomachine(uint64(m.Timestamp)) + } + return n +} + +func (m *TimestampedSignatureData) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SignatureData) + if l > 0 { + n += 1 + l + sovSolomachine(uint64(l)) + } + if m.Timestamp != 0 { + n += 1 + sovSolomachine(uint64(m.Timestamp)) + } + return n +} + +func (m *SignBytes) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sequence != 0 { + n += 1 + sovSolomachine(uint64(m.Sequence)) + } + if m.Timestamp != 0 { + n += 1 + sovSolomachine(uint64(m.Timestamp)) + } + l = len(m.Diversifier) + if l > 0 { + n += 1 + l + sovSolomachine(uint64(l)) + } + l = len(m.Path) + if l > 0 { + n += 1 + l + sovSolomachine(uint64(l)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovSolomachine(uint64(l)) + } + return n +} + +func (m *HeaderData) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.NewPubKey != nil { + l = m.NewPubKey.Size() + n += 1 + l + sovSolomachine(uint64(l)) + } + l = len(m.NewDiversifier) + if l > 0 { + n += 1 + l + sovSolomachine(uint64(l)) + } + return n +} + +func sovSolomachine(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozSolomachine(x uint64) (n int) { + return sovSolomachine(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ClientState) 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 ErrIntOverflowSolomachine + } + 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: ClientState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ClientState: 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 ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Sequence |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsFrozen", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsFrozen = bool(v != 0) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsensusState", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSolomachine + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSolomachine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ConsensusState == nil { + m.ConsensusState = &ConsensusState{} + } + if err := m.ConsensusState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AllowUpdateAfterProposal", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AllowUpdateAfterProposal = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipSolomachine(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSolomachine + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ConsensusState) 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 ErrIntOverflowSolomachine + } + 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: ConsensusState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ConsensusState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PublicKey", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSolomachine + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSolomachine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.PublicKey == nil { + m.PublicKey = &types.Any{} + } + if err := m.PublicKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Diversifier", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + 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 ErrInvalidLengthSolomachine + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSolomachine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Diversifier = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) + } + m.Timestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Timestamp |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipSolomachine(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSolomachine + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Header) 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 ErrIntOverflowSolomachine + } + 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: Header: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Header: 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 ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Sequence |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) + } + m.Timestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Timestamp |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signature", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthSolomachine + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthSolomachine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signature = append(m.Signature[:0], dAtA[iNdEx:postIndex]...) + if m.Signature == nil { + m.Signature = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewPublicKey", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSolomachine + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSolomachine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.NewPublicKey == nil { + m.NewPublicKey = &types.Any{} + } + if err := m.NewPublicKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewDiversifier", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + 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 ErrInvalidLengthSolomachine + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSolomachine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NewDiversifier = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSolomachine(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSolomachine + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Misbehaviour) 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 ErrIntOverflowSolomachine + } + 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: Misbehaviour: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Misbehaviour: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ClientId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + 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 ErrInvalidLengthSolomachine + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSolomachine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ClientId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + 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 ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Sequence |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SignatureOne", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSolomachine + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSolomachine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.SignatureOne == nil { + m.SignatureOne = &SignatureAndData{} + } + if err := m.SignatureOne.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SignatureTwo", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSolomachine + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSolomachine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.SignatureTwo == nil { + m.SignatureTwo = &SignatureAndData{} + } + if err := m.SignatureTwo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSolomachine(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSolomachine + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SignatureAndData) 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 ErrIntOverflowSolomachine + } + 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: SignatureAndData: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SignatureAndData: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signature", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthSolomachine + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthSolomachine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signature = append(m.Signature[:0], dAtA[iNdEx:postIndex]...) + if m.Signature == nil { + m.Signature = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Path", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthSolomachine + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthSolomachine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Path = append(m.Path[:0], dAtA[iNdEx:postIndex]...) + if m.Path == nil { + m.Path = []byte{} + } + iNdEx = postIndex + case 3: + 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 ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthSolomachine + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthSolomachine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) + } + m.Timestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Timestamp |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipSolomachine(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSolomachine + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TimestampedSignatureData) 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 ErrIntOverflowSolomachine + } + 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: TimestampedSignatureData: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TimestampedSignatureData: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SignatureData", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthSolomachine + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthSolomachine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SignatureData = append(m.SignatureData[:0], dAtA[iNdEx:postIndex]...) + if m.SignatureData == nil { + m.SignatureData = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) + } + m.Timestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Timestamp |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipSolomachine(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSolomachine + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SignBytes) 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 ErrIntOverflowSolomachine + } + 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: SignBytes: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SignBytes: 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 ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Sequence |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) + } + m.Timestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Timestamp |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Diversifier", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + 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 ErrInvalidLengthSolomachine + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSolomachine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Diversifier = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Path", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthSolomachine + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthSolomachine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Path = append(m.Path[:0], dAtA[iNdEx:postIndex]...) + if m.Path == nil { + m.Path = []byte{} + } + iNdEx = postIndex + case 5: + 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 ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthSolomachine + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthSolomachine + } + 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 := skipSolomachine(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSolomachine + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *HeaderData) 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 ErrIntOverflowSolomachine + } + 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: HeaderData: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HeaderData: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewPubKey", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSolomachine + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSolomachine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.NewPubKey == nil { + m.NewPubKey = &types.Any{} + } + if err := m.NewPubKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewDiversifier", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSolomachine + } + 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 ErrInvalidLengthSolomachine + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSolomachine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NewDiversifier = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSolomachine(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSolomachine + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipSolomachine(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, ErrIntOverflowSolomachine + } + 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, ErrIntOverflowSolomachine + } + 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, ErrIntOverflowSolomachine + } + 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, ErrInvalidLengthSolomachine + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupSolomachine + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthSolomachine + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthSolomachine = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowSolomachine = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupSolomachine = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/light-clients/06-solomachine/types/solomachine_test.go b/modules/light-clients/06-solomachine/solomachine_test.go similarity index 85% rename from modules/light-clients/06-solomachine/types/solomachine_test.go rename to modules/light-clients/06-solomachine/solomachine_test.go index c789df47228..c73a8ecebc4 100644 --- a/modules/light-clients/06-solomachine/types/solomachine_test.go +++ b/modules/light-clients/06-solomachine/solomachine_test.go @@ -1,4 +1,4 @@ -package types_test +package solomachine_test import ( "testing" @@ -6,7 +6,6 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" @@ -14,7 +13,7 @@ import ( host "github.com/cosmos/ibc-go/v5/modules/core/24-host" "github.com/cosmos/ibc-go/v5/modules/core/exported" - "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine/types" + solomachine "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) @@ -58,7 +57,7 @@ func (suite *SoloMachineTestSuite) GetSequenceFromStore() uint64 { } func (suite *SoloMachineTestSuite) GetInvalidProof() []byte { - invalidProof, err := suite.chainA.Codec.Marshal(&types.TimestampedSignatureData{Timestamp: suite.solomachine.Time}) + invalidProof, err := suite.chainA.Codec.Marshal(&solomachine.TimestampedSignatureData{Timestamp: suite.solomachine.Time}) suite.Require().NoError(err) return invalidProof @@ -68,17 +67,17 @@ func TestUnpackInterfaces_Header(t *testing.T) { registry := testdata.NewTestInterfaceRegistry() cryptocodec.RegisterInterfaces(registry) - pk := secp256k1.GenPrivKey().PubKey().(cryptotypes.PubKey) + pk := secp256k1.GenPrivKey().PubKey() any, err := codectypes.NewAnyWithValue(pk) require.NoError(t, err) - header := types.Header{ + header := solomachine.Header{ NewPublicKey: any, } bz, err := header.Marshal() require.NoError(t, err) - var header2 types.Header + var header2 solomachine.Header err = header2.Unmarshal(bz) require.NoError(t, err) @@ -92,17 +91,17 @@ func TestUnpackInterfaces_HeaderData(t *testing.T) { registry := testdata.NewTestInterfaceRegistry() cryptocodec.RegisterInterfaces(registry) - pk := secp256k1.GenPrivKey().PubKey().(cryptotypes.PubKey) + pk := secp256k1.GenPrivKey().PubKey() any, err := codectypes.NewAnyWithValue(pk) require.NoError(t, err) - hd := types.HeaderData{ + hd := solomachine.HeaderData{ NewPubKey: any, } bz, err := hd.Marshal() require.NoError(t, err) - var hd2 types.HeaderData + var hd2 solomachine.HeaderData err = hd2.Unmarshal(bz) require.NoError(t, err) diff --git a/modules/light-clients/06-solomachine/spec/01_concepts.md b/modules/light-clients/06-solomachine/spec/01_concepts.md index 75d31bf5340..602c9947f71 100644 --- a/modules/light-clients/06-solomachine/spec/01_concepts.md +++ b/modules/light-clients/06-solomachine/spec/01_concepts.md @@ -56,7 +56,7 @@ data := &ClientStateData{ dataBz, err := cdc.Marshal(data) ``` -The helper functions `...DataBytes()` in [proof.go](../types/proof.go) handle this +The helper functions `...DataBytes()` in [proof.go](../proof.go) handle this functionality. 2. Construct the `SignBytes` and marshal it. @@ -75,7 +75,7 @@ signBytes := &SignBytes{ signBz, err := cdc.Marshal(signBytes) ``` -The helper functions `...SignBytes()` in [proof.go](../types/proof.go) handle this functionality. +The helper functions `...SignBytes()` in [proof.go](../proof.go) handle this functionality. The `DataType` field is used to disambiguate what type of data was signed to prevent potential proto encoding overlap. @@ -100,7 +100,7 @@ as the proof parameter to the verification functions. For example: ```go -timestampedSignatureData := &types.TimestampedSignatureData{ +timestampedSignatureData := &solomachine.TimestampedSignatureData{ SignatureData: sigData, Timestamp: solomachine.Time, } diff --git a/modules/light-clients/06-solomachine/types/client_state.go b/modules/light-clients/06-solomachine/types/client_state.go deleted file mode 100644 index e489486ed4f..00000000000 --- a/modules/light-clients/06-solomachine/types/client_state.go +++ /dev/null @@ -1,491 +0,0 @@ -package types - -import ( - "reflect" - - "github.com/cosmos/cosmos-sdk/codec" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/types/tx/signing" - - clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v5/modules/core/24-host" - "github.com/cosmos/ibc-go/v5/modules/core/exported" -) - -var _ exported.ClientState = (*ClientState)(nil) - -// NewClientState creates a new ClientState instance. -func NewClientState(latestSequence uint64, consensusState *ConsensusState, allowUpdateAfterProposal bool) *ClientState { - return &ClientState{ - Sequence: latestSequence, - IsFrozen: false, - ConsensusState: consensusState, - AllowUpdateAfterProposal: allowUpdateAfterProposal, - } -} - -// ClientType is Solo Machine. -func (cs ClientState) ClientType() string { - return exported.Solomachine -} - -// GetLatestHeight returns the latest sequence number. -// Return exported.Height to satisfy ClientState interface -// Revision number is always 0 for a solo-machine. -func (cs ClientState) GetLatestHeight() exported.Height { - return clienttypes.NewHeight(0, cs.Sequence) -} - -// Status returns the status of the solo machine client. -// The client may be: -// - Active: if frozen sequence is 0 -// - Frozen: otherwise solo machine is frozen -func (cs ClientState) Status(_ sdk.Context, _ sdk.KVStore, _ codec.BinaryCodec) exported.Status { - if cs.IsFrozen { - return exported.Frozen - } - - return exported.Active -} - -// Validate performs basic validation of the client state fields. -func (cs ClientState) Validate() error { - if cs.Sequence == 0 { - return sdkerrors.Wrap(clienttypes.ErrInvalidClient, "sequence cannot be 0") - } - if cs.ConsensusState == nil { - return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "consensus state cannot be nil") - } - return cs.ConsensusState.ValidateBasic() -} - -// ZeroCustomFields returns solomachine client state with client-specific fields FrozenSequence, -// and AllowUpdateAfterProposal zeroed out -func (cs ClientState) ZeroCustomFields() exported.ClientState { - return NewClientState( - cs.Sequence, cs.ConsensusState, false, - ) -} - -// Initialize will check that initial consensus state is equal to the latest consensus state of the initial client. -func (cs ClientState) Initialize(_ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, consState exported.ConsensusState) error { - if !reflect.DeepEqual(cs.ConsensusState, consState) { - return sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "consensus state in initial client does not equal initial consensus state. expected: %s, got: %s", - cs.ConsensusState, consState) - } - return nil -} - -// ExportMetadata is a no-op since solomachine does not store any metadata in client store -func (cs ClientState) ExportMetadata(_ sdk.KVStore) []exported.GenesisMetadata { - return nil -} - -// VerifyUpgradeAndUpdateState returns an error since solomachine client does not support upgrades -func (cs ClientState) VerifyUpgradeAndUpdateState( - _ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, - _ exported.ClientState, _ exported.ConsensusState, _, _ []byte, -) (exported.ClientState, exported.ConsensusState, error) { - return nil, nil, sdkerrors.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade solomachine client") -} - -// VerifyClientState verifies a proof of the client state of the running chain -// stored on the solo machine. -func (cs *ClientState) VerifyClientState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - prefix exported.Prefix, - counterpartyClientIdentifier string, - proof []byte, - clientState exported.ClientState, -) error { - // NOTE: the proof height sequence is incremented by one due to the connection handshake verification ordering - height = clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+1) - - publicKey, sigData, timestamp, sequence, err := produceVerificationArgs(cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - clientPrefixedPath := commitmenttypes.NewMerklePath(host.FullClientStatePath(counterpartyClientIdentifier)) - path, err := commitmenttypes.ApplyPrefix(prefix, clientPrefixedPath) - if err != nil { - return err - } - - signBz, err := ClientStateSignBytes(cdc, sequence, timestamp, cs.ConsensusState.Diversifier, path, clientState) - if err != nil { - return err - } - - if err := VerifySignature(publicKey, signBz, sigData); err != nil { - return err - } - - cs.Sequence++ - cs.ConsensusState.Timestamp = timestamp - setClientState(store, cdc, cs) - return nil -} - -// VerifyClientConsensusState verifies a proof of the consensus state of the -// running chain stored on the solo machine. -func (cs *ClientState) VerifyClientConsensusState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - counterpartyClientIdentifier string, - consensusHeight exported.Height, - prefix exported.Prefix, - proof []byte, - consensusState exported.ConsensusState, -) error { - // NOTE: the proof height sequence is incremented by two due to the connection handshake verification ordering - height = clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+2) - - publicKey, sigData, timestamp, sequence, err := produceVerificationArgs(cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - clientPrefixedPath := commitmenttypes.NewMerklePath(host.FullConsensusStatePath(counterpartyClientIdentifier, consensusHeight)) - path, err := commitmenttypes.ApplyPrefix(prefix, clientPrefixedPath) - if err != nil { - return err - } - - signBz, err := ConsensusStateSignBytes(cdc, sequence, timestamp, cs.ConsensusState.Diversifier, path, consensusState) - if err != nil { - return err - } - - if err := VerifySignature(publicKey, signBz, sigData); err != nil { - return err - } - - cs.Sequence++ - cs.ConsensusState.Timestamp = timestamp - setClientState(store, cdc, cs) - return nil -} - -// VerifyConnectionState verifies a proof of the connection state of the -// specified connection end stored on the target machine. -func (cs *ClientState) VerifyConnectionState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - prefix exported.Prefix, - proof []byte, - connectionID string, - connectionEnd exported.ConnectionI, -) error { - publicKey, sigData, timestamp, sequence, err := produceVerificationArgs(cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - connectionPath := commitmenttypes.NewMerklePath(host.ConnectionPath(connectionID)) - path, err := commitmenttypes.ApplyPrefix(prefix, connectionPath) - if err != nil { - return err - } - - signBz, err := ConnectionStateSignBytes(cdc, sequence, timestamp, cs.ConsensusState.Diversifier, path, connectionEnd) - if err != nil { - return err - } - - if err := VerifySignature(publicKey, signBz, sigData); err != nil { - return err - } - - cs.Sequence++ - cs.ConsensusState.Timestamp = timestamp - setClientState(store, cdc, cs) - return nil -} - -// VerifyChannelState verifies a proof of the channel state of the specified -// channel end, under the specified port, stored on the target machine. -func (cs *ClientState) VerifyChannelState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - prefix exported.Prefix, - proof []byte, - portID, - channelID string, - channel exported.ChannelI, -) error { - publicKey, sigData, timestamp, sequence, err := produceVerificationArgs(cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - channelPath := commitmenttypes.NewMerklePath(host.ChannelPath(portID, channelID)) - path, err := commitmenttypes.ApplyPrefix(prefix, channelPath) - if err != nil { - return err - } - - signBz, err := ChannelStateSignBytes(cdc, sequence, timestamp, cs.ConsensusState.Diversifier, path, channel) - if err != nil { - return err - } - - if err := VerifySignature(publicKey, signBz, sigData); err != nil { - return err - } - - cs.Sequence++ - cs.ConsensusState.Timestamp = timestamp - setClientState(store, cdc, cs) - return nil -} - -// VerifyPacketCommitment verifies a proof of an outgoing packet commitment at -// the specified port, specified channel, and specified sequence. -func (cs *ClientState) VerifyPacketCommitment( - ctx sdk.Context, - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - _ uint64, - _ uint64, - prefix exported.Prefix, - proof []byte, - portID, - channelID string, - packetSequence uint64, - commitmentBytes []byte, -) error { - publicKey, sigData, timestamp, sequence, err := produceVerificationArgs(cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - commitmentPath := commitmenttypes.NewMerklePath(host.PacketCommitmentPath(portID, channelID, packetSequence)) - path, err := commitmenttypes.ApplyPrefix(prefix, commitmentPath) - if err != nil { - return err - } - - signBz, err := PacketCommitmentSignBytes(cdc, sequence, timestamp, cs.ConsensusState.Diversifier, path, commitmentBytes) - if err != nil { - return err - } - - if err := VerifySignature(publicKey, signBz, sigData); err != nil { - return err - } - - cs.Sequence++ - cs.ConsensusState.Timestamp = timestamp - setClientState(store, cdc, cs) - return nil -} - -// VerifyPacketAcknowledgement verifies a proof of an incoming packet -// acknowledgement at the specified port, specified channel, and specified sequence. -func (cs *ClientState) VerifyPacketAcknowledgement( - ctx sdk.Context, - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - _ uint64, - _ uint64, - prefix exported.Prefix, - proof []byte, - portID, - channelID string, - packetSequence uint64, - acknowledgement []byte, -) error { - publicKey, sigData, timestamp, sequence, err := produceVerificationArgs(cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - ackPath := commitmenttypes.NewMerklePath(host.PacketAcknowledgementPath(portID, channelID, packetSequence)) - path, err := commitmenttypes.ApplyPrefix(prefix, ackPath) - if err != nil { - return err - } - - signBz, err := PacketAcknowledgementSignBytes(cdc, sequence, timestamp, cs.ConsensusState.Diversifier, path, acknowledgement) - if err != nil { - return err - } - - if err := VerifySignature(publicKey, signBz, sigData); err != nil { - return err - } - - cs.Sequence++ - cs.ConsensusState.Timestamp = timestamp - setClientState(store, cdc, cs) - return nil -} - -// VerifyPacketReceiptAbsence verifies a proof of the absence of an -// incoming packet receipt at the specified port, specified channel, and -// specified sequence. -func (cs *ClientState) VerifyPacketReceiptAbsence( - ctx sdk.Context, - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - _ uint64, - _ uint64, - prefix exported.Prefix, - proof []byte, - portID, - channelID string, - packetSequence uint64, -) error { - publicKey, sigData, timestamp, sequence, err := produceVerificationArgs(cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - receiptPath := commitmenttypes.NewMerklePath(host.PacketReceiptPath(portID, channelID, packetSequence)) - path, err := commitmenttypes.ApplyPrefix(prefix, receiptPath) - if err != nil { - return err - } - - signBz, err := PacketReceiptAbsenceSignBytes(cdc, sequence, timestamp, cs.ConsensusState.Diversifier, path) - if err != nil { - return err - } - - if err := VerifySignature(publicKey, signBz, sigData); err != nil { - return err - } - - cs.Sequence++ - cs.ConsensusState.Timestamp = timestamp - setClientState(store, cdc, cs) - return nil -} - -// VerifyNextSequenceRecv verifies a proof of the next sequence number to be -// received of the specified channel at the specified port. -func (cs *ClientState) VerifyNextSequenceRecv( - ctx sdk.Context, - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - _ uint64, - _ uint64, - prefix exported.Prefix, - proof []byte, - portID, - channelID string, - nextSequenceRecv uint64, -) error { - publicKey, sigData, timestamp, sequence, err := produceVerificationArgs(cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - nextSequenceRecvPath := commitmenttypes.NewMerklePath(host.NextSequenceRecvPath(portID, channelID)) - path, err := commitmenttypes.ApplyPrefix(prefix, nextSequenceRecvPath) - if err != nil { - return err - } - - signBz, err := NextSequenceRecvSignBytes(cdc, sequence, timestamp, cs.ConsensusState.Diversifier, path, nextSequenceRecv) - if err != nil { - return err - } - - if err := VerifySignature(publicKey, signBz, sigData); err != nil { - return err - } - - cs.Sequence++ - cs.ConsensusState.Timestamp = timestamp - setClientState(store, cdc, cs) - return nil -} - -// produceVerificationArgs perfoms the basic checks on the arguments that are -// shared between the verification functions and returns the public key of the -// consensus state, the unmarshalled proof representing the signature and timestamp -// along with the solo-machine sequence encoded in the proofHeight. -func produceVerificationArgs( - cdc codec.BinaryCodec, - cs *ClientState, - height exported.Height, - prefix exported.Prefix, - proof []byte, -) (cryptotypes.PubKey, signing.SignatureData, uint64, uint64, error) { - if revision := height.GetRevisionNumber(); revision != 0 { - return nil, nil, 0, 0, sdkerrors.Wrapf(sdkerrors.ErrInvalidHeight, "revision must be 0 for solomachine, got revision-number: %d", revision) - } - // sequence is encoded in the revision height of height struct - sequence := height.GetRevisionHeight() - if prefix == nil { - return nil, nil, 0, 0, sdkerrors.Wrap(commitmenttypes.ErrInvalidPrefix, "prefix cannot be empty") - } - - _, ok := prefix.(*commitmenttypes.MerklePrefix) - if !ok { - return nil, nil, 0, 0, sdkerrors.Wrapf(commitmenttypes.ErrInvalidPrefix, "invalid prefix type %T, expected MerklePrefix", prefix) - } - - if proof == nil { - return nil, nil, 0, 0, sdkerrors.Wrap(ErrInvalidProof, "proof cannot be empty") - } - - timestampedSigData := &TimestampedSignatureData{} - if err := cdc.Unmarshal(proof, timestampedSigData); err != nil { - return nil, nil, 0, 0, sdkerrors.Wrapf(err, "failed to unmarshal proof into type %T", timestampedSigData) - } - - timestamp := timestampedSigData.Timestamp - - if len(timestampedSigData.SignatureData) == 0 { - return nil, nil, 0, 0, sdkerrors.Wrap(ErrInvalidProof, "signature data cannot be empty") - } - - sigData, err := UnmarshalSignatureData(cdc, timestampedSigData.SignatureData) - if err != nil { - return nil, nil, 0, 0, err - } - - if cs.ConsensusState == nil { - return nil, nil, 0, 0, sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "consensus state cannot be empty") - } - - latestSequence := cs.GetLatestHeight().GetRevisionHeight() - if latestSequence != sequence { - return nil, nil, 0, 0, sdkerrors.Wrapf( - sdkerrors.ErrInvalidHeight, - "client state sequence != proof sequence (%d != %d)", latestSequence, sequence, - ) - } - - if cs.ConsensusState.GetTimestamp() > timestamp { - return nil, nil, 0, 0, sdkerrors.Wrapf(ErrInvalidProof, "the consensus state timestamp is greater than the signature timestamp (%d >= %d)", cs.ConsensusState.GetTimestamp(), timestamp) - } - - publicKey, err := cs.ConsensusState.GetPubKey() - if err != nil { - return nil, nil, 0, 0, err - } - - return publicKey, sigData, timestamp, sequence, nil -} - -// sets the client state to the store -func setClientState(store sdk.KVStore, cdc codec.BinaryCodec, clientState exported.ClientState) { - bz := clienttypes.MustMarshalClientState(cdc, clientState) - store.Set([]byte(host.KeyClientState), bz) -} diff --git a/modules/light-clients/06-solomachine/types/client_state_test.go b/modules/light-clients/06-solomachine/types/client_state_test.go deleted file mode 100644 index 496688bb43d..00000000000 --- a/modules/light-clients/06-solomachine/types/client_state_test.go +++ /dev/null @@ -1,844 +0,0 @@ -package types_test - -import ( - clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v5/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v5/modules/core/exported" - "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine/types" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v5/testing" -) - -const ( - counterpartyClientIdentifier = "chainA" - testConnectionID = "connectionid" - testChannelID = "testchannelid" - testPortID = "testportid" -) - -var ( - prefix = &commitmenttypes.MerklePrefix{ - KeyPrefix: []byte("ibc"), - } - consensusHeight = clienttypes.ZeroHeight() -) - -func (suite *SoloMachineTestSuite) TestStatus() { - clientState := suite.solomachine.ClientState() - // solo machine discards arguments - status := clientState.Status(suite.chainA.GetContext(), nil, nil) - suite.Require().Equal(exported.Active, status) - - // freeze solo machine - clientState.IsFrozen = true - status = clientState.Status(suite.chainA.GetContext(), nil, nil) - suite.Require().Equal(exported.Frozen, status) -} - -func (suite *SoloMachineTestSuite) TestClientStateValidateBasic() { - // test singlesig and multisig public keys - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { - - testCases := []struct { - name string - clientState *types.ClientState - expPass bool - }{ - { - "valid client state", - solomachine.ClientState(), - true, - }, - { - "empty ClientState", - &types.ClientState{}, - false, - }, - { - "sequence is zero", - types.NewClientState(0, &types.ConsensusState{solomachine.ConsensusState().PublicKey, solomachine.Diversifier, solomachine.Time}, false), - false, - }, - { - "timestamp is zero", - types.NewClientState(1, &types.ConsensusState{solomachine.ConsensusState().PublicKey, solomachine.Diversifier, 0}, false), - false, - }, - { - "diversifier is blank", - types.NewClientState(1, &types.ConsensusState{solomachine.ConsensusState().PublicKey, " ", 1}, false), - false, - }, - { - "pubkey is empty", - types.NewClientState(1, &types.ConsensusState{nil, solomachine.Diversifier, solomachine.Time}, false), - false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - err := tc.clientState.Validate() - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } - } -} - -func (suite *SoloMachineTestSuite) TestInitialize() { - // test singlesig and multisig public keys - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { - malleatedConsensus := solomachine.ClientState().ConsensusState - malleatedConsensus.Timestamp = malleatedConsensus.Timestamp + 10 - - testCases := []struct { - name string - consState exported.ConsensusState - expPass bool - }{ - { - "valid consensus state", - solomachine.ConsensusState(), - true, - }, - { - "nil consensus state", - nil, - false, - }, - { - "invalid consensus state: Tendermint consensus state", - &ibctmtypes.ConsensusState{}, - false, - }, - { - "invalid consensus state: consensus state does not match consensus state in client", - malleatedConsensus, - false, - }, - } - - for _, tc := range testCases { - err := solomachine.ClientState().Initialize( - suite.chainA.GetContext(), suite.chainA.Codec, - suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "solomachine"), - tc.consState, - ) - - if tc.expPass { - suite.Require().NoError(err, "valid testcase: %s failed", tc.name) - } else { - suite.Require().Error(err, "invalid testcase: %s passed", tc.name) - } - } - } -} - -func (suite *SoloMachineTestSuite) TestVerifyClientState() { - // create client for tendermint so we can use client state for verification - tmPath := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.SetupClients(tmPath) - clientState := suite.chainA.GetClientState(tmPath.EndpointA.ClientID) - path := suite.solomachine.GetClientStatePath(counterpartyClientIdentifier) - - // test singlesig and multisig public keys - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { - - value, err := types.ClientStateSignBytes(suite.chainA.Codec, solomachine.Sequence, solomachine.Time, solomachine.Diversifier, path, clientState) - suite.Require().NoError(err) - - sig := solomachine.GenerateSignature(value) - - signatureDoc := &types.TimestampedSignatureData{ - SignatureData: sig, - Timestamp: solomachine.Time, - } - - proof, err := suite.chainA.Codec.Marshal(signatureDoc) - suite.Require().NoError(err) - - testCases := []struct { - name string - clientState *types.ClientState - prefix exported.Prefix - proof []byte - expPass bool - }{ - { - "successful verification", - solomachine.ClientState(), - prefix, - proof, - true, - }, - { - "ApplyPrefix failed", - solomachine.ClientState(), - nil, - proof, - false, - }, - { - "consensus state in client state is nil", - types.NewClientState(1, nil, false), - prefix, - proof, - false, - }, - { - "client state latest height is less than sequence", - types.NewClientState(solomachine.Sequence-1, - &types.ConsensusState{ - Timestamp: solomachine.Time, - PublicKey: solomachine.ConsensusState().PublicKey, - }, false), - prefix, - proof, - false, - }, - { - "consensus state timestamp is greater than signature", - types.NewClientState(solomachine.Sequence, - &types.ConsensusState{ - Timestamp: solomachine.Time + 1, - PublicKey: solomachine.ConsensusState().PublicKey, - }, false), - prefix, - proof, - false, - }, - - { - "proof is nil", - solomachine.ClientState(), - prefix, - nil, - false, - }, - { - "proof verification failed", - solomachine.ClientState(), - prefix, - suite.GetInvalidProof(), - false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - var expSeq uint64 - if tc.clientState.ConsensusState != nil { - expSeq = tc.clientState.Sequence + 1 - } - - // NOTE: to replicate the ordering of connection handshake, we must decrement proof height by 1 - height := clienttypes.NewHeight(solomachine.GetHeight().GetRevisionNumber(), solomachine.GetHeight().GetRevisionHeight()-1) - - err := tc.clientState.VerifyClientState( - suite.store, suite.chainA.Codec, height, tc.prefix, counterpartyClientIdentifier, tc.proof, clientState, - ) - - if tc.expPass { - suite.Require().NoError(err) - suite.Require().Equal(expSeq, tc.clientState.Sequence) - suite.Require().Equal(expSeq, suite.GetSequenceFromStore(), "sequence not updated in the store (%d) on valid test case %s", suite.GetSequenceFromStore(), tc.name) - } else { - suite.Require().Error(err) - } - }) - } - } -} - -func (suite *SoloMachineTestSuite) TestVerifyClientConsensusState() { - // create client for tendermint so we can use consensus state for verification - tmPath := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.SetupClients(tmPath) - clientState := suite.chainA.GetClientState(tmPath.EndpointA.ClientID) - consensusState, found := suite.chainA.GetConsensusState(tmPath.EndpointA.ClientID, clientState.GetLatestHeight()) - suite.Require().True(found) - - path := suite.solomachine.GetConsensusStatePath(counterpartyClientIdentifier, consensusHeight) - - // test singlesig and multisig public keys - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { - - value, err := types.ConsensusStateSignBytes(suite.chainA.Codec, solomachine.Sequence, solomachine.Time, solomachine.Diversifier, path, consensusState) - suite.Require().NoError(err) - - sig := solomachine.GenerateSignature(value) - signatureDoc := &types.TimestampedSignatureData{ - SignatureData: sig, - Timestamp: solomachine.Time, - } - - proof, err := suite.chainA.Codec.Marshal(signatureDoc) - suite.Require().NoError(err) - - testCases := []struct { - name string - clientState *types.ClientState - prefix exported.Prefix - proof []byte - expPass bool - }{ - { - "successful verification", - solomachine.ClientState(), - prefix, - proof, - true, - }, - { - "ApplyPrefix failed", - solomachine.ClientState(), - nil, - proof, - false, - }, - { - "consensus state in client state is nil", - types.NewClientState(1, nil, false), - prefix, - proof, - false, - }, - { - "client state latest height is less than sequence", - types.NewClientState(solomachine.Sequence-1, - &types.ConsensusState{ - Timestamp: solomachine.Time, - PublicKey: solomachine.ConsensusState().PublicKey, - }, false), - prefix, - proof, - false, - }, - { - "consensus state timestamp is greater than signature", - types.NewClientState(solomachine.Sequence, - &types.ConsensusState{ - Timestamp: solomachine.Time + 1, - PublicKey: solomachine.ConsensusState().PublicKey, - }, false), - prefix, - proof, - false, - }, - - { - "proof is nil", - solomachine.ClientState(), - prefix, - nil, - false, - }, - { - "proof verification failed", - solomachine.ClientState(), - prefix, - suite.GetInvalidProof(), - false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - var expSeq uint64 - if tc.clientState.ConsensusState != nil { - expSeq = tc.clientState.Sequence + 1 - } - - // NOTE: to replicate the ordering of connection handshake, we must decrement proof height by 1 - height := clienttypes.NewHeight(solomachine.GetHeight().GetRevisionNumber(), solomachine.GetHeight().GetRevisionHeight()-2) - - err := tc.clientState.VerifyClientConsensusState( - suite.store, suite.chainA.Codec, height, counterpartyClientIdentifier, consensusHeight, tc.prefix, tc.proof, consensusState, - ) - - if tc.expPass { - suite.Require().NoError(err) - suite.Require().Equal(expSeq, tc.clientState.Sequence) - suite.Require().Equal(expSeq, suite.GetSequenceFromStore(), "sequence not updated in the store (%d) on valid test case %s", suite.GetSequenceFromStore(), tc.name) - } else { - suite.Require().Error(err) - } - }) - } - } -} - -func (suite *SoloMachineTestSuite) TestVerifyConnectionState() { - counterparty := connectiontypes.NewCounterparty("clientB", testConnectionID, *prefix) - conn := connectiontypes.NewConnectionEnd(connectiontypes.OPEN, "clientA", counterparty, connectiontypes.ExportedVersionsToProto(connectiontypes.GetCompatibleVersions()), 0) - - path := suite.solomachine.GetConnectionStatePath(testConnectionID) - - // test singlesig and multisig public keys - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { - - value, err := types.ConnectionStateSignBytes(suite.chainA.Codec, solomachine.Sequence, solomachine.Time, solomachine.Diversifier, path, conn) - suite.Require().NoError(err) - - sig := solomachine.GenerateSignature(value) - signatureDoc := &types.TimestampedSignatureData{ - SignatureData: sig, - Timestamp: solomachine.Time, - } - - proof, err := suite.chainA.Codec.Marshal(signatureDoc) - suite.Require().NoError(err) - - testCases := []struct { - name string - clientState *types.ClientState - prefix exported.Prefix - proof []byte - expPass bool - }{ - { - "successful verification", - solomachine.ClientState(), - prefix, - proof, - true, - }, - { - "ApplyPrefix failed", - solomachine.ClientState(), - commitmenttypes.NewMerklePrefix([]byte{}), - proof, - false, - }, - { - "proof is nil", - solomachine.ClientState(), - prefix, - nil, - false, - }, - { - "proof verification failed", - solomachine.ClientState(), - prefix, - suite.GetInvalidProof(), - false, - }, - } - - for i, tc := range testCases { - tc := tc - - expSeq := tc.clientState.Sequence + 1 - - err := tc.clientState.VerifyConnectionState( - suite.store, suite.chainA.Codec, solomachine.GetHeight(), tc.prefix, tc.proof, testConnectionID, conn, - ) - - if tc.expPass { - suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) - suite.Require().Equal(expSeq, tc.clientState.Sequence) - suite.Require().Equal(expSeq, suite.GetSequenceFromStore(), "sequence not updated in the store (%d) on valid test case %d: %s", suite.GetSequenceFromStore(), i, tc.name) - } else { - suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) - } - } - } -} - -func (suite *SoloMachineTestSuite) TestVerifyChannelState() { - counterparty := channeltypes.NewCounterparty(testPortID, testChannelID) - ch := channeltypes.NewChannel(channeltypes.OPEN, channeltypes.ORDERED, counterparty, []string{testConnectionID}, "1.0.0") - - path := suite.solomachine.GetChannelStatePath(testPortID, testChannelID) - - // test singlesig and multisig public keys - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { - - value, err := types.ChannelStateSignBytes(suite.chainA.Codec, solomachine.Sequence, solomachine.Time, solomachine.Diversifier, path, ch) - suite.Require().NoError(err) - - sig := solomachine.GenerateSignature(value) - signatureDoc := &types.TimestampedSignatureData{ - SignatureData: sig, - Timestamp: solomachine.Time, - } - - proof, err := suite.chainA.Codec.Marshal(signatureDoc) - suite.Require().NoError(err) - - testCases := []struct { - name string - clientState *types.ClientState - prefix exported.Prefix - proof []byte - expPass bool - }{ - { - "successful verification", - solomachine.ClientState(), - prefix, - proof, - true, - }, - { - "ApplyPrefix failed", - solomachine.ClientState(), - nil, - proof, - false, - }, - { - "proof is nil", - solomachine.ClientState(), - prefix, - nil, - false, - }, - { - "proof verification failed", - solomachine.ClientState(), - prefix, - suite.GetInvalidProof(), - false, - }, - } - - for i, tc := range testCases { - tc := tc - - expSeq := tc.clientState.Sequence + 1 - - err := tc.clientState.VerifyChannelState( - suite.store, suite.chainA.Codec, solomachine.GetHeight(), tc.prefix, tc.proof, testPortID, testChannelID, ch, - ) - - if tc.expPass { - suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) - suite.Require().Equal(expSeq, tc.clientState.Sequence) - suite.Require().Equal(expSeq, suite.GetSequenceFromStore(), "sequence not updated in the store (%d) on valid test case %d: %s", suite.GetSequenceFromStore(), i, tc.name) - } else { - suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) - } - } - } -} - -func (suite *SoloMachineTestSuite) TestVerifyPacketCommitment() { - commitmentBytes := []byte("COMMITMENT BYTES") - - // test singlesig and multisig public keys - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { - - path := solomachine.GetPacketCommitmentPath(testPortID, testChannelID) - - value, err := types.PacketCommitmentSignBytes(suite.chainA.Codec, solomachine.Sequence, solomachine.Time, solomachine.Diversifier, path, commitmentBytes) - suite.Require().NoError(err) - - sig := solomachine.GenerateSignature(value) - signatureDoc := &types.TimestampedSignatureData{ - SignatureData: sig, - Timestamp: solomachine.Time, - } - - proof, err := suite.chainA.Codec.Marshal(signatureDoc) - suite.Require().NoError(err) - - testCases := []struct { - name string - clientState *types.ClientState - prefix exported.Prefix - proof []byte - expPass bool - }{ - { - "successful verification", - solomachine.ClientState(), - prefix, - proof, - true, - }, - { - "ApplyPrefix failed", - solomachine.ClientState(), - commitmenttypes.NewMerklePrefix([]byte{}), - proof, - false, - }, - { - "proof is nil", - solomachine.ClientState(), - prefix, - nil, - false, - }, - { - "proof verification failed", - solomachine.ClientState(), - prefix, - suite.GetInvalidProof(), - false, - }, - } - - for i, tc := range testCases { - tc := tc - - expSeq := tc.clientState.Sequence + 1 - ctx := suite.chainA.GetContext() - - err := tc.clientState.VerifyPacketCommitment( - ctx, suite.store, suite.chainA.Codec, solomachine.GetHeight(), 0, 0, tc.prefix, tc.proof, testPortID, testChannelID, solomachine.Sequence, commitmentBytes, - ) - - if tc.expPass { - suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) - suite.Require().Equal(expSeq, suite.GetSequenceFromStore(), "sequence not updated in the store (%d) on valid test case %d: %s", suite.GetSequenceFromStore(), i, tc.name) - } else { - suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) - } - } - } -} - -func (suite *SoloMachineTestSuite) TestVerifyPacketAcknowledgement() { - ack := []byte("ACK") - // test singlesig and multisig public keys - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { - - path := solomachine.GetPacketAcknowledgementPath(testPortID, testChannelID) - - value, err := types.PacketAcknowledgementSignBytes(suite.chainA.Codec, solomachine.Sequence, solomachine.Time, solomachine.Diversifier, path, ack) - suite.Require().NoError(err) - - sig := solomachine.GenerateSignature(value) - signatureDoc := &types.TimestampedSignatureData{ - SignatureData: sig, - Timestamp: solomachine.Time, - } - - proof, err := suite.chainA.Codec.Marshal(signatureDoc) - suite.Require().NoError(err) - - testCases := []struct { - name string - clientState *types.ClientState - prefix exported.Prefix - proof []byte - expPass bool - }{ - { - "successful verification", - solomachine.ClientState(), - prefix, - proof, - true, - }, - { - "ApplyPrefix failed", - solomachine.ClientState(), - commitmenttypes.NewMerklePrefix([]byte{}), - proof, - false, - }, - { - "proof is nil", - solomachine.ClientState(), - prefix, - nil, - false, - }, - { - "proof verification failed", - solomachine.ClientState(), - prefix, - suite.GetInvalidProof(), - false, - }, - } - - for i, tc := range testCases { - tc := tc - - expSeq := tc.clientState.Sequence + 1 - ctx := suite.chainA.GetContext() - - err := tc.clientState.VerifyPacketAcknowledgement( - ctx, suite.store, suite.chainA.Codec, solomachine.GetHeight(), 0, 0, tc.prefix, tc.proof, testPortID, testChannelID, solomachine.Sequence, ack, - ) - - if tc.expPass { - suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) - suite.Require().Equal(expSeq, suite.GetSequenceFromStore(), "sequence not updated in the store (%d) on valid test case %d: %s", suite.GetSequenceFromStore(), i, tc.name) - } else { - suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) - } - } - } -} - -func (suite *SoloMachineTestSuite) TestVerifyPacketReceiptAbsence() { - // test singlesig and multisig public keys - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { - - // absence uses receipt path as well - path := solomachine.GetPacketReceiptPath(testPortID, testChannelID) - - value, err := types.PacketReceiptAbsenceSignBytes(suite.chainA.Codec, solomachine.Sequence, solomachine.Time, solomachine.Diversifier, path) - suite.Require().NoError(err) - - sig := solomachine.GenerateSignature(value) - signatureDoc := &types.TimestampedSignatureData{ - SignatureData: sig, - Timestamp: solomachine.Time, - } - - proof, err := suite.chainA.Codec.Marshal(signatureDoc) - suite.Require().NoError(err) - - testCases := []struct { - name string - clientState *types.ClientState - prefix exported.Prefix - proof []byte - expPass bool - }{ - { - "successful verification", - solomachine.ClientState(), - prefix, - proof, - true, - }, - { - "ApplyPrefix failed", - solomachine.ClientState(), - commitmenttypes.NewMerklePrefix([]byte{}), - proof, - false, - }, - { - "proof is nil", - solomachine.ClientState(), - prefix, - nil, - false, - }, - { - "proof verification failed", - solomachine.ClientState(), - prefix, - suite.GetInvalidProof(), - false, - }, - } - - for i, tc := range testCases { - tc := tc - - expSeq := tc.clientState.Sequence + 1 - ctx := suite.chainA.GetContext() - - err := tc.clientState.VerifyPacketReceiptAbsence( - ctx, suite.store, suite.chainA.Codec, solomachine.GetHeight(), 0, 0, tc.prefix, tc.proof, testPortID, testChannelID, solomachine.Sequence, - ) - - if tc.expPass { - suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) - suite.Require().Equal(expSeq, suite.GetSequenceFromStore(), "sequence not updated in the store (%d) on valid test case %d: %s", suite.GetSequenceFromStore(), i, tc.name) - } else { - suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) - } - } - } -} - -func (suite *SoloMachineTestSuite) TestVerifyNextSeqRecv() { - // test singlesig and multisig public keys - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { - - nextSeqRecv := solomachine.Sequence + 1 - path := solomachine.GetNextSequenceRecvPath(testPortID, testChannelID) - - value, err := types.NextSequenceRecvSignBytes(suite.chainA.Codec, solomachine.Sequence, solomachine.Time, solomachine.Diversifier, path, nextSeqRecv) - suite.Require().NoError(err) - - sig := solomachine.GenerateSignature(value) - signatureDoc := &types.TimestampedSignatureData{ - SignatureData: sig, - Timestamp: solomachine.Time, - } - - proof, err := suite.chainA.Codec.Marshal(signatureDoc) - suite.Require().NoError(err) - - testCases := []struct { - name string - clientState *types.ClientState - prefix exported.Prefix - proof []byte - expPass bool - }{ - { - "successful verification", - solomachine.ClientState(), - prefix, - proof, - true, - }, - { - "ApplyPrefix failed", - solomachine.ClientState(), - commitmenttypes.NewMerklePrefix([]byte{}), - proof, - false, - }, - { - "proof is nil", - solomachine.ClientState(), - prefix, - nil, - false, - }, - { - "proof verification failed", - solomachine.ClientState(), - prefix, - suite.GetInvalidProof(), - false, - }, - } - - for i, tc := range testCases { - tc := tc - - expSeq := tc.clientState.Sequence + 1 - ctx := suite.chainA.GetContext() - - err := tc.clientState.VerifyNextSequenceRecv( - ctx, suite.store, suite.chainA.Codec, solomachine.GetHeight(), 0, 0, tc.prefix, tc.proof, testPortID, testChannelID, nextSeqRecv, - ) - - if tc.expPass { - suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) - suite.Require().Equal(expSeq, tc.clientState.Sequence) - suite.Require().Equal(expSeq, suite.GetSequenceFromStore(), "sequence not updated in the store (%d) on valid test case %d: %s", suite.GetSequenceFromStore(), i, tc.name) - } else { - suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) - } - } - } -} diff --git a/modules/light-clients/06-solomachine/types/codec.go b/modules/light-clients/06-solomachine/types/codec.go deleted file mode 100644 index 3946b3ee2b5..00000000000 --- a/modules/light-clients/06-solomachine/types/codec.go +++ /dev/null @@ -1,131 +0,0 @@ -package types - -import ( - "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/types/tx/signing" - - clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v5/modules/core/exported" -) - -// RegisterInterfaces register the ibc channel submodule interfaces to protobuf -// Any. -func RegisterInterfaces(registry codectypes.InterfaceRegistry) { - registry.RegisterImplementations( - (*exported.ClientState)(nil), - &ClientState{}, - ) - registry.RegisterImplementations( - (*exported.ConsensusState)(nil), - &ConsensusState{}, - ) - registry.RegisterImplementations( - (*exported.Header)(nil), - &Header{}, - ) - registry.RegisterImplementations( - (*exported.Misbehaviour)(nil), - &Misbehaviour{}, - ) -} - -func UnmarshalSignatureData(cdc codec.BinaryCodec, data []byte) (signing.SignatureData, error) { - protoSigData := &signing.SignatureDescriptor_Data{} - if err := cdc.Unmarshal(data, protoSigData); err != nil { - return nil, sdkerrors.Wrapf(err, "failed to unmarshal proof into type %T", protoSigData) - } - - sigData := signing.SignatureDataFromProto(protoSigData) - - return sigData, nil -} - -// UnmarshalDataByType attempts to unmarshal the data to the specified type. An error is -// return if it fails. -func UnmarshalDataByType(cdc codec.BinaryCodec, dataType DataType, data []byte) (Data, error) { - if len(data) == 0 { - return nil, sdkerrors.Wrap(ErrInvalidSignatureAndData, "data cannot be empty") - } - - switch dataType { - case UNSPECIFIED: - return nil, sdkerrors.Wrap(ErrInvalidDataType, "data type cannot be UNSPECIFIED") - - case CLIENT: - clientData := &ClientStateData{} - if err := cdc.Unmarshal(data, clientData); err != nil { - return nil, err - } - - // unpack any - if _, err := clienttypes.UnpackClientState(clientData.ClientState); err != nil { - return nil, err - } - return clientData, nil - - case CONSENSUS: - consensusData := &ConsensusStateData{} - if err := cdc.Unmarshal(data, consensusData); err != nil { - return nil, err - } - - // unpack any - if _, err := clienttypes.UnpackConsensusState(consensusData.ConsensusState); err != nil { - return nil, err - } - return consensusData, nil - - case CONNECTION: - connectionData := &ConnectionStateData{} - if err := cdc.Unmarshal(data, connectionData); err != nil { - return nil, err - } - - return connectionData, nil - - case CHANNEL: - channelData := &ChannelStateData{} - if err := cdc.Unmarshal(data, channelData); err != nil { - return nil, err - } - - return channelData, nil - - case PACKETCOMMITMENT: - commitmentData := &PacketCommitmentData{} - if err := cdc.Unmarshal(data, commitmentData); err != nil { - return nil, err - } - - return commitmentData, nil - - case PACKETACKNOWLEDGEMENT: - ackData := &PacketAcknowledgementData{} - if err := cdc.Unmarshal(data, ackData); err != nil { - return nil, err - } - - return ackData, nil - - case PACKETRECEIPTABSENCE: - receiptAbsenceData := &PacketReceiptAbsenceData{} - if err := cdc.Unmarshal(data, receiptAbsenceData); err != nil { - return nil, err - } - - return receiptAbsenceData, nil - - case NEXTSEQUENCERECV: - nextSeqRecvData := &NextSequenceRecvData{} - if err := cdc.Unmarshal(data, nextSeqRecvData); err != nil { - return nil, err - } - - return nextSeqRecvData, nil - - default: - return nil, sdkerrors.Wrapf(ErrInvalidDataType, "unsupported data type %T", dataType) - } -} diff --git a/modules/light-clients/06-solomachine/types/codec_test.go b/modules/light-clients/06-solomachine/types/codec_test.go deleted file mode 100644 index bef62d2654d..00000000000 --- a/modules/light-clients/06-solomachine/types/codec_test.go +++ /dev/null @@ -1,186 +0,0 @@ -package types_test - -import ( - clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v5/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine/types" - ibctesting "github.com/cosmos/ibc-go/v5/testing" -) - -func (suite SoloMachineTestSuite) TestUnmarshalDataByType() { - var ( - data []byte - err error - ) - - // test singlesig and multisig public keys - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { - - cdc := suite.chainA.App.AppCodec() - cases := []struct { - name string - dataType types.DataType - malleate func() - expPass bool - }{ - { - "empty data", types.CLIENT, func() { - data = []byte{} - }, false, - }, - { - "unspecified", types.UNSPECIFIED, func() { - path := solomachine.GetClientStatePath(counterpartyClientIdentifier) - data, err = types.ClientStateDataBytes(cdc, path, solomachine.ClientState()) - suite.Require().NoError(err) - }, false, - }, - { - "client", types.CLIENT, func() { - path := solomachine.GetClientStatePath(counterpartyClientIdentifier) - data, err = types.ClientStateDataBytes(cdc, path, solomachine.ClientState()) - suite.Require().NoError(err) - }, true, - }, - { - "bad client (provides consensus state data)", types.CLIENT, func() { - path := solomachine.GetConsensusStatePath(counterpartyClientIdentifier, clienttypes.NewHeight(0, 5)) - data, err = types.ConsensusStateDataBytes(cdc, path, solomachine.ConsensusState()) - suite.Require().NoError(err) - }, false, - }, - { - "consensus", types.CONSENSUS, func() { - path := solomachine.GetConsensusStatePath(counterpartyClientIdentifier, clienttypes.NewHeight(0, 5)) - data, err = types.ConsensusStateDataBytes(cdc, path, solomachine.ConsensusState()) - suite.Require().NoError(err) - }, true, - }, - { - "bad consensus (provides client state data)", types.CONSENSUS, func() { - path := solomachine.GetClientStatePath(counterpartyClientIdentifier) - data, err = types.ClientStateDataBytes(cdc, path, solomachine.ClientState()) - suite.Require().NoError(err) - }, false, - }, - { - "connection", types.CONNECTION, func() { - counterparty := connectiontypes.NewCounterparty("clientB", testConnectionID, *prefix) - conn := connectiontypes.NewConnectionEnd(connectiontypes.OPEN, "clientA", counterparty, connectiontypes.ExportedVersionsToProto(connectiontypes.GetCompatibleVersions()), 0) - path := solomachine.GetConnectionStatePath("connectionID") - - data, err = types.ConnectionStateDataBytes(cdc, path, conn) - suite.Require().NoError(err) - }, true, - }, - { - "bad connection (uses channel data)", types.CONNECTION, func() { - counterparty := channeltypes.NewCounterparty(testPortID, testChannelID) - ch := channeltypes.NewChannel(channeltypes.OPEN, channeltypes.ORDERED, counterparty, []string{testConnectionID}, "1.0.0") - path := solomachine.GetChannelStatePath("portID", "channelID") - - data, err = types.ChannelStateDataBytes(cdc, path, ch) - suite.Require().NoError(err) - }, false, - }, - { - "channel", types.CHANNEL, func() { - counterparty := channeltypes.NewCounterparty(testPortID, testChannelID) - ch := channeltypes.NewChannel(channeltypes.OPEN, channeltypes.ORDERED, counterparty, []string{testConnectionID}, "1.0.0") - path := solomachine.GetChannelStatePath("portID", "channelID") - - data, err = types.ChannelStateDataBytes(cdc, path, ch) - suite.Require().NoError(err) - }, true, - }, - { - "bad channel (uses connection data)", types.CHANNEL, func() { - counterparty := connectiontypes.NewCounterparty("clientB", testConnectionID, *prefix) - conn := connectiontypes.NewConnectionEnd(connectiontypes.OPEN, "clientA", counterparty, connectiontypes.ExportedVersionsToProto(connectiontypes.GetCompatibleVersions()), 0) - path := solomachine.GetConnectionStatePath("connectionID") - - data, err = types.ConnectionStateDataBytes(cdc, path, conn) - suite.Require().NoError(err) - }, false, - }, - { - "packet commitment", types.PACKETCOMMITMENT, func() { - commitment := []byte("packet commitment") - path := solomachine.GetPacketCommitmentPath("portID", "channelID") - - data, err = types.PacketCommitmentDataBytes(cdc, path, commitment) - suite.Require().NoError(err) - }, true, - }, - { - "bad packet commitment (uses next seq recv)", types.PACKETCOMMITMENT, func() { - path := solomachine.GetNextSequenceRecvPath("portID", "channelID") - - data, err = types.NextSequenceRecvDataBytes(cdc, path, 10) - suite.Require().NoError(err) - }, false, - }, - { - "packet acknowledgement", types.PACKETACKNOWLEDGEMENT, func() { - commitment := []byte("packet acknowledgement") - path := solomachine.GetPacketAcknowledgementPath("portID", "channelID") - - data, err = types.PacketAcknowledgementDataBytes(cdc, path, commitment) - suite.Require().NoError(err) - }, true, - }, - { - "bad packet acknowledgement (uses next sequence recv)", types.PACKETACKNOWLEDGEMENT, func() { - path := solomachine.GetNextSequenceRecvPath("portID", "channelID") - - data, err = types.NextSequenceRecvDataBytes(cdc, path, 10) - suite.Require().NoError(err) - }, false, - }, - { - "packet acknowledgement absence", types.PACKETRECEIPTABSENCE, func() { - path := solomachine.GetPacketReceiptPath("portID", "channelID") - - data, err = types.PacketReceiptAbsenceDataBytes(cdc, path) - suite.Require().NoError(err) - }, true, - }, - { - "next sequence recv", types.NEXTSEQUENCERECV, func() { - path := solomachine.GetNextSequenceRecvPath("portID", "channelID") - - data, err = types.NextSequenceRecvDataBytes(cdc, path, 10) - suite.Require().NoError(err) - }, true, - }, - { - "bad next sequence recv (uses packet commitment)", types.NEXTSEQUENCERECV, func() { - commitment := []byte("packet commitment") - path := solomachine.GetPacketCommitmentPath("portID", "channelID") - - data, err = types.PacketCommitmentDataBytes(cdc, path, commitment) - suite.Require().NoError(err) - }, false, - }, - } - - for _, tc := range cases { - tc := tc - - suite.Run(tc.name, func() { - tc.malleate() - - data, err := types.UnmarshalDataByType(cdc, tc.dataType, data) - - if tc.expPass { - suite.Require().NoError(err) - suite.Require().NotNil(data) - } else { - suite.Require().Error(err) - suite.Require().Nil(data) - } - }) - } - } -} diff --git a/modules/light-clients/06-solomachine/types/misbehaviour_handle.go b/modules/light-clients/06-solomachine/types/misbehaviour_handle.go deleted file mode 100644 index 805847e9b21..00000000000 --- a/modules/light-clients/06-solomachine/types/misbehaviour_handle.go +++ /dev/null @@ -1,86 +0,0 @@ -package types - -import ( - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v5/modules/core/exported" -) - -// CheckMisbehaviourAndUpdateState determines whether or not the currently registered -// public key signed over two different messages with the same sequence. If this is true -// the client state is updated to a frozen status. -// NOTE: Misbehaviour is not tracked for previous public keys, a solo machine may update to -// a new public key before the misbehaviour is processed. Therefore, misbehaviour is data -// order processing dependent. -func (cs ClientState) CheckMisbehaviourAndUpdateState( - ctx sdk.Context, - cdc codec.BinaryCodec, - clientStore sdk.KVStore, - misbehaviour exported.Misbehaviour, -) (exported.ClientState, error) { - soloMisbehaviour, ok := misbehaviour.(*Misbehaviour) - if !ok { - return nil, sdkerrors.Wrapf( - clienttypes.ErrInvalidClientType, - "misbehaviour type %T, expected %T", misbehaviour, &Misbehaviour{}, - ) - } - - // NOTE: a check that the misbehaviour message data are not equal is done by - // misbehaviour.ValidateBasic which is called by the 02-client keeper. - - // verify first signature - if err := verifySignatureAndData(cdc, cs, soloMisbehaviour, soloMisbehaviour.SignatureOne); err != nil { - return nil, sdkerrors.Wrap(err, "failed to verify signature one") - } - - // verify second signature - if err := verifySignatureAndData(cdc, cs, soloMisbehaviour, soloMisbehaviour.SignatureTwo); err != nil { - return nil, sdkerrors.Wrap(err, "failed to verify signature two") - } - - cs.IsFrozen = true - return &cs, nil -} - -// verifySignatureAndData verifies that the currently registered public key has signed -// over the provided data and that the data is valid. The data is valid if it can be -// unmarshaled into the specified data type. -func verifySignatureAndData(cdc codec.BinaryCodec, clientState ClientState, misbehaviour *Misbehaviour, sigAndData *SignatureAndData) error { - // do not check misbehaviour timestamp since we want to allow processing of past misbehaviour - - // ensure data can be unmarshaled to the specified data type - if _, err := UnmarshalDataByType(cdc, sigAndData.DataType, sigAndData.Data); err != nil { - return err - } - - data, err := MisbehaviourSignBytes( - cdc, - misbehaviour.Sequence, sigAndData.Timestamp, - clientState.ConsensusState.Diversifier, - sigAndData.DataType, - sigAndData.Data, - ) - if err != nil { - return err - } - - sigData, err := UnmarshalSignatureData(cdc, sigAndData.Signature) - if err != nil { - return err - } - - publicKey, err := clientState.ConsensusState.GetPubKey() - if err != nil { - return err - } - - if err := VerifySignature(publicKey, data, sigData); err != nil { - return err - } - - return nil -} diff --git a/modules/light-clients/06-solomachine/types/misbehaviour_handle_test.go b/modules/light-clients/06-solomachine/types/misbehaviour_handle_test.go deleted file mode 100644 index 945aff3c481..00000000000 --- a/modules/light-clients/06-solomachine/types/misbehaviour_handle_test.go +++ /dev/null @@ -1,264 +0,0 @@ -package types_test - -import ( - "github.com/cosmos/ibc-go/v5/modules/core/exported" - "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine/types" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v5/testing" -) - -func (suite *SoloMachineTestSuite) TestCheckMisbehaviourAndUpdateState() { - var ( - clientState exported.ClientState - misbehaviour exported.Misbehaviour - ) - - // test singlesig and multisig public keys - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { - - testCases := []struct { - name string - setup func() - expPass bool - }{ - { - "valid misbehaviour", - func() { - clientState = solomachine.ClientState() - misbehaviour = solomachine.CreateMisbehaviour() - }, - true, - }, - { - "old misbehaviour is successful (timestamp is less than current consensus state)", - func() { - clientState = solomachine.ClientState() - solomachine.Time = solomachine.Time - 5 - misbehaviour = solomachine.CreateMisbehaviour() - }, true, - }, - { - "wrong client state type", - func() { - clientState = &ibctmtypes.ClientState{} - misbehaviour = solomachine.CreateMisbehaviour() - }, - false, - }, - { - "invalid misbehaviour type", - func() { - clientState = solomachine.ClientState() - misbehaviour = &ibctmtypes.Misbehaviour{} - }, - false, - }, - { - "invalid SignatureOne SignatureData", - func() { - clientState = solomachine.ClientState() - m := solomachine.CreateMisbehaviour() - - m.SignatureOne.Signature = suite.GetInvalidProof() - misbehaviour = m - }, false, - }, - { - "invalid SignatureTwo SignatureData", - func() { - clientState = solomachine.ClientState() - m := solomachine.CreateMisbehaviour() - - m.SignatureTwo.Signature = suite.GetInvalidProof() - misbehaviour = m - }, false, - }, - { - "invalid SignatureOne timestamp", - func() { - clientState = solomachine.ClientState() - m := solomachine.CreateMisbehaviour() - - m.SignatureOne.Timestamp = 1000000000000 - misbehaviour = m - }, false, - }, - { - "invalid SignatureTwo timestamp", - func() { - clientState = solomachine.ClientState() - m := solomachine.CreateMisbehaviour() - - m.SignatureTwo.Timestamp = 1000000000000 - misbehaviour = m - }, false, - }, - { - "invalid first signature data", - func() { - clientState = solomachine.ClientState() - - // store in temp before assigning to interface type - m := solomachine.CreateMisbehaviour() - - msg := []byte("DATA ONE") - signBytes := &types.SignBytes{ - Sequence: solomachine.Sequence + 1, - Timestamp: solomachine.Time, - Diversifier: solomachine.Diversifier, - DataType: types.CLIENT, - Data: msg, - } - - data, err := suite.chainA.Codec.Marshal(signBytes) - suite.Require().NoError(err) - - sig := solomachine.GenerateSignature(data) - - m.SignatureOne.Signature = sig - m.SignatureOne.Data = msg - misbehaviour = m - }, - false, - }, - { - "invalid second signature data", - func() { - clientState = solomachine.ClientState() - - // store in temp before assigning to interface type - m := solomachine.CreateMisbehaviour() - - msg := []byte("DATA TWO") - signBytes := &types.SignBytes{ - Sequence: solomachine.Sequence + 1, - Timestamp: solomachine.Time, - Diversifier: solomachine.Diversifier, - DataType: types.CLIENT, - Data: msg, - } - - data, err := suite.chainA.Codec.Marshal(signBytes) - suite.Require().NoError(err) - - sig := solomachine.GenerateSignature(data) - - m.SignatureTwo.Signature = sig - m.SignatureTwo.Data = msg - misbehaviour = m - }, - false, - }, - { - "wrong pubkey generates first signature", - func() { - clientState = solomachine.ClientState() - badMisbehaviour := solomachine.CreateMisbehaviour() - - // update public key to a new one - solomachine.CreateHeader() - m := solomachine.CreateMisbehaviour() - - // set SignatureOne to use the wrong signature - m.SignatureOne = badMisbehaviour.SignatureOne - misbehaviour = m - }, false, - }, - { - "wrong pubkey generates second signature", - func() { - clientState = solomachine.ClientState() - badMisbehaviour := solomachine.CreateMisbehaviour() - - // update public key to a new one - solomachine.CreateHeader() - m := solomachine.CreateMisbehaviour() - - // set SignatureTwo to use the wrong signature - m.SignatureTwo = badMisbehaviour.SignatureTwo - misbehaviour = m - }, false, - }, - - { - "signatures sign over different sequence", - func() { - clientState = solomachine.ClientState() - - // store in temp before assigning to interface type - m := solomachine.CreateMisbehaviour() - - // Signature One - msg := []byte("DATA ONE") - // sequence used is plus 1 - signBytes := &types.SignBytes{ - Sequence: solomachine.Sequence + 1, - Timestamp: solomachine.Time, - Diversifier: solomachine.Diversifier, - DataType: types.CLIENT, - Data: msg, - } - - data, err := suite.chainA.Codec.Marshal(signBytes) - suite.Require().NoError(err) - - sig := solomachine.GenerateSignature(data) - - m.SignatureOne.Signature = sig - m.SignatureOne.Data = msg - - // Signature Two - msg = []byte("DATA TWO") - // sequence used is minus 1 - - signBytes = &types.SignBytes{ - Sequence: solomachine.Sequence - 1, - Timestamp: solomachine.Time, - Diversifier: solomachine.Diversifier, - DataType: types.CLIENT, - Data: msg, - } - data, err = suite.chainA.Codec.Marshal(signBytes) - suite.Require().NoError(err) - - sig = solomachine.GenerateSignature(data) - - m.SignatureTwo.Signature = sig - m.SignatureTwo.Data = msg - - misbehaviour = m - }, - false, - }, - { - "consensus state pubkey is nil", - func() { - cs := solomachine.ClientState() - cs.ConsensusState.PublicKey = nil - clientState = cs - misbehaviour = solomachine.CreateMisbehaviour() - }, - false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - // setup test - tc.setup() - - clientState, err := clientState.CheckMisbehaviourAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), suite.store, misbehaviour) - - if tc.expPass { - suite.Require().NoError(err) - suite.Require().True(clientState.(*types.ClientState).IsFrozen, "client not frozen") - } else { - suite.Require().Error(err) - suite.Require().Nil(clientState) - } - }) - } - } -} diff --git a/modules/light-clients/06-solomachine/types/proof.go b/modules/light-clients/06-solomachine/types/proof.go deleted file mode 100644 index 35ce4d9cd54..00000000000 --- a/modules/light-clients/06-solomachine/types/proof.go +++ /dev/null @@ -1,477 +0,0 @@ -package types - -import ( - "github.com/cosmos/cosmos-sdk/codec" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - "github.com/cosmos/cosmos-sdk/crypto/types/multisig" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/types/tx/signing" - - clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v5/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v5/modules/core/exported" -) - -// VerifySignature verifies if the the provided public key generated the signature -// over the given data. Single and Multi signature public keys are supported. -// The signature data type must correspond to the public key type. An error is -// returned if signature verification fails or an invalid SignatureData type is -// provided. -func VerifySignature(pubKey cryptotypes.PubKey, signBytes []byte, sigData signing.SignatureData) error { - switch pubKey := pubKey.(type) { - case multisig.PubKey: - data, ok := sigData.(*signing.MultiSignatureData) - if !ok { - return sdkerrors.Wrapf(ErrSignatureVerificationFailed, "invalid signature data type, expected %T, got %T", (*signing.MultiSignatureData)(nil), data) - } - - // The function supplied fulfills the VerifyMultisignature interface. No special - // adjustments need to be made to the sign bytes based on the sign mode. - if err := pubKey.VerifyMultisignature(func(signing.SignMode) ([]byte, error) { - return signBytes, nil - }, data); err != nil { - return err - } - - default: - data, ok := sigData.(*signing.SingleSignatureData) - if !ok { - return sdkerrors.Wrapf(ErrSignatureVerificationFailed, "invalid signature data type, expected %T, got %T", (*signing.SingleSignatureData)(nil), data) - } - - if !pubKey.VerifySignature(signBytes, data.Signature) { - return ErrSignatureVerificationFailed - } - } - - return nil -} - -// MisbehaviourSignBytes returns the sign bytes for verification of misbehaviour. -func MisbehaviourSignBytes( - cdc codec.BinaryCodec, - sequence, timestamp uint64, - diversifier string, - dataType DataType, - data []byte, -) ([]byte, error) { - signBytes := &SignBytes{ - Sequence: sequence, - Timestamp: timestamp, - Diversifier: diversifier, - DataType: dataType, - Data: data, - } - - return cdc.Marshal(signBytes) -} - -// HeaderSignBytes returns the sign bytes for verification of misbehaviour. -func HeaderSignBytes( - cdc codec.BinaryCodec, - header *Header, -) ([]byte, error) { - data := &HeaderData{ - NewPubKey: header.NewPublicKey, - NewDiversifier: header.NewDiversifier, - } - - dataBz, err := cdc.Marshal(data) - if err != nil { - return nil, err - } - - signBytes := &SignBytes{ - Sequence: header.Sequence, - Timestamp: header.Timestamp, - Diversifier: header.NewDiversifier, - DataType: HEADER, - Data: dataBz, - } - - return cdc.Marshal(signBytes) -} - -// ClientStateSignBytes returns the sign bytes for verification of the -// client state. -func ClientStateSignBytes( - cdc codec.BinaryCodec, - sequence, timestamp uint64, - diversifier string, - path commitmenttypes.MerklePath, - clientState exported.ClientState, -) ([]byte, error) { - dataBz, err := ClientStateDataBytes(cdc, path, clientState) - if err != nil { - return nil, err - } - - signBytes := &SignBytes{ - Sequence: sequence, - Timestamp: timestamp, - Diversifier: diversifier, - DataType: CLIENT, - Data: dataBz, - } - - return cdc.Marshal(signBytes) -} - -// ClientStateDataBytes returns the client state data bytes used in constructing -// SignBytes. -func ClientStateDataBytes( - cdc codec.BinaryCodec, - path commitmenttypes.MerklePath, //nolint:interfacer - clientState exported.ClientState, -) ([]byte, error) { - any, err := clienttypes.PackClientState(clientState) - if err != nil { - return nil, err - } - - data := &ClientStateData{ - Path: []byte(path.String()), - ClientState: any, - } - - dataBz, err := cdc.Marshal(data) - if err != nil { - return nil, err - } - - return dataBz, nil -} - -// ConsensusStateSignBytes returns the sign bytes for verification of the -// consensus state. -func ConsensusStateSignBytes( - cdc codec.BinaryCodec, - sequence, timestamp uint64, - diversifier string, - path commitmenttypes.MerklePath, - consensusState exported.ConsensusState, -) ([]byte, error) { - dataBz, err := ConsensusStateDataBytes(cdc, path, consensusState) - if err != nil { - return nil, err - } - - signBytes := &SignBytes{ - Sequence: sequence, - Timestamp: timestamp, - Diversifier: diversifier, - DataType: CONSENSUS, - Data: dataBz, - } - - return cdc.Marshal(signBytes) -} - -// ConsensusStateDataBytes returns the consensus state data bytes used in constructing -// SignBytes. -func ConsensusStateDataBytes( - cdc codec.BinaryCodec, - path commitmenttypes.MerklePath, //nolint:interfacer - consensusState exported.ConsensusState, -) ([]byte, error) { - any, err := clienttypes.PackConsensusState(consensusState) - if err != nil { - return nil, err - } - - data := &ConsensusStateData{ - Path: []byte(path.String()), - ConsensusState: any, - } - - dataBz, err := cdc.Marshal(data) - if err != nil { - return nil, err - } - - return dataBz, nil -} - -// ConnectionStateSignBytes returns the sign bytes for verification of the -// connection state. -func ConnectionStateSignBytes( - cdc codec.BinaryCodec, - sequence, timestamp uint64, - diversifier string, - path commitmenttypes.MerklePath, - connectionEnd exported.ConnectionI, -) ([]byte, error) { - dataBz, err := ConnectionStateDataBytes(cdc, path, connectionEnd) - if err != nil { - return nil, err - } - - signBytes := &SignBytes{ - Sequence: sequence, - Timestamp: timestamp, - Diversifier: diversifier, - DataType: CONNECTION, - Data: dataBz, - } - - return cdc.Marshal(signBytes) -} - -// ConnectionStateDataBytes returns the connection state data bytes used in constructing -// SignBytes. -func ConnectionStateDataBytes( - cdc codec.BinaryCodec, - path commitmenttypes.MerklePath, //nolint:interfacer - connectionEnd exported.ConnectionI, -) ([]byte, error) { - connection, ok := connectionEnd.(connectiontypes.ConnectionEnd) - if !ok { - return nil, sdkerrors.Wrapf( - connectiontypes.ErrInvalidConnection, - "expected type %T, got %T", connectiontypes.ConnectionEnd{}, connectionEnd, - ) - } - - data := &ConnectionStateData{ - Path: []byte(path.String()), - Connection: &connection, - } - - dataBz, err := cdc.Marshal(data) - if err != nil { - return nil, err - } - - return dataBz, nil -} - -// ChannelStateSignBytes returns the sign bytes for verification of the -// channel state. -func ChannelStateSignBytes( - cdc codec.BinaryCodec, - sequence, timestamp uint64, - diversifier string, - path commitmenttypes.MerklePath, - channelEnd exported.ChannelI, -) ([]byte, error) { - dataBz, err := ChannelStateDataBytes(cdc, path, channelEnd) - if err != nil { - return nil, err - } - - signBytes := &SignBytes{ - Sequence: sequence, - Timestamp: timestamp, - Diversifier: diversifier, - DataType: CHANNEL, - Data: dataBz, - } - - return cdc.Marshal(signBytes) -} - -// ChannelStateDataBytes returns the channel state data bytes used in constructing -// SignBytes. -func ChannelStateDataBytes( - cdc codec.BinaryCodec, - path commitmenttypes.MerklePath, //nolint:interfacer - channelEnd exported.ChannelI, -) ([]byte, error) { - channel, ok := channelEnd.(channeltypes.Channel) - if !ok { - return nil, sdkerrors.Wrapf( - channeltypes.ErrInvalidChannel, - "expected channel type %T, got %T", channeltypes.Channel{}, channelEnd) - } - - data := &ChannelStateData{ - Path: []byte(path.String()), - Channel: &channel, - } - - dataBz, err := cdc.Marshal(data) - if err != nil { - return nil, err - } - - return dataBz, nil -} - -// PacketCommitmentSignBytes returns the sign bytes for verification of the -// packet commitment. -func PacketCommitmentSignBytes( - cdc codec.BinaryCodec, - sequence, timestamp uint64, - diversifier string, - path commitmenttypes.MerklePath, - commitmentBytes []byte, -) ([]byte, error) { - dataBz, err := PacketCommitmentDataBytes(cdc, path, commitmentBytes) - if err != nil { - return nil, err - } - - signBytes := &SignBytes{ - Sequence: sequence, - Timestamp: timestamp, - Diversifier: diversifier, - DataType: PACKETCOMMITMENT, - Data: dataBz, - } - - return cdc.Marshal(signBytes) -} - -// PacketCommitmentDataBytes returns the packet commitment data bytes used in constructing -// SignBytes. -func PacketCommitmentDataBytes( - cdc codec.BinaryCodec, - path commitmenttypes.MerklePath, //nolint:interfacer - commitmentBytes []byte, -) ([]byte, error) { - data := &PacketCommitmentData{ - Path: []byte(path.String()), - Commitment: commitmentBytes, - } - - dataBz, err := cdc.Marshal(data) - if err != nil { - return nil, err - } - - return dataBz, nil -} - -// PacketAcknowledgementSignBytes returns the sign bytes for verification of -// the acknowledgement. -func PacketAcknowledgementSignBytes( - cdc codec.BinaryCodec, - sequence, timestamp uint64, - diversifier string, - path commitmenttypes.MerklePath, - acknowledgement []byte, -) ([]byte, error) { - dataBz, err := PacketAcknowledgementDataBytes(cdc, path, acknowledgement) - if err != nil { - return nil, err - } - - signBytes := &SignBytes{ - Sequence: sequence, - Timestamp: timestamp, - Diversifier: diversifier, - DataType: PACKETACKNOWLEDGEMENT, - Data: dataBz, - } - - return cdc.Marshal(signBytes) -} - -// PacketAcknowledgementDataBytes returns the packet acknowledgement data bytes used in constructing -// SignBytes. -func PacketAcknowledgementDataBytes( - cdc codec.BinaryCodec, - path commitmenttypes.MerklePath, //nolint:interfacer - acknowledgement []byte, -) ([]byte, error) { - data := &PacketAcknowledgementData{ - Path: []byte(path.String()), - Acknowledgement: acknowledgement, - } - - dataBz, err := cdc.Marshal(data) - if err != nil { - return nil, err - } - - return dataBz, nil -} - -// PacketReceiptAbsenceSignBytes returns the sign bytes for verification -// of the absence of an receipt. -func PacketReceiptAbsenceSignBytes( - cdc codec.BinaryCodec, - sequence, timestamp uint64, - diversifier string, - path commitmenttypes.MerklePath, -) ([]byte, error) { - dataBz, err := PacketReceiptAbsenceDataBytes(cdc, path) - if err != nil { - return nil, err - } - - signBytes := &SignBytes{ - Sequence: sequence, - Timestamp: timestamp, - Diversifier: diversifier, - DataType: PACKETRECEIPTABSENCE, - Data: dataBz, - } - - return cdc.Marshal(signBytes) -} - -// PacketReceiptAbsenceDataBytes returns the packet receipt absence data bytes -// used in constructing SignBytes. -func PacketReceiptAbsenceDataBytes( - cdc codec.BinaryCodec, - path commitmenttypes.MerklePath, //nolint:interfacer -) ([]byte, error) { - data := &PacketReceiptAbsenceData{ - Path: []byte(path.String()), - } - - dataBz, err := cdc.Marshal(data) - if err != nil { - return nil, err - } - - return dataBz, nil -} - -// NextSequenceRecvSignBytes returns the sign bytes for verification of the next -// sequence to be received. -func NextSequenceRecvSignBytes( - cdc codec.BinaryCodec, - sequence, timestamp uint64, - diversifier string, - path commitmenttypes.MerklePath, - nextSequenceRecv uint64, -) ([]byte, error) { - dataBz, err := NextSequenceRecvDataBytes(cdc, path, nextSequenceRecv) - if err != nil { - return nil, err - } - - signBytes := &SignBytes{ - Sequence: sequence, - Timestamp: timestamp, - Diversifier: diversifier, - DataType: NEXTSEQUENCERECV, - Data: dataBz, - } - - return cdc.Marshal(signBytes) -} - -// NextSequenceRecvDataBytes returns the next sequence recv data bytes used in constructing -// SignBytes. -func NextSequenceRecvDataBytes( - cdc codec.BinaryCodec, - path commitmenttypes.MerklePath, //nolint:interfacer - nextSequenceRecv uint64, -) ([]byte, error) { - data := &NextSequenceRecvData{ - Path: []byte(path.String()), - NextSeqRecv: nextSequenceRecv, - } - - dataBz, err := cdc.Marshal(data) - if err != nil { - return nil, err - } - - return dataBz, nil -} diff --git a/modules/light-clients/06-solomachine/types/proof_test.go b/modules/light-clients/06-solomachine/types/proof_test.go deleted file mode 100644 index 6a79998ab33..00000000000 --- a/modules/light-clients/06-solomachine/types/proof_test.go +++ /dev/null @@ -1,103 +0,0 @@ -package types_test - -import ( - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - "github.com/cosmos/cosmos-sdk/types/tx/signing" - - "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine/types" - solomachinetypes "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine/types" - ibctesting "github.com/cosmos/ibc-go/v5/testing" -) - -func (suite *SoloMachineTestSuite) TestVerifySignature() { - cdc := suite.chainA.App.AppCodec() - signBytes := []byte("sign bytes") - - singleSignature := suite.solomachine.GenerateSignature(signBytes) - singleSigData, err := solomachinetypes.UnmarshalSignatureData(cdc, singleSignature) - suite.Require().NoError(err) - - multiSignature := suite.solomachineMulti.GenerateSignature(signBytes) - multiSigData, err := solomachinetypes.UnmarshalSignatureData(cdc, multiSignature) - suite.Require().NoError(err) - - testCases := []struct { - name string - publicKey cryptotypes.PubKey - sigData signing.SignatureData - expPass bool - }{ - { - "single signature with regular public key", - suite.solomachine.PublicKey, - singleSigData, - true, - }, - { - "multi signature with multisig public key", - suite.solomachineMulti.PublicKey, - multiSigData, - true, - }, - { - "single signature with multisig public key", - suite.solomachineMulti.PublicKey, - singleSigData, - false, - }, - { - "multi signature with regular public key", - suite.solomachine.PublicKey, - multiSigData, - false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - err := solomachinetypes.VerifySignature(tc.publicKey, signBytes, tc.sigData) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -func (suite *SoloMachineTestSuite) TestClientStateSignBytes() { - cdc := suite.chainA.App.AppCodec() - - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { - // success - path := solomachine.GetClientStatePath(counterpartyClientIdentifier) - bz, err := types.ClientStateSignBytes(cdc, solomachine.Sequence, solomachine.Time, solomachine.Diversifier, path, solomachine.ClientState()) - suite.Require().NoError(err) - suite.Require().NotNil(bz) - - // nil client state - bz, err = types.ClientStateSignBytes(cdc, solomachine.Sequence, solomachine.Time, solomachine.Diversifier, path, nil) - suite.Require().Error(err) - suite.Require().Nil(bz) - } -} - -func (suite *SoloMachineTestSuite) TestConsensusStateSignBytes() { - cdc := suite.chainA.App.AppCodec() - - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { - // success - path := solomachine.GetConsensusStatePath(counterpartyClientIdentifier, consensusHeight) - bz, err := types.ConsensusStateSignBytes(cdc, solomachine.Sequence, solomachine.Time, solomachine.Diversifier, path, solomachine.ConsensusState()) - suite.Require().NoError(err) - suite.Require().NotNil(bz) - - // nil consensus state - bz, err = types.ConsensusStateSignBytes(cdc, solomachine.Sequence, solomachine.Time, solomachine.Diversifier, path, nil) - suite.Require().Error(err) - suite.Require().Nil(bz) - } -} diff --git a/modules/light-clients/06-solomachine/types/update.go b/modules/light-clients/06-solomachine/types/update.go deleted file mode 100644 index 38db4a6b9cd..00000000000 --- a/modules/light-clients/06-solomachine/types/update.go +++ /dev/null @@ -1,90 +0,0 @@ -package types - -import ( - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v5/modules/core/exported" -) - -// CheckHeaderAndUpdateState checks if the provided header is valid and updates -// the consensus state if appropriate. It returns an error if: -// - the header provided is not parseable to a solo machine header -// - the header sequence does not match the current sequence -// - the header timestamp is less than the consensus state timestamp -// - the currently registered public key did not provide the update signature -func (cs ClientState) CheckHeaderAndUpdateState( - ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, - header exported.Header, -) (exported.ClientState, exported.ConsensusState, error) { - smHeader, ok := header.(*Header) - if !ok { - return nil, nil, sdkerrors.Wrapf( - clienttypes.ErrInvalidHeader, "header type %T, expected %T", header, &Header{}, - ) - } - - if err := checkHeader(cdc, &cs, smHeader); err != nil { - return nil, nil, err - } - - clientState, consensusState := update(&cs, smHeader) - return clientState, consensusState, nil -} - -// checkHeader checks if the Solo Machine update signature is valid. -func checkHeader(cdc codec.BinaryCodec, clientState *ClientState, header *Header) error { - // assert update sequence is current sequence - if header.Sequence != clientState.Sequence { - return sdkerrors.Wrapf( - clienttypes.ErrInvalidHeader, - "header sequence does not match the client state sequence (%d != %d)", header.Sequence, clientState.Sequence, - ) - } - - // assert update timestamp is not less than current consensus state timestamp - if header.Timestamp < clientState.ConsensusState.Timestamp { - return sdkerrors.Wrapf( - clienttypes.ErrInvalidHeader, - "header timestamp is less than to the consensus state timestamp (%d < %d)", header.Timestamp, clientState.ConsensusState.Timestamp, - ) - } - - // assert currently registered public key signed over the new public key with correct sequence - data, err := HeaderSignBytes(cdc, header) - if err != nil { - return err - } - - sigData, err := UnmarshalSignatureData(cdc, header.Signature) - if err != nil { - return err - } - - publicKey, err := clientState.ConsensusState.GetPubKey() - if err != nil { - return err - } - - if err := VerifySignature(publicKey, data, sigData); err != nil { - return sdkerrors.Wrap(ErrInvalidHeader, err.Error()) - } - - return nil -} - -// update the consensus state to the new public key and an incremented sequence -func update(clientState *ClientState, header *Header) (*ClientState, *ConsensusState) { - consensusState := &ConsensusState{ - PublicKey: header.NewPublicKey, - Diversifier: header.NewDiversifier, - Timestamp: header.Timestamp, - } - - // increment sequence number - clientState.Sequence++ - clientState.ConsensusState = consensusState - return clientState, consensusState -} diff --git a/modules/light-clients/06-solomachine/types/update_test.go b/modules/light-clients/06-solomachine/types/update_test.go deleted file mode 100644 index f1bcaac9d98..00000000000 --- a/modules/light-clients/06-solomachine/types/update_test.go +++ /dev/null @@ -1,181 +0,0 @@ -package types_test - -import ( - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/cosmos/ibc-go/v5/modules/core/exported" - "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine/types" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v5/testing" -) - -func (suite *SoloMachineTestSuite) TestCheckHeaderAndUpdateState() { - var ( - clientState exported.ClientState - header exported.Header - ) - - // test singlesig and multisig public keys - for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { - - testCases := []struct { - name string - setup func() - expPass bool - }{ - { - "successful update", - func() { - clientState = solomachine.ClientState() - header = solomachine.CreateHeader() - }, - true, - }, - { - "wrong client state type", - func() { - clientState = &ibctmtypes.ClientState{} - header = solomachine.CreateHeader() - }, - false, - }, - { - "invalid header type", - func() { - clientState = solomachine.ClientState() - header = &ibctmtypes.Header{} - }, - false, - }, - { - "wrong sequence in header", - func() { - clientState = solomachine.ClientState() - // store in temp before assigning to interface type - h := solomachine.CreateHeader() - h.Sequence++ - header = h - }, - false, - }, - { - "invalid header Signature", - func() { - clientState = solomachine.ClientState() - h := solomachine.CreateHeader() - h.Signature = suite.GetInvalidProof() - header = h - }, false, - }, - { - "invalid timestamp in header", - func() { - clientState = solomachine.ClientState() - h := solomachine.CreateHeader() - h.Timestamp-- - header = h - }, false, - }, - { - "signature uses wrong sequence", - func() { - clientState = solomachine.ClientState() - solomachine.Sequence++ - header = solomachine.CreateHeader() - }, - false, - }, - { - "signature uses new pubkey to sign", - func() { - // store in temp before assinging to interface type - cs := solomachine.ClientState() - h := solomachine.CreateHeader() - - publicKey, err := codectypes.NewAnyWithValue(solomachine.PublicKey) - suite.NoError(err) - - data := &types.HeaderData{ - NewPubKey: publicKey, - NewDiversifier: h.NewDiversifier, - } - - dataBz, err := suite.chainA.Codec.Marshal(data) - suite.Require().NoError(err) - - // generate invalid signature - signBytes := &types.SignBytes{ - Sequence: cs.Sequence, - Timestamp: solomachine.Time, - Diversifier: solomachine.Diversifier, - DataType: types.CLIENT, - Data: dataBz, - } - - signBz, err := suite.chainA.Codec.Marshal(signBytes) - suite.Require().NoError(err) - - sig := solomachine.GenerateSignature(signBz) - suite.Require().NoError(err) - h.Signature = sig - - clientState = cs - header = h - }, - false, - }, - { - "signature signs over old pubkey", - func() { - // store in temp before assinging to interface type - cs := solomachine.ClientState() - oldPubKey := solomachine.PublicKey - h := solomachine.CreateHeader() - - // generate invalid signature - data := append(sdk.Uint64ToBigEndian(cs.Sequence), oldPubKey.Bytes()...) - sig := solomachine.GenerateSignature(data) - h.Signature = sig - - clientState = cs - header = h - }, - false, - }, - { - "consensus state public key is nil", - func() { - cs := solomachine.ClientState() - cs.ConsensusState.PublicKey = nil - clientState = cs - header = solomachine.CreateHeader() - }, - false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - // setup test - tc.setup() - - clientState, consensusState, err := clientState.CheckHeaderAndUpdateState(suite.chainA.GetContext(), suite.chainA.Codec, suite.store, header) - - if tc.expPass { - suite.Require().NoError(err) - suite.Require().Equal(header.(*types.Header).NewPublicKey, clientState.(*types.ClientState).ConsensusState.PublicKey) - suite.Require().Equal(false, clientState.(*types.ClientState).IsFrozen) - suite.Require().Equal(header.(*types.Header).Sequence+1, clientState.(*types.ClientState).Sequence) - suite.Require().Equal(consensusState, clientState.(*types.ClientState).ConsensusState) - } else { - suite.Require().Error(err) - suite.Require().Nil(clientState) - suite.Require().Nil(consensusState) - } - }) - } - } -} diff --git a/modules/light-clients/06-solomachine/update.go b/modules/light-clients/06-solomachine/update.go new file mode 100644 index 00000000000..4594363a5af --- /dev/null +++ b/modules/light-clients/06-solomachine/update.go @@ -0,0 +1,140 @@ +package solomachine + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v5/modules/core/exported" +) + +// VerifyClientMessage introspects the provided ClientMessage and checks its validity +// A Solomachine Header is considered valid if the currently registered public key has signed over the new public key with the correct sequence +// A Solomachine Misbehaviour is considered valid if duplicate signatures of the current public key are found on two different messages at a given sequence +func (cs ClientState) VerifyClientMessage(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg exported.ClientMessage) error { + switch msg := clientMsg.(type) { + case *Header: + return cs.verifyHeader(ctx, cdc, clientStore, msg) + case *Misbehaviour: + return cs.verifyMisbehaviour(ctx, cdc, clientStore, msg) + default: + return sdkerrors.Wrapf(clienttypes.ErrInvalidClientType, "expected type of %T or %T, got type %T", Header{}, Misbehaviour{}, msg) + } +} + +func (cs ClientState) verifyHeader(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, header *Header) error { + // assert update sequence is current sequence + if header.Sequence != cs.Sequence { + return sdkerrors.Wrapf( + clienttypes.ErrInvalidHeader, + "header sequence does not match the client state sequence (%d != %d)", header.Sequence, cs.Sequence, + ) + } + + // assert update timestamp is not less than current consensus state timestamp + if header.Timestamp < cs.ConsensusState.Timestamp { + return sdkerrors.Wrapf( + clienttypes.ErrInvalidHeader, + "header timestamp is less than to the consensus state timestamp (%d < %d)", header.Timestamp, cs.ConsensusState.Timestamp, + ) + } + + // assert currently registered public key signed over the new public key with correct sequence + headerData := &HeaderData{ + NewPubKey: header.NewPublicKey, + NewDiversifier: header.NewDiversifier, + } + + dataBz, err := cdc.Marshal(headerData) + if err != nil { + return err + } + + signBytes := &SignBytes{ + Sequence: header.Sequence, + Timestamp: header.Timestamp, + Diversifier: cs.ConsensusState.Diversifier, + Path: []byte{}, + Data: dataBz, + } + + data, err := cdc.Marshal(signBytes) + if err != nil { + return err + } + + sigData, err := UnmarshalSignatureData(cdc, header.Signature) + if err != nil { + return err + } + + publicKey, err := cs.ConsensusState.GetPubKey() + if err != nil { + return err + } + + if err := VerifySignature(publicKey, data, sigData); err != nil { + return sdkerrors.Wrap(ErrInvalidHeader, err.Error()) + } + + return nil +} + +func (cs ClientState) verifyMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, misbehaviour *Misbehaviour) error { + // NOTE: a check that the misbehaviour message data are not equal is done by + // misbehaviour.ValidateBasic which is called by the 02-client keeper. + // verify first signature + if err := cs.verifySignatureAndData(cdc, misbehaviour, misbehaviour.SignatureOne); err != nil { + return sdkerrors.Wrap(err, "failed to verify signature one") + } + + // verify second signature + if err := cs.verifySignatureAndData(cdc, misbehaviour, misbehaviour.SignatureTwo); err != nil { + return sdkerrors.Wrap(err, "failed to verify signature two") + } + + return nil +} + +// UpdateState updates the consensus state to the new public key and an incremented sequence. +// A list containing the updated consensus height is returned. +func (cs ClientState) UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg exported.ClientMessage) []exported.Height { + smHeader, ok := clientMsg.(*Header) + if !ok { + panic(fmt.Errorf("unsupported ClientMessage: %T", clientMsg)) + } + + // create new solomachine ConsensusState + consensusState := &ConsensusState{ + PublicKey: smHeader.NewPublicKey, + Diversifier: smHeader.NewDiversifier, + Timestamp: smHeader.Timestamp, + } + + cs.Sequence++ + cs.ConsensusState = consensusState + + setClientState(clientStore, cdc, &cs) + + return []exported.Height{clienttypes.NewHeight(0, cs.Sequence)} +} + +// CheckForMisbehaviour returns true for type Misbehaviour (passed VerifyClientMessage check), otherwise returns false +func (cs ClientState) CheckForMisbehaviour(_ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, clientMsg exported.ClientMessage) bool { + if _, ok := clientMsg.(*Misbehaviour); ok { + return true + } + + return false +} + +// UpdateStateOnMisbehaviour updates state upon misbehaviour. This method should only be called on misbehaviour +// as it does not perform any misbehaviour checks. +func (cs ClientState) UpdateStateOnMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, _ exported.ClientMessage) { + cs.IsFrozen = true + + setClientState(clientStore, cdc, &cs) +} diff --git a/modules/light-clients/06-solomachine/update_test.go b/modules/light-clients/06-solomachine/update_test.go new file mode 100644 index 00000000000..12ef195b220 --- /dev/null +++ b/modules/light-clients/06-solomachine/update_test.go @@ -0,0 +1,564 @@ +package solomachine_test + +import ( + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v5/modules/core/24-host" + "github.com/cosmos/ibc-go/v5/modules/core/exported" + solomachine "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v5/testing" +) + +func (suite *SoloMachineTestSuite) TestVerifyClientMessageHeader() { + var ( + clientMsg exported.ClientMessage + clientState *solomachine.ClientState + ) + + // test singlesig and multisig public keys + for _, sm := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { + + testCases := []struct { + name string + setup func() + expPass bool + }{ + { + "successful header", + func() { + clientMsg = sm.CreateHeader(sm.Diversifier) + }, + true, + }, + { + "successful header with new diversifier", + func() { + clientMsg = sm.CreateHeader(sm.Diversifier + "0") + }, + true, + }, + { + "successful misbehaviour", + func() { + clientMsg = sm.CreateMisbehaviour() + }, + true, + }, + { + "invalid client message type", + func() { + clientMsg = &ibctm.Header{} + }, + false, + }, + { + "wrong sequence in header", + func() { + // store in temp before assigning to interface type + h := sm.CreateHeader(sm.Diversifier) + h.Sequence++ + clientMsg = h + }, + false, + }, + { + "invalid header Signature", + func() { + h := sm.CreateHeader(sm.Diversifier) + h.Signature = suite.GetInvalidProof() + clientMsg = h + }, false, + }, + { + "invalid timestamp in header", + func() { + h := sm.CreateHeader(sm.Diversifier) + h.Timestamp-- + clientMsg = h + }, false, + }, + { + "signature uses wrong sequence", + func() { + + sm.Sequence++ + clientMsg = sm.CreateHeader(sm.Diversifier) + }, + false, + }, + { + "signature uses new pubkey to sign", + func() { + // store in temp before assinging to interface type + cs := sm.ClientState() + h := sm.CreateHeader(sm.Diversifier) + + publicKey, err := codectypes.NewAnyWithValue(sm.PublicKey) + suite.NoError(err) + + data := &solomachine.HeaderData{ + NewPubKey: publicKey, + NewDiversifier: h.NewDiversifier, + } + + dataBz, err := suite.chainA.Codec.Marshal(data) + suite.Require().NoError(err) + + // generate invalid signature + signBytes := &solomachine.SignBytes{ + Sequence: cs.Sequence, + Timestamp: sm.Time, + Diversifier: sm.Diversifier, + Path: []byte("invalid signature data"), + Data: dataBz, + } + + signBz, err := suite.chainA.Codec.Marshal(signBytes) + suite.Require().NoError(err) + + sig := sm.GenerateSignature(signBz) + suite.Require().NoError(err) + h.Signature = sig + + clientState = cs + clientMsg = h + + }, + false, + }, + { + "signature signs over old pubkey", + func() { + // store in temp before assinging to interface type + cs := sm.ClientState() + oldPubKey := sm.PublicKey + h := sm.CreateHeader(sm.Diversifier) + + // generate invalid signature + data := append(sdk.Uint64ToBigEndian(cs.Sequence), oldPubKey.Bytes()...) + sig := sm.GenerateSignature(data) + h.Signature = sig + + clientState = cs + clientMsg = h + }, + false, + }, + { + "consensus state public key is nil - header", + func() { + clientState.ConsensusState.PublicKey = nil + clientMsg = sm.CreateHeader(sm.Diversifier) + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + clientState = sm.ClientState() + + // setup test + tc.setup() + + err := clientState.VerifyClientMessage(suite.chainA.GetContext(), suite.chainA.Codec, suite.store, clientMsg) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } + } +} + +func (suite *SoloMachineTestSuite) TestVerifyClientMessageMisbehaviour() { + var ( + clientMsg exported.ClientMessage + clientState *solomachine.ClientState + ) + + // test singlesig and multisig public keys + for _, sm := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { + + testCases := []struct { + name string + setup func() + expPass bool + }{ + { + "successful misbehaviour", + func() { + clientMsg = sm.CreateMisbehaviour() + }, + true, + }, + { + "old misbehaviour is successful (timestamp is less than current consensus state)", + func() { + clientState = sm.ClientState() + sm.Time = sm.Time - 5 + clientMsg = sm.CreateMisbehaviour() + }, true, + }, + { + "invalid client message type", + func() { + clientMsg = &ibctm.Header{} + }, + false, + }, + { + "consensus state pubkey is nil", + func() { + clientState.ConsensusState.PublicKey = nil + clientMsg = sm.CreateMisbehaviour() + }, + false, + }, + { + "invalid SignatureOne SignatureData", + func() { + m := sm.CreateMisbehaviour() + + m.SignatureOne.Signature = suite.GetInvalidProof() + clientMsg = m + }, false, + }, + { + "invalid SignatureTwo SignatureData", + func() { + m := sm.CreateMisbehaviour() + + m.SignatureTwo.Signature = suite.GetInvalidProof() + clientMsg = m + }, false, + }, + { + "invalid SignatureOne timestamp", + func() { + m := sm.CreateMisbehaviour() + + m.SignatureOne.Timestamp = 1000000000000 + clientMsg = m + }, false, + }, + { + "invalid SignatureTwo timestamp", + func() { + m := sm.CreateMisbehaviour() + + m.SignatureTwo.Timestamp = 1000000000000 + clientMsg = m + }, false, + }, + { + "invalid first signature data", + func() { + // store in temp before assigning to interface type + m := sm.CreateMisbehaviour() + + msg := []byte("DATA ONE") + signBytes := &solomachine.SignBytes{ + Sequence: sm.Sequence + 1, + Timestamp: sm.Time, + Diversifier: sm.Diversifier, + Path: []byte("invalid signature data"), + Data: msg, + } + + data, err := suite.chainA.Codec.Marshal(signBytes) + suite.Require().NoError(err) + + sig := sm.GenerateSignature(data) + + m.SignatureOne.Signature = sig + m.SignatureOne.Data = msg + clientMsg = m + }, + false, + }, + { + "invalid second signature data", + func() { + // store in temp before assigning to interface type + m := sm.CreateMisbehaviour() + + msg := []byte("DATA TWO") + signBytes := &solomachine.SignBytes{ + Sequence: sm.Sequence + 1, + Timestamp: sm.Time, + Diversifier: sm.Diversifier, + Path: []byte("invalid signature data"), + Data: msg, + } + + data, err := suite.chainA.Codec.Marshal(signBytes) + suite.Require().NoError(err) + + sig := sm.GenerateSignature(data) + + m.SignatureTwo.Signature = sig + m.SignatureTwo.Data = msg + clientMsg = m + }, + false, + }, + { + "wrong pubkey generates first signature", + func() { + badMisbehaviour := sm.CreateMisbehaviour() + + // update public key to a new one + sm.CreateHeader(sm.Diversifier) + m := sm.CreateMisbehaviour() + + // set SignatureOne to use the wrong signature + m.SignatureOne = badMisbehaviour.SignatureOne + clientMsg = m + }, false, + }, + { + "wrong pubkey generates second signature", + func() { + badMisbehaviour := sm.CreateMisbehaviour() + + // update public key to a new one + sm.CreateHeader(sm.Diversifier) + m := sm.CreateMisbehaviour() + + // set SignatureTwo to use the wrong signature + m.SignatureTwo = badMisbehaviour.SignatureTwo + clientMsg = m + }, false, + }, + { + "signatures sign over different sequence", + func() { + + // store in temp before assigning to interface type + m := sm.CreateMisbehaviour() + + // Signature One + msg := []byte("DATA ONE") + // sequence used is plus 1 + signBytes := &solomachine.SignBytes{ + Sequence: sm.Sequence + 1, + Timestamp: sm.Time, + Diversifier: sm.Diversifier, + Path: []byte("invalid signature data"), + Data: msg, + } + + data, err := suite.chainA.Codec.Marshal(signBytes) + suite.Require().NoError(err) + + sig := sm.GenerateSignature(data) + + m.SignatureOne.Signature = sig + m.SignatureOne.Data = msg + + // Signature Two + msg = []byte("DATA TWO") + // sequence used is minus 1 + + signBytes = &solomachine.SignBytes{ + Sequence: sm.Sequence - 1, + Timestamp: sm.Time, + Diversifier: sm.Diversifier, + Path: []byte("invalid signature data"), + Data: msg, + } + data, err = suite.chainA.Codec.Marshal(signBytes) + suite.Require().NoError(err) + + sig = sm.GenerateSignature(data) + + m.SignatureTwo.Signature = sig + m.SignatureTwo.Data = msg + + clientMsg = m + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + clientState = sm.ClientState() + + // setup test + tc.setup() + + err := clientState.VerifyClientMessage(suite.chainA.GetContext(), suite.chainA.Codec, suite.store, clientMsg) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } + } +} + +func (suite *SoloMachineTestSuite) TestUpdateState() { + var ( + clientState exported.ClientState + clientMsg exported.ClientMessage + ) + + // test singlesig and multisig public keys + for _, sm := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { + + testCases := []struct { + name string + setup func() + expPass bool + }{ + { + "successful update", + func() { + clientState = sm.ClientState() + clientMsg = sm.CreateHeader(sm.Diversifier) + }, + true, + }, + { + "invalid type misbehaviour", + func() { + clientState = sm.ClientState() + clientMsg = sm.CreateMisbehaviour() + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + tc.setup() // setup test + + if tc.expPass { + consensusHeights := clientState.UpdateState(suite.chainA.GetContext(), suite.chainA.Codec, suite.store, clientMsg) + + clientStateBz := suite.store.Get(host.ClientStateKey()) + suite.Require().NotEmpty(clientStateBz) + + newClientState := clienttypes.MustUnmarshalClientState(suite.chainA.Codec, clientStateBz) + + suite.Require().Len(consensusHeights, 1) + suite.Require().Equal(uint64(0), consensusHeights[0].GetRevisionNumber()) + suite.Require().Equal(newClientState.(*solomachine.ClientState).Sequence, consensusHeights[0].GetRevisionHeight()) + + suite.Require().False(newClientState.(*solomachine.ClientState).IsFrozen) + suite.Require().Equal(clientMsg.(*solomachine.Header).Sequence+1, newClientState.(*solomachine.ClientState).Sequence) + suite.Require().Equal(clientMsg.(*solomachine.Header).NewPublicKey, newClientState.(*solomachine.ClientState).ConsensusState.PublicKey) + suite.Require().Equal(clientMsg.(*solomachine.Header).NewDiversifier, newClientState.(*solomachine.ClientState).ConsensusState.Diversifier) + suite.Require().Equal(clientMsg.(*solomachine.Header).Timestamp, newClientState.(*solomachine.ClientState).ConsensusState.Timestamp) + } else { + suite.Require().Panics(func() { + clientState.UpdateState(suite.chainA.GetContext(), suite.chainA.Codec, suite.store, clientMsg) + }) + } + + }) + } + } +} + +func (suite *SoloMachineTestSuite) TestCheckForMisbehaviour() { + var ( + clientMsg exported.ClientMessage + ) + + // test singlesig and multisig public keys + for _, sm := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() { + clientMsg = sm.CreateMisbehaviour() + }, + true, + }, + { + "normal header returns false", + func() { + clientMsg = sm.CreateHeader(sm.Diversifier) + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + clientState := sm.ClientState() + + tc.malleate() + + foundMisbehaviour := clientState.CheckForMisbehaviour(suite.chainA.GetContext(), suite.chainA.Codec, suite.store, clientMsg) + + if tc.expPass { + suite.Require().True(foundMisbehaviour) + } else { + suite.Require().False(foundMisbehaviour) + } + + }) + } + } +} + +func (suite *SoloMachineTestSuite) TestUpdateStateOnMisbehaviour() { + // test singlesig and multisig public keys + for _, sm := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + clientState := sm.ClientState() + + tc.malleate() + + clientState.UpdateStateOnMisbehaviour(suite.chainA.GetContext(), suite.chainA.Codec, suite.store, nil) + + if tc.expPass { + clientStateBz := suite.store.Get(host.ClientStateKey()) + suite.Require().NotEmpty(clientStateBz) + + newClientState := clienttypes.MustUnmarshalClientState(suite.chainA.Codec, clientStateBz) + + suite.Require().True(newClientState.(*solomachine.ClientState).IsFrozen) + } + }) + } + } +} diff --git a/modules/light-clients/07-tendermint/client_state.go b/modules/light-clients/07-tendermint/client_state.go new file mode 100644 index 00000000000..0c3715e4db1 --- /dev/null +++ b/modules/light-clients/07-tendermint/client_state.go @@ -0,0 +1,335 @@ +package tendermint + +import ( + "strings" + "time" + + ics23 "github.com/confio/ics23/go" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/tendermint/tendermint/light" + tmtypes "github.com/tendermint/tendermint/types" + + clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v5/modules/core/exported" +) + +var _ exported.ClientState = (*ClientState)(nil) + +// NewClientState creates a new ClientState instance +func NewClientState( + chainID string, trustLevel Fraction, + trustingPeriod, ubdPeriod, maxClockDrift time.Duration, + latestHeight clienttypes.Height, specs []*ics23.ProofSpec, + upgradePath []string, allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour bool, +) *ClientState { + return &ClientState{ + ChainId: chainID, + TrustLevel: trustLevel, + TrustingPeriod: trustingPeriod, + UnbondingPeriod: ubdPeriod, + MaxClockDrift: maxClockDrift, + LatestHeight: latestHeight, + FrozenHeight: clienttypes.ZeroHeight(), + ProofSpecs: specs, + UpgradePath: upgradePath, + AllowUpdateAfterExpiry: allowUpdateAfterExpiry, + AllowUpdateAfterMisbehaviour: allowUpdateAfterMisbehaviour, + } +} + +// GetChainID returns the chain-id +func (cs ClientState) GetChainID() string { + return cs.ChainId +} + +// ClientType is tendermint. +func (cs ClientState) ClientType() string { + return exported.Tendermint +} + +// GetLatestHeight returns latest block height. +func (cs ClientState) GetLatestHeight() exported.Height { + return cs.LatestHeight +} + +// GetTimestampAtHeight returns the timestamp in nanoseconds of the consensus state at the given height. +func (cs ClientState) GetTimestampAtHeight( + ctx sdk.Context, + clientStore sdk.KVStore, + cdc codec.BinaryCodec, + height exported.Height, +) (uint64, error) { + // get consensus state at height from clientStore to check for expiry + consState, found := GetConsensusState(clientStore, cdc, height) + if !found { + return 0, sdkerrors.Wrapf(clienttypes.ErrConsensusStateNotFound, "height (%s)", height) + } + return consState.GetTimestamp(), nil +} + +// Status returns the status of the tendermint client. +// The client may be: +// - Active: FrozenHeight is zero and client is not expired +// - Frozen: Frozen Height is not zero +// - Expired: the latest consensus state timestamp + trusting period <= current time +// +// A frozen client will become expired, so the Frozen status +// has higher precedence. +func (cs ClientState) Status( + ctx sdk.Context, + clientStore sdk.KVStore, + cdc codec.BinaryCodec, +) exported.Status { + if !cs.FrozenHeight.IsZero() { + return exported.Frozen + } + + // get latest consensus state from clientStore to check for expiry + consState, found := GetConsensusState(clientStore, cdc, cs.GetLatestHeight()) + if !found { + // if the client state does not have an associated consensus state for its latest height + // then it must be expired + return exported.Expired + } + + if cs.IsExpired(consState.Timestamp, ctx.BlockTime()) { + return exported.Expired + } + + return exported.Active +} + +// IsExpired returns whether or not the client has passed the trusting period since the last +// update (in which case no headers are considered valid). +func (cs ClientState) IsExpired(latestTimestamp, now time.Time) bool { + expirationTime := latestTimestamp.Add(cs.TrustingPeriod) + return !expirationTime.After(now) +} + +// Validate performs a basic validation of the client state fields. +func (cs ClientState) Validate() error { + if strings.TrimSpace(cs.ChainId) == "" { + return sdkerrors.Wrap(ErrInvalidChainID, "chain id cannot be empty string") + } + + // NOTE: the value of tmtypes.MaxChainIDLen may change in the future. + // If this occurs, the code here must account for potential difference + // between the tendermint version being run by the counterparty chain + // and the tendermint version used by this light client. + // https://github.com/cosmos/ibc-go/issues/177 + if len(cs.ChainId) > tmtypes.MaxChainIDLen { + return sdkerrors.Wrapf(ErrInvalidChainID, "chainID is too long; got: %d, max: %d", len(cs.ChainId), tmtypes.MaxChainIDLen) + } + + if err := light.ValidateTrustLevel(cs.TrustLevel.ToTendermint()); err != nil { + return err + } + if cs.TrustingPeriod == 0 { + return sdkerrors.Wrap(ErrInvalidTrustingPeriod, "trusting period cannot be zero") + } + if cs.UnbondingPeriod == 0 { + return sdkerrors.Wrap(ErrInvalidUnbondingPeriod, "unbonding period cannot be zero") + } + if cs.MaxClockDrift == 0 { + return sdkerrors.Wrap(ErrInvalidMaxClockDrift, "max clock drift cannot be zero") + } + + // the latest height revision number must match the chain id revision number + if cs.LatestHeight.RevisionNumber != clienttypes.ParseChainID(cs.ChainId) { + return sdkerrors.Wrapf(ErrInvalidHeaderHeight, + "latest height revision number must match chain id revision number (%d != %d)", cs.LatestHeight.RevisionNumber, clienttypes.ParseChainID(cs.ChainId)) + } + if cs.LatestHeight.RevisionHeight == 0 { + return sdkerrors.Wrapf(ErrInvalidHeaderHeight, "tendermint client's latest height revision height cannot be zero") + } + if cs.TrustingPeriod >= cs.UnbondingPeriod { + return sdkerrors.Wrapf( + ErrInvalidTrustingPeriod, + "trusting period (%s) should be < unbonding period (%s)", cs.TrustingPeriod, cs.UnbondingPeriod, + ) + } + + if cs.ProofSpecs == nil { + return sdkerrors.Wrap(ErrInvalidProofSpecs, "proof specs cannot be nil for tm client") + } + for i, spec := range cs.ProofSpecs { + if spec == nil { + return sdkerrors.Wrapf(ErrInvalidProofSpecs, "proof spec cannot be nil at index: %d", i) + } + } + // UpgradePath may be empty, but if it isn't, each key must be non-empty + for i, k := range cs.UpgradePath { + if strings.TrimSpace(k) == "" { + return sdkerrors.Wrapf(clienttypes.ErrInvalidClient, "key in upgrade path at index %d cannot be empty", i) + } + } + + return nil +} + +// GetProofSpecs returns the format the client expects for proof verification +// as a string array specifying the proof type for each position in chained proof +func (cs ClientState) GetProofSpecs() []*ics23.ProofSpec { + return cs.ProofSpecs +} + +// ZeroCustomFields returns a ClientState that is a copy of the current ClientState +// with all client customizable fields zeroed out +func (cs ClientState) ZeroCustomFields() exported.ClientState { + // copy over all chain-specified fields + // and leave custom fields empty + return &ClientState{ + ChainId: cs.ChainId, + UnbondingPeriod: cs.UnbondingPeriod, + LatestHeight: cs.LatestHeight, + ProofSpecs: cs.ProofSpecs, + UpgradePath: cs.UpgradePath, + } +} + +// Initialize will check that initial consensus state is a Tendermint consensus state +// and will store ProcessedTime for initial consensus state as ctx.BlockTime() +func (cs ClientState) Initialize(ctx sdk.Context, _ codec.BinaryCodec, clientStore sdk.KVStore, consState exported.ConsensusState) error { + if _, ok := consState.(*ConsensusState); !ok { + return sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "invalid initial consensus state. expected type: %T, got: %T", + &ConsensusState{}, consState) + } + // set metadata for initial consensus state. + setConsensusMetadata(ctx, clientStore, cs.GetLatestHeight()) + return nil +} + +// VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. +// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +func (cs ClientState) VerifyMembership( + ctx sdk.Context, + clientStore sdk.KVStore, + cdc codec.BinaryCodec, + height exported.Height, + delayTimePeriod uint64, + delayBlockPeriod uint64, + proof []byte, + path []byte, + value []byte, +) error { + if cs.GetLatestHeight().LT(height) { + return sdkerrors.Wrapf( + sdkerrors.ErrInvalidHeight, + "client state height < proof height (%d < %d), please ensure the client has been updated", cs.GetLatestHeight(), height, + ) + } + + if err := verifyDelayPeriodPassed(ctx, clientStore, height, delayTimePeriod, delayBlockPeriod); err != nil { + return err + } + + var merkleProof commitmenttypes.MerkleProof + if err := cdc.Unmarshal(proof, &merkleProof); err != nil { + return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "failed to unmarshal proof into ICS 23 commitment merkle proof") + } + + var merklePath commitmenttypes.MerklePath + if err := cdc.Unmarshal(path, &merklePath); err != nil { + return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "failed to unmarshal path into ICS 23 commitment merkle path") + } + + consensusState, found := GetConsensusState(clientStore, cdc, height) + if !found { + return sdkerrors.Wrap(clienttypes.ErrConsensusStateNotFound, "please ensure the proof was constructed against a height that exists on the client") + } + + if err := merkleProof.VerifyMembership(cs.ProofSpecs, consensusState.GetRoot(), merklePath, value); err != nil { + return err + } + + return nil +} + +// 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). +func (cs ClientState) VerifyNonMembership( + ctx sdk.Context, + clientStore sdk.KVStore, + cdc codec.BinaryCodec, + height exported.Height, + delayTimePeriod uint64, + delayBlockPeriod uint64, + proof []byte, + path []byte, +) error { + if cs.GetLatestHeight().LT(height) { + return sdkerrors.Wrapf( + sdkerrors.ErrInvalidHeight, + "client state height < proof height (%d < %d), please ensure the client has been updated", cs.GetLatestHeight(), height, + ) + } + + if err := verifyDelayPeriodPassed(ctx, clientStore, height, delayTimePeriod, delayBlockPeriod); err != nil { + return err + } + + var merkleProof commitmenttypes.MerkleProof + if err := cdc.Unmarshal(proof, &merkleProof); err != nil { + return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "failed to unmarshal proof into ICS 23 commitment merkle proof") + } + + var merklePath commitmenttypes.MerklePath + if err := cdc.Unmarshal(path, &merklePath); err != nil { + return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "failed to unmarshal path into ICS 23 commitment merkle path") + } + + consensusState, found := GetConsensusState(clientStore, cdc, height) + if !found { + return sdkerrors.Wrap(clienttypes.ErrConsensusStateNotFound, "please ensure the proof was constructed against a height that exists on the client") + } + + if err := merkleProof.VerifyNonMembership(cs.ProofSpecs, consensusState.GetRoot(), merklePath); err != nil { + return err + } + + return nil +} + +// verifyDelayPeriodPassed will ensure that at least delayTimePeriod amount of time and delayBlockPeriod number of blocks have passed +// since consensus state was submitted before allowing verification to continue. +func verifyDelayPeriodPassed(ctx sdk.Context, store sdk.KVStore, proofHeight exported.Height, delayTimePeriod, delayBlockPeriod uint64) error { + if delayTimePeriod != 0 { + // check that executing chain's timestamp has passed consensusState's processed time + delay time period + processedTime, ok := GetProcessedTime(store, proofHeight) + if !ok { + return sdkerrors.Wrapf(ErrProcessedTimeNotFound, "processed time not found for height: %s", proofHeight) + } + + currentTimestamp := uint64(ctx.BlockTime().UnixNano()) + validTime := processedTime + delayTimePeriod + + // NOTE: delay time period is inclusive, so if currentTimestamp is validTime, then we return no error + if currentTimestamp < validTime { + return sdkerrors.Wrapf(ErrDelayPeriodNotPassed, "cannot verify packet until time: %d, current time: %d", + validTime, currentTimestamp) + } + + } + + if delayBlockPeriod != 0 { + // check that executing chain's height has passed consensusState's processed height + delay block period + processedHeight, ok := GetProcessedHeight(store, proofHeight) + if !ok { + return sdkerrors.Wrapf(ErrProcessedHeightNotFound, "processed height not found for height: %s", proofHeight) + } + + currentHeight := clienttypes.GetSelfHeight(ctx) + validHeight := clienttypes.NewHeight(processedHeight.GetRevisionNumber(), processedHeight.GetRevisionHeight()+delayBlockPeriod) + + // NOTE: delay block period is inclusive, so if currentHeight is validHeight, then we return no error + if currentHeight.LT(validHeight) { + return sdkerrors.Wrapf(ErrDelayPeriodNotPassed, "cannot verify packet until height: %s, current height: %s", + validHeight, currentHeight) + } + } + + return nil +} diff --git a/modules/light-clients/07-tendermint/client_state_test.go b/modules/light-clients/07-tendermint/client_state_test.go new file mode 100644 index 00000000000..9284e44cec8 --- /dev/null +++ b/modules/light-clients/07-tendermint/client_state_test.go @@ -0,0 +1,700 @@ +package tendermint_test + +import ( + "time" + + ics23 "github.com/confio/ics23/go" + sdk "github.com/cosmos/cosmos-sdk/types" + + transfertypes "github.com/cosmos/ibc-go/v5/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v5/modules/core/24-host" + "github.com/cosmos/ibc-go/v5/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v5/testing" + ibcmock "github.com/cosmos/ibc-go/v5/testing/mock" +) + +const ( + // Do not change the length of these variables + fiftyCharChainID = "12345678901234567890123456789012345678901234567890" + fiftyOneCharChainID = "123456789012345678901234567890123456789012345678901" +) + +var ( + invalidProof = []byte("invalid proof") +) + +func (suite *TendermintTestSuite) TestStatus() { + var ( + path *ibctesting.Path + clientState *ibctm.ClientState + ) + + testCases := []struct { + name string + malleate func() + expStatus exported.Status + }{ + {"client is active", func() {}, exported.Active}, + {"client is frozen", func() { + clientState.FrozenHeight = clienttypes.NewHeight(0, 1) + path.EndpointA.SetClientState(clientState) + }, exported.Frozen}, + {"client status without consensus state", func() { + clientState.LatestHeight = clientState.LatestHeight.Increment().(clienttypes.Height) + path.EndpointA.SetClientState(clientState) + }, exported.Expired}, + {"client status is expired", func() { + suite.coordinator.IncrementTimeBy(clientState.TrustingPeriod) + }, exported.Expired}, + } + + for _, tc := range testCases { + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupClients(path) + + clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + clientState = path.EndpointA.GetClientState().(*ibctm.ClientState) + + tc.malleate() + + status := clientState.Status(suite.chainA.GetContext(), clientStore, suite.chainA.App.AppCodec()) + suite.Require().Equal(tc.expStatus, status) + + } +} + +func (suite *TendermintTestSuite) TestValidate() { + testCases := []struct { + name string + clientState *ibctm.ClientState + expPass bool + }{ + { + name: "valid client", + clientState: ibctm.NewClientState(chainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), + expPass: true, + }, + { + name: "valid client with nil upgrade path", + clientState: ibctm.NewClientState(chainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), nil, false, false), + expPass: true, + }, + { + name: "invalid chainID", + clientState: ibctm.NewClientState(" ", ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), + expPass: false, + }, + { + // NOTE: if this test fails, the code must account for the change in chainID length across tendermint versions! + // Do not only fix the test, fix the code! + // https://github.com/cosmos/ibc-go/issues/177 + name: "valid chainID - chainID validation failed for chainID of length 50! ", + clientState: ibctm.NewClientState(fiftyCharChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), + expPass: true, + }, + { + // NOTE: if this test fails, the code must account for the change in chainID length across tendermint versions! + // Do not only fix the test, fix the code! + // https://github.com/cosmos/ibc-go/issues/177 + name: "invalid chainID - chainID validation did not fail for chainID of length 51! ", + clientState: ibctm.NewClientState(fiftyOneCharChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), + expPass: false, + }, + { + name: "invalid trust level", + clientState: ibctm.NewClientState(chainID, ibctm.Fraction{Numerator: 0, Denominator: 1}, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), + expPass: false, + }, + { + name: "invalid trusting period", + clientState: ibctm.NewClientState(chainID, ibctm.DefaultTrustLevel, 0, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), + expPass: false, + }, + { + name: "invalid unbonding period", + clientState: ibctm.NewClientState(chainID, ibctm.DefaultTrustLevel, trustingPeriod, 0, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), + expPass: false, + }, + { + name: "invalid max clock drift", + clientState: ibctm.NewClientState(chainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, 0, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), + expPass: false, + }, + { + name: "invalid revision number", + clientState: ibctm.NewClientState(chainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(1, 1), commitmenttypes.GetSDKSpecs(), upgradePath, false, false), + expPass: false, + }, + { + name: "invalid revision height", + clientState: ibctm.NewClientState(chainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.ZeroHeight(), commitmenttypes.GetSDKSpecs(), upgradePath, false, false), + expPass: false, + }, + { + name: "trusting period not less than unbonding period", + clientState: ibctm.NewClientState(chainID, ibctm.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), + expPass: false, + }, + { + name: "proof specs is nil", + clientState: ibctm.NewClientState(chainID, ibctm.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, height, nil, upgradePath, false, false), + expPass: false, + }, + { + name: "proof specs contains nil", + clientState: ibctm.NewClientState(chainID, ibctm.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, height, []*ics23.ProofSpec{ics23.TendermintSpec, nil}, upgradePath, false, false), + expPass: false, + }, + } + + for _, tc := range testCases { + err := tc.clientState.Validate() + if tc.expPass { + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Error(err, tc.name) + } + } +} + +func (suite *TendermintTestSuite) TestInitialize() { + + testCases := []struct { + name string + consensusState exported.ConsensusState + expPass bool + }{ + { + name: "valid consensus", + consensusState: &ibctm.ConsensusState{}, + expPass: true, + }, + { + name: "invalid consensus: consensus state is solomachine consensus", + consensusState: ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachine", "", 2).ConsensusState(), + expPass: false, + }, + } + + path := ibctesting.NewPath(suite.chainA, suite.chainB) + err := path.EndpointA.CreateClient() + suite.Require().NoError(err) + + clientState := suite.chainA.GetClientState(path.EndpointA.ClientID) + store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + + for _, tc := range testCases { + err := clientState.Initialize(suite.chainA.GetContext(), suite.chainA.Codec, store, tc.consensusState) + if tc.expPass { + suite.Require().NoError(err, "valid case returned an error") + } else { + suite.Require().Error(err, "invalid case didn't return an error") + } + } +} + +func (suite *TendermintTestSuite) TestVerifyMembership() { + var ( + testingpath *ibctesting.Path + delayTimePeriod uint64 + delayBlockPeriod uint64 + proofHeight exported.Height + proof []byte + path []byte + value []byte + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "successful ClientState verification", + func() { + // default proof construction uses ClientState + }, + true, + }, + { + "successful ConsensusState verification", func() { + key := host.FullConsensusStateKey(testingpath.EndpointB.ClientID, testingpath.EndpointB.GetClientState().GetLatestHeight()) + merklePath := commitmenttypes.NewMerklePath(string(key)) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chainB.GetPrefix(), merklePath) + suite.Require().NoError(err) + + path, err = suite.chainB.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, proofHeight = suite.chainB.QueryProof(key) + + consensusState := testingpath.EndpointB.GetConsensusState(testingpath.EndpointB.GetClientState().GetLatestHeight()).(*ibctm.ConsensusState) + value, err = suite.chainB.Codec.MarshalInterface(consensusState) + suite.Require().NoError(err) + }, + true, + }, + { + "successful Connection verification", func() { + key := host.ConnectionKey(testingpath.EndpointB.ConnectionID) + merklePath := commitmenttypes.NewMerklePath(string(key)) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chainB.GetPrefix(), merklePath) + suite.Require().NoError(err) + + path, err = suite.chainB.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, proofHeight = suite.chainB.QueryProof(key) + + connection := testingpath.EndpointB.GetConnection() + value, err = suite.chainB.Codec.Marshal(&connection) + suite.Require().NoError(err) + }, + true, + }, + { + "successful Channel verification", func() { + key := host.ChannelKey(testingpath.EndpointB.ChannelConfig.PortID, testingpath.EndpointB.ChannelID) + merklePath := commitmenttypes.NewMerklePath(string(key)) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chainB.GetPrefix(), merklePath) + suite.Require().NoError(err) + + path, err = suite.chainB.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, proofHeight = suite.chainB.QueryProof(key) + + channel := testingpath.EndpointB.GetChannel() + value, err = suite.chainB.Codec.Marshal(&channel) + suite.Require().NoError(err) + }, + true, + }, + { + "successful PacketCommitment verification", func() { + // send from chainB to chainA since we are proving chainB sent a packet + packet := channeltypes.NewPacket(ibctesting.MockPacketData, 1, testingpath.EndpointB.ChannelConfig.PortID, testingpath.EndpointB.ChannelID, testingpath.EndpointA.ChannelConfig.PortID, testingpath.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) + err := testingpath.EndpointB.SendPacket(packet) + suite.Require().NoError(err) + + // make packet commitment proof + key := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + merklePath := commitmenttypes.NewMerklePath(string(key)) + merklePath, err = commitmenttypes.ApplyPrefix(suite.chainB.GetPrefix(), merklePath) + suite.Require().NoError(err) + + path, err = suite.chainB.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, proofHeight = testingpath.EndpointB.QueryProof(key) + + value = channeltypes.CommitPacket(suite.chainA.App.GetIBCKeeper().Codec(), packet) + }, true, + }, + { + "successful Acknowledgement verification", func() { + // send from chainA to chainB since we are proving chainB wrote an acknowledgement + packet := channeltypes.NewPacket(ibctesting.MockPacketData, 1, testingpath.EndpointA.ChannelConfig.PortID, testingpath.EndpointA.ChannelID, testingpath.EndpointB.ChannelConfig.PortID, testingpath.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) + err := testingpath.EndpointA.SendPacket(packet) + suite.Require().NoError(err) + + // write receipt and ack + err = testingpath.EndpointB.RecvPacket(packet) + suite.Require().NoError(err) + + key := host.PacketAcknowledgementKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + merklePath := commitmenttypes.NewMerklePath(string(key)) + merklePath, err = commitmenttypes.ApplyPrefix(suite.chainB.GetPrefix(), merklePath) + suite.Require().NoError(err) + + path, err = suite.chainB.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, proofHeight = testingpath.EndpointB.QueryProof(key) + + value = channeltypes.CommitAcknowledgement(ibcmock.MockAcknowledgement.Acknowledgement()) + }, + true, + }, + { + "successful NextSequenceRecv verification", func() { + // send from chainA to chainB since we are proving chainB incremented the sequence recv + packet := channeltypes.NewPacket(ibctesting.MockPacketData, 1, testingpath.EndpointA.ChannelConfig.PortID, testingpath.EndpointA.ChannelID, testingpath.EndpointB.ChannelConfig.PortID, testingpath.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) + + // send packet + err := testingpath.EndpointA.SendPacket(packet) + suite.Require().NoError(err) + + // next seq recv incremented + err = testingpath.EndpointB.RecvPacket(packet) + suite.Require().NoError(err) + + key := host.NextSequenceRecvKey(packet.GetSourcePort(), packet.GetSourceChannel()) + merklePath := commitmenttypes.NewMerklePath(string(key)) + merklePath, err = commitmenttypes.ApplyPrefix(suite.chainB.GetPrefix(), merklePath) + suite.Require().NoError(err) + + path, err = suite.chainB.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, proofHeight = testingpath.EndpointB.QueryProof(key) + + value = sdk.Uint64ToBigEndian(packet.GetSequence() + 1) + }, + true, + }, + { + "successful verification outside IBC store", func() { + key := transfertypes.PortKey + merklePath := commitmenttypes.NewMerklePath(string(key)) + merklePath, err := commitmenttypes.ApplyPrefix(commitmenttypes.NewMerklePrefix([]byte(transfertypes.StoreKey)), merklePath) + suite.Require().NoError(err) + + path, err = suite.chainB.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + clientState := testingpath.EndpointA.GetClientState() + proof, proofHeight = suite.chainB.QueryProofForStore(transfertypes.StoreKey, key, int64(clientState.GetLatestHeight().GetRevisionHeight())) + + value = []byte(suite.chainB.GetSimApp().TransferKeeper.GetPort(suite.chainB.GetContext())) + suite.Require().NoError(err) + }, + true, + }, + { + "delay time period has passed", func() { + delayTimePeriod = uint64(time.Second.Nanoseconds()) + }, + true, + }, + { + "delay time period has not passed", func() { + delayTimePeriod = uint64(time.Hour.Nanoseconds()) + }, + false, + }, + { + "delay block period has passed", func() { + delayBlockPeriod = 1 + }, + true, + }, + { + "delay block period has not passed", func() { + delayBlockPeriod = 1000 + }, + false, + }, + { + "latest client height < height", func() { + proofHeight = testingpath.EndpointA.GetClientState().GetLatestHeight().Increment() + }, false, + }, + { + "failed to unmarshal merkle path", func() { + path = []byte("invalid merkle path") + }, false, + }, + { + "failed to unmarshal merkle proof", func() { + proof = invalidProof + }, false, + }, + { + "consensus state not found", func() { + proofHeight = clienttypes.ZeroHeight() + }, false, + }, + { + "proof verification failed", func() { + // change the value being proved + value = []byte("invalid value") + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + testingpath = ibctesting.NewPath(suite.chainA, suite.chainB) + testingpath.SetChannelOrdered() + suite.coordinator.Setup(testingpath) + + // reset time and block delays to 0, malleate may change to a specific non-zero value. + delayTimePeriod = 0 + delayBlockPeriod = 0 + + // create default proof, merklePath, and value which passes + // may be overwritten by malleate() + key := host.FullClientStateKey(testingpath.EndpointB.ClientID) + merklePath := commitmenttypes.NewMerklePath(string(key)) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chainB.GetPrefix(), merklePath) + suite.Require().NoError(err) + + path, err = suite.chainA.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, proofHeight = suite.chainB.QueryProof(key) + + clientState := testingpath.EndpointB.GetClientState().(*ibctm.ClientState) + value, err = suite.chainB.Codec.MarshalInterface(clientState) + suite.Require().NoError(err) + + tc.malleate() // make changes as necessary + + clientState = testingpath.EndpointA.GetClientState().(*ibctm.ClientState) + + ctx := suite.chainA.GetContext() + store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, testingpath.EndpointA.ClientID) + + err = clientState.VerifyMembership( + ctx, store, suite.chainA.Codec, proofHeight, delayTimePeriod, delayBlockPeriod, + proof, path, value, + ) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *TendermintTestSuite) TestVerifyNonMembership() { + var ( + testingpath *ibctesting.Path + delayTimePeriod uint64 + delayBlockPeriod uint64 + proofHeight exported.Height + proof []byte + path []byte + invalidClientID = "09-tendermint" + invalidConnectionID = "connection-100" + invalidChannelID = "channel-800" + invalidPortID = "invalid-port" + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "successful ClientState verification of non membership", + func() { + // default proof construction uses ClientState + }, + true, + }, + { + "successful ConsensusState verification of non membership", func() { + key := host.FullConsensusStateKey(invalidClientID, testingpath.EndpointB.GetClientState().GetLatestHeight()) + merklePath := commitmenttypes.NewMerklePath(string(key)) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chainB.GetPrefix(), merklePath) + suite.Require().NoError(err) + + path, err = suite.chainB.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, proofHeight = suite.chainB.QueryProof(key) + }, + true, + }, + { + "successful Connection verification of non membership", func() { + key := host.ConnectionKey(invalidConnectionID) + merklePath := commitmenttypes.NewMerklePath(string(key)) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chainB.GetPrefix(), merklePath) + suite.Require().NoError(err) + + path, err = suite.chainB.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, proofHeight = suite.chainB.QueryProof(key) + }, + true, + }, + { + "successful Channel verification of non membership", func() { + key := host.ChannelKey(testingpath.EndpointB.ChannelConfig.PortID, invalidChannelID) + merklePath := commitmenttypes.NewMerklePath(string(key)) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chainB.GetPrefix(), merklePath) + suite.Require().NoError(err) + + path, err = suite.chainB.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, proofHeight = suite.chainB.QueryProof(key) + }, + true, + }, + { + "successful PacketCommitment verification of non membership", func() { + // make packet commitment proof + key := host.PacketCommitmentKey(invalidPortID, invalidChannelID, 1) + merklePath := commitmenttypes.NewMerklePath(string(key)) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chainB.GetPrefix(), merklePath) + suite.Require().NoError(err) + + path, err = suite.chainB.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, proofHeight = testingpath.EndpointB.QueryProof(key) + }, true, + }, + { + "successful Acknowledgement verification of non membership", func() { + key := host.PacketAcknowledgementKey(invalidPortID, invalidChannelID, 1) + merklePath := commitmenttypes.NewMerklePath(string(key)) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chainB.GetPrefix(), merklePath) + suite.Require().NoError(err) + + path, err = suite.chainB.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, proofHeight = testingpath.EndpointB.QueryProof(key) + }, + true, + }, + { + "successful NextSequenceRecv verification of non membership", func() { + key := host.NextSequenceRecvKey(invalidPortID, invalidChannelID) + merklePath := commitmenttypes.NewMerklePath(string(key)) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chainB.GetPrefix(), merklePath) + suite.Require().NoError(err) + + path, err = suite.chainB.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, proofHeight = testingpath.EndpointB.QueryProof(key) + }, + true, + }, + { + "successful verification of non membership outside IBC store", func() { + key := []byte{0x08} + merklePath := commitmenttypes.NewMerklePath(string(key)) + merklePath, err := commitmenttypes.ApplyPrefix(commitmenttypes.NewMerklePrefix([]byte(transfertypes.StoreKey)), merklePath) + suite.Require().NoError(err) + + path, err = suite.chainB.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + clientState := testingpath.EndpointA.GetClientState() + proof, proofHeight = suite.chainB.QueryProofForStore(transfertypes.StoreKey, key, int64(clientState.GetLatestHeight().GetRevisionHeight())) + }, + true, + }, + { + "delay time period has passed", func() { + delayTimePeriod = uint64(time.Second.Nanoseconds()) + }, + true, + }, + { + "delay time period has not passed", func() { + delayTimePeriod = uint64(time.Hour.Nanoseconds()) + }, + false, + }, + { + "delay block period has passed", func() { + delayBlockPeriod = 1 + }, + true, + }, + { + "delay block period has not passed", func() { + delayBlockPeriod = 1000 + }, + false, + }, + { + "latest client height < height", func() { + proofHeight = testingpath.EndpointA.GetClientState().GetLatestHeight().Increment() + }, false, + }, + { + "failed to unmarshal merkle path", func() { + path = []byte("invalid merkle path") + }, false, + }, + { + "failed to unmarshal merkle proof", func() { + proof = invalidProof + }, false, + }, + { + "consensus state not found", func() { + proofHeight = clienttypes.ZeroHeight() + }, false, + }, + { + "verify non membership fails as path exists", func() { + // change the value being proved + key := host.FullClientStateKey(testingpath.EndpointB.ClientID) + merklePath := commitmenttypes.NewMerklePath(string(key)) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chainB.GetPrefix(), merklePath) + suite.Require().NoError(err) + + path, err = suite.chainA.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, proofHeight = suite.chainB.QueryProof(key) + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + testingpath = ibctesting.NewPath(suite.chainA, suite.chainB) + testingpath.SetChannelOrdered() + suite.coordinator.Setup(testingpath) + + // reset time and block delays to 0, malleate may change to a specific non-zero value. + delayTimePeriod = 0 + delayBlockPeriod = 0 + + // create default proof, merklePath, and value which passes + // may be overwritten by malleate() + key := host.FullClientStateKey("invalid-client-id") + + merklePath := commitmenttypes.NewMerklePath(string(key)) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chainB.GetPrefix(), merklePath) + suite.Require().NoError(err) + + path, err = suite.chainA.Codec.Marshal(&merklePath) + suite.Require().NoError(err) + + proof, proofHeight = suite.chainB.QueryProof(key) + + tc.malleate() // make changes as necessary + + clientState := testingpath.EndpointA.GetClientState().(*ibctm.ClientState) + + ctx := suite.chainA.GetContext() + store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, testingpath.EndpointA.ClientID) + + err = clientState.VerifyNonMembership( + ctx, store, suite.chainA.Codec, proofHeight, delayTimePeriod, delayBlockPeriod, + proof, path, + ) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/modules/light-clients/07-tendermint/types/codec.go b/modules/light-clients/07-tendermint/codec.go similarity index 87% rename from modules/light-clients/07-tendermint/types/codec.go rename to modules/light-clients/07-tendermint/codec.go index bf25097b4af..5e98991f24e 100644 --- a/modules/light-clients/07-tendermint/types/codec.go +++ b/modules/light-clients/07-tendermint/codec.go @@ -1,4 +1,4 @@ -package types +package tendermint import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" @@ -18,11 +18,11 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { &ConsensusState{}, ) registry.RegisterImplementations( - (*exported.Header)(nil), + (*exported.ClientMessage)(nil), &Header{}, ) registry.RegisterImplementations( - (*exported.Misbehaviour)(nil), + (*exported.ClientMessage)(nil), &Misbehaviour{}, ) } diff --git a/modules/light-clients/07-tendermint/types/consensus_state.go b/modules/light-clients/07-tendermint/consensus_state.go similarity index 99% rename from modules/light-clients/07-tendermint/types/consensus_state.go rename to modules/light-clients/07-tendermint/consensus_state.go index 7a2a32d2789..ce0e3006afe 100644 --- a/modules/light-clients/07-tendermint/types/consensus_state.go +++ b/modules/light-clients/07-tendermint/consensus_state.go @@ -1,4 +1,4 @@ -package types +package tendermint import ( "time" diff --git a/modules/light-clients/07-tendermint/types/consensus_state_test.go b/modules/light-clients/07-tendermint/consensus_state_test.go similarity index 73% rename from modules/light-clients/07-tendermint/types/consensus_state_test.go rename to modules/light-clients/07-tendermint/consensus_state_test.go index d4b24ddb510..b20b86fed4d 100644 --- a/modules/light-clients/07-tendermint/types/consensus_state_test.go +++ b/modules/light-clients/07-tendermint/consensus_state_test.go @@ -1,58 +1,49 @@ -package types_test +package tendermint_test import ( "time" commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" "github.com/cosmos/ibc-go/v5/modules/core/exported" - "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ) func (suite *TendermintTestSuite) TestConsensusStateValidateBasic() { testCases := []struct { msg string - consensusState *types.ConsensusState + consensusState *ibctm.ConsensusState expectPass bool }{ - { - "success", - &types.ConsensusState{ + {"success", + &ibctm.ConsensusState{ Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot([]byte("app_hash")), NextValidatorsHash: suite.valsHash, }, - true, - }, - { - "success with sentinel", - &types.ConsensusState{ + true}, + {"success with sentinel", + &ibctm.ConsensusState{ Timestamp: suite.now, - Root: commitmenttypes.NewMerkleRoot([]byte(types.SentinelRoot)), + Root: commitmenttypes.NewMerkleRoot([]byte(ibctm.SentinelRoot)), NextValidatorsHash: suite.valsHash, }, - true, - }, - { - "root is nil", - &types.ConsensusState{ + true}, + {"root is nil", + &ibctm.ConsensusState{ Timestamp: suite.now, Root: commitmenttypes.MerkleRoot{}, NextValidatorsHash: suite.valsHash, }, - false, - }, - { - "root is empty", - &types.ConsensusState{ + false}, + {"root is empty", + &ibctm.ConsensusState{ Timestamp: suite.now, Root: commitmenttypes.MerkleRoot{}, NextValidatorsHash: suite.valsHash, }, - false, - }, - { - "nextvalshash is invalid", - &types.ConsensusState{ + false}, + {"nextvalshash is invalid", + &ibctm.ConsensusState{ Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot([]byte("app_hash")), NextValidatorsHash: []byte("hi"), @@ -60,9 +51,8 @@ func (suite *TendermintTestSuite) TestConsensusStateValidateBasic() { false, }, - { - "timestamp is zero", - &types.ConsensusState{ + {"timestamp is zero", + &ibctm.ConsensusState{ Timestamp: time.Time{}, Root: commitmenttypes.NewMerkleRoot([]byte("app_hash")), NextValidatorsHash: suite.valsHash, diff --git a/modules/light-clients/07-tendermint/types/errors.go b/modules/light-clients/07-tendermint/errors.go similarity index 98% rename from modules/light-clients/07-tendermint/types/errors.go rename to modules/light-clients/07-tendermint/errors.go index 7b087e41af5..2839beb5291 100644 --- a/modules/light-clients/07-tendermint/types/errors.go +++ b/modules/light-clients/07-tendermint/errors.go @@ -1,4 +1,4 @@ -package types +package tendermint import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" diff --git a/modules/light-clients/07-tendermint/types/fraction.go b/modules/light-clients/07-tendermint/fraction.go similarity index 97% rename from modules/light-clients/07-tendermint/types/fraction.go rename to modules/light-clients/07-tendermint/fraction.go index e445f19ba6f..772c6d9c171 100644 --- a/modules/light-clients/07-tendermint/types/fraction.go +++ b/modules/light-clients/07-tendermint/fraction.go @@ -1,4 +1,4 @@ -package types +package tendermint import ( tmmath "github.com/tendermint/tendermint/libs/math" diff --git a/modules/light-clients/07-tendermint/types/genesis.go b/modules/light-clients/07-tendermint/genesis.go similarity index 97% rename from modules/light-clients/07-tendermint/types/genesis.go rename to modules/light-clients/07-tendermint/genesis.go index 8f9a8731a80..ab9159a00a8 100644 --- a/modules/light-clients/07-tendermint/types/genesis.go +++ b/modules/light-clients/07-tendermint/genesis.go @@ -1,4 +1,4 @@ -package types +package tendermint import ( sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/modules/light-clients/07-tendermint/types/genesis_test.go b/modules/light-clients/07-tendermint/genesis_test.go similarity index 77% rename from modules/light-clients/07-tendermint/types/genesis_test.go rename to modules/light-clients/07-tendermint/genesis_test.go index 86a601d1f60..517147a8dc1 100644 --- a/modules/light-clients/07-tendermint/types/genesis_test.go +++ b/modules/light-clients/07-tendermint/genesis_test.go @@ -1,10 +1,10 @@ -package types_test +package tendermint_test import ( sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) @@ -19,26 +19,26 @@ func (suite *TendermintTestSuite) TestExportMetadata() { clientState := path.EndpointA.GetClientState() height := clientState.GetLatestHeight() - initIteration := types.GetIterationKey(clientStore, height) + initIteration := ibctm.GetIterationKey(clientStore, height) suite.Require().NotEqual(0, len(initIteration)) - initProcessedTime, found := types.GetProcessedTime(clientStore, height) + initProcessedTime, found := ibctm.GetProcessedTime(clientStore, height) suite.Require().True(found) - initProcessedHeight, found := types.GetProcessedHeight(clientStore, height) + initProcessedHeight, found := ibctm.GetProcessedHeight(clientStore, height) suite.Require().True(found) gm := clientState.ExportMetadata(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID)) suite.Require().NotNil(gm, "client with metadata returned nil exported metadata") suite.Require().Len(gm, 3, "exported metadata has unexpected length") - suite.Require().Equal(types.ProcessedHeightKey(height), gm[0].GetKey(), "metadata has unexpected key") + suite.Require().Equal(ibctm.ProcessedHeightKey(height), gm[0].GetKey(), "metadata has unexpected key") actualProcessedHeight, err := clienttypes.ParseHeight(string(gm[0].GetValue())) suite.Require().NoError(err) suite.Require().Equal(initProcessedHeight, actualProcessedHeight, "metadata has unexpected value") - suite.Require().Equal(types.ProcessedTimeKey(height), gm[1].GetKey(), "metadata has unexpected key") + suite.Require().Equal(ibctm.ProcessedTimeKey(height), gm[1].GetKey(), "metadata has unexpected key") suite.Require().Equal(initProcessedTime, sdk.BigEndianToUint64(gm[1].GetValue()), "metadata has unexpected value") - suite.Require().Equal(types.IterationKey(height), gm[2].GetKey(), "metadata has unexpected key") + suite.Require().Equal(ibctm.IterationKey(height), gm[2].GetKey(), "metadata has unexpected key") suite.Require().Equal(initIteration, gm[2].GetValue(), "metadata has unexpected value") // test updating client and exporting metadata @@ -48,11 +48,11 @@ func (suite *TendermintTestSuite) TestExportMetadata() { clientState = path.EndpointA.GetClientState() updateHeight := clientState.GetLatestHeight() - iteration := types.GetIterationKey(clientStore, updateHeight) + iteration := ibctm.GetIterationKey(clientStore, updateHeight) suite.Require().NotEqual(0, len(initIteration)) - processedTime, found := types.GetProcessedTime(clientStore, updateHeight) + processedTime, found := ibctm.GetProcessedTime(clientStore, updateHeight) suite.Require().True(found) - processedHeight, found := types.GetProcessedHeight(clientStore, updateHeight) + processedHeight, found := ibctm.GetProcessedHeight(clientStore, updateHeight) suite.Require().True(found) gm = clientState.ExportMetadata(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID)) @@ -63,27 +63,27 @@ func (suite *TendermintTestSuite) TestExportMetadata() { // initProcessedHeight, initProcessedTime, processedHeight, processedTime, initIteration, iteration // check init processed height and time - suite.Require().Equal(types.ProcessedHeightKey(height), gm[0].GetKey(), "metadata has unexpected key") + suite.Require().Equal(ibctm.ProcessedHeightKey(height), gm[0].GetKey(), "metadata has unexpected key") actualProcessedHeight, err = clienttypes.ParseHeight(string(gm[0].GetValue())) suite.Require().NoError(err) suite.Require().Equal(initProcessedHeight, actualProcessedHeight, "metadata has unexpected value") - suite.Require().Equal(types.ProcessedTimeKey(height), gm[1].GetKey(), "metadata has unexpected key") + suite.Require().Equal(ibctm.ProcessedTimeKey(height), gm[1].GetKey(), "metadata has unexpected key") suite.Require().Equal(initProcessedTime, sdk.BigEndianToUint64(gm[1].GetValue()), "metadata has unexpected value") // check processed height and time after update - suite.Require().Equal(types.ProcessedHeightKey(updateHeight), gm[2].GetKey(), "metadata has unexpected key") + suite.Require().Equal(ibctm.ProcessedHeightKey(updateHeight), gm[2].GetKey(), "metadata has unexpected key") actualProcessedHeight, err = clienttypes.ParseHeight(string(gm[2].GetValue())) suite.Require().NoError(err) suite.Require().Equal(processedHeight, actualProcessedHeight, "metadata has unexpected value") - suite.Require().Equal(types.ProcessedTimeKey(updateHeight), gm[3].GetKey(), "metadata has unexpected key") + suite.Require().Equal(ibctm.ProcessedTimeKey(updateHeight), gm[3].GetKey(), "metadata has unexpected key") suite.Require().Equal(processedTime, sdk.BigEndianToUint64(gm[3].GetValue()), "metadata has unexpected value") // check iteration keys - suite.Require().Equal(types.IterationKey(height), gm[4].GetKey(), "metadata has unexpected key") + suite.Require().Equal(ibctm.IterationKey(height), gm[4].GetKey(), "metadata has unexpected key") suite.Require().Equal(initIteration, gm[4].GetValue(), "metadata has unexpected value") - suite.Require().Equal(types.IterationKey(updateHeight), gm[5].GetKey(), "metadata has unexpected key") + suite.Require().Equal(ibctm.IterationKey(updateHeight), gm[5].GetKey(), "metadata has unexpected key") suite.Require().Equal(iteration, gm[5].GetValue(), "metadata has unexpected value") } diff --git a/modules/light-clients/07-tendermint/types/header.go b/modules/light-clients/07-tendermint/header.go similarity index 97% rename from modules/light-clients/07-tendermint/types/header.go rename to modules/light-clients/07-tendermint/header.go index 2da01504710..9fc00198245 100644 --- a/modules/light-clients/07-tendermint/types/header.go +++ b/modules/light-clients/07-tendermint/header.go @@ -1,4 +1,4 @@ -package types +package tendermint import ( "bytes" @@ -12,7 +12,7 @@ import ( "github.com/cosmos/ibc-go/v5/modules/core/exported" ) -var _ exported.Header = &Header{} +var _ exported.ClientMessage = &Header{} // ConsensusState returns the updated consensus state associated with the header func (h Header) ConsensusState() *ConsensusState { diff --git a/modules/light-clients/07-tendermint/types/header_test.go b/modules/light-clients/07-tendermint/header_test.go similarity index 94% rename from modules/light-clients/07-tendermint/types/header_test.go rename to modules/light-clients/07-tendermint/header_test.go index 933ae8d9d70..8e916177877 100644 --- a/modules/light-clients/07-tendermint/types/header_test.go +++ b/modules/light-clients/07-tendermint/header_test.go @@ -1,4 +1,4 @@ -package types_test +package tendermint_test import ( "time" @@ -7,7 +7,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" "github.com/cosmos/ibc-go/v5/modules/core/exported" - "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ) func (suite *TendermintTestSuite) TestGetHeight() { @@ -21,7 +21,7 @@ func (suite *TendermintTestSuite) TestGetTime() { } func (suite *TendermintTestSuite) TestHeaderValidateBasic() { - var header *types.Header + var header *ibctm.Header testCases := []struct { name string malleate func() diff --git a/modules/light-clients/07-tendermint/types/misbehaviour.go b/modules/light-clients/07-tendermint/misbehaviour.go similarity index 95% rename from modules/light-clients/07-tendermint/types/misbehaviour.go rename to modules/light-clients/07-tendermint/misbehaviour.go index a15699767f3..3fc237621ab 100644 --- a/modules/light-clients/07-tendermint/types/misbehaviour.go +++ b/modules/light-clients/07-tendermint/misbehaviour.go @@ -1,4 +1,4 @@ -package types +package tendermint import ( "time" @@ -12,7 +12,7 @@ import ( "github.com/cosmos/ibc-go/v5/modules/core/exported" ) -var _ exported.Misbehaviour = &Misbehaviour{} +var _ exported.ClientMessage = &Misbehaviour{} // FrozenHeight is same for all misbehaviour var FrozenHeight = clienttypes.NewHeight(0, 1) @@ -31,11 +31,6 @@ func (misbehaviour Misbehaviour) ClientType() string { return exported.Tendermint } -// GetClientID returns the ID of the client that committed a misbehaviour. -func (misbehaviour Misbehaviour) GetClientID() string { - return misbehaviour.ClientId -} - // GetTime returns the timestamp at which misbehaviour occurred. It uses the // maximum value from both headers to prevent producing an invalid header outside // of the misbehaviour age range. @@ -130,3 +125,9 @@ func validCommit(chainID string, blockID tmtypes.BlockID, commit *tmproto.Commit return nil } + +// TODO: Remove GetHeight() +// GetHeight implements the curret exported.Header interface, to be updated +func (misbehaviour Misbehaviour) GetHeight() exported.Height { + return nil +} diff --git a/modules/light-clients/07-tendermint/types/misbehaviour_handle.go b/modules/light-clients/07-tendermint/misbehaviour_handle.go similarity index 61% rename from modules/light-clients/07-tendermint/types/misbehaviour_handle.go rename to modules/light-clients/07-tendermint/misbehaviour_handle.go index 17883824cb6..0417dd4da17 100644 --- a/modules/light-clients/07-tendermint/types/misbehaviour_handle.go +++ b/modules/light-clients/07-tendermint/misbehaviour_handle.go @@ -1,4 +1,4 @@ -package types +package tendermint import ( "bytes" @@ -10,10 +10,9 @@ import ( tmtypes "github.com/tendermint/tendermint/types" clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v5/modules/core/exported" ) -// CheckMisbehaviourAndUpdateState determines whether or not two conflicting +// verifyMisbehaviour determines whether or not two conflicting // headers at the same height would have convinced the light client. // // NOTE: consensusState1 is the trusted consensus state that corresponds to the TrustedHeight @@ -21,57 +20,42 @@ import ( // Similarly, consensusState2 is the trusted consensus state that corresponds // to misbehaviour.Header2 // Misbehaviour sets frozen height to {0, 1} since it is only used as a boolean value (zero or non-zero). -func (cs ClientState) CheckMisbehaviourAndUpdateState( - ctx sdk.Context, - cdc codec.BinaryCodec, - clientStore sdk.KVStore, - misbehaviour exported.Misbehaviour, -) (exported.ClientState, error) { - tmMisbehaviour, ok := misbehaviour.(*Misbehaviour) - if !ok { - return nil, sdkerrors.Wrapf(clienttypes.ErrInvalidClientType, "expected type %T, got %T", misbehaviour, &Misbehaviour{}) - } - - // The status of the client is checked in 02-client - +func (cs *ClientState) verifyMisbehaviour(ctx sdk.Context, clientStore sdk.KVStore, cdc codec.BinaryCodec, misbehaviour *Misbehaviour) error { // if heights are equal check that this is valid misbehaviour of a fork // otherwise if heights are unequal check that this is valid misbehavior of BFT time violation - if tmMisbehaviour.Header1.GetHeight().EQ(tmMisbehaviour.Header2.GetHeight()) { - blockID1, err := tmtypes.BlockIDFromProto(&tmMisbehaviour.Header1.SignedHeader.Commit.BlockID) + if misbehaviour.Header1.GetHeight().EQ(misbehaviour.Header2.GetHeight()) { + blockID1, err := tmtypes.BlockIDFromProto(&misbehaviour.Header1.SignedHeader.Commit.BlockID) if err != nil { - return nil, sdkerrors.Wrap(err, "invalid block ID from header 1 in misbehaviour") + return sdkerrors.Wrap(err, "invalid block ID from header 1 in misbehaviour") } - blockID2, err := tmtypes.BlockIDFromProto(&tmMisbehaviour.Header2.SignedHeader.Commit.BlockID) + + blockID2, err := tmtypes.BlockIDFromProto(&misbehaviour.Header2.SignedHeader.Commit.BlockID) if err != nil { - return nil, sdkerrors.Wrap(err, "invalid block ID from header 2 in misbehaviour") + return sdkerrors.Wrap(err, "invalid block ID from header 2 in misbehaviour") } // Ensure that Commit Hashes are different if bytes.Equal(blockID1.Hash, blockID2.Hash) { - return nil, sdkerrors.Wrap(clienttypes.ErrInvalidMisbehaviour, "headers block hashes are equal") + return sdkerrors.Wrap(clienttypes.ErrInvalidMisbehaviour, "headers block hashes are equal") } - } else if tmMisbehaviour.Header1.SignedHeader.Header.Time.After(tmMisbehaviour.Header2.SignedHeader.Header.Time) { + } else if misbehaviour.Header1.SignedHeader.Header.Time.After(misbehaviour.Header2.SignedHeader.Header.Time) { // Header1 is at greater height than Header2, therefore Header1 time must be less than or equal to // Header2 time in order to be valid misbehaviour (violation of monotonic time). - return nil, sdkerrors.Wrap(clienttypes.ErrInvalidMisbehaviour, "headers are not at same height and are monotonically increasing") + return sdkerrors.Wrap(clienttypes.ErrInvalidMisbehaviour, "headers are not at same height and are monotonically increasing") } // Regardless of the type of misbehaviour, ensure that both headers are valid and would have been accepted by light-client // Retrieve trusted consensus states for each Header in misbehaviour - // and unmarshal from clientStore - - // Get consensus bytes from clientStore - tmConsensusState1, err := GetConsensusState(clientStore, cdc, tmMisbehaviour.Header1.TrustedHeight) - if err != nil { - return nil, sdkerrors.Wrapf(err, "could not get trusted consensus state from clientStore for Header1 at TrustedHeight: %s", tmMisbehaviour.Header1) + tmConsensusState1, found := GetConsensusState(clientStore, cdc, misbehaviour.Header1.TrustedHeight) + if !found { + return sdkerrors.Wrapf(clienttypes.ErrConsensusStateNotFound, "could not get trusted consensus state from clientStore for Header1 at TrustedHeight: %s", misbehaviour.Header1.TrustedHeight) } - // Get consensus bytes from clientStore - tmConsensusState2, err := GetConsensusState(clientStore, cdc, tmMisbehaviour.Header2.TrustedHeight) - if err != nil { - return nil, sdkerrors.Wrapf(err, "could not get trusted consensus state from clientStore for Header2 at TrustedHeight: %s", tmMisbehaviour.Header2) + tmConsensusState2, found := GetConsensusState(clientStore, cdc, misbehaviour.Header2.TrustedHeight) + if !found { + return sdkerrors.Wrapf(clienttypes.ErrConsensusStateNotFound, "could not get trusted consensus state from clientStore for Header2 at TrustedHeight: %s", misbehaviour.Header2.TrustedHeight) } // Check the validity of the two conflicting headers against their respective @@ -80,19 +64,17 @@ func (cs ClientState) CheckMisbehaviourAndUpdateState( // misbehaviour.ValidateBasic by the client keeper and msg.ValidateBasic // by the base application. if err := checkMisbehaviourHeader( - &cs, tmConsensusState1, tmMisbehaviour.Header1, ctx.BlockTime(), + cs, tmConsensusState1, misbehaviour.Header1, ctx.BlockTime(), ); err != nil { - return nil, sdkerrors.Wrap(err, "verifying Header1 in Misbehaviour failed") + return sdkerrors.Wrap(err, "verifying Header1 in Misbehaviour failed") } if err := checkMisbehaviourHeader( - &cs, tmConsensusState2, tmMisbehaviour.Header2, ctx.BlockTime(), + cs, tmConsensusState2, misbehaviour.Header2, ctx.BlockTime(), ); err != nil { - return nil, sdkerrors.Wrap(err, "verifying Header2 in Misbehaviour failed") + return sdkerrors.Wrap(err, "verifying Header2 in Misbehaviour failed") } - cs.FrozenHeight = FrozenHeight - - return &cs, nil + return nil } // checkMisbehaviourHeader checks that a Header in Misbehaviour is valid misbehaviour given @@ -127,6 +109,8 @@ func checkMisbehaviourHeader( chainID := clientState.GetChainID() // If chainID is in revision format, then set revision number of chainID with the revision number // of the misbehaviour header + // NOTE: misbehaviour verification is not supported for chains which upgrade to a new chainID without + // strictly following the chainID revision format if clienttypes.IsRevisionFormat(chainID) { chainID, _ = clienttypes.SetRevisionNumber(chainID, header.GetHeight().GetRevisionNumber()) } diff --git a/modules/light-clients/07-tendermint/misbehaviour_handle_test.go b/modules/light-clients/07-tendermint/misbehaviour_handle_test.go new file mode 100644 index 00000000000..7b42d6ab19a --- /dev/null +++ b/modules/light-clients/07-tendermint/misbehaviour_handle_test.go @@ -0,0 +1,717 @@ +package tendermint_test + +import ( + "fmt" + "strings" + "time" + + tmtypes "github.com/tendermint/tendermint/types" + + clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v5/modules/core/exported" + smtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v5/testing" + ibctestingmock "github.com/cosmos/ibc-go/v5/testing/mock" +) + +func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { + // Setup different validators and signers for testing different types of updates + altPrivVal := ibctestingmock.NewPV() + altPubKey, err := altPrivVal.GetPubKey() + suite.Require().NoError(err) + + // create modified heights to use for test-cases + altVal := tmtypes.NewValidator(altPubKey, 100) + + // Create alternative validator set with only altVal, invalid update (too much change in valSet) + altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal}) + altSigners := getAltSigners(altVal, altPrivVal) + + var ( + path *ibctesting.Path + misbehaviour exported.ClientMessage + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "valid fork misbehaviour", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + }, + true, + }, + { + "valid time misbehaviour", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height+3, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + }, + true, + }, + { + "valid time misbehaviour, header 1 time stricly less than header 2 time", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height+3, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Hour), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + }, + true, + }, + { + "valid misbehavior at height greater than last consensusState", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height+1, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height+1, trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + }, true, + }, + { + "valid misbehaviour with different trusted heights", func() { + trustedHeight1 := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals1, found := suite.chainB.GetValsAtHeight(int64(trustedHeight1.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + trustedHeight2 := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals2, found := suite.chainB.GetValsAtHeight(int64(trustedHeight2.RevisionHeight) + 1) + suite.Require().True(found) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight1, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals1, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight2, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals2, suite.chainB.Signers), + } + + }, + true, + }, + { + + "valid misbehaviour at a previous revision", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + + // increment revision number + err = path.EndpointB.UpgradeChain() + suite.Require().NoError(err) + }, + true, + }, + { + "valid misbehaviour at a future revision", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + futureRevision := fmt.Sprintf("%s-%d", strings.TrimSuffix(suite.chainB.ChainID, fmt.Sprintf("-%d", clienttypes.ParseChainID(suite.chainB.ChainID))), height.GetRevisionNumber()+1) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(futureRevision, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(futureRevision, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + }, + true, + }, + { + "valid misbehaviour with trusted heights at a previous revision", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + // increment revision of chainID + err = path.EndpointB.UpgradeChain() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + }, + true, + }, + { + "consensus state's valset hash different from misbehaviour should still pass", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + // Create bothValSet with both suite validator and altVal + bothValSet := tmtypes.NewValidatorSet(append(suite.chainB.Vals.Validators, altValSet.Proposer)) + bothSigners := suite.chainB.Signers + bothSigners[altValSet.Proposer.Address.String()] = altPrivVal + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), bothValSet, suite.chainB.NextVals, trustedVals, bothSigners), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, bothValSet, suite.chainB.NextVals, trustedVals, bothSigners), + } + }, true, + }, + { + "invalid fork misbehaviour: identical headers", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + misbehaviourHeader := suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers) + misbehaviour = &ibctm.Misbehaviour{ + Header1: misbehaviourHeader, + Header2: misbehaviourHeader, + } + }, false, + }, + { + "invalid time misbehaviour: monotonically increasing time", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height+3, trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + }, false, + }, + { + "invalid misbehaviour: misbehaviour from different chain", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader("evmos", int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader("evmos", int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + + }, false, + }, + { + "misbehaviour trusted validators does not match validator hash in trusted consensus state", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, altValSet, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, altValSet, suite.chainB.Signers), + } + }, false, + }, + { + "trusted consensus state does not exist", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight.Increment().(clienttypes.Height), suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + }, false, + }, + { + "invalid tendermint misbehaviour", func() { + misbehaviour = &smtypes.Misbehaviour{} + }, false, + }, + { + "trusting period expired", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + suite.chainA.ExpireClient(path.EndpointA.ClientConfig.(*ibctesting.TendermintConfig).TrustingPeriod) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + }, false, + }, + { + "header 1 valset has too much change", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), altValSet, suite.chainB.NextVals, trustedVals, altSigners), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + }, false, + }, + { + "header 2 valset has too much change", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, altValSet, suite.chainB.NextVals, trustedVals, altSigners), + } + }, false, + }, + { + "both header 1 and header 2 valsets have too much change", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), altValSet, suite.chainB.NextVals, trustedVals, altSigners), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, altValSet, suite.chainB.NextVals, trustedVals, altSigners), + } + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() + path = ibctesting.NewPath(suite.chainA, suite.chainB) + + err := path.EndpointA.CreateClient() + suite.Require().NoError(err) + + tc.malleate() + + clientState := path.EndpointA.GetClientState() + clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + + err = clientState.VerifyClientMessage(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, misbehaviour) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + +// test both fork and time misbehaviour for chainIDs not in the revision format +// this function is separate as it must use a global variable in the testing package +// to initialize chains not in the revision format +func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { + // NOTE: chains set to non revision format + ibctesting.ChainIDSuffix = "" + + // Setup different validators and signers for testing different types of updates + altPrivVal := ibctestingmock.NewPV() + altPubKey, err := altPrivVal.GetPubKey() + suite.Require().NoError(err) + + // create modified heights to use for test-cases + altVal := tmtypes.NewValidator(altPubKey, 100) + + // Create alternative validator set with only altVal, invalid update (too much change in valSet) + altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal}) + altSigners := getAltSigners(altVal, altPrivVal) + + var ( + path *ibctesting.Path + misbehaviour exported.ClientMessage + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "valid fork misbehaviour", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + }, + true, + }, + { + "valid time misbehaviour", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height+3, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + }, + true, + }, + { + "valid time misbehaviour, header 1 time stricly less than header 2 time", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height+3, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Hour), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + }, + true, + }, + { + "valid misbehavior at height greater than last consensusState", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height+1, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height+1, trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + }, true, + }, + { + "valid misbehaviour with different trusted heights", func() { + trustedHeight1 := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals1, found := suite.chainB.GetValsAtHeight(int64(trustedHeight1.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + trustedHeight2 := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals2, found := suite.chainB.GetValsAtHeight(int64(trustedHeight2.RevisionHeight) + 1) + suite.Require().True(found) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight1, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals1, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight2, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals2, suite.chainB.Signers), + } + + }, + true, + }, + { + "consensus state's valset hash different from misbehaviour should still pass", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + // Create bothValSet with both suite validator and altVal + bothValSet := tmtypes.NewValidatorSet(append(suite.chainB.Vals.Validators, altValSet.Proposer)) + bothSigners := suite.chainB.Signers + bothSigners[altValSet.Proposer.Address.String()] = altPrivVal + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), bothValSet, suite.chainB.NextVals, trustedVals, bothSigners), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, bothValSet, suite.chainB.NextVals, trustedVals, bothSigners), + } + }, true, + }, + { + "invalid fork misbehaviour: identical headers", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + misbehaviourHeader := suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers) + misbehaviour = &ibctm.Misbehaviour{ + Header1: misbehaviourHeader, + Header2: misbehaviourHeader, + } + }, false, + }, + { + "invalid time misbehaviour: monotonically increasing time", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height+3, trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + }, false, + }, + { + "invalid misbehaviour: misbehaviour from different chain", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader("evmos", int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader("evmos", int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + + }, false, + }, + { + "misbehaviour trusted validators does not match validator hash in trusted consensus state", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, altValSet, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, altValSet, suite.chainB.Signers), + } + }, false, + }, + { + "trusted consensus state does not exist", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight.Increment().(clienttypes.Height), suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + }, false, + }, + { + "invalid tendermint misbehaviour", func() { + misbehaviour = &smtypes.Misbehaviour{} + }, false, + }, + { + "trusting period expired", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + suite.chainA.ExpireClient(path.EndpointA.ClientConfig.(*ibctesting.TendermintConfig).TrustingPeriod) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + }, false, + }, + { + "header 1 valset has too much change", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), altValSet, suite.chainB.NextVals, trustedVals, altSigners), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + } + }, false, + }, + { + "header 2 valset has too much change", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, altValSet, suite.chainB.NextVals, trustedVals, altSigners), + } + }, false, + }, + { + "both header 1 and header 2 valsets have too much change", func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + misbehaviour = &ibctm.Misbehaviour{ + Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time.Add(time.Minute), altValSet, suite.chainB.NextVals, trustedVals, altSigners), + Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, altValSet, suite.chainB.NextVals, trustedVals, altSigners), + } + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() + path = ibctesting.NewPath(suite.chainA, suite.chainB) + + err := path.EndpointA.CreateClient() + suite.Require().NoError(err) + + tc.malleate() + + clientState := path.EndpointA.GetClientState() + clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + + err = clientState.VerifyClientMessage(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, misbehaviour) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } + + // NOTE: reset chain creation to revision format + ibctesting.ChainIDSuffix = "-1" +} diff --git a/modules/light-clients/07-tendermint/types/misbehaviour_test.go b/modules/light-clients/07-tendermint/misbehaviour_test.go similarity index 82% rename from modules/light-clients/07-tendermint/types/misbehaviour_test.go rename to modules/light-clients/07-tendermint/misbehaviour_test.go index 0731cd25489..979b5d1c203 100644 --- a/modules/light-clients/07-tendermint/types/misbehaviour_test.go +++ b/modules/light-clients/07-tendermint/misbehaviour_test.go @@ -1,4 +1,4 @@ -package types_test +package tendermint_test import ( "time" @@ -9,7 +9,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" "github.com/cosmos/ibc-go/v5/modules/core/exported" - "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ibctestingmock "github.com/cosmos/ibc-go/v5/testing/mock" ) @@ -17,14 +17,13 @@ import ( func (suite *TendermintTestSuite) TestMisbehaviour() { heightMinus1 := clienttypes.NewHeight(0, height.RevisionHeight-1) - misbehaviour := &types.Misbehaviour{ + misbehaviour := &ibctm.Misbehaviour{ Header1: suite.header, Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now, suite.valSet, suite.valSet, suite.valSet, suite.signers), ClientId: clientID, } suite.Require().Equal(exported.Tendermint, misbehaviour.ClientType()) - suite.Require().Equal(clientID, misbehaviour.GetClientID()) } func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { @@ -48,130 +47,130 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { testCases := []struct { name string - misbehaviour *types.Misbehaviour - malleateMisbehaviour func(misbehaviour *types.Misbehaviour) error + misbehaviour *ibctm.Misbehaviour + malleateMisbehaviour func(misbehaviour *ibctm.Misbehaviour) error expPass bool }{ { "valid fork misbehaviour, two headers at same height have different time", - &types.Misbehaviour{ + &ibctm.Misbehaviour{ Header1: suite.header, Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now.Add(time.Minute), suite.valSet, suite.valSet, suite.valSet, suite.signers), ClientId: clientID, }, - func(misbehaviour *types.Misbehaviour) error { return nil }, + func(misbehaviour *ibctm.Misbehaviour) error { return nil }, true, }, { "valid time misbehaviour, both headers at different heights are at same time", - &types.Misbehaviour{ + &ibctm.Misbehaviour{ Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+5), heightMinus1, suite.now, suite.valSet, suite.valSet, suite.valSet, suite.signers), Header2: suite.header, ClientId: clientID, }, - func(misbehaviour *types.Misbehaviour) error { return nil }, + func(misbehaviour *ibctm.Misbehaviour) error { return nil }, true, }, { "misbehaviour Header1 is nil", - types.NewMisbehaviour(clientID, nil, suite.header), - func(m *types.Misbehaviour) error { return nil }, + ibctm.NewMisbehaviour(clientID, nil, suite.header), + func(m *ibctm.Misbehaviour) error { return nil }, false, }, { "misbehaviour Header2 is nil", - types.NewMisbehaviour(clientID, suite.header, nil), - func(m *types.Misbehaviour) error { return nil }, + ibctm.NewMisbehaviour(clientID, suite.header, nil), + func(m *ibctm.Misbehaviour) error { return nil }, false, }, { "valid misbehaviour with different trusted headers", - &types.Misbehaviour{ + &ibctm.Misbehaviour{ Header1: suite.header, Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), clienttypes.NewHeight(0, height.RevisionHeight-3), suite.now.Add(time.Minute), suite.valSet, suite.valSet, bothValSet, suite.signers), ClientId: clientID, }, - func(misbehaviour *types.Misbehaviour) error { return nil }, + func(misbehaviour *ibctm.Misbehaviour) error { return nil }, true, }, { "trusted height is 0 in Header1", - &types.Misbehaviour{ + &ibctm.Misbehaviour{ Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), clienttypes.ZeroHeight(), suite.now.Add(time.Minute), suite.valSet, suite.valSet, suite.valSet, suite.signers), Header2: suite.header, ClientId: clientID, }, - func(misbehaviour *types.Misbehaviour) error { return nil }, + func(misbehaviour *ibctm.Misbehaviour) error { return nil }, false, }, { "trusted height is 0 in Header2", - &types.Misbehaviour{ + &ibctm.Misbehaviour{ Header1: suite.header, Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), clienttypes.ZeroHeight(), suite.now.Add(time.Minute), suite.valSet, suite.valSet, suite.valSet, suite.signers), ClientId: clientID, }, - func(misbehaviour *types.Misbehaviour) error { return nil }, + func(misbehaviour *ibctm.Misbehaviour) error { return nil }, false, }, { "trusted valset is nil in Header1", - &types.Misbehaviour{ + &ibctm.Misbehaviour{ Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now.Add(time.Minute), suite.valSet, suite.valSet, nil, suite.signers), Header2: suite.header, ClientId: clientID, }, - func(misbehaviour *types.Misbehaviour) error { return nil }, + func(misbehaviour *ibctm.Misbehaviour) error { return nil }, false, }, { "trusted valset is nil in Header2", - &types.Misbehaviour{ + &ibctm.Misbehaviour{ Header1: suite.header, Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now.Add(time.Minute), suite.valSet, suite.valSet, nil, suite.signers), ClientId: clientID, }, - func(misbehaviour *types.Misbehaviour) error { return nil }, + func(misbehaviour *ibctm.Misbehaviour) error { return nil }, false, }, { "invalid client ID ", - &types.Misbehaviour{ + &ibctm.Misbehaviour{ Header1: suite.header, Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now, suite.valSet, suite.valSet, suite.valSet, suite.signers), ClientId: "GAIA", }, - func(misbehaviour *types.Misbehaviour) error { return nil }, + func(misbehaviour *ibctm.Misbehaviour) error { return nil }, false, }, { "chainIDs do not match", - &types.Misbehaviour{ + &ibctm.Misbehaviour{ Header1: suite.header, Header2: suite.chainA.CreateTMClientHeader("ethermint", int64(height.RevisionHeight), heightMinus1, suite.now, suite.valSet, suite.valSet, suite.valSet, suite.signers), ClientId: clientID, }, - func(misbehaviour *types.Misbehaviour) error { return nil }, + func(misbehaviour *ibctm.Misbehaviour) error { return nil }, false, }, { "header2 height is greater", - &types.Misbehaviour{ + &ibctm.Misbehaviour{ Header1: suite.header, Header2: suite.chainA.CreateTMClientHeader(chainID, 6, clienttypes.NewHeight(0, height.RevisionHeight+1), suite.now, suite.valSet, suite.valSet, suite.valSet, suite.signers), ClientId: clientID, }, - func(misbehaviour *types.Misbehaviour) error { return nil }, + func(misbehaviour *ibctm.Misbehaviour) error { return nil }, false, }, { "header 1 doesn't have 2/3 majority", - &types.Misbehaviour{ + &ibctm.Misbehaviour{ Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now, bothValSet, bothValSet, suite.valSet, bothSigners), Header2: suite.header, ClientId: clientID, }, - func(misbehaviour *types.Misbehaviour) error { + func(misbehaviour *ibctm.Misbehaviour) error { // voteSet contains only altVal which is less than 2/3 of total power (height/1height) wrongVoteSet := tmtypes.NewVoteSet(chainID, int64(misbehaviour.Header1.GetHeight().GetRevisionHeight()), 1, tmproto.PrecommitType, altValSet) blockID, err := tmtypes.BlockIDFromProto(&misbehaviour.Header1.Commit.BlockID) @@ -187,12 +186,12 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { }, { "header 2 doesn't have 2/3 majority", - &types.Misbehaviour{ + &ibctm.Misbehaviour{ Header1: suite.header, Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now, bothValSet, bothValSet, suite.valSet, bothSigners), ClientId: clientID, }, - func(misbehaviour *types.Misbehaviour) error { + func(misbehaviour *ibctm.Misbehaviour) error { // voteSet contains only altVal which is less than 2/3 of total power (height/1height) wrongVoteSet := tmtypes.NewVoteSet(chainID, int64(misbehaviour.Header2.GetHeight().GetRevisionHeight()), 1, tmproto.PrecommitType, altValSet) blockID, err := tmtypes.BlockIDFromProto(&misbehaviour.Header2.Commit.BlockID) @@ -208,12 +207,12 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { }, { "validators sign off on wrong commit", - &types.Misbehaviour{ + &ibctm.Misbehaviour{ Header1: suite.header, Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now, bothValSet, bothValSet, suite.valSet, bothSigners), ClientId: clientID, }, - func(misbehaviour *types.Misbehaviour) error { + func(misbehaviour *ibctm.Misbehaviour) error { tmBlockID := ibctesting.MakeBlockID(tmhash.Sum([]byte("other_hash")), 3, tmhash.Sum([]byte("other_partset"))) misbehaviour.Header2.Commit.BlockID = tmBlockID.ToProto() return nil diff --git a/modules/light-clients/07-tendermint/module.go b/modules/light-clients/07-tendermint/module.go index 532f3158f44..935bf34cafd 100644 --- a/modules/light-clients/07-tendermint/module.go +++ b/modules/light-clients/07-tendermint/module.go @@ -1,10 +1,6 @@ package tendermint -import ( - "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" -) - // Name returns the IBC client name func Name() string { - return types.SubModuleName + return SubModuleName } diff --git a/modules/light-clients/07-tendermint/types/proposal_handle.go b/modules/light-clients/07-tendermint/proposal_handle.go similarity index 78% rename from modules/light-clients/07-tendermint/types/proposal_handle.go rename to modules/light-clients/07-tendermint/proposal_handle.go index 9a75c5f9b9f..39700ed3418 100644 --- a/modules/light-clients/07-tendermint/types/proposal_handle.go +++ b/modules/light-clients/07-tendermint/proposal_handle.go @@ -1,4 +1,4 @@ -package types +package tendermint import ( "reflect" @@ -27,16 +27,14 @@ import ( func (cs ClientState) CheckSubstituteAndUpdateState( ctx sdk.Context, cdc codec.BinaryCodec, subjectClientStore, substituteClientStore sdk.KVStore, substituteClient exported.ClientState, -) (exported.ClientState, error) { +) error { substituteClientState, ok := substituteClient.(*ClientState) if !ok { - return nil, sdkerrors.Wrapf( - clienttypes.ErrInvalidClient, "expected type %T, got %T", &ClientState{}, substituteClient, - ) + return sdkerrors.Wrapf(clienttypes.ErrInvalidClient, "expected type %T, got %T", &ClientState{}, substituteClient) } if !IsMatchingClientState(cs, *substituteClientState) { - return nil, sdkerrors.Wrap(clienttypes.ErrInvalidSubstitute, "subject client state does not match substitute client state") + return sdkerrors.Wrap(clienttypes.ErrInvalidSubstitute, "subject client state does not match substitute client state") } if cs.Status(ctx, subjectClientStore, cdc) == exported.Frozen { @@ -48,22 +46,22 @@ func (cs ClientState) CheckSubstituteAndUpdateState( // starting from initial height and ending on the latest height (inclusive) height := substituteClientState.GetLatestHeight() - consensusState, err := GetConsensusState(substituteClientStore, cdc, height) - if err != nil { - return nil, sdkerrors.Wrap(err, "unable to retrieve latest consensus state for substitute client") + consensusState, found := GetConsensusState(substituteClientStore, cdc, height) + if !found { + return sdkerrors.Wrap(clienttypes.ErrConsensusStateNotFound, "unable to retrieve latest consensus state for substitute client") } - SetConsensusState(subjectClientStore, cdc, consensusState, height) + setConsensusState(subjectClientStore, cdc, consensusState, height) // set metadata stored for the substitute consensus state processedHeight, found := GetProcessedHeight(substituteClientStore, height) if !found { - return nil, sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "unable to retrieve processed height for substitute client latest height") + return sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "unable to retrieve processed height for substitute client latest height") } processedTime, found := GetProcessedTime(substituteClientStore, height) if !found { - return nil, sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "unable to retrieve processed time for substitute client latest height") + return sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "unable to retrieve processed time for substitute client latest height") } setConsensusMetadataWithValues(subjectClientStore, height, processedHeight, processedTime) @@ -76,8 +74,9 @@ func (cs ClientState) CheckSubstituteAndUpdateState( // no validation is necessary since the substitute is verified to be Active // in 02-client. + setClientState(subjectClientStore, cdc, &cs) - return &cs, nil + return nil } // IsMatchingClientState returns true if all the client state parameters match diff --git a/modules/light-clients/07-tendermint/types/proposal_handle_test.go b/modules/light-clients/07-tendermint/proposal_handle_test.go similarity index 83% rename from modules/light-clients/07-tendermint/types/proposal_handle_test.go rename to modules/light-clients/07-tendermint/proposal_handle_test.go index 62e65e05053..3d7e5e3e688 100644 --- a/modules/light-clients/07-tendermint/types/proposal_handle_test.go +++ b/modules/light-clients/07-tendermint/proposal_handle_test.go @@ -1,11 +1,11 @@ -package types_test +package tendermint_test import ( "time" clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" "github.com/cosmos/ibc-go/v5/modules/core/exported" - "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) @@ -28,7 +28,7 @@ func (suite *TendermintTestSuite) TestCheckSubstituteUpdateStateBasic() { { "non-matching substitute", func() { suite.coordinator.SetupClients(substitutePath) - substituteClientState, ok := suite.chainA.GetClientState(substitutePath.EndpointA.ClientID).(*types.ClientState) + substituteClientState, ok := suite.chainA.GetClientState(substitutePath.EndpointA.ClientID).(*ibctm.ClientState) suite.Require().True(ok) // change trusting period so that test should fail substituteClientState.TrustingPeriod = time.Hour * 24 * 7 @@ -48,7 +48,7 @@ func (suite *TendermintTestSuite) TestCheckSubstituteUpdateStateBasic() { substitutePath = ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(subjectPath) - subjectClientState := suite.chainA.GetClientState(subjectPath.EndpointA.ClientID).(*types.ClientState) + subjectClientState := suite.chainA.GetClientState(subjectPath.EndpointA.ClientID).(*ibctm.ClientState) // expire subject client suite.coordinator.IncrementTimeBy(subjectClientState.TrustingPeriod) @@ -59,9 +59,8 @@ func (suite *TendermintTestSuite) TestCheckSubstituteUpdateStateBasic() { subjectClientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), subjectPath.EndpointA.ClientID) substituteClientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), substitutePath.EndpointA.ClientID) - updatedClient, err := subjectClientState.CheckSubstituteAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), subjectClientStore, substituteClientStore, substituteClientState) + err := subjectClientState.CheckSubstituteAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), subjectClientStore, substituteClientStore, substituteClientState) suite.Require().Error(err) - suite.Require().Nil(updatedClient) }) } } @@ -120,7 +119,7 @@ func (suite *TendermintTestSuite) TestCheckSubstituteAndUpdateState() { // construct subject using test case parameters subjectPath := ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(subjectPath) - subjectClientState := suite.chainA.GetClientState(subjectPath.EndpointA.ClientID).(*types.ClientState) + subjectClientState := suite.chainA.GetClientState(subjectPath.EndpointA.ClientID).(*ibctm.ClientState) // apply freezing or expiry as determined by the test case if tc.FreezeClient { @@ -140,7 +139,7 @@ func (suite *TendermintTestSuite) TestCheckSubstituteAndUpdateState() { substitutePath := ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(substitutePath) - substituteClientState := suite.chainA.GetClientState(substitutePath.EndpointA.ClientID).(*types.ClientState) + substituteClientState := suite.chainA.GetClientState(substitutePath.EndpointA.ClientID).(*ibctm.ClientState) // update trusting period of substitute client state substituteClientState.TrustingPeriod = time.Hour * 24 * 7 suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), substitutePath.EndpointA.ClientID, substituteClientState) @@ -154,7 +153,7 @@ func (suite *TendermintTestSuite) TestCheckSubstituteAndUpdateState() { } // get updated substitute - substituteClientState = suite.chainA.GetClientState(substitutePath.EndpointA.ClientID).(*types.ClientState) + substituteClientState = suite.chainA.GetClientState(substitutePath.EndpointA.ClientID).(*ibctm.ClientState) // test that subject gets updated chain-id newChainID := "new-chain-id" @@ -164,39 +163,40 @@ func (suite *TendermintTestSuite) TestCheckSubstituteAndUpdateState() { substituteClientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), substitutePath.EndpointA.ClientID) expectedConsState := substitutePath.EndpointA.GetConsensusState(substituteClientState.GetLatestHeight()) - expectedProcessedTime, found := types.GetProcessedTime(substituteClientStore, substituteClientState.GetLatestHeight()) + expectedProcessedTime, found := ibctm.GetProcessedTime(substituteClientStore, substituteClientState.GetLatestHeight()) suite.Require().True(found) - expectedProcessedHeight, found := types.GetProcessedTime(substituteClientStore, substituteClientState.GetLatestHeight()) + expectedProcessedHeight, found := ibctm.GetProcessedTime(substituteClientStore, substituteClientState.GetLatestHeight()) suite.Require().True(found) - expectedIterationKey := types.GetIterationKey(substituteClientStore, substituteClientState.GetLatestHeight()) + expectedIterationKey := ibctm.GetIterationKey(substituteClientStore, substituteClientState.GetLatestHeight()) - updatedClient, err := subjectClientState.CheckSubstituteAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), subjectClientStore, substituteClientStore, substituteClientState) + err := subjectClientState.CheckSubstituteAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), subjectClientStore, substituteClientStore, substituteClientState) if tc.expPass { suite.Require().NoError(err) - suite.Require().Equal(clienttypes.ZeroHeight(), updatedClient.(*types.ClientState).FrozenHeight) + + updatedClient := subjectPath.EndpointA.GetClientState() + suite.Require().Equal(clienttypes.ZeroHeight(), updatedClient.(*ibctm.ClientState).FrozenHeight) subjectClientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), subjectPath.EndpointA.ClientID) // check that the correct consensus state was copied over suite.Require().Equal(substituteClientState.GetLatestHeight(), updatedClient.GetLatestHeight()) subjectConsState := subjectPath.EndpointA.GetConsensusState(updatedClient.GetLatestHeight()) - subjectProcessedTime, found := types.GetProcessedTime(subjectClientStore, updatedClient.GetLatestHeight()) + subjectProcessedTime, found := ibctm.GetProcessedTime(subjectClientStore, updatedClient.GetLatestHeight()) suite.Require().True(found) - subjectProcessedHeight, found := types.GetProcessedTime(substituteClientStore, updatedClient.GetLatestHeight()) + subjectProcessedHeight, found := ibctm.GetProcessedTime(substituteClientStore, updatedClient.GetLatestHeight()) suite.Require().True(found) - subjectIterationKey := types.GetIterationKey(substituteClientStore, updatedClient.GetLatestHeight()) + subjectIterationKey := ibctm.GetIterationKey(substituteClientStore, updatedClient.GetLatestHeight()) suite.Require().Equal(expectedConsState, subjectConsState) suite.Require().Equal(expectedProcessedTime, subjectProcessedTime) suite.Require().Equal(expectedProcessedHeight, subjectProcessedHeight) suite.Require().Equal(expectedIterationKey, subjectIterationKey) - suite.Require().Equal(newChainID, updatedClient.(*types.ClientState).ChainId) - suite.Require().Equal(time.Hour*24*7, updatedClient.(*types.ClientState).TrustingPeriod) + suite.Require().Equal(newChainID, updatedClient.(*ibctm.ClientState).ChainId) + suite.Require().Equal(time.Hour*24*7, updatedClient.(*ibctm.ClientState).TrustingPeriod) } else { suite.Require().Error(err) - suite.Require().Nil(updatedClient) } }) } @@ -205,7 +205,7 @@ func (suite *TendermintTestSuite) TestCheckSubstituteAndUpdateState() { func (suite *TendermintTestSuite) TestIsMatchingClientState() { var ( subjectPath, substitutePath *ibctesting.Path - subjectClientState, substituteClientState *types.ClientState + subjectClientState, substituteClientState *ibctm.ClientState ) testCases := []struct { @@ -215,8 +215,8 @@ func (suite *TendermintTestSuite) TestIsMatchingClientState() { }{ { "matching clients", func() { - subjectClientState = suite.chainA.GetClientState(subjectPath.EndpointA.ClientID).(*types.ClientState) - substituteClientState = suite.chainA.GetClientState(substitutePath.EndpointA.ClientID).(*types.ClientState) + subjectClientState = suite.chainA.GetClientState(subjectPath.EndpointA.ClientID).(*ibctm.ClientState) + substituteClientState = suite.chainA.GetClientState(substitutePath.EndpointA.ClientID).(*ibctm.ClientState) }, true, }, { @@ -245,8 +245,8 @@ func (suite *TendermintTestSuite) TestIsMatchingClientState() { }, { "not matching, trust level is different", func() { - subjectClientState.TrustLevel = types.Fraction{2, 3} - substituteClientState.TrustLevel = types.Fraction{1, 3} + subjectClientState.TrustLevel = ibctm.Fraction{2, 3} + substituteClientState.TrustLevel = ibctm.Fraction{1, 3} }, false, }, } @@ -264,7 +264,7 @@ func (suite *TendermintTestSuite) TestIsMatchingClientState() { tc.malleate() - suite.Require().Equal(tc.expPass, types.IsMatchingClientState(*subjectClientState, *substituteClientState)) + suite.Require().Equal(tc.expPass, ibctm.IsMatchingClientState(*subjectClientState, *substituteClientState)) }) } } diff --git a/modules/light-clients/07-tendermint/types/store.go b/modules/light-clients/07-tendermint/store.go similarity index 91% rename from modules/light-clients/07-tendermint/types/store.go rename to modules/light-clients/07-tendermint/store.go index 301918c6bdf..e8824d06e1d 100644 --- a/modules/light-clients/07-tendermint/types/store.go +++ b/modules/light-clients/07-tendermint/store.go @@ -1,4 +1,4 @@ -package types +package tendermint import ( "bytes" @@ -8,7 +8,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" host "github.com/cosmos/ibc-go/v5/modules/core/24-host" @@ -43,38 +42,30 @@ var ( KeyIteration = []byte("/iterationKey") ) -// SetConsensusState stores the consensus state at the given height. -func SetConsensusState(clientStore sdk.KVStore, cdc codec.BinaryCodec, consensusState *ConsensusState, height exported.Height) { +// setClientState stores the client state +func setClientState(clientStore sdk.KVStore, cdc codec.BinaryCodec, clientState *ClientState) { + key := host.ClientStateKey() + val := clienttypes.MustMarshalClientState(cdc, clientState) + clientStore.Set(key, val) +} + +// setConsensusState stores the consensus state at the given height. +func setConsensusState(clientStore sdk.KVStore, cdc codec.BinaryCodec, consensusState *ConsensusState, height exported.Height) { key := host.ConsensusStateKey(height) val := clienttypes.MustMarshalConsensusState(cdc, consensusState) clientStore.Set(key, val) } -// GetConsensusState retrieves the consensus state from the client prefixed -// store. An error is returned if the consensus state does not exist. -func GetConsensusState(store sdk.KVStore, cdc codec.BinaryCodec, height exported.Height) (*ConsensusState, error) { +// GetConsensusState retrieves the consensus state from the client prefixed store. +// If the ConsensusState does not exist in state for the provided height a nil value and false boolean flag is returned +func GetConsensusState(store sdk.KVStore, cdc codec.BinaryCodec, height exported.Height) (*ConsensusState, bool) { bz := store.Get(host.ConsensusStateKey(height)) if bz == nil { - return nil, sdkerrors.Wrapf( - clienttypes.ErrConsensusStateNotFound, - "consensus state does not exist for height %s", height, - ) - } - - consensusStateI, err := clienttypes.UnmarshalConsensusState(cdc, bz) - if err != nil { - return nil, sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "unmarshal error: %v", err) - } - - consensusState, ok := consensusStateI.(*ConsensusState) - if !ok { - return nil, sdkerrors.Wrapf( - clienttypes.ErrInvalidConsensus, - "invalid consensus type %T, expected %T", consensusState, &ConsensusState{}, - ) + return nil, false } - return consensusState, nil + consensusStateI := clienttypes.MustUnmarshalConsensusState(cdc, bz) + return consensusStateI.(*ConsensusState), true } // deleteConsensusState deletes the consensus state at the given height @@ -224,7 +215,7 @@ func GetHeightFromIterationKey(iterKey []byte) exported.Height { // IterateConsensusStateAscending iterates through the consensus states in ascending order. It calls the provided // callback on each height, until stop=true is returned. -func IterateConsensusStateAscending(clientStore sdk.KVStore, cb func(height exported.Height) (stop bool)) error { +func IterateConsensusStateAscending(clientStore sdk.KVStore, cb func(height exported.Height) (stop bool)) { iterator := sdk.KVStorePrefixIterator(clientStore, []byte(KeyIterateConsensusStatePrefix)) defer iterator.Close() @@ -232,10 +223,9 @@ func IterateConsensusStateAscending(clientStore sdk.KVStore, cb func(height expo iterKey := iterator.Key() height := GetHeightFromIterationKey(iterKey) if cb(height) { - return nil + break } } - return nil } // GetNextConsensusState returns the lowest consensus state that is larger than the given height. @@ -287,13 +277,12 @@ func GetPreviousConsensusState(clientStore sdk.KVStore, cdc codec.BinaryCodec, h func PruneAllExpiredConsensusStates( ctx sdk.Context, clientStore sdk.KVStore, cdc codec.BinaryCodec, clientState *ClientState, -) (err error) { +) { var heights []exported.Height pruneCb := func(height exported.Height) bool { - consState, err := GetConsensusState(clientStore, cdc, height) - // this error should never occur - if err != nil { + consState, found := GetConsensusState(clientStore, cdc, height) + if !found { // consensus state should always be found return true } @@ -304,17 +293,12 @@ func PruneAllExpiredConsensusStates( return false } - err = IterateConsensusStateAscending(clientStore, pruneCb) - if err != nil { - return err - } + IterateConsensusStateAscending(clientStore, pruneCb) for _, height := range heights { deleteConsensusState(clientStore, height) deleteConsensusMetadata(clientStore, height) } - - return nil } // Helper function for GetNextConsensusState and GetPreviousConsensusState diff --git a/modules/light-clients/07-tendermint/types/store_test.go b/modules/light-clients/07-tendermint/store_test.go similarity index 60% rename from modules/light-clients/07-tendermint/types/store_test.go rename to modules/light-clients/07-tendermint/store_test.go index a482fad007e..851a39c1945 100644 --- a/modules/light-clients/07-tendermint/types/store_test.go +++ b/modules/light-clients/07-tendermint/store_test.go @@ -1,4 +1,4 @@ -package types_test +package tendermint_test import ( "math" @@ -8,8 +8,8 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" host "github.com/cosmos/ibc-go/v5/modules/core/24-host" "github.com/cosmos/ibc-go/v5/modules/core/exported" - solomachinetypes "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine/types" - "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + solomachine "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine" + tendermint "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) @@ -23,31 +23,32 @@ func (suite *TendermintTestSuite) TestGetConsensusState() { name string malleate func() expPass bool + expPanic bool }{ { - "success", func() {}, true, + "success", func() {}, true, false, }, { "consensus state not found", func() { // use height with no consensus state set height = height.(clienttypes.Height).Increment() - }, false, + }, false, false, }, { "not a consensus state interface", func() { // marshal an empty client state and set as consensus state store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) - clientStateBz := suite.chainA.App.GetIBCKeeper().ClientKeeper.MustMarshalClientState(&types.ClientState{}) + clientStateBz := suite.chainA.App.GetIBCKeeper().ClientKeeper.MustMarshalClientState(&tendermint.ClientState{}) store.Set(host.ConsensusStateKey(height), clientStateBz) - }, false, + }, false, true, }, { "invalid consensus state (solomachine)", func() { // marshal and set solomachine consensus state store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) - consensusStateBz := suite.chainA.App.GetIBCKeeper().ClientKeeper.MustMarshalConsensusState(&solomachinetypes.ConsensusState{}) + consensusStateBz := suite.chainA.App.GetIBCKeeper().ClientKeeper.MustMarshalConsensusState(&solomachine.ConsensusState{}) store.Set(host.ConsensusStateKey(height), consensusStateBz) - }, false, + }, false, true, }, } @@ -64,16 +65,26 @@ func (suite *TendermintTestSuite) TestGetConsensusState() { tc.malleate() // change vars as necessary + if tc.expPanic { + suite.Require().Panics(func() { + store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + tendermint.GetConsensusState(store, suite.chainA.Codec, height) + }) + + return + } + store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) - consensusState, err := types.GetConsensusState(store, suite.chainA.Codec, height) + consensusState, found := tendermint.GetConsensusState(store, suite.chainA.Codec, height) if tc.expPass { - suite.Require().NoError(err) + suite.Require().True(found) + expConsensusState, found := suite.chainA.GetConsensusState(path.EndpointA.ClientID, height) suite.Require().True(found) suite.Require().Equal(expConsensusState, consensusState) } else { - suite.Require().Error(err) + suite.Require().False(found) suite.Require().Nil(consensusState) } }) @@ -96,7 +107,7 @@ func (suite *TendermintTestSuite) TestGetProcessedTime() { height := clientState.GetLatestHeight() store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) - actualTime, ok := types.GetProcessedTime(store, height) + actualTime, ok := tendermint.GetProcessedTime(store, height) suite.Require().True(ok, "could not retrieve processed time for stored consensus state") suite.Require().Equal(uint64(expectedTime.UnixNano()), actualTime, "retrieved processed time is not expected value") @@ -112,12 +123,12 @@ func (suite *TendermintTestSuite) TestGetProcessedTime() { height = clientState.GetLatestHeight() store = suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) - actualTime, ok = types.GetProcessedTime(store, height) + actualTime, ok = tendermint.GetProcessedTime(store, height) suite.Require().True(ok, "could not retrieve processed time for stored consensus state") suite.Require().Equal(uint64(expectedTime.UnixNano()), actualTime, "retrieved processed time is not expected value") // try to get processed time for height that doesn't exist in store - _, ok = types.GetProcessedTime(store, clienttypes.NewHeight(1, 1)) + _, ok = tendermint.GetProcessedTime(store, clienttypes.NewHeight(1, 1)) suite.Require().False(ok, "retrieved processed time for a non-existent consensus state") } @@ -129,8 +140,8 @@ func (suite *TendermintTestSuite) TestIterationKey() { clienttypes.NewHeight(math.MaxUint64, math.MaxUint64), } for _, h := range testHeights { - k := types.IterationKey(h) - retrievedHeight := types.GetHeightFromIterationKey(k) + k := tendermint.IterationKey(h) + retrievedHeight := tendermint.GetHeightFromIterationKey(k) suite.Require().Equal(h, retrievedHeight, "retrieving height from iteration key failed") } } @@ -139,16 +150,16 @@ func (suite *TendermintTestSuite) TestIterateConsensusStates() { nextValsHash := []byte("nextVals") // Set iteration keys and consensus states - types.SetIterationKey(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), clienttypes.NewHeight(0, 1)) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), "testClient", clienttypes.NewHeight(0, 1), types.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("hash0-1")), nextValsHash)) - types.SetIterationKey(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), clienttypes.NewHeight(4, 9)) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), "testClient", clienttypes.NewHeight(4, 9), types.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("hash4-9")), nextValsHash)) - types.SetIterationKey(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), clienttypes.NewHeight(0, 10)) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), "testClient", clienttypes.NewHeight(0, 10), types.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("hash0-10")), nextValsHash)) - types.SetIterationKey(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), clienttypes.NewHeight(0, 4)) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), "testClient", clienttypes.NewHeight(0, 4), types.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("hash0-4")), nextValsHash)) - types.SetIterationKey(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), clienttypes.NewHeight(40, 1)) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), "testClient", clienttypes.NewHeight(40, 1), types.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("hash40-1")), nextValsHash)) + tendermint.SetIterationKey(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), clienttypes.NewHeight(0, 1)) + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), "testClient", clienttypes.NewHeight(0, 1), tendermint.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("hash0-1")), nextValsHash)) + tendermint.SetIterationKey(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), clienttypes.NewHeight(4, 9)) + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), "testClient", clienttypes.NewHeight(4, 9), tendermint.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("hash4-9")), nextValsHash)) + tendermint.SetIterationKey(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), clienttypes.NewHeight(0, 10)) + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), "testClient", clienttypes.NewHeight(0, 10), tendermint.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("hash0-10")), nextValsHash)) + tendermint.SetIterationKey(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), clienttypes.NewHeight(0, 4)) + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), "testClient", clienttypes.NewHeight(0, 4), tendermint.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("hash0-4")), nextValsHash)) + tendermint.SetIterationKey(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), clienttypes.NewHeight(40, 1)) + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), "testClient", clienttypes.NewHeight(40, 1), tendermint.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("hash40-1")), nextValsHash)) var testArr []string cb := func(height exported.Height) bool { @@ -156,39 +167,39 @@ func (suite *TendermintTestSuite) TestIterateConsensusStates() { return false } - types.IterateConsensusStateAscending(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), cb) + tendermint.IterateConsensusStateAscending(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), cb) expectedArr := []string{"0-1", "0-4", "0-10", "4-9", "40-1"} suite.Require().Equal(expectedArr, testArr) } func (suite *TendermintTestSuite) TestGetNeighboringConsensusStates() { nextValsHash := []byte("nextVals") - cs01 := types.NewConsensusState(time.Now().UTC(), commitmenttypes.NewMerkleRoot([]byte("hash0-1")), nextValsHash) - cs04 := types.NewConsensusState(time.Now().UTC(), commitmenttypes.NewMerkleRoot([]byte("hash0-4")), nextValsHash) - cs49 := types.NewConsensusState(time.Now().UTC(), commitmenttypes.NewMerkleRoot([]byte("hash4-9")), nextValsHash) + cs01 := tendermint.NewConsensusState(time.Now().UTC(), commitmenttypes.NewMerkleRoot([]byte("hash0-1")), nextValsHash) + cs04 := tendermint.NewConsensusState(time.Now().UTC(), commitmenttypes.NewMerkleRoot([]byte("hash0-4")), nextValsHash) + cs49 := tendermint.NewConsensusState(time.Now().UTC(), commitmenttypes.NewMerkleRoot([]byte("hash4-9")), nextValsHash) height01 := clienttypes.NewHeight(0, 1) height04 := clienttypes.NewHeight(0, 4) height49 := clienttypes.NewHeight(4, 9) // Set iteration keys and consensus states - types.SetIterationKey(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), height01) + tendermint.SetIterationKey(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), height01) suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), "testClient", height01, cs01) - types.SetIterationKey(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), height04) + tendermint.SetIterationKey(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), height04) suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), "testClient", height04, cs04) - types.SetIterationKey(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), height49) + tendermint.SetIterationKey(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), height49) suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), "testClient", height49, cs49) - prevCs01, ok := types.GetPreviousConsensusState(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), suite.chainA.Codec, height01) + prevCs01, ok := tendermint.GetPreviousConsensusState(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), suite.chainA.Codec, height01) suite.Require().Nil(prevCs01, "consensus state exists before lowest consensus state") suite.Require().False(ok) - prevCs49, ok := types.GetPreviousConsensusState(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), suite.chainA.Codec, height49) + prevCs49, ok := tendermint.GetPreviousConsensusState(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), suite.chainA.Codec, height49) suite.Require().Equal(cs04, prevCs49, "previous consensus state is not returned correctly") suite.Require().True(ok) - nextCs01, ok := types.GetNextConsensusState(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), suite.chainA.Codec, height01) + nextCs01, ok := tendermint.GetNextConsensusState(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), suite.chainA.Codec, height01) suite.Require().Equal(cs04, nextCs01, "next consensus state not returned correctly") suite.Require().True(ok) - nextCs49, ok := types.GetNextConsensusState(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), suite.chainA.Codec, height49) + nextCs49, ok := tendermint.GetNextConsensusState(suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), "testClient"), suite.chainA.Codec, height49) suite.Require().Nil(nextCs49, "next consensus state exists after highest consensus state") suite.Require().False(ok) } diff --git a/modules/light-clients/07-tendermint/types/tendermint.pb.go b/modules/light-clients/07-tendermint/tendermint.pb.go similarity index 87% rename from modules/light-clients/07-tendermint/types/tendermint.pb.go rename to modules/light-clients/07-tendermint/tendermint.pb.go index 2df221d3d39..46a11f4537f 100644 --- a/modules/light-clients/07-tendermint/types/tendermint.pb.go +++ b/modules/light-clients/07-tendermint/tendermint.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: ibc/lightclients/tendermint/v1/tendermint.proto -package types +package tendermint import ( fmt "fmt" @@ -144,7 +144,8 @@ var xxx_messageInfo_ConsensusState proto.InternalMessageInfo // Misbehaviour is a wrapper over two conflicting Headers // that implements Misbehaviour interface expected by ICS-02 type Misbehaviour struct { - ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` + // ClientID is deprecated + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` // Deprecated: Do not use. Header1 *Header `protobuf:"bytes,2,opt,name=header_1,json=header1,proto3" json:"header_1,omitempty" yaml:"header_1"` Header2 *Header `protobuf:"bytes,3,opt,name=header_2,json=header2,proto3" json:"header_2,omitempty" yaml:"header_2"` } @@ -322,75 +323,75 @@ func init() { } var fileDescriptor_c6d6cf2b288949be = []byte{ - // 1082 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xcf, 0x6f, 0xe3, 0xc4, - 0x17, 0x6f, 0xda, 0x7e, 0xb7, 0xc9, 0x24, 0xdd, 0xf6, 0x6b, 0x4a, 0x37, 0x2d, 0xdd, 0x38, 0x32, - 0x52, 0xc9, 0x81, 0xda, 0x24, 0x0b, 0x42, 0xaa, 0xb8, 0xe0, 0xee, 0xa2, 0x16, 0xb1, 0x52, 0xe5, - 0xf2, 0x43, 0x42, 0x42, 0x66, 0x62, 0x4f, 0x92, 0xd1, 0xda, 0x1e, 0xcb, 0x33, 0x09, 0x2d, 0x7f, - 0x01, 0x1c, 0x90, 0xf6, 0x88, 0x38, 0x71, 0xe0, 0x8f, 0xd9, 0x63, 0x8f, 0x9c, 0x0c, 0x6a, 0xaf, - 0x9c, 0x72, 0xe4, 0x84, 0xe6, 0x87, 0xed, 0x69, 0xb6, 0x4b, 0xb5, 0x5c, 0xa2, 0x79, 0xef, 0x7d, - 0xde, 0xe7, 0x93, 0x79, 0xf3, 0xe6, 0x8d, 0x81, 0x83, 0x87, 0x81, 0x13, 0xe1, 0xf1, 0x84, 0x05, - 0x11, 0x46, 0x09, 0xa3, 0x0e, 0x43, 0x49, 0x88, 0xb2, 0x18, 0x27, 0xcc, 0x99, 0xf5, 0x35, 0xcb, - 0x4e, 0x33, 0xc2, 0x88, 0xd1, 0xc1, 0xc3, 0xc0, 0xd6, 0x13, 0x6c, 0x0d, 0x32, 0xeb, 0xef, 0x76, - 0xb5, 0x7c, 0x76, 0x91, 0x22, 0xea, 0xcc, 0x60, 0x84, 0x43, 0xc8, 0x48, 0x26, 0x19, 0x76, 0xf7, - 0x5e, 0x42, 0x88, 0x5f, 0x15, 0x6d, 0xa5, 0x19, 0x21, 0xa3, 0xc2, 0xea, 0x8c, 0x09, 0x19, 0x47, - 0xc8, 0x11, 0xd6, 0x70, 0x3a, 0x72, 0xc2, 0x69, 0x06, 0x19, 0x26, 0x89, 0x8a, 0x9b, 0x8b, 0x71, - 0x86, 0x63, 0x44, 0x19, 0x8c, 0xd3, 0x02, 0xc0, 0xf7, 0x17, 0x90, 0x0c, 0x39, 0xf2, 0xef, 0xf2, - 0x3d, 0xc9, 0x95, 0x02, 0xbc, 0x53, 0x01, 0x48, 0x1c, 0x63, 0x16, 0x17, 0xa0, 0xd2, 0x52, 0xc0, - 0xad, 0x31, 0x19, 0x13, 0xb1, 0x74, 0xf8, 0x4a, 0x7a, 0xad, 0xbf, 0xd6, 0x40, 0xf3, 0x48, 0xf0, - 0x9d, 0x31, 0xc8, 0x90, 0xb1, 0x03, 0xea, 0xc1, 0x04, 0xe2, 0xc4, 0xc7, 0x61, 0xbb, 0xd6, 0xad, - 0xf5, 0x1a, 0xde, 0x9a, 0xb0, 0x4f, 0x42, 0x03, 0x81, 0x26, 0xcb, 0xa6, 0x94, 0xf9, 0x11, 0x9a, - 0xa1, 0xa8, 0xbd, 0xdc, 0xad, 0xf5, 0x9a, 0x83, 0x9e, 0xfd, 0xef, 0xf5, 0xb4, 0x3f, 0xc9, 0x60, - 0xc0, 0x37, 0xec, 0xee, 0xbe, 0xc8, 0xcd, 0xa5, 0x79, 0x6e, 0x1a, 0x17, 0x30, 0x8e, 0x0e, 0x2d, - 0x8d, 0xca, 0xf2, 0x80, 0xb0, 0x3e, 0xe3, 0x86, 0x31, 0x02, 0x1b, 0xc2, 0xc2, 0xc9, 0xd8, 0x4f, - 0x51, 0x86, 0x49, 0xd8, 0x5e, 0x11, 0x52, 0x3b, 0xb6, 0x2c, 0x96, 0x5d, 0x14, 0xcb, 0x7e, 0xac, - 0x8a, 0xe9, 0x5a, 0x8a, 0x7b, 0x5b, 0xe3, 0xae, 0xf2, 0xad, 0x9f, 0xff, 0x30, 0x6b, 0xde, 0xfd, - 0xc2, 0x7b, 0x2a, 0x9c, 0x06, 0x06, 0x9b, 0xd3, 0x64, 0x48, 0x92, 0x50, 0x13, 0x5a, 0xbd, 0x4b, - 0xe8, 0x6d, 0x25, 0xf4, 0x40, 0x0a, 0x2d, 0x12, 0x48, 0xa5, 0x8d, 0xd2, 0xad, 0xa4, 0x10, 0xd8, - 0x88, 0xe1, 0xb9, 0x1f, 0x44, 0x24, 0x78, 0xe6, 0x87, 0x19, 0x1e, 0xb1, 0xf6, 0xff, 0x5e, 0x73, - 0x4b, 0x0b, 0xf9, 0x52, 0x68, 0x3d, 0x86, 0xe7, 0x47, 0xdc, 0xf9, 0x98, 0xfb, 0x8c, 0x6f, 0xc0, - 0xfa, 0x28, 0x23, 0xdf, 0xa3, 0xc4, 0x9f, 0x20, 0x7e, 0x20, 0xed, 0x7b, 0x42, 0x64, 0x57, 0x1c, - 0x11, 0x6f, 0x11, 0x5b, 0x75, 0xce, 0xac, 0x6f, 0x1f, 0x0b, 0x84, 0xbb, 0xa7, 0x54, 0xb6, 0xa4, - 0xca, 0x8d, 0x74, 0xcb, 0x6b, 0x49, 0x5b, 0x62, 0x39, 0x7d, 0x04, 0x19, 0xa2, 0xac, 0xa0, 0x5f, - 0x7b, 0x5d, 0xfa, 0x1b, 0xe9, 0x96, 0xd7, 0x92, 0xb6, 0xa2, 0x3f, 0x01, 0x4d, 0x71, 0x75, 0x7c, - 0x9a, 0xa2, 0x80, 0xb6, 0xeb, 0xdd, 0x95, 0x5e, 0x73, 0xb0, 0x69, 0xe3, 0x80, 0x0e, 0x1e, 0xd9, - 0xa7, 0x3c, 0x72, 0x96, 0xa2, 0xc0, 0xdd, 0xae, 0x5a, 0x48, 0x83, 0x5b, 0x1e, 0x48, 0x0b, 0x08, - 0x35, 0x0e, 0x41, 0x6b, 0x9a, 0x8e, 0x33, 0x18, 0x22, 0x3f, 0x85, 0x6c, 0xd2, 0x6e, 0x74, 0x57, - 0x7a, 0x0d, 0xf7, 0xc1, 0x3c, 0x37, 0xdf, 0x50, 0xe7, 0xa6, 0x45, 0x2d, 0xaf, 0xa9, 0xcc, 0x53, - 0xc8, 0x26, 0x06, 0x04, 0x3b, 0x30, 0x8a, 0xc8, 0x77, 0xfe, 0x34, 0x0d, 0x21, 0x43, 0x3e, 0x1c, - 0x31, 0x94, 0xf9, 0xe8, 0x3c, 0xc5, 0xd9, 0x45, 0x1b, 0x74, 0x6b, 0xbd, 0xba, 0xbb, 0x3f, 0xcf, - 0xcd, 0xae, 0x24, 0x7a, 0x25, 0xd4, 0x6a, 0xd7, 0xbc, 0x6d, 0x11, 0xfd, 0x42, 0x04, 0x3f, 0xe6, - 0xb1, 0x27, 0x22, 0x64, 0x50, 0x60, 0xde, 0x92, 0x17, 0x63, 0x3a, 0x44, 0x13, 0x38, 0xc3, 0x64, - 0x9a, 0xb5, 0x9b, 0x42, 0xe8, 0xdd, 0x79, 0x6e, 0xee, 0xbf, 0x52, 0x48, 0x4f, 0xe0, 0x72, 0x7b, - 0x8b, 0x72, 0x4f, 0x35, 0xc0, 0xe1, 0xea, 0x0f, 0xbf, 0x9a, 0x4b, 0xd6, 0x6f, 0xcb, 0xe0, 0xfe, - 0x11, 0x49, 0x28, 0x4a, 0xe8, 0x94, 0xca, 0x1b, 0xef, 0x82, 0x46, 0x39, 0x74, 0xc4, 0x95, 0xe7, - 0x47, 0xba, 0xd8, 0x96, 0x9f, 0x17, 0x08, 0xb7, 0xce, 0x8f, 0xf4, 0x39, 0xef, 0xbe, 0x2a, 0xcd, - 0xf8, 0x08, 0xac, 0x66, 0x84, 0x30, 0x35, 0x13, 0x2c, 0xad, 0x23, 0xaa, 0x29, 0x34, 0xeb, 0xdb, - 0x4f, 0x51, 0xf6, 0x2c, 0x42, 0x1e, 0x21, 0xcc, 0x5d, 0xe5, 0x34, 0x9e, 0xc8, 0x32, 0x7e, 0xac, - 0x81, 0xad, 0x04, 0x9d, 0x33, 0xbf, 0x9c, 0xb4, 0xd4, 0x9f, 0x40, 0x3a, 0x11, 0xf7, 0xbe, 0xe5, - 0x7e, 0x35, 0xcf, 0xcd, 0xb7, 0x64, 0x15, 0x6e, 0x43, 0x59, 0x7f, 0xe7, 0xe6, 0xfb, 0x63, 0xcc, - 0x26, 0xd3, 0x21, 0x97, 0xd3, 0xe7, 0xbf, 0xb6, 0x8c, 0xf0, 0x90, 0x3a, 0xc3, 0x0b, 0x86, 0xa8, - 0x7d, 0x8c, 0xce, 0x5d, 0xbe, 0xf0, 0x0c, 0x4e, 0xf7, 0x65, 0xc9, 0x76, 0x0c, 0xe9, 0x44, 0x95, - 0xe9, 0xa7, 0x65, 0xd0, 0xd2, 0xab, 0x67, 0xf4, 0x41, 0x43, 0x36, 0x77, 0x39, 0x17, 0xdd, 0xad, - 0x79, 0x6e, 0x6e, 0xca, 0xbf, 0x55, 0x86, 0x2c, 0xaf, 0x2e, 0xd7, 0x27, 0xa1, 0x01, 0x41, 0x7d, - 0x82, 0x60, 0x88, 0x32, 0xbf, 0xaf, 0xea, 0xb2, 0x7f, 0xd7, 0xac, 0x3c, 0x16, 0x78, 0xb7, 0x73, - 0x95, 0x9b, 0x6b, 0x72, 0xdd, 0x9f, 0xe7, 0xe6, 0x86, 0x14, 0x29, 0xc8, 0x2c, 0x6f, 0x4d, 0x2e, - 0xfb, 0x9a, 0xc4, 0x40, 0xcd, 0xc8, 0xff, 0x20, 0x31, 0x78, 0x49, 0x62, 0x50, 0x4a, 0x0c, 0x54, - 0x3d, 0x7e, 0x59, 0x01, 0xf7, 0x24, 0xda, 0x80, 0x60, 0x9d, 0xe2, 0x71, 0x82, 0x42, 0x5f, 0x42, - 0x54, 0xcb, 0x74, 0x74, 0x1d, 0xf9, 0x1e, 0x9e, 0x09, 0x98, 0x12, 0xdc, 0xbb, 0xcc, 0xcd, 0x5a, - 0x35, 0x09, 0x6e, 0x50, 0x58, 0x5e, 0x8b, 0x6a, 0x58, 0x3e, 0x68, 0xca, 0x33, 0xf6, 0x29, 0x2a, - 0xda, 0xea, 0x16, 0x89, 0xf2, 0xf0, 0xce, 0x10, 0x73, 0xdb, 0x15, 0xfd, 0x8d, 0x74, 0xcb, 0x6b, - 0xcd, 0x34, 0x9c, 0xf1, 0x2d, 0x90, 0x4f, 0x81, 0xd0, 0x17, 0x83, 0x6c, 0xe5, 0xce, 0x41, 0xf6, - 0x50, 0x0d, 0xb2, 0x37, 0xb5, 0x07, 0xa6, 0xcc, 0xb7, 0xbc, 0x75, 0xe5, 0x50, 0xa3, 0x2c, 0x02, - 0x46, 0x81, 0xa8, 0x9a, 0x55, 0x3d, 0x2e, 0x77, 0xed, 0xe2, 0xe1, 0x3c, 0x37, 0x77, 0x6e, 0xaa, - 0x54, 0x1c, 0x96, 0xf7, 0x7f, 0xe5, 0xac, 0xda, 0xd6, 0xfa, 0x14, 0xd4, 0x8b, 0x47, 0xd6, 0xd8, - 0x03, 0x8d, 0x64, 0x1a, 0xa3, 0x8c, 0x47, 0xc4, 0xc9, 0xac, 0x7a, 0x95, 0xc3, 0xe8, 0x82, 0x66, - 0x88, 0x12, 0x12, 0xe3, 0x44, 0xc4, 0x97, 0x45, 0x5c, 0x77, 0xb9, 0xfe, 0x8b, 0xab, 0x4e, 0xed, - 0xf2, 0xaa, 0x53, 0xfb, 0xf3, 0xaa, 0x53, 0x7b, 0x7e, 0xdd, 0x59, 0xba, 0xbc, 0xee, 0x2c, 0xfd, - 0x7e, 0xdd, 0x59, 0xfa, 0xfa, 0x89, 0x76, 0xc5, 0x02, 0x42, 0x63, 0x42, 0xf9, 0xa7, 0xd7, 0xc1, - 0x98, 0x38, 0xb3, 0x0f, 0x9c, 0x98, 0x84, 0xd3, 0x08, 0x51, 0xf9, 0x21, 0x76, 0x50, 0x7c, 0x89, - 0xbd, 0xf7, 0xe1, 0xc1, 0xe2, 0xa7, 0xd2, 0xf0, 0x9e, 0x18, 0x29, 0x8f, 0xfe, 0x09, 0x00, 0x00, - 0xff, 0xff, 0x98, 0x6c, 0x12, 0x96, 0xb8, 0x09, 0x00, 0x00, + // 1080 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xcf, 0x6f, 0xe3, 0x44, + 0x14, 0x6e, 0xda, 0xb2, 0x4d, 0x26, 0xe9, 0xb6, 0x98, 0xd2, 0x4d, 0x4b, 0x37, 0x8e, 0x8c, 0x54, + 0x72, 0xa0, 0x36, 0x49, 0x41, 0x48, 0x85, 0x0b, 0xee, 0x82, 0xda, 0x15, 0x2b, 0x55, 0x2e, 0x3f, + 0x24, 0x24, 0x64, 0x26, 0xf6, 0x24, 0x19, 0xad, 0xed, 0xb1, 0x3c, 0x93, 0xd0, 0xf2, 0x17, 0xc0, + 0x89, 0x3d, 0x22, 0x4e, 0x1c, 0xf8, 0x63, 0xf6, 0xd8, 0x23, 0x27, 0x83, 0xda, 0x2b, 0xa7, 0x1c, + 0x39, 0xa1, 0xf9, 0x61, 0x7b, 0xda, 0xed, 0x52, 0x2d, 0x97, 0x68, 0xde, 0x7b, 0xdf, 0xfb, 0xbe, + 0xcc, 0xbc, 0x37, 0x6f, 0x0c, 0x1c, 0x3c, 0x0c, 0x9c, 0x08, 0x8f, 0x27, 0x2c, 0x88, 0x30, 0x4a, + 0x18, 0x75, 0x18, 0x4a, 0x42, 0x94, 0xc5, 0x38, 0x61, 0xce, 0xac, 0xaf, 0x59, 0x76, 0x9a, 0x11, + 0x46, 0x8c, 0x0e, 0x1e, 0x06, 0xb6, 0x9e, 0x60, 0x6b, 0x90, 0x59, 0x7f, 0xbb, 0xab, 0xe5, 0xb3, + 0xf3, 0x14, 0x51, 0x67, 0x06, 0x23, 0x1c, 0x42, 0x46, 0x32, 0xc9, 0xb0, 0xbd, 0xf3, 0x02, 0x42, + 0xfc, 0xaa, 0x68, 0x2b, 0xcd, 0x08, 0x19, 0x15, 0x56, 0x67, 0x4c, 0xc8, 0x38, 0x42, 0x8e, 0xb0, + 0x86, 0xd3, 0x91, 0x13, 0x4e, 0x33, 0xc8, 0x30, 0x49, 0x54, 0xdc, 0xbc, 0x19, 0x67, 0x38, 0x46, + 0x94, 0xc1, 0x38, 0x2d, 0x00, 0x7c, 0x7f, 0x01, 0xc9, 0x90, 0x23, 0xff, 0x2e, 0xdf, 0x93, 0x5c, + 0x29, 0xc0, 0x3b, 0x15, 0x80, 0xc4, 0x31, 0x66, 0x71, 0x01, 0x2a, 0x2d, 0x05, 0xdc, 0x18, 0x93, + 0x31, 0x11, 0x4b, 0x87, 0xaf, 0xa4, 0xd7, 0xfa, 0x7b, 0x05, 0x34, 0x0f, 0x05, 0xdf, 0x29, 0x83, + 0x0c, 0x19, 0x5b, 0xa0, 0x1e, 0x4c, 0x20, 0x4e, 0x7c, 0x1c, 0xb6, 0x6b, 0xdd, 0x5a, 0xaf, 0xe1, + 0xad, 0x08, 0xfb, 0x38, 0x34, 0x10, 0x68, 0xb2, 0x6c, 0x4a, 0x99, 0x1f, 0xa1, 0x19, 0x8a, 0xda, + 0x8b, 0xdd, 0x5a, 0xaf, 0x39, 0xe8, 0xd9, 0xff, 0x7d, 0x9e, 0xf6, 0x67, 0x19, 0x0c, 0xf8, 0x86, + 0xdd, 0xed, 0xe7, 0xb9, 0xb9, 0x30, 0xcf, 0x4d, 0xe3, 0x1c, 0xc6, 0xd1, 0x81, 0xa5, 0x51, 0x59, + 0x1e, 0x10, 0xd6, 0xe7, 0xdc, 0x30, 0x46, 0x60, 0x4d, 0x58, 0x38, 0x19, 0xfb, 0x29, 0xca, 0x30, + 0x09, 0xdb, 0x4b, 0x42, 0x6a, 0xcb, 0x96, 0x87, 0x65, 0x17, 0x87, 0x65, 0x3f, 0x52, 0x87, 0xe9, + 0x5a, 0x8a, 0x7b, 0x53, 0xe3, 0xae, 0xf2, 0xad, 0x5f, 0xfe, 0x34, 0x6b, 0xde, 0xfd, 0xc2, 0x7b, + 0x22, 0x9c, 0x06, 0x06, 0xeb, 0xd3, 0x64, 0x48, 0x92, 0x50, 0x13, 0x5a, 0xbe, 0x4b, 0xe8, 0x6d, + 0x25, 0xf4, 0x40, 0x0a, 0xdd, 0x24, 0x90, 0x4a, 0x6b, 0xa5, 0x5b, 0x49, 0x21, 0xb0, 0x16, 0xc3, + 0x33, 0x3f, 0x88, 0x48, 0xf0, 0xd4, 0x0f, 0x33, 0x3c, 0x62, 0xed, 0xd7, 0x5e, 0x71, 0x4b, 0x37, + 0xf2, 0xa5, 0xd0, 0x6a, 0x0c, 0xcf, 0x0e, 0xb9, 0xf3, 0x11, 0xf7, 0x19, 0xdf, 0x82, 0xd5, 0x51, + 0x46, 0x7e, 0x40, 0x89, 0x3f, 0x41, 0xbc, 0x20, 0xed, 0x7b, 0x42, 0x64, 0x5b, 0x94, 0x88, 0xb7, + 0x88, 0xad, 0x3a, 0x67, 0xd6, 0xb7, 0x8f, 0x04, 0xc2, 0xdd, 0x51, 0x2a, 0x1b, 0x52, 0xe5, 0x5a, + 0xba, 0xe5, 0xb5, 0xa4, 0x2d, 0xb1, 0x9c, 0x3e, 0x82, 0x0c, 0x51, 0x56, 0xd0, 0xaf, 0xbc, 0x2a, + 0xfd, 0xb5, 0x74, 0xcb, 0x6b, 0x49, 0x5b, 0xd1, 0x1f, 0x83, 0xa6, 0xb8, 0x3a, 0x3e, 0x4d, 0x51, + 0x40, 0xdb, 0xf5, 0xee, 0x52, 0xaf, 0x39, 0x58, 0xb7, 0x71, 0x40, 0x07, 0xfb, 0xf6, 0x09, 0x8f, + 0x9c, 0xa6, 0x28, 0x70, 0x37, 0xab, 0x16, 0xd2, 0xe0, 0x96, 0x07, 0xd2, 0x02, 0x42, 0x8d, 0x03, + 0xd0, 0x9a, 0xa6, 0xe3, 0x0c, 0x86, 0xc8, 0x4f, 0x21, 0x9b, 0xb4, 0x1b, 0xdd, 0xa5, 0x5e, 0xc3, + 0x7d, 0x30, 0xcf, 0xcd, 0x37, 0x54, 0xdd, 0xb4, 0xa8, 0xe5, 0x35, 0x95, 0x79, 0x02, 0xd9, 0xc4, + 0x80, 0x60, 0x0b, 0x46, 0x11, 0xf9, 0xde, 0x9f, 0xa6, 0x21, 0x64, 0xc8, 0x87, 0x23, 0x86, 0x32, + 0x1f, 0x9d, 0xa5, 0x38, 0x3b, 0x6f, 0x83, 0x6e, 0xad, 0x57, 0x77, 0x77, 0xe7, 0xb9, 0xd9, 0x95, + 0x44, 0x2f, 0x85, 0x5a, 0xed, 0x9a, 0xb7, 0x29, 0xa2, 0x5f, 0x8a, 0xe0, 0x27, 0x3c, 0xf6, 0xa9, + 0x08, 0x19, 0x14, 0x98, 0xb7, 0xe4, 0xc5, 0x98, 0x0e, 0xd1, 0x04, 0xce, 0x30, 0x99, 0x66, 0xed, + 0xa6, 0x10, 0x7a, 0x77, 0x9e, 0x9b, 0xbb, 0x2f, 0x15, 0xd2, 0x13, 0xb8, 0xdc, 0xce, 0x4d, 0xb9, + 0x27, 0x1a, 0xe0, 0x60, 0xf9, 0xc7, 0xdf, 0xcc, 0x05, 0xeb, 0xf7, 0x45, 0x70, 0xff, 0x90, 0x24, + 0x14, 0x25, 0x74, 0x4a, 0xe5, 0x8d, 0x77, 0x41, 0xa3, 0x1c, 0x3a, 0xe2, 0xca, 0xf3, 0x92, 0xde, + 0x6c, 0xcb, 0x2f, 0x0a, 0x84, 0x5b, 0xe7, 0x25, 0x7d, 0xc6, 0xbb, 0xaf, 0x4a, 0x33, 0x3e, 0x06, + 0xcb, 0x19, 0x21, 0x4c, 0xcd, 0x04, 0x4b, 0xeb, 0x88, 0x6a, 0x0a, 0xcd, 0xfa, 0xf6, 0x13, 0x94, + 0x3d, 0x8d, 0x90, 0x47, 0x08, 0x73, 0x97, 0x39, 0x8d, 0x27, 0xb2, 0x8c, 0x9f, 0x6a, 0x60, 0x23, + 0x41, 0x67, 0xcc, 0x2f, 0x27, 0x2d, 0xf5, 0x27, 0x90, 0x4e, 0xc4, 0xbd, 0x6f, 0xb9, 0x5f, 0xcf, + 0x73, 0xf3, 0x2d, 0x79, 0x0a, 0xb7, 0xa1, 0xac, 0x7f, 0x72, 0xf3, 0xfd, 0x31, 0x66, 0x93, 0xe9, + 0x90, 0xcb, 0xe9, 0xf3, 0x5f, 0x5b, 0x46, 0x78, 0x48, 0x9d, 0xe1, 0x39, 0x43, 0xd4, 0x3e, 0x42, + 0x67, 0x2e, 0x5f, 0x78, 0x06, 0xa7, 0xfb, 0xaa, 0x64, 0x3b, 0x82, 0x74, 0xa2, 0x8e, 0xe9, 0xe7, + 0x45, 0xd0, 0xd2, 0x4f, 0xcf, 0xd8, 0x07, 0x0d, 0xd9, 0xdc, 0xe5, 0x5c, 0x14, 0x8d, 0xb8, 0x2e, + 0xff, 0x56, 0x19, 0xe2, 0x65, 0xa8, 0x4b, 0xeb, 0x38, 0x34, 0x20, 0xa8, 0x4f, 0x10, 0x0c, 0x51, + 0xe6, 0xf7, 0xd5, 0xc9, 0xec, 0xde, 0x35, 0x2d, 0x8f, 0x04, 0xde, 0xed, 0x5c, 0xe6, 0xe6, 0x8a, + 0x5c, 0xf7, 0xe7, 0xb9, 0xb9, 0x26, 0x65, 0x0a, 0x32, 0xcb, 0x5b, 0x91, 0xcb, 0xbe, 0x26, 0x31, + 0x50, 0x53, 0xf2, 0x7f, 0x48, 0x0c, 0x5e, 0x90, 0x18, 0x94, 0x12, 0x03, 0x75, 0x22, 0xbf, 0x2e, + 0x81, 0x7b, 0x12, 0x6d, 0x40, 0xb0, 0x4a, 0xf1, 0x38, 0x41, 0xa1, 0x2f, 0x21, 0xaa, 0x69, 0x3a, + 0xba, 0x8e, 0x7c, 0x11, 0x4f, 0x05, 0x4c, 0x09, 0xee, 0x5c, 0xe4, 0x66, 0xad, 0x9a, 0x05, 0xd7, + 0x28, 0x2c, 0xaf, 0x45, 0x35, 0x2c, 0x1f, 0x35, 0x65, 0x95, 0x7d, 0x8a, 0x8a, 0xc6, 0xba, 0x45, + 0xa2, 0x2c, 0xdf, 0x29, 0x62, 0x6e, 0xbb, 0xa2, 0xbf, 0x96, 0x6e, 0x79, 0xad, 0x99, 0x86, 0x33, + 0xbe, 0x03, 0xf2, 0x31, 0x10, 0xfa, 0x62, 0x94, 0x2d, 0xdd, 0x39, 0xca, 0x1e, 0xaa, 0x51, 0xf6, + 0xa6, 0xf6, 0xc4, 0x94, 0xf9, 0x96, 0xb7, 0xaa, 0x1c, 0x6a, 0x98, 0x45, 0xc0, 0x28, 0x10, 0x55, + 0xbb, 0xaa, 0xe7, 0xe5, 0xae, 0x5d, 0x3c, 0x9c, 0xe7, 0xe6, 0xd6, 0x75, 0x95, 0x8a, 0xc3, 0xf2, + 0x5e, 0x57, 0xce, 0xaa, 0x71, 0xad, 0xc7, 0xa0, 0x5e, 0x3c, 0xb3, 0xc6, 0x0e, 0x68, 0x24, 0xd3, + 0x18, 0x65, 0x3c, 0x22, 0x2a, 0xb3, 0xec, 0x55, 0x0e, 0xa3, 0x0b, 0x9a, 0x21, 0x4a, 0x48, 0x8c, + 0x13, 0x11, 0x5f, 0x14, 0x71, 0xdd, 0xe5, 0x86, 0xcf, 0x2f, 0x3b, 0xb5, 0x8b, 0xcb, 0x4e, 0xed, + 0xaf, 0xcb, 0x4e, 0xed, 0xd9, 0x55, 0x67, 0xe1, 0xe2, 0xaa, 0xb3, 0xf0, 0xc7, 0x55, 0x67, 0xe1, + 0x9b, 0xc7, 0xda, 0x25, 0x0b, 0x08, 0x8d, 0x09, 0xe5, 0x1f, 0x5f, 0x7b, 0x63, 0xe2, 0xcc, 0x3e, + 0x70, 0x62, 0x12, 0x4e, 0x23, 0x44, 0xe5, 0xa7, 0xd8, 0x5e, 0xf1, 0x2d, 0xf6, 0xde, 0x87, 0x7b, + 0xd5, 0x5e, 0x3f, 0xaa, 0x96, 0xc3, 0x7b, 0x62, 0xb2, 0xec, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, + 0xcc, 0x58, 0x27, 0x4c, 0xbf, 0x09, 0x00, 0x00, } func (m *ClientState) Marshal() (dAtA []byte, err error) { diff --git a/modules/light-clients/07-tendermint/types/tendermint_test.go b/modules/light-clients/07-tendermint/tendermint_test.go similarity index 96% rename from modules/light-clients/07-tendermint/types/tendermint_test.go rename to modules/light-clients/07-tendermint/tendermint_test.go index d82d91e2059..7ad52f62299 100644 --- a/modules/light-clients/07-tendermint/types/tendermint_test.go +++ b/modules/light-clients/07-tendermint/tendermint_test.go @@ -1,4 +1,4 @@ -package types_test +package tendermint_test import ( "testing" @@ -12,7 +12,7 @@ import ( tmtypes "github.com/tendermint/tendermint/types" clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ibctestingmock "github.com/cosmos/ibc-go/v5/testing/mock" "github.com/cosmos/ibc-go/v5/testing/simapp" @@ -50,7 +50,7 @@ type TendermintTestSuite struct { valSet *tmtypes.ValidatorSet signers map[string]tmtypes.PrivValidator valsHash tmbytes.HexBytes - header *ibctmtypes.Header + header *ibctm.Header now time.Time headerTime time.Time clientTime time.Time diff --git a/modules/light-clients/07-tendermint/types/client_state.go b/modules/light-clients/07-tendermint/types/client_state.go deleted file mode 100644 index 8db1903e76a..00000000000 --- a/modules/light-clients/07-tendermint/types/client_state.go +++ /dev/null @@ -1,583 +0,0 @@ -package types - -import ( - "strings" - "time" - - ics23 "github.com/confio/ics23/go" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/tendermint/tendermint/light" - tmtypes "github.com/tendermint/tendermint/types" - - clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v5/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v5/modules/core/24-host" - "github.com/cosmos/ibc-go/v5/modules/core/exported" -) - -var _ exported.ClientState = (*ClientState)(nil) - -// NewClientState creates a new ClientState instance -func NewClientState( - chainID string, trustLevel Fraction, - trustingPeriod, ubdPeriod, maxClockDrift time.Duration, - latestHeight clienttypes.Height, specs []*ics23.ProofSpec, - upgradePath []string, allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour bool, -) *ClientState { - return &ClientState{ - ChainId: chainID, - TrustLevel: trustLevel, - TrustingPeriod: trustingPeriod, - UnbondingPeriod: ubdPeriod, - MaxClockDrift: maxClockDrift, - LatestHeight: latestHeight, - FrozenHeight: clienttypes.ZeroHeight(), - ProofSpecs: specs, - UpgradePath: upgradePath, - AllowUpdateAfterExpiry: allowUpdateAfterExpiry, - AllowUpdateAfterMisbehaviour: allowUpdateAfterMisbehaviour, - } -} - -// GetChainID returns the chain-id -func (cs ClientState) GetChainID() string { - return cs.ChainId -} - -// ClientType is tendermint. -func (cs ClientState) ClientType() string { - return exported.Tendermint -} - -// GetLatestHeight returns latest block height. -func (cs ClientState) GetLatestHeight() exported.Height { - return cs.LatestHeight -} - -// Status returns the status of the tendermint client. -// The client may be: -// - Active: FrozenHeight is zero and client is not expired -// - Frozen: Frozen Height is not zero -// - Expired: the latest consensus state timestamp + trusting period <= current time -// -// A frozen client will become expired, so the Frozen status -// has higher precedence. -func (cs ClientState) Status( - ctx sdk.Context, - clientStore sdk.KVStore, - cdc codec.BinaryCodec, -) exported.Status { - if !cs.FrozenHeight.IsZero() { - return exported.Frozen - } - - // get latest consensus state from clientStore to check for expiry - consState, err := GetConsensusState(clientStore, cdc, cs.GetLatestHeight()) - if err != nil { - // if the client state does not have an associated consensus state for its latest height - // then it must be expired - return exported.Expired - } - - if cs.IsExpired(consState.Timestamp, ctx.BlockTime()) { - return exported.Expired - } - - return exported.Active -} - -// IsExpired returns whether or not the client has passed the trusting period since the last -// update (in which case no headers are considered valid). -func (cs ClientState) IsExpired(latestTimestamp, now time.Time) bool { - expirationTime := latestTimestamp.Add(cs.TrustingPeriod) - return !expirationTime.After(now) -} - -// Validate performs a basic validation of the client state fields. -func (cs ClientState) Validate() error { - if strings.TrimSpace(cs.ChainId) == "" { - return sdkerrors.Wrap(ErrInvalidChainID, "chain id cannot be empty string") - } - - // NOTE: the value of tmtypes.MaxChainIDLen may change in the future. - // If this occurs, the code here must account for potential difference - // between the tendermint version being run by the counterparty chain - // and the tendermint version used by this light client. - // https://github.com/cosmos/ibc-go/issues/177 - if len(cs.ChainId) > tmtypes.MaxChainIDLen { - return sdkerrors.Wrapf(ErrInvalidChainID, "chainID is too long; got: %d, max: %d", len(cs.ChainId), tmtypes.MaxChainIDLen) - } - - if err := light.ValidateTrustLevel(cs.TrustLevel.ToTendermint()); err != nil { - return err - } - if cs.TrustingPeriod == 0 { - return sdkerrors.Wrap(ErrInvalidTrustingPeriod, "trusting period cannot be zero") - } - if cs.UnbondingPeriod == 0 { - return sdkerrors.Wrap(ErrInvalidUnbondingPeriod, "unbonding period cannot be zero") - } - if cs.MaxClockDrift == 0 { - return sdkerrors.Wrap(ErrInvalidMaxClockDrift, "max clock drift cannot be zero") - } - - // the latest height revision number must match the chain id revision number - if cs.LatestHeight.RevisionNumber != clienttypes.ParseChainID(cs.ChainId) { - return sdkerrors.Wrapf(ErrInvalidHeaderHeight, - "latest height revision number must match chain id revision number (%d != %d)", cs.LatestHeight.RevisionNumber, clienttypes.ParseChainID(cs.ChainId)) - } - if cs.LatestHeight.RevisionHeight == 0 { - return sdkerrors.Wrapf(ErrInvalidHeaderHeight, "tendermint client's latest height revision height cannot be zero") - } - if cs.TrustingPeriod >= cs.UnbondingPeriod { - return sdkerrors.Wrapf( - ErrInvalidTrustingPeriod, - "trusting period (%s) should be < unbonding period (%s)", cs.TrustingPeriod, cs.UnbondingPeriod, - ) - } - - if cs.ProofSpecs == nil { - return sdkerrors.Wrap(ErrInvalidProofSpecs, "proof specs cannot be nil for tm client") - } - for i, spec := range cs.ProofSpecs { - if spec == nil { - return sdkerrors.Wrapf(ErrInvalidProofSpecs, "proof spec cannot be nil at index: %d", i) - } - } - // UpgradePath may be empty, but if it isn't, each key must be non-empty - for i, k := range cs.UpgradePath { - if strings.TrimSpace(k) == "" { - return sdkerrors.Wrapf(clienttypes.ErrInvalidClient, "key in upgrade path at index %d cannot be empty", i) - } - } - - return nil -} - -// GetProofSpecs returns the format the client expects for proof verification -// as a string array specifying the proof type for each position in chained proof -func (cs ClientState) GetProofSpecs() []*ics23.ProofSpec { - return cs.ProofSpecs -} - -// ZeroCustomFields returns a ClientState that is a copy of the current ClientState -// with all client customizable fields zeroed out -func (cs ClientState) ZeroCustomFields() exported.ClientState { - // copy over all chain-specified fields - // and leave custom fields empty - return &ClientState{ - ChainId: cs.ChainId, - UnbondingPeriod: cs.UnbondingPeriod, - LatestHeight: cs.LatestHeight, - ProofSpecs: cs.ProofSpecs, - UpgradePath: cs.UpgradePath, - } -} - -// Initialize will check that initial consensus state is a Tendermint consensus state -// and will store ProcessedTime for initial consensus state as ctx.BlockTime() -func (cs ClientState) Initialize(ctx sdk.Context, _ codec.BinaryCodec, clientStore sdk.KVStore, consState exported.ConsensusState) error { - if _, ok := consState.(*ConsensusState); !ok { - return sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "invalid initial consensus state. expected type: %T, got: %T", - &ConsensusState{}, consState) - } - // set metadata for initial consensus state. - setConsensusMetadata(ctx, clientStore, cs.GetLatestHeight()) - return nil -} - -// VerifyClientState verifies a proof of the client state of the running chain -// stored on the target machine -func (cs ClientState) VerifyClientState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - prefix exported.Prefix, - counterpartyClientIdentifier string, - proof []byte, - clientState exported.ClientState, -) error { - merkleProof, provingConsensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - clientPrefixedPath := commitmenttypes.NewMerklePath(host.FullClientStatePath(counterpartyClientIdentifier)) - path, err := commitmenttypes.ApplyPrefix(prefix, clientPrefixedPath) - if err != nil { - return err - } - - if clientState == nil { - return sdkerrors.Wrap(clienttypes.ErrInvalidClient, "client state cannot be empty") - } - - _, ok := clientState.(*ClientState) - if !ok { - return sdkerrors.Wrapf(clienttypes.ErrInvalidClient, "invalid client type %T, expected %T", clientState, &ClientState{}) - } - - bz, err := cdc.MarshalInterface(clientState) - if err != nil { - return err - } - - return merkleProof.VerifyMembership(cs.ProofSpecs, provingConsensusState.GetRoot(), path, bz) -} - -// VerifyClientConsensusState verifies a proof of the consensus state of the -// Tendermint client stored on the target machine. -func (cs ClientState) VerifyClientConsensusState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - counterpartyClientIdentifier string, - consensusHeight exported.Height, - prefix exported.Prefix, - proof []byte, - consensusState exported.ConsensusState, -) error { - merkleProof, provingConsensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - clientPrefixedPath := commitmenttypes.NewMerklePath(host.FullConsensusStatePath(counterpartyClientIdentifier, consensusHeight)) - path, err := commitmenttypes.ApplyPrefix(prefix, clientPrefixedPath) - if err != nil { - return err - } - - if consensusState == nil { - return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "consensus state cannot be empty") - } - - _, ok := consensusState.(*ConsensusState) - if !ok { - return sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "invalid consensus type %T, expected %T", consensusState, &ConsensusState{}) - } - - bz, err := cdc.MarshalInterface(consensusState) - if err != nil { - return err - } - - if err := merkleProof.VerifyMembership(cs.ProofSpecs, provingConsensusState.GetRoot(), path, bz); err != nil { - return err - } - - return nil -} - -// VerifyConnectionState verifies a proof of the connection state of the -// specified connection end stored on the target machine. -func (cs ClientState) VerifyConnectionState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - prefix exported.Prefix, - proof []byte, - connectionID string, - connectionEnd exported.ConnectionI, -) error { - merkleProof, consensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - connectionPath := commitmenttypes.NewMerklePath(host.ConnectionPath(connectionID)) - path, err := commitmenttypes.ApplyPrefix(prefix, connectionPath) - if err != nil { - return err - } - - connection, ok := connectionEnd.(connectiontypes.ConnectionEnd) - if !ok { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "invalid connection type %T", connectionEnd) - } - - bz, err := cdc.Marshal(&connection) - if err != nil { - return err - } - - if err := merkleProof.VerifyMembership(cs.ProofSpecs, consensusState.GetRoot(), path, bz); err != nil { - return err - } - - return nil -} - -// VerifyChannelState verifies a proof of the channel state of the specified -// channel end, under the specified port, stored on the target machine. -func (cs ClientState) VerifyChannelState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - prefix exported.Prefix, - proof []byte, - portID, - channelID string, - channel exported.ChannelI, -) error { - merkleProof, consensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - channelPath := commitmenttypes.NewMerklePath(host.ChannelPath(portID, channelID)) - path, err := commitmenttypes.ApplyPrefix(prefix, channelPath) - if err != nil { - return err - } - - channelEnd, ok := channel.(channeltypes.Channel) - if !ok { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "invalid channel type %T", channel) - } - - bz, err := cdc.Marshal(&channelEnd) - if err != nil { - return err - } - - if err := merkleProof.VerifyMembership(cs.ProofSpecs, consensusState.GetRoot(), path, bz); err != nil { - return err - } - - return nil -} - -// VerifyPacketCommitment verifies a proof of an outgoing packet commitment at -// the specified port, specified channel, and specified sequence. -func (cs ClientState) VerifyPacketCommitment( - ctx sdk.Context, - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - prefix exported.Prefix, - proof []byte, - portID, - channelID string, - sequence uint64, - commitmentBytes []byte, -) error { - merkleProof, consensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - // check delay period has passed - if err := verifyDelayPeriodPassed(ctx, store, height, delayTimePeriod, delayBlockPeriod); err != nil { - return err - } - - commitmentPath := commitmenttypes.NewMerklePath(host.PacketCommitmentPath(portID, channelID, sequence)) - path, err := commitmenttypes.ApplyPrefix(prefix, commitmentPath) - if err != nil { - return err - } - - if err := merkleProof.VerifyMembership(cs.ProofSpecs, consensusState.GetRoot(), path, commitmentBytes); err != nil { - return err - } - - return nil -} - -// VerifyPacketAcknowledgement verifies a proof of an incoming packet -// acknowledgement at the specified port, specified channel, and specified sequence. -func (cs ClientState) VerifyPacketAcknowledgement( - ctx sdk.Context, - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - prefix exported.Prefix, - proof []byte, - portID, - channelID string, - sequence uint64, - acknowledgement []byte, -) error { - merkleProof, consensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - // check delay period has passed - if err := verifyDelayPeriodPassed(ctx, store, height, delayTimePeriod, delayBlockPeriod); err != nil { - return err - } - - ackPath := commitmenttypes.NewMerklePath(host.PacketAcknowledgementPath(portID, channelID, sequence)) - path, err := commitmenttypes.ApplyPrefix(prefix, ackPath) - if err != nil { - return err - } - - if err := merkleProof.VerifyMembership(cs.ProofSpecs, consensusState.GetRoot(), path, channeltypes.CommitAcknowledgement(acknowledgement)); err != nil { - return err - } - - return nil -} - -// VerifyPacketReceiptAbsence verifies a proof of the absence of an -// incoming packet receipt at the specified port, specified channel, and -// specified sequence. -func (cs ClientState) VerifyPacketReceiptAbsence( - ctx sdk.Context, - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - prefix exported.Prefix, - proof []byte, - portID, - channelID string, - sequence uint64, -) error { - merkleProof, consensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - // check delay period has passed - if err := verifyDelayPeriodPassed(ctx, store, height, delayTimePeriod, delayBlockPeriod); err != nil { - return err - } - - receiptPath := commitmenttypes.NewMerklePath(host.PacketReceiptPath(portID, channelID, sequence)) - path, err := commitmenttypes.ApplyPrefix(prefix, receiptPath) - if err != nil { - return err - } - - if err := merkleProof.VerifyNonMembership(cs.ProofSpecs, consensusState.GetRoot(), path); err != nil { - return err - } - - return nil -} - -// VerifyNextSequenceRecv verifies a proof of the next sequence number to be -// received of the specified channel at the specified port. -func (cs ClientState) VerifyNextSequenceRecv( - ctx sdk.Context, - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - prefix exported.Prefix, - proof []byte, - portID, - channelID string, - nextSequenceRecv uint64, -) error { - merkleProof, consensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - // check delay period has passed - if err := verifyDelayPeriodPassed(ctx, store, height, delayTimePeriod, delayBlockPeriod); err != nil { - return err - } - - nextSequenceRecvPath := commitmenttypes.NewMerklePath(host.NextSequenceRecvPath(portID, channelID)) - path, err := commitmenttypes.ApplyPrefix(prefix, nextSequenceRecvPath) - if err != nil { - return err - } - - bz := sdk.Uint64ToBigEndian(nextSequenceRecv) - - if err := merkleProof.VerifyMembership(cs.ProofSpecs, consensusState.GetRoot(), path, bz); err != nil { - return err - } - - return nil -} - -// verifyDelayPeriodPassed will ensure that at least delayTimePeriod amount of time and delayBlockPeriod number of blocks have passed -// since consensus state was submitted before allowing verification to continue. -func verifyDelayPeriodPassed(ctx sdk.Context, store sdk.KVStore, proofHeight exported.Height, delayTimePeriod, delayBlockPeriod uint64) error { - // check that executing chain's timestamp has passed consensusState's processed time + delay time period - processedTime, ok := GetProcessedTime(store, proofHeight) - if !ok { - return sdkerrors.Wrapf(ErrProcessedTimeNotFound, "processed time not found for height: %s", proofHeight) - } - currentTimestamp := uint64(ctx.BlockTime().UnixNano()) - validTime := processedTime + delayTimePeriod - // NOTE: delay time period is inclusive, so if currentTimestamp is validTime, then we return no error - if currentTimestamp < validTime { - return sdkerrors.Wrapf(ErrDelayPeriodNotPassed, "cannot verify packet until time: %d, current time: %d", - validTime, currentTimestamp) - } - // check that executing chain's height has passed consensusState's processed height + delay block period - processedHeight, ok := GetProcessedHeight(store, proofHeight) - if !ok { - return sdkerrors.Wrapf(ErrProcessedHeightNotFound, "processed height not found for height: %s", proofHeight) - } - currentHeight := clienttypes.GetSelfHeight(ctx) - validHeight := clienttypes.NewHeight(processedHeight.GetRevisionNumber(), processedHeight.GetRevisionHeight()+delayBlockPeriod) - // NOTE: delay block period is inclusive, so if currentHeight is validHeight, then we return no error - if currentHeight.LT(validHeight) { - return sdkerrors.Wrapf(ErrDelayPeriodNotPassed, "cannot verify packet until height: %s, current height: %s", - validHeight, currentHeight) - } - return nil -} - -// produceVerificationArgs perfoms the basic checks on the arguments that are -// shared between the verification functions and returns the unmarshalled -// merkle proof, the consensus state and an error if one occurred. -func produceVerificationArgs( - store sdk.KVStore, - cdc codec.BinaryCodec, - cs ClientState, - height exported.Height, - prefix exported.Prefix, - proof []byte, -) (merkleProof commitmenttypes.MerkleProof, consensusState *ConsensusState, err error) { - if cs.GetLatestHeight().LT(height) { - return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrapf( - sdkerrors.ErrInvalidHeight, - "client state height < proof height (%d < %d), please ensure the client has been updated", cs.GetLatestHeight(), height, - ) - } - - if prefix == nil { - return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrap(commitmenttypes.ErrInvalidPrefix, "prefix cannot be empty") - } - - _, ok := prefix.(*commitmenttypes.MerklePrefix) - if !ok { - return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrapf(commitmenttypes.ErrInvalidPrefix, "invalid prefix type %T, expected *MerklePrefix", prefix) - } - - if proof == nil { - return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "proof cannot be empty") - } - - if err = cdc.Unmarshal(proof, &merkleProof); err != nil { - return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "failed to unmarshal proof into commitment merkle proof") - } - - consensusState, err = GetConsensusState(store, cdc, height) - if err != nil { - return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrap(err, "please ensure the proof was constructed against a height that exists on the client") - } - - return merkleProof, consensusState, nil -} diff --git a/modules/light-clients/07-tendermint/types/client_state_test.go b/modules/light-clients/07-tendermint/types/client_state_test.go deleted file mode 100644 index 9c9a781fdb3..00000000000 --- a/modules/light-clients/07-tendermint/types/client_state_test.go +++ /dev/null @@ -1,880 +0,0 @@ -package types_test - -import ( - "time" - - ics23 "github.com/confio/ics23/go" - - clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v5/modules/core/24-host" - "github.com/cosmos/ibc-go/v5/modules/core/exported" - "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v5/testing" - ibcmock "github.com/cosmos/ibc-go/v5/testing/mock" -) - -const ( - testClientID = "clientidone" - testConnectionID = "connectionid" - testPortID = "testportid" - testChannelID = "testchannelid" - testSequence = 1 - - // Do not change the length of these variables - fiftyCharChainID = "12345678901234567890123456789012345678901234567890" - fiftyOneCharChainID = "123456789012345678901234567890123456789012345678901" -) - -var invalidProof = []byte("invalid proof") - -func (suite *TendermintTestSuite) TestStatus() { - var ( - path *ibctesting.Path - clientState *types.ClientState - ) - - testCases := []struct { - name string - malleate func() - expStatus exported.Status - }{ - {"client is active", func() {}, exported.Active}, - {"client is frozen", func() { - clientState.FrozenHeight = clienttypes.NewHeight(0, 1) - path.EndpointA.SetClientState(clientState) - }, exported.Frozen}, - {"client status without consensus state", func() { - clientState.LatestHeight = clientState.LatestHeight.Increment().(clienttypes.Height) - path.EndpointA.SetClientState(clientState) - }, exported.Expired}, - {"client status is expired", func() { - suite.coordinator.IncrementTimeBy(clientState.TrustingPeriod) - }, exported.Expired}, - } - - for _, tc := range testCases { - path = ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.SetupClients(path) - - clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) - clientState = path.EndpointA.GetClientState().(*types.ClientState) - - tc.malleate() - - status := clientState.Status(suite.chainA.GetContext(), clientStore, suite.chainA.App.AppCodec()) - suite.Require().Equal(tc.expStatus, status) - - } -} - -func (suite *TendermintTestSuite) TestValidate() { - testCases := []struct { - name string - clientState *types.ClientState - expPass bool - }{ - { - name: "valid client", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - expPass: true, - }, - { - name: "valid client with nil upgrade path", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), nil, false, false), - expPass: true, - }, - { - name: "invalid chainID", - clientState: types.NewClientState(" ", types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - expPass: false, - }, - { - // NOTE: if this test fails, the code must account for the change in chainID length across tendermint versions! - // Do not only fix the test, fix the code! - // https://github.com/cosmos/ibc-go/issues/177 - name: "valid chainID - chainID validation failed for chainID of length 50! ", - clientState: types.NewClientState(fiftyCharChainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - expPass: true, - }, - { - // NOTE: if this test fails, the code must account for the change in chainID length across tendermint versions! - // Do not only fix the test, fix the code! - // https://github.com/cosmos/ibc-go/issues/177 - name: "invalid chainID - chainID validation did not fail for chainID of length 51! ", - clientState: types.NewClientState(fiftyOneCharChainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - expPass: false, - }, - { - name: "invalid trust level", - clientState: types.NewClientState(chainID, types.Fraction{Numerator: 0, Denominator: 1}, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - expPass: false, - }, - { - name: "invalid trusting period", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, 0, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - expPass: false, - }, - { - name: "invalid unbonding period", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, 0, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - expPass: false, - }, - { - name: "invalid max clock drift", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, 0, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - expPass: false, - }, - { - name: "invalid revision number", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(1, 1), commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - expPass: false, - }, - { - name: "invalid revision height", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.ZeroHeight(), commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - expPass: false, - }, - { - name: "trusting period not less than unbonding period", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - expPass: false, - }, - { - name: "proof specs is nil", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, height, nil, upgradePath, false, false), - expPass: false, - }, - { - name: "proof specs contains nil", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, height, []*ics23.ProofSpec{ics23.TendermintSpec, nil}, upgradePath, false, false), - expPass: false, - }, - } - - for _, tc := range testCases { - err := tc.clientState.Validate() - if tc.expPass { - suite.Require().NoError(err, tc.name) - } else { - suite.Require().Error(err, tc.name) - } - } -} - -func (suite *TendermintTestSuite) TestInitialize() { - testCases := []struct { - name string - consensusState exported.ConsensusState - expPass bool - }{ - { - name: "valid consensus", - consensusState: &types.ConsensusState{}, - expPass: true, - }, - { - name: "invalid consensus: consensus state is solomachine consensus", - consensusState: ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachine", "", 2).ConsensusState(), - expPass: false, - }, - } - - path := ibctesting.NewPath(suite.chainA, suite.chainB) - err := path.EndpointA.CreateClient() - suite.Require().NoError(err) - - clientState := suite.chainA.GetClientState(path.EndpointA.ClientID) - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) - - for _, tc := range testCases { - err := clientState.Initialize(suite.chainA.GetContext(), suite.chainA.Codec, store, tc.consensusState) - if tc.expPass { - suite.Require().NoError(err, "valid case returned an error") - } else { - suite.Require().Error(err, "invalid case didn't return an error") - } - } -} - -func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { - testCases := []struct { - name string - clientState *types.ClientState - consensusState *types.ConsensusState - prefix commitmenttypes.MerklePrefix - proof []byte - expPass bool - }{ - // FIXME: uncomment - // { - // name: "successful verification", - // clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()), - // consensusState: types.ConsensusState{ - // Root: commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), - // }, - // prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), - // expPass: true, - // }, - { - name: "ApplyPrefix failed", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - consensusState: &types.ConsensusState{ - Root: commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), - }, - prefix: commitmenttypes.MerklePrefix{}, - expPass: false, - }, - { - name: "latest client height < height", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - consensusState: &types.ConsensusState{ - Root: commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), - }, - prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), - expPass: false, - }, - { - name: "proof verification failed", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - consensusState: &types.ConsensusState{ - Root: commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), - NextValidatorsHash: suite.valsHash, - }, - prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), - proof: []byte{}, - expPass: false, - }, - } - - for i, tc := range testCases { - tc := tc - - err := tc.clientState.VerifyClientConsensusState( - nil, suite.cdc, height, "chainA", tc.clientState.LatestHeight, tc.prefix, tc.proof, tc.consensusState, - ) - - if tc.expPass { - suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) - } else { - suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) - } - } -} - -// test verification of the connection on chainB being represented in the -// light client on chainA -func (suite *TendermintTestSuite) TestVerifyConnectionState() { - var ( - clientState *types.ClientState - proof []byte - proofHeight exported.Height - prefix commitmenttypes.MerklePrefix - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "successful verification", func() {}, true, - }, - { - "ApplyPrefix failed", func() { - prefix = commitmenttypes.MerklePrefix{} - }, false, - }, - { - "latest client height < height", func() { - proofHeight = clientState.LatestHeight.Increment() - }, false, - }, - { - "proof verification failed", func() { - proof = invalidProof - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - // setup testing conditions - path := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.Setup(path) - connection := path.EndpointB.GetConnection() - - var ok bool - clientStateI := suite.chainA.GetClientState(path.EndpointA.ClientID) - clientState, ok = clientStateI.(*types.ClientState) - suite.Require().True(ok) - - prefix = suite.chainB.GetPrefix() - - // make connection proof - connectionKey := host.ConnectionKey(path.EndpointB.ConnectionID) - proof, proofHeight = suite.chainB.QueryProof(connectionKey) - - tc.malleate() // make changes as necessary - - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) - - err := clientState.VerifyConnectionState( - store, suite.chainA.Codec, proofHeight, &prefix, proof, path.EndpointB.ConnectionID, connection, - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -// test verification of the channel on chainB being represented in the light -// client on chainA -func (suite *TendermintTestSuite) TestVerifyChannelState() { - var ( - clientState *types.ClientState - proof []byte - proofHeight exported.Height - prefix commitmenttypes.MerklePrefix - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "successful verification", func() {}, true, - }, - { - "ApplyPrefix failed", func() { - prefix = commitmenttypes.MerklePrefix{} - }, false, - }, - { - "latest client height < height", func() { - proofHeight = clientState.LatestHeight.Increment() - }, false, - }, - { - "proof verification failed", func() { - proof = invalidProof - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - // setup testing conditions - path := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.Setup(path) - channel := path.EndpointB.GetChannel() - - var ok bool - clientStateI := suite.chainA.GetClientState(path.EndpointA.ClientID) - clientState, ok = clientStateI.(*types.ClientState) - suite.Require().True(ok) - - prefix = suite.chainB.GetPrefix() - - // make channel proof - channelKey := host.ChannelKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - proof, proofHeight = suite.chainB.QueryProof(channelKey) - - tc.malleate() // make changes as necessary - - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) - - err := clientState.VerifyChannelState( - store, suite.chainA.Codec, proofHeight, &prefix, proof, - path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, channel, - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -// test verification of the packet commitment on chainB being represented -// in the light client on chainA. A send from chainB to chainA is simulated. -func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { - var ( - clientState *types.ClientState - proof []byte - delayTimePeriod uint64 - delayBlockPeriod uint64 - proofHeight exported.Height - prefix commitmenttypes.MerklePrefix - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "successful verification", func() {}, true, - }, - { - name: "delay time period has passed", - malleate: func() { - delayTimePeriod = uint64(time.Second.Nanoseconds()) - }, - expPass: true, - }, - { - name: "delay time period has not passed", - malleate: func() { - delayTimePeriod = uint64(time.Hour.Nanoseconds()) - }, - expPass: false, - }, - { - name: "delay block period has passed", - malleate: func() { - delayBlockPeriod = 1 - }, - expPass: true, - }, - { - name: "delay block period has not passed", - malleate: func() { - delayBlockPeriod = 1000 - }, - expPass: false, - }, - - { - "ApplyPrefix failed", func() { - prefix = commitmenttypes.MerklePrefix{} - }, false, - }, - { - "latest client height < height", func() { - proofHeight = clientState.LatestHeight.Increment() - }, false, - }, - { - "proof verification failed", func() { - proof = invalidProof - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - // setup testing conditions - path := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.Setup(path) - packet := channeltypes.NewPacket(ibctesting.MockPacketData, 1, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, clienttypes.NewHeight(0, 100), 0) - err := path.EndpointB.SendPacket(packet) - suite.Require().NoError(err) - - var ok bool - clientStateI := suite.chainA.GetClientState(path.EndpointA.ClientID) - clientState, ok = clientStateI.(*types.ClientState) - suite.Require().True(ok) - - prefix = suite.chainB.GetPrefix() - - // make packet commitment proof - packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - proof, proofHeight = path.EndpointB.QueryProof(packetKey) - - // reset time and block delays to 0, malleate may change to a specific non-zero value. - delayTimePeriod = 0 - delayBlockPeriod = 0 - tc.malleate() // make changes as necessary - - ctx := suite.chainA.GetContext() - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) - - commitment := channeltypes.CommitPacket(suite.chainA.App.GetIBCKeeper().Codec(), packet) - err = clientState.VerifyPacketCommitment( - ctx, store, suite.chainA.Codec, proofHeight, delayTimePeriod, delayBlockPeriod, &prefix, proof, - packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), commitment, - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -// test verification of the acknowledgement on chainB being represented -// in the light client on chainA. A send and ack from chainA to chainB -// is simulated. -func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { - var ( - clientState *types.ClientState - proof []byte - delayTimePeriod uint64 - delayBlockPeriod uint64 - proofHeight exported.Height - prefix commitmenttypes.MerklePrefix - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "successful verification", func() {}, true, - }, - { - name: "delay time period has passed", - malleate: func() { - delayTimePeriod = uint64(time.Second.Nanoseconds()) - }, - expPass: true, - }, - { - name: "delay time period has not passed", - malleate: func() { - delayTimePeriod = uint64(time.Hour.Nanoseconds()) - }, - expPass: false, - }, - { - name: "delay block period has passed", - malleate: func() { - delayBlockPeriod = 1 - }, - expPass: true, - }, - { - name: "delay block period has not passed", - malleate: func() { - delayBlockPeriod = 10 - }, - expPass: false, - }, - - { - "ApplyPrefix failed", func() { - prefix = commitmenttypes.MerklePrefix{} - }, false, - }, - { - "latest client height < height", func() { - proofHeight = clientState.LatestHeight.Increment() - }, false, - }, - { - "proof verification failed", func() { - proof = invalidProof - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - // setup testing conditions - path := ibctesting.NewPath(suite.chainA, suite.chainB) - 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, 100), 0) - - // send packet - err := path.EndpointA.SendPacket(packet) - suite.Require().NoError(err) - - // write receipt and ack - err = path.EndpointB.RecvPacket(packet) - suite.Require().NoError(err) - - var ok bool - clientStateI := suite.chainA.GetClientState(path.EndpointA.ClientID) - clientState, ok = clientStateI.(*types.ClientState) - suite.Require().True(ok) - - prefix = suite.chainB.GetPrefix() - - // make packet acknowledgement proof - acknowledgementKey := host.PacketAcknowledgementKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - proof, proofHeight = suite.chainB.QueryProof(acknowledgementKey) - - // reset time and block delays to 0, malleate may change to a specific non-zero value. - delayTimePeriod = 0 - delayBlockPeriod = 0 - tc.malleate() // make changes as necessary - - ctx := suite.chainA.GetContext() - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) - - err = clientState.VerifyPacketAcknowledgement( - ctx, store, suite.chainA.Codec, proofHeight, delayTimePeriod, delayBlockPeriod, &prefix, proof, - packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), ibcmock.MockAcknowledgement.Acknowledgement(), - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -// test verification of the absent acknowledgement on chainB being represented -// in the light client on chainA. A send from chainB to chainA is simulated, but -// no receive. -func (suite *TendermintTestSuite) TestVerifyPacketReceiptAbsence() { - var ( - clientState *types.ClientState - proof []byte - delayTimePeriod uint64 - delayBlockPeriod uint64 - proofHeight exported.Height - prefix commitmenttypes.MerklePrefix - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "successful verification", func() {}, true, - }, - { - name: "delay time period has passed", - malleate: func() { - delayTimePeriod = uint64(time.Second.Nanoseconds()) - }, - expPass: true, - }, - { - name: "delay time period has not passed", - malleate: func() { - delayTimePeriod = uint64(time.Hour.Nanoseconds()) - }, - expPass: false, - }, - { - name: "delay block period has passed", - malleate: func() { - delayBlockPeriod = 1 - }, - expPass: true, - }, - { - name: "delay block period has not passed", - malleate: func() { - delayBlockPeriod = 10 - }, - expPass: false, - }, - - { - "ApplyPrefix failed", func() { - prefix = commitmenttypes.MerklePrefix{} - }, false, - }, - { - "latest client height < height", func() { - proofHeight = clientState.LatestHeight.Increment() - }, false, - }, - { - "proof verification failed", func() { - proof = invalidProof - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - // setup testing conditions - path := ibctesting.NewPath(suite.chainA, suite.chainB) - 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, 100), 0) - - // send packet, but no recv - err := path.EndpointA.SendPacket(packet) - suite.Require().NoError(err) - - var ok bool - clientStateI := suite.chainA.GetClientState(path.EndpointA.ClientID) - clientState, ok = clientStateI.(*types.ClientState) - suite.Require().True(ok) - - prefix = suite.chainB.GetPrefix() - - // make packet receipt absence proof - receiptKey := host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - proof, proofHeight = path.EndpointB.QueryProof(receiptKey) - - // reset time and block delays to 0, malleate may change to a specific non-zero value. - delayTimePeriod = 0 - delayBlockPeriod = 0 - tc.malleate() // make changes as necessary - - ctx := suite.chainA.GetContext() - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) - - err = clientState.VerifyPacketReceiptAbsence( - ctx, store, suite.chainA.Codec, proofHeight, delayTimePeriod, delayBlockPeriod, &prefix, proof, - packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -// test verification of the next receive sequence on chainB being represented -// in the light client on chainA. A send and receive from chainB to chainA is -// simulated. -func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { - var ( - clientState *types.ClientState - proof []byte - delayTimePeriod uint64 - delayBlockPeriod uint64 - proofHeight exported.Height - prefix commitmenttypes.MerklePrefix - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "successful verification", func() {}, true, - }, - { - name: "delay time period has passed", - malleate: func() { - delayTimePeriod = uint64(time.Second.Nanoseconds()) - }, - expPass: true, - }, - { - name: "delay time period has not passed", - malleate: func() { - delayTimePeriod = uint64(time.Hour.Nanoseconds()) - }, - expPass: false, - }, - { - name: "delay block period has passed", - malleate: func() { - delayBlockPeriod = 1 - }, - expPass: true, - }, - { - name: "delay block period has not passed", - malleate: func() { - delayBlockPeriod = 10 - }, - expPass: false, - }, - - { - "ApplyPrefix failed", func() { - prefix = commitmenttypes.MerklePrefix{} - }, false, - }, - { - "latest client height < height", func() { - proofHeight = clientState.LatestHeight.Increment() - }, false, - }, - { - "proof verification failed", func() { - proof = invalidProof - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - // setup testing conditions - path := ibctesting.NewPath(suite.chainA, suite.chainB) - path.SetChannelOrdered() - 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, 100), 0) - - // send packet - err := path.EndpointA.SendPacket(packet) - suite.Require().NoError(err) - - // next seq recv incremented - err = path.EndpointB.RecvPacket(packet) - suite.Require().NoError(err) - - var ok bool - clientStateI := suite.chainA.GetClientState(path.EndpointA.ClientID) - clientState, ok = clientStateI.(*types.ClientState) - suite.Require().True(ok) - - prefix = suite.chainB.GetPrefix() - - // make next seq recv proof - nextSeqRecvKey := host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel()) - proof, proofHeight = suite.chainB.QueryProof(nextSeqRecvKey) - - // reset time and block delays to 0, malleate may change to a specific non-zero value. - delayTimePeriod = 0 - delayBlockPeriod = 0 - tc.malleate() // make changes as necessary - - ctx := suite.chainA.GetContext() - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) - - err = clientState.VerifyNextSequenceRecv( - ctx, store, suite.chainA.Codec, proofHeight, delayTimePeriod, delayBlockPeriod, &prefix, proof, - packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()+1, - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} diff --git a/modules/light-clients/07-tendermint/types/misbehaviour_handle_test.go b/modules/light-clients/07-tendermint/types/misbehaviour_handle_test.go deleted file mode 100644 index 6e699dcaa49..00000000000 --- a/modules/light-clients/07-tendermint/types/misbehaviour_handle_test.go +++ /dev/null @@ -1,425 +0,0 @@ -package types_test - -import ( - "fmt" - "time" - - "github.com/tendermint/tendermint/crypto/tmhash" - tmtypes "github.com/tendermint/tendermint/types" - - clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v5/modules/core/exported" - "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" - ibctestingmock "github.com/cosmos/ibc-go/v5/testing/mock" -) - -func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { - altPrivVal := ibctestingmock.NewPV() - altPubKey, err := altPrivVal.GetPubKey() - suite.Require().NoError(err) - - altVal := tmtypes.NewValidator(altPubKey, 4) - - // Create alternative validator set with only altVal - altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal}) - - // Create bothValSet with both suite validator and altVal - bothValSet, bothSigners := getBothSigners(suite, altVal, altPrivVal) - bothValsHash := bothValSet.Hash() - - altSigners := getAltSigners(altVal, altPrivVal) - - heightMinus1 := clienttypes.NewHeight(height.RevisionNumber, height.RevisionHeight-1) - heightMinus3 := clienttypes.NewHeight(height.RevisionNumber, height.RevisionHeight-3) - - testCases := []struct { - name string - clientState exported.ClientState - consensusState1 exported.ConsensusState - height1 clienttypes.Height - consensusState2 exported.ConsensusState - height2 clienttypes.Height - misbehaviour exported.Misbehaviour - timestamp time.Time - expPass bool - }{ - { - "valid fork misbehaviour", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: chainID, - }, - suite.now, - true, - }, - { - "valid time misbehaviour", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+3), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: chainID, - }, - suite.now, - true, - }, - { - "valid time misbehaviour header 1 stricly less than header 2", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+3), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Hour), bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: chainID, - }, - suite.now, - true, - }, - { - "valid misbehavior at height greater than last consensusState", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - heightMinus1, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - heightMinus1, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: chainID, - }, - suite.now, - true, - }, - { - "valid misbehaviour with different trusted heights", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - heightMinus1, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), - heightMinus3, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus3, suite.now.Add(time.Minute), bothValSet, bothValSet, suite.valSet, bothSigners), - ClientId: chainID, - }, - suite.now, - true, - }, - { - "valid misbehaviour at a previous revision", - types.NewClientState(chainIDRevision1, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(1, 1), commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - heightMinus1, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), - heightMinus3, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainIDRevision0, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainIDRevision0, int64(height.RevisionHeight+1), heightMinus3, suite.now.Add(time.Minute), bothValSet, bothValSet, suite.valSet, bothSigners), - ClientId: chainID, - }, - suite.now, - true, - }, - { - "valid misbehaviour at a future revision", - types.NewClientState(chainIDRevision0, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - heightMinus1, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), - heightMinus3, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainIDRevision0, 3, heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainIDRevision0, 3, heightMinus3, suite.now.Add(time.Minute), bothValSet, bothValSet, suite.valSet, bothSigners), - ClientId: chainID, - }, - suite.now, - true, - }, - { - "valid misbehaviour with trusted heights at a previous revision", - types.NewClientState(chainIDRevision1, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(1, 1), commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - heightMinus1, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), - heightMinus3, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainIDRevision1, 1, heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainIDRevision1, 1, heightMinus3, suite.now.Add(time.Minute), bothValSet, bothValSet, suite.valSet, bothSigners), - ClientId: chainID, - }, - suite.now, - true, - }, - { - "consensus state's valset hash different from misbehaviour should still pass", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), - height, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), - height, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, suite.valSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, suite.valSet, bothSigners), - ClientId: chainID, - }, - suite.now, - true, - }, - { - "invalid fork misbehaviour: identical headers", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: chainID, - }, - suite.now, - false, - }, - { - "invalid time misbehaviour: monotonically increasing time", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+3), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: chainID, - }, - suite.now, - false, - }, - { - "invalid misbehavior misbehaviour from different chain", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader("ethermint", int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader("ethermint", int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: chainID, - }, - suite.now, - false, - }, - { - "invalid misbehavior misbehaviour with trusted height different from trusted consensus state", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - heightMinus1, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), - heightMinus3, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, suite.valSet, bothSigners), - ClientId: chainID, - }, - suite.now, - false, - }, - { - "invalid misbehavior misbehaviour with trusted validators different from trusted consensus state", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - heightMinus1, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), - heightMinus3, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus3, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: chainID, - }, - suite.now, - false, - }, - { - "already frozen client state", - &types.ClientState{FrozenHeight: clienttypes.NewHeight(0, 1)}, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: chainID, - }, - suite.now, - false, - }, - { - "trusted consensus state does not exist", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - nil, // consensus state for trusted height - 1 does not exist in store - clienttypes.Height{}, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: chainID, - }, - suite.now, - false, - }, - { - "invalid tendermint misbehaviour", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - nil, - suite.now, - false, - }, - { - "provided height > header height", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: chainID, - }, - suite.now, - false, - }, - { - "trusting period expired", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(time.Time{}, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - heightMinus1, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: chainID, - }, - suite.now.Add(trustingPeriod), - false, - }, - { - "trusted validators is incorrect for given consensus state", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, suite.valSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, suite.valSet, bothSigners), - ClientId: chainID, - }, - suite.now, - false, - }, - { - "first valset has too much change", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, altValSet, altValSet, bothValSet, altSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), - ClientId: chainID, - }, - suite.now, - false, - }, - { - "second valset has too much change", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), altValSet, altValSet, bothValSet, altSigners), - ClientId: chainID, - }, - suite.now, - false, - }, - { - "both valsets have too much change", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), - height, - &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, altValSet, altValSet, bothValSet, altSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), altValSet, altValSet, bothValSet, altSigners), - ClientId: chainID, - }, - suite.now, - false, - }, - } - - for i, tc := range testCases { - tc := tc - suite.Run(fmt.Sprintf("Case: %s", tc.name), func() { - // reset suite to create fresh application state - suite.SetupTest() - - // Set current timestamp in context - ctx := suite.chainA.GetContext().WithBlockTime(tc.timestamp) - - // Set trusted consensus states in client store - - if tc.consensusState1 != nil { - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(ctx, clientID, tc.height1, tc.consensusState1) - } - if tc.consensusState2 != nil { - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(ctx, clientID, tc.height2, tc.consensusState2) - } - - clientState, err := tc.clientState.CheckMisbehaviourAndUpdateState( - ctx, - suite.chainA.App.AppCodec(), - suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, clientID), // pass in clientID prefixed clientStore - tc.misbehaviour, - ) - - if tc.expPass { - suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) - suite.Require().NotNil(clientState, "valid test case %d failed: %s", i, tc.name) - suite.Require().True(!clientState.(*types.ClientState).FrozenHeight.IsZero(), "valid test case %d failed: %s", i, tc.name) - } else { - suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) - suite.Require().Nil(clientState, "invalid test case %d passed: %s", i, tc.name) - } - }) - } -} diff --git a/modules/light-clients/07-tendermint/types/update_test.go b/modules/light-clients/07-tendermint/types/update_test.go deleted file mode 100644 index aaf1936d8d7..00000000000 --- a/modules/light-clients/07-tendermint/types/update_test.go +++ /dev/null @@ -1,450 +0,0 @@ -package types_test - -import ( - "fmt" - "time" - - tmtypes "github.com/tendermint/tendermint/types" - - clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v5/modules/core/exported" - types "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v5/testing" - ibctestingmock "github.com/cosmos/ibc-go/v5/testing/mock" -) - -func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { - var ( - clientState *types.ClientState - consensusState *types.ConsensusState - consStateHeight clienttypes.Height - newHeader *types.Header - currentTime time.Time - bothValSet *tmtypes.ValidatorSet - bothSigners map[string]tmtypes.PrivValidator - ) - - // Setup different validators and signers for testing different types of updates - altPrivVal := ibctestingmock.NewPV() - altPubKey, err := altPrivVal.GetPubKey() - suite.Require().NoError(err) - - revisionHeight := int64(height.RevisionHeight) - - // create modified heights to use for test-cases - heightPlus1 := clienttypes.NewHeight(height.RevisionNumber, height.RevisionHeight+1) - heightMinus1 := clienttypes.NewHeight(height.RevisionNumber, height.RevisionHeight-1) - heightMinus3 := clienttypes.NewHeight(height.RevisionNumber, height.RevisionHeight-3) - heightPlus5 := clienttypes.NewHeight(height.RevisionNumber, height.RevisionHeight+5) - - altVal := tmtypes.NewValidator(altPubKey, revisionHeight) - // Create alternative validator set with only altVal, invalid update (too much change in valSet) - altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal}) - altSigners := getAltSigners(altVal, altPrivVal) - - testCases := []struct { - name string - setup func(*TendermintTestSuite) - expFrozen bool - expPass bool - }{ - { - name: "successful update with next height and same validator set", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) - currentTime = suite.now - }, - expFrozen: false, - expPass: true, - }, - { - name: "successful update with future height and different validator set", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus5.RevisionHeight), height, suite.headerTime, bothValSet, bothValSet, suite.valSet, bothSigners) - currentTime = suite.now - }, - expFrozen: false, - expPass: true, - }, - { - name: "successful update with next height and different validator set", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), bothValSet.Hash()) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, bothValSet, bothValSet, bothValSet, bothSigners) - currentTime = suite.now - }, - expFrozen: false, - expPass: true, - }, - { - name: "successful update for a previous height", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - consStateHeight = heightMinus3 - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightMinus1.RevisionHeight), heightMinus3, suite.headerTime, bothValSet, bothValSet, suite.valSet, bothSigners) - currentTime = suite.now - }, - expFrozen: false, - expPass: true, - }, - { - name: "successful update for a previous revision", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainIDRevision1, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - consStateHeight = heightMinus3 - newHeader = suite.chainA.CreateTMClientHeader(chainIDRevision0, int64(height.RevisionHeight), heightMinus3, suite.headerTime, bothValSet, bothValSet, suite.valSet, bothSigners) - currentTime = suite.now - }, - expPass: true, - }, - { - name: "successful update with identical header to a previous update", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, heightPlus1, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) - currentTime = suite.now - ctx := suite.chainA.GetContext().WithBlockTime(currentTime) - // Store the header's consensus state in client store before UpdateClient call - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(ctx, clientID, heightPlus1, newHeader.ConsensusState()) - }, - expFrozen: false, - expPass: true, - }, - { - name: "misbehaviour detection: header conflicts with existing consensus state", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, heightPlus1, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) - currentTime = suite.now - ctx := suite.chainA.GetContext().WithBlockTime(currentTime) - // Change the consensus state of header and store in client store to create a conflict - conflictConsState := newHeader.ConsensusState() - conflictConsState.Root = commitmenttypes.NewMerkleRoot([]byte("conflicting apphash")) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(ctx, clientID, heightPlus1, conflictConsState) - }, - expFrozen: true, - expPass: true, - }, - { - name: "misbehaviour detection: previous consensus state time is not before header time. time monotonicity violation", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - // create an intermediate consensus state with the same time as the newHeader to create a time violation. - // header time is after client time - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus5.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) - currentTime = suite.now - prevConsensusState := types.NewConsensusState(suite.headerTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - ctx := suite.chainA.GetContext().WithBlockTime(currentTime) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(ctx, clientID, heightPlus1, prevConsensusState) - clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, clientID) - types.SetIterationKey(clientStore, heightPlus1) - }, - expFrozen: true, - expPass: true, - }, - { - name: "misbehaviour detection: next consensus state time is not after header time. time monotonicity violation", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - // create the next consensus state with the same time as the intermediate newHeader to create a time violation. - // header time is after clientTime - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) - currentTime = suite.now - nextConsensusState := types.NewConsensusState(suite.headerTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - ctx := suite.chainA.GetContext().WithBlockTime(currentTime) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(ctx, clientID, heightPlus5, nextConsensusState) - clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, clientID) - types.SetIterationKey(clientStore, heightPlus5) - }, - expFrozen: true, - expPass: true, - }, - { - name: "unsuccessful update with incorrect header chain-id", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader("ethermint", int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) - currentTime = suite.now - }, - expFrozen: false, - expPass: false, - }, - { - name: "unsuccessful update to a future revision", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainIDRevision0, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainIDRevision1, 1, height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) - currentTime = suite.now - }, - expPass: false, - }, - { - name: "unsuccessful update: header height revision and trusted height revision mismatch", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainIDRevision1, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(1, 1), commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainIDRevision1, 3, height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) - currentTime = suite.now - }, - expFrozen: false, - expPass: false, - }, - { - name: "unsuccessful update with next height: update header mismatches nextValSetHash", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, bothValSet, bothValSet, suite.valSet, bothSigners) - currentTime = suite.now - }, - expFrozen: false, - expPass: false, - }, - { - name: "unsuccessful update with next height: update header mismatches different nextValSetHash", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), bothValSet.Hash()) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, bothValSet, suite.signers) - currentTime = suite.now - }, - expFrozen: false, - expPass: false, - }, - { - name: "unsuccessful update with future height: too much change in validator set", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus5.RevisionHeight), height, suite.headerTime, altValSet, altValSet, suite.valSet, altSigners) - currentTime = suite.now - }, - expFrozen: false, - expPass: false, - }, - { - name: "unsuccessful updates, passed in incorrect trusted validators for given consensus state", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus5.RevisionHeight), height, suite.headerTime, bothValSet, bothValSet, bothValSet, bothSigners) - currentTime = suite.now - }, - expFrozen: false, - expPass: false, - }, - { - name: "unsuccessful update: trusting period has passed since last client timestamp", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) - // make current time pass trusting period from last timestamp on clientstate - currentTime = suite.now.Add(trustingPeriod) - }, - expFrozen: false, - expPass: false, - }, - { - name: "unsuccessful update: header timestamp is past current timestamp", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.now.Add(time.Minute), suite.valSet, suite.valSet, suite.valSet, suite.signers) - currentTime = suite.now - }, - expFrozen: false, - expPass: false, - }, - { - name: "unsuccessful update: header timestamp is not past last client timestamp", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.clientTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) - currentTime = suite.now - }, - expFrozen: false, - expPass: false, - }, - { - name: "header basic validation failed", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) - // cause new header to fail validatebasic by changing commit height to mismatch header height - newHeader.SignedHeader.Commit.Height = revisionHeight - 1 - currentTime = suite.now - }, - expFrozen: false, - expPass: false, - }, - { - name: "header height < consensus height", - setup: func(suite *TendermintTestSuite) { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(height.RevisionNumber, heightPlus5.RevisionHeight), commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - // Make new header at height less than latest client state - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightMinus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) - currentTime = suite.now - }, - expFrozen: false, - expPass: false, - }, - } - - for i, tc := range testCases { - tc := tc - suite.Run(fmt.Sprintf("Case: %s", tc.name), func() { - suite.SetupTest() // reset metadata writes - // Create bothValSet with both suite validator and altVal. Would be valid update - bothValSet, bothSigners = getBothSigners(suite, altVal, altPrivVal) - - consStateHeight = height // must be explicitly changed - // setup test - tc.setup(suite) - - // Set current timestamp in context - ctx := suite.chainA.GetContext().WithBlockTime(currentTime) - - // Set trusted consensus state in client store - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(ctx, clientID, consStateHeight, consensusState) - - height := newHeader.GetHeight() - expectedConsensus := &types.ConsensusState{ - Timestamp: newHeader.GetTime(), - Root: commitmenttypes.NewMerkleRoot(newHeader.Header.GetAppHash()), - NextValidatorsHash: newHeader.Header.NextValidatorsHash, - } - - newClientState, consensusState, err := clientState.CheckHeaderAndUpdateState( - ctx, - suite.cdc, - suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), clientID), // pass in clientID prefixed clientStore - newHeader, - ) - - if tc.expPass { - suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) - - suite.Require().Equal(tc.expFrozen, !newClientState.(*types.ClientState).FrozenHeight.IsZero(), "client state status is unexpected after update") - - // further writes only happen if update is not misbehaviour - if !tc.expFrozen { - // Determine if clientState should be updated or not - // TODO: check the entire Height struct once GetLatestHeight returns clienttypes.Height - if height.GT(clientState.LatestHeight) { - // Header Height is greater than clientState latest Height, clientState should be updated with header.GetHeight() - suite.Require().Equal(height, newClientState.GetLatestHeight(), "clientstate height did not update") - } else { - // Update will add past consensus state, clientState should not be updated at all - suite.Require().Equal(clientState.LatestHeight, newClientState.GetLatestHeight(), "client state height updated for past header") - } - - suite.Require().Equal(expectedConsensus, consensusState, "valid test case %d failed: %s", i, tc.name) - } - } else { - suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) - suite.Require().Nil(newClientState, "invalid test case %d passed: %s", i, tc.name) - suite.Require().Nil(consensusState, "invalid test case %d passed: %s", i, tc.name) - } - }) - } -} - -func (suite *TendermintTestSuite) TestPruneConsensusState() { - // create path and setup clients - path := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.SetupClients(path) - - // 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) - err := types.IterateConsensusStateAscending(clientStore, getFirstHeightCb) - suite.Require().Nil(err) - - // this height will be expired but not pruned - path.EndpointA.UpdateClient() - expiredHeight := path.EndpointA.GetClientState().GetLatestHeight() - - // expected values that must still remain in store after pruning - expectedConsState, ok := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, expiredHeight) - suite.Require().True(ok) - ctx = path.EndpointA.Chain.GetContext() - clientStore = path.EndpointA.Chain.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) - expectedProcessTime, ok := types.GetProcessedTime(clientStore, expiredHeight) - suite.Require().True(ok) - expectedProcessHeight, ok := types.GetProcessedHeight(clientStore, expiredHeight) - suite.Require().True(ok) - expectedConsKey := types.GetIterationKey(clientStore, expiredHeight) - suite.Require().NotNil(expectedConsKey) - - // Increment the time by a week - suite.coordinator.IncrementTimeBy(7 * 24 * time.Hour) - - // create the consensus state that can be used as trusted height for next update - path.EndpointA.UpdateClient() - - // 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) - path.EndpointA.UpdateClient() - - ctx = path.EndpointA.Chain.GetContext() - clientStore = path.EndpointA.Chain.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) - - // check that the first expired consensus state got deleted along with all associated metadata - consState, ok := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, pruneHeight) - suite.Require().Nil(consState, "expired consensus state not pruned") - suite.Require().False(ok) - // check processed time metadata is pruned - processTime, ok := types.GetProcessedTime(clientStore, pruneHeight) - suite.Require().Equal(uint64(0), processTime, "processed time metadata not pruned") - suite.Require().False(ok) - processHeight, ok := types.GetProcessedHeight(clientStore, pruneHeight) - suite.Require().Nil(processHeight, "processed height metadata not pruned") - suite.Require().False(ok) - - // check iteration key metadata is pruned - consKey := types.GetIterationKey(clientStore, pruneHeight) - suite.Require().Nil(consKey, "iteration key not pruned") - - // check that second expired consensus state doesn't get deleted - // this ensures that there is a cap on gas cost of UpdateClient - consState, ok = path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, expiredHeight) - suite.Require().Equal(expectedConsState, consState, "consensus state incorrectly pruned") - suite.Require().True(ok) - // check processed time metadata is not pruned - processTime, ok = types.GetProcessedTime(clientStore, expiredHeight) - suite.Require().Equal(expectedProcessTime, processTime, "processed time metadata incorrectly pruned") - suite.Require().True(ok) - - // check processed height metadata is not pruned - processHeight, ok = types.GetProcessedHeight(clientStore, expiredHeight) - suite.Require().Equal(expectedProcessHeight, processHeight, "processed height metadata incorrectly pruned") - suite.Require().True(ok) - - // check iteration key metadata is not pruned - consKey = types.GetIterationKey(clientStore, expiredHeight) - suite.Require().Equal(expectedConsKey, consKey, "iteration key incorrectly pruned") -} diff --git a/modules/light-clients/07-tendermint/types/update.go b/modules/light-clients/07-tendermint/update.go similarity index 50% rename from modules/light-clients/07-tendermint/types/update.go rename to modules/light-clients/07-tendermint/update.go index 90243235a52..32b5857ad19 100644 --- a/modules/light-clients/07-tendermint/types/update.go +++ b/modules/light-clients/07-tendermint/update.go @@ -1,9 +1,9 @@ -package types +package tendermint import ( "bytes" + "fmt" "reflect" - "time" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -13,13 +13,26 @@ import ( clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v5/modules/core/24-host" "github.com/cosmos/ibc-go/v5/modules/core/exported" ) -// CheckHeaderAndUpdateState checks if the provided header is valid, and if valid it will: -// create the consensus state for the header.Height -// and update the client state if the header height is greater than the latest client state height -// It returns an error if: +// VerifyClientMessage checks if the clientMessage is of type Header or Misbehaviour and verifies the message +func (cs *ClientState) VerifyClientMessage( + ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, + clientMsg exported.ClientMessage, +) error { + switch msg := clientMsg.(type) { + case *Header: + return cs.verifyHeader(ctx, clientStore, cdc, msg) + case *Misbehaviour: + return cs.verifyMisbehaviour(ctx, clientStore, cdc, msg) + default: + return clienttypes.ErrInvalidClientType + } +} + +// verifyHeader returns an error if: // - the client or header provided are not parseable to tendermint types // - the header is invalid // - header height is less than or equal to the trusted header height @@ -27,150 +40,18 @@ import ( // - header valset commit verification fails // - header timestamp is past the trusting period in relation to the consensus state // - header timestamp is less than or equal to the consensus state timestamp -// -// UpdateClient may be used to either create a consensus state for: -// - a future height greater than the latest client state height -// - a past height that was skipped during bisection -// If we are updating to a past height, a consensus state is created for that height to be persisted in client store -// If we are updating to a future height, the consensus state is created and the client state is updated to reflect -// the new latest height -// UpdateClient 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 -// Tendermint client validity checking uses the bisection algorithm described -// in the [Tendermint spec](https://github.com/tendermint/spec/blob/master/spec/consensus/light-client.md). -// -// Misbehaviour Detection: -// UpdateClient will detect implicit misbehaviour by enforcing certain invariants on any new update call and will return a frozen client. -// 1. Any valid update that creates a different consensus state for an already existing height is evidence of misbehaviour and will freeze client. -// 2. Any valid update that breaks time monotonicity with respect to its neighboring consensus states is evidence of misbehaviour and will freeze client. -// Misbehaviour sets frozen height to {0, 1} since it is only used as a boolean value (zero or non-zero). -// -// Pruning: -// UpdateClient will additionally retrieve the earliest consensus state for this clientID and check if it is expired. If it is, -// that consensus state will be pruned from store along with all associated metadata. This will prevent the client store from -// becoming bloated with expired consensus states that can no longer be used for updates and packet verification. -func (cs ClientState) CheckHeaderAndUpdateState( - ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, - header exported.Header, -) (exported.ClientState, exported.ConsensusState, error) { - tmHeader, ok := header.(*Header) - if !ok { - return nil, nil, sdkerrors.Wrapf( - clienttypes.ErrInvalidHeader, "expected type %T, got %T", &Header{}, header, - ) - } - - // Check if the Client store already has a consensus state for the header's height - // If the consensus state exists, and it matches the header then we return early - // since header has already been submitted in a previous UpdateClient. - var conflictingHeader bool - prevConsState, _ := GetConsensusState(clientStore, cdc, header.GetHeight()) - if prevConsState != nil { - // This header has already been submitted and the necessary state is already stored - // in client store, thus we can return early without further validation. - if reflect.DeepEqual(prevConsState, tmHeader.ConsensusState()) { - return &cs, prevConsState, nil - } - // A consensus state already exists for this height, but it does not match the provided header. - // Thus, we must check that this header is valid, and if so we will freeze the client. - conflictingHeader = true - } - - // get consensus state from clientStore - trustedConsState, err := GetConsensusState(clientStore, cdc, tmHeader.TrustedHeight) - if err != nil { - return nil, nil, sdkerrors.Wrapf( - err, "could not get consensus state from clientstore at TrustedHeight: %s", tmHeader.TrustedHeight, - ) - } - - if err := checkValidity(&cs, trustedConsState, tmHeader, ctx.BlockTime()); err != nil { - return nil, nil, err - } - - consState := tmHeader.ConsensusState() - // Header is different from existing consensus state and also valid, so freeze the client and return - if conflictingHeader { - cs.FrozenHeight = FrozenHeight - return &cs, consState, nil - } - // Check that consensus state timestamps are monotonic - prevCons, prevOk := GetPreviousConsensusState(clientStore, cdc, header.GetHeight()) - nextCons, nextOk := GetNextConsensusState(clientStore, cdc, header.GetHeight()) - // if previous consensus state exists, check consensus state time is greater than previous consensus state time - // if previous consensus state is not before current consensus state, freeze the client and return. - if prevOk && !prevCons.Timestamp.Before(consState.Timestamp) { - cs.FrozenHeight = FrozenHeight - return &cs, consState, nil - } - // if next consensus state exists, check consensus state time is less than next consensus state time - // if next consensus state is not after current consensus state, freeze the client and return. - if nextOk && !nextCons.Timestamp.After(consState.Timestamp) { - cs.FrozenHeight = FrozenHeight - return &cs, consState, nil - } - - // Check the earliest consensus state to see if it is expired, if so then set the prune height - // so that we can delete consensus state and all associated metadata. - var ( - pruneHeight exported.Height - pruneError error - ) - pruneCb := func(height exported.Height) bool { - consState, err := GetConsensusState(clientStore, cdc, height) - // this error should never occur - if err != nil { - pruneError = err - return true - } - if cs.IsExpired(consState.Timestamp, ctx.BlockTime()) { - pruneHeight = height - } - return true - } - err = IterateConsensusStateAscending(clientStore, pruneCb) - if err != nil { - return nil, nil, err - } - if pruneError != nil { - return nil, nil, pruneError - } - // if pruneHeight is set, delete consensus state and metadata - if pruneHeight != nil { - deleteConsensusState(clientStore, pruneHeight) - deleteConsensusMetadata(clientStore, pruneHeight) - } - - newClientState, consensusState := update(ctx, clientStore, &cs, tmHeader) - return newClientState, consensusState, nil -} - -// checkTrustedHeader checks that consensus state matches trusted fields of Header -func checkTrustedHeader(header *Header, consState *ConsensusState) error { - tmTrustedValidators, err := tmtypes.ValidatorSetFromProto(header.TrustedValidators) - if err != nil { - return sdkerrors.Wrap(err, "trusted validator set in not tendermint validator set type") - } +func (cs *ClientState) verifyHeader( + ctx sdk.Context, clientStore sdk.KVStore, cdc codec.BinaryCodec, + header *Header, +) error { + currentTimestamp := ctx.BlockTime() - // assert that trustedVals is NextValidators of last trusted header - // to do this, we check that trustedVals.Hash() == consState.NextValidatorsHash - tvalHash := tmTrustedValidators.Hash() - if !bytes.Equal(consState.NextValidatorsHash, tvalHash) { - return sdkerrors.Wrapf( - ErrInvalidValidatorSet, - "trusted validators %s, does not hash to latest trusted validators. Expected: %X, got: %X", - header.TrustedValidators, consState.NextValidatorsHash, tvalHash, - ) + // Retrieve trusted consensus states for each Header in misbehaviour + consState, found := GetConsensusState(clientStore, cdc, header.TrustedHeight) + if !found { + return sdkerrors.Wrapf(clienttypes.ErrConsensusStateNotFound, "could not get trusted consensus state from clientStore for Header at TrustedHeight: %s", header.TrustedHeight) } - return nil -} -// checkValidity checks if the Tendermint header is valid. -// CONTRACT: consState.Height == header.TrustedHeight -func checkValidity( - clientState *ClientState, consState *ConsensusState, - header *Header, currentTimestamp time.Time, -) error { if err := checkTrustedHeader(header, consState); err != nil { return err } @@ -208,21 +89,11 @@ func checkValidity( ) } - chainID := clientState.GetChainID() - // If chainID is in revision format, then set revision number of chainID with the revision number - // of the header we are verifying - // This is useful if the update is at a previous revision rather than an update to the latest revision - // of the client. - // The chainID must be set correctly for the previous revision before attempting verification. - // Updates for previous revisions are not supported if the chainID is not in revision format. - if clienttypes.IsRevisionFormat(chainID) { - chainID, _ = clienttypes.SetRevisionNumber(chainID, header.GetHeight().GetRevisionNumber()) - } - // Construct a trusted header using the fields in consensus state // Only Height, Time, and NextValidatorsHash are necessary for verification + // NOTE: updates must be within the same revision trustedHeader := tmtypes.Header{ - ChainID: chainID, + ChainID: cs.GetChainID(), Height: int64(header.TrustedHeight.RevisionHeight), Time: consState.Timestamp, NextValidatorsHash: consState.NextValidatorsHash, @@ -239,28 +110,160 @@ func checkValidity( err = light.Verify( &signedHeader, tmTrustedValidators, tmSignedHeader, tmValidatorSet, - clientState.TrustingPeriod, currentTimestamp, clientState.MaxClockDrift, clientState.TrustLevel.ToTendermint(), + cs.TrustingPeriod, currentTimestamp, cs.MaxClockDrift, cs.TrustLevel.ToTendermint(), ) if err != nil { return sdkerrors.Wrap(err, "failed to verify header") } + return nil } -// update the consensus state from a new header and set processed time metadata -func update(ctx sdk.Context, clientStore sdk.KVStore, clientState *ClientState, header *Header) (*ClientState, *ConsensusState) { +// UpdateState may be used to either create a consensus state for: +// - a future height greater than the latest client state height +// - a past height that was skipped during bisection +// If we are updating to a past height, a consensus state is created for that height to be persisted in client store +// If we are updating to a future height, the consensus state is created and the client state is updated to reflect +// the new latest height +// A list containing the updated consensus height is returned. +// 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. +func (cs ClientState) UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg exported.ClientMessage) []exported.Height { + header, ok := clientMsg.(*Header) + if !ok { + panic(fmt.Errorf("expected type %T, got %T", &Header{}, clientMsg)) + } + + // check for duplicate update + if consensusState, _ := GetConsensusState(clientStore, cdc, header.GetHeight()); consensusState != nil { + // perform no-op + return []exported.Height{header.GetHeight()} + } + + cs.pruneOldestConsensusState(ctx, cdc, clientStore) + height := header.GetHeight().(clienttypes.Height) - if height.GT(clientState.LatestHeight) { - clientState.LatestHeight = height + if height.GT(cs.LatestHeight) { + cs.LatestHeight = height } + consensusState := &ConsensusState{ Timestamp: header.GetTime(), Root: commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), NextValidatorsHash: header.Header.NextValidatorsHash, } - // set metadata for this consensus state + // set client state, consensus state and asssociated metadata + setClientState(clientStore, cdc, &cs) + setConsensusState(clientStore, cdc, consensusState, header.GetHeight()) setConsensusMetadata(ctx, clientStore, header.GetHeight()) - return clientState, consensusState + return []exported.Height{height} +} + +// pruneOldestConsensusState will retrieve the earliest consensus state for this clientID and check if it is expired. If it is, +// that consensus state will be pruned from store along with all associated metadata. This will prevent the client store from +// becoming bloated with expired consensus states that can no longer be used for updates and packet verification. +func (cs ClientState) pruneOldestConsensusState(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore) { + // Check the earliest consensus state to see if it is expired, if so then set the prune height + // so that we can delete consensus state and all associated metadata. + var ( + pruneHeight exported.Height + ) + + pruneCb := func(height exported.Height) bool { + consState, found := GetConsensusState(clientStore, cdc, height) + // this error should never occur + if !found { + panic(sdkerrors.Wrapf(clienttypes.ErrConsensusStateNotFound, "failed to retrieve consensus state at height: %s", height)) + } + + if cs.IsExpired(consState.Timestamp, ctx.BlockTime()) { + pruneHeight = height + } + + return true + } + + IterateConsensusStateAscending(clientStore, pruneCb) + + // if pruneHeight is set, delete consensus state and metadata + if pruneHeight != nil { + deleteConsensusState(clientStore, pruneHeight) + deleteConsensusMetadata(clientStore, pruneHeight) + } +} + +// CheckForMisbehaviour detects duplicate height misbehaviour and BFT time violation misbehaviour +func (cs ClientState) CheckForMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, msg exported.ClientMessage) bool { + switch msg := msg.(type) { + case *Header: + tmHeader := msg + consState := tmHeader.ConsensusState() + + // Check if the Client store already has a consensus state for the header's height + // If the consensus state exists, and it matches the header then we return early + // since header has already been submitted in a previous UpdateClient. + existingConsState, _ := GetConsensusState(clientStore, cdc, tmHeader.GetHeight()) + if existingConsState != nil { + // This header has already been submitted and the necessary state is already stored + // in client store, thus we can return early without further validation. + if reflect.DeepEqual(existingConsState, tmHeader.ConsensusState()) { //nolint:gosimple + return false + } + + // A consensus state already exists for this height, but it does not match the provided header. + // The assumption is that Header has already been validated. Thus we can return true as misbehaviour is present + return true + } + + // Check that consensus state timestamps are monotonic + prevCons, prevOk := GetPreviousConsensusState(clientStore, cdc, tmHeader.GetHeight()) + nextCons, nextOk := GetNextConsensusState(clientStore, cdc, tmHeader.GetHeight()) + // if previous consensus state exists, check consensus state time is greater than previous consensus state time + // if previous consensus state is not before current consensus state return true + if prevOk && !prevCons.Timestamp.Before(consState.Timestamp) { + return true + } + // if next consensus state exists, check consensus state time is less than next consensus state time + // if next consensus state is not after current consensus state return true + if nextOk && !nextCons.Timestamp.After(consState.Timestamp) { + return true + } + case *Misbehaviour: + // The correctness of Misbehaviour ClientMessage types is ensured by calling VerifyClientMessage prior to this function + // Thus, here we can return true, as ClientMessage is of type Misbehaviour + return true + } + + return false +} + +// UpdateStateOnMisbehaviour updates state upon misbehaviour, freezing the ClientState. This method should only be called when misbehaviour is detected +// as it does not perform any misbehaviour checks. +func (cs ClientState) UpdateStateOnMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, _ exported.ClientMessage) { + cs.FrozenHeight = FrozenHeight + + clientStore.Set(host.ClientStateKey(), clienttypes.MustMarshalClientState(cdc, &cs)) +} + +// checkTrustedHeader checks that consensus state matches trusted fields of Header +func checkTrustedHeader(header *Header, consState *ConsensusState) error { + tmTrustedValidators, err := tmtypes.ValidatorSetFromProto(header.TrustedValidators) + if err != nil { + return sdkerrors.Wrap(err, "trusted validator set in not tendermint validator set type") + } + + // assert that trustedVals is NextValidators of last trusted header + // to do this, we check that trustedVals.Hash() == consState.NextValidatorsHash + tvalHash := tmTrustedValidators.Hash() + if !bytes.Equal(consState.NextValidatorsHash, tvalHash) { + return sdkerrors.Wrapf( + ErrInvalidValidatorSet, + "trusted validators %s, does not hash to latest trusted validators. Expected: %X, got: %X", + header.TrustedValidators, consState.NextValidatorsHash, tvalHash, + ) + } + return nil } diff --git a/modules/light-clients/07-tendermint/update_test.go b/modules/light-clients/07-tendermint/update_test.go new file mode 100644 index 00000000000..0b5b55eb1cc --- /dev/null +++ b/modules/light-clients/07-tendermint/update_test.go @@ -0,0 +1,745 @@ +package tendermint_test + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + tmtypes "github.com/tendermint/tendermint/types" + + clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v5/modules/core/24-host" + "github.com/cosmos/ibc-go/v5/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v5/testing" + ibctestingmock "github.com/cosmos/ibc-go/v5/testing/mock" +) + +func (suite *TendermintTestSuite) TestVerifyHeader() { + var ( + path *ibctesting.Path + header *ibctm.Header + ) + + // Setup different validators and signers for testing different types of updates + altPrivVal := ibctestingmock.NewPV() + altPubKey, err := altPrivVal.GetPubKey() + suite.Require().NoError(err) + + revisionHeight := int64(height.RevisionHeight) + + // create modified heights to use for test-cases + altVal := tmtypes.NewValidator(altPubKey, 100) + // Create alternative validator set with only altVal, invalid update (too much change in valSet) + altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal}) + altSigners := getAltSigners(altVal, altPrivVal) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + name: "success", + malleate: func() {}, + expPass: true, + }, + { + name: "successful verify header for header with a previous height", + malleate: func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + // passing the CurrentHeader.Height as the block height as it will become a previous height once we commit N blocks + header = suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers) + + // commit some blocks so that the created Header now has a previous height as the BlockHeight + suite.coordinator.CommitNBlocks(suite.chainB, 5) + + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + }, + expPass: true, + }, + { + name: "successful verify header: header with future height and different validator set", + malleate: func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + // Create bothValSet with both suite validator and altVal + bothValSet := tmtypes.NewValidatorSet(append(suite.chainB.Vals.Validators, altVal)) + bothSigners := suite.chainB.Signers + bothSigners[altVal.Address.String()] = altPrivVal + + header = suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height+5, trustedHeight, suite.chainB.CurrentHeader.Time, bothValSet, suite.chainB.NextVals, trustedVals, bothSigners) + }, + expPass: true, + }, + { + name: "successful verify header: header with next height and different validator set", + malleate: func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + // Create bothValSet with both suite validator and altVal + bothValSet := tmtypes.NewValidatorSet(append(suite.chainB.Vals.Validators, altVal)) + bothSigners := suite.chainB.Signers + bothSigners[altVal.Address.String()] = altPrivVal + + header = suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight, suite.chainB.CurrentHeader.Time, bothValSet, suite.chainB.NextVals, trustedVals, bothSigners) + }, + expPass: true, + }, + { + name: "unsuccessful updates, passed in incorrect trusted validators for given consensus state", + malleate: func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + // Create bothValSet with both suite validator and altVal + bothValSet := tmtypes.NewValidatorSet(append(suite.chainB.Vals.Validators, altVal)) + bothSigners := suite.chainB.Signers + bothSigners[altVal.Address.String()] = altPrivVal + + header = suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height+1, trustedHeight, suite.chainB.CurrentHeader.Time, bothValSet, bothValSet, bothValSet, bothSigners) + }, + expPass: false, + }, + { + name: "unsuccessful verify header with next height: update header mismatches nextValSetHash", + malleate: func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + // this will err as altValSet.Hash() != consState.NextValidatorsHash + header = suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height+1, trustedHeight, suite.chainB.CurrentHeader.Time, altValSet, altValSet, trustedVals, altSigners) + }, + expPass: false, + }, + { + name: "unsuccessful update with future height: too much change in validator set", + malleate: func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + header = suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height+1, trustedHeight, suite.chainB.CurrentHeader.Time, altValSet, altValSet, trustedVals, altSigners) + }, + expPass: false, + }, + { + name: "unsuccessful verify header: header height revision and trusted height revision mismatch", + malleate: func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + header = suite.chainB.CreateTMClientHeader(chainIDRevision1, 3, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers) + }, + expPass: false, + }, + { + name: "unsuccessful verify header: header height < consensus height", + malleate: func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + heightMinus1 := clienttypes.NewHeight(trustedHeight.RevisionNumber, trustedHeight.RevisionHeight-1) + + // Make new header at height less than latest client state + header = suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(heightMinus1.RevisionHeight), trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers) + }, + expPass: false, + }, + { + name: "unsuccessful verify header: header basic validation failed", + malleate: func() { + // cause header to fail validatebasic by changing commit height to mismatch header height + header.SignedHeader.Commit.Height = revisionHeight - 1 + }, + expPass: false, + }, + { + name: "unsuccessful verify header: header timestamp is not past last client timestamp", + malleate: func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight)) + suite.Require().True(found) + + header = suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height+1, trustedHeight, suite.chainB.CurrentHeader.Time.Add(-time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers) + }, + expPass: false, + }, + { + name: "unsuccessful verify header: header with incorrect header chain-id", + malleate: func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight)) + suite.Require().True(found) + + header = suite.chainB.CreateTMClientHeader(chainID, suite.chainB.CurrentHeader.Height+1, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers) + }, + expPass: false, + }, + { + name: "unsuccessful update: trusting period has passed since last client timestamp", + malleate: func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight)) + suite.Require().True(found) + + header = suite.chainA.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height+1, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers) + + suite.chainB.ExpireClient(ibctesting.TrustingPeriod) + }, + expPass: false, + }, + { + name: "unsuccessful update for a previous revision", + malleate: func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + // passing the CurrentHeader.Height as the block height as it will become an update to previous revision once we upgrade the client + header = suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers) + + // increment the revision of the chain + err = path.EndpointB.UpgradeChain() + suite.Require().NoError(err) + }, + expPass: false, + }, + { + name: "successful update with identical header to a previous update", + malleate: func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + // passing the CurrentHeader.Height as the block height as it will become a previous height once we commit N blocks + header = suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers) + + // update client so the header constructed becomes a duplicate + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + }, + expPass: true, + }, + + { + name: "unsuccessful update to a future revision", + malleate: func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + header = suite.chainB.CreateTMClientHeader(suite.chainB.ChainID+"-1", suite.chainB.CurrentHeader.Height+5, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers) + }, + expPass: false, + }, + + { + name: "unsuccessful update: header height revision and trusted height revision mismatch", + malleate: func() { + trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + trustedVals, found := suite.chainB.GetValsAtHeight(int64(trustedHeight.RevisionHeight) + 1) + suite.Require().True(found) + + // increment the revision of the chain + err = path.EndpointB.UpgradeChain() + suite.Require().NoError(err) + + header = suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.CurrentHeader.Height, trustedHeight, suite.chainB.CurrentHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers) + }, + expPass: false, + }, + } + + for _, tc := range testCases { + tc := tc + suite.SetupTest() + path = ibctesting.NewPath(suite.chainA, suite.chainB) + + err := path.EndpointA.CreateClient() + suite.Require().NoError(err) + + // ensure counterparty state is committed + suite.coordinator.CommitBlock(suite.chainB) + header, err = path.EndpointA.Chain.ConstructUpdateTMClientHeader(path.EndpointA.Counterparty.Chain, path.EndpointA.ClientID) + suite.Require().NoError(err) + + tc.malleate() + + clientState := path.EndpointA.GetClientState() + + clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + + err = clientState.VerifyClientMessage(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, header) + + if tc.expPass { + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Error(err) + } + } +} + +func (suite *TendermintTestSuite) TestUpdateState() { + var ( + path *ibctesting.Path + clientMessage exported.ClientMessage + clientStore sdk.KVStore + consensusHeights []exported.Height + pruneHeight clienttypes.Height + prevClientState exported.ClientState + prevConsensusState exported.ConsensusState + ) + + testCases := []struct { + name string + malleate func() + expResult func() + expPass bool + }{ + { + "success with height later than latest height", func() { + tmHeader, ok := clientMessage.(*ibctm.Header) + suite.Require().True(ok) + suite.Require().True(path.EndpointA.GetClientState().GetLatestHeight().LT(tmHeader.GetHeight())) + }, + func() { + tmHeader, ok := clientMessage.(*ibctm.Header) + suite.Require().True(ok) + + clientState := path.EndpointA.GetClientState() + suite.Require().True(clientState.GetLatestHeight().EQ(tmHeader.GetHeight())) // new update, updated client state should have changed + suite.Require().True(clientState.GetLatestHeight().EQ(consensusHeights[0])) + }, true, + }, + { + "success with height earlier than latest height", func() { + // commit a block so the pre-created ClientMessage + // isn't used to update the client to a newer height + suite.coordinator.CommitBlock(suite.chainB) + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + tmHeader, ok := clientMessage.(*ibctm.Header) + suite.Require().True(ok) + suite.Require().True(path.EndpointA.GetClientState().GetLatestHeight().GT(tmHeader.GetHeight())) + + prevClientState = path.EndpointA.GetClientState() + }, + func() { + clientState := path.EndpointA.GetClientState() + suite.Require().Equal(clientState, prevClientState) // fill in height, no change to client state + suite.Require().True(clientState.GetLatestHeight().GT(consensusHeights[0])) + }, true, + }, + { + "success with duplicate header", func() { + // update client in advance + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + // use the same header which just updated the client + clientMessage, err = path.EndpointA.Chain.ConstructUpdateTMClientHeader(path.EndpointA.Counterparty.Chain, path.EndpointA.ClientID) + suite.Require().NoError(err) + + tmHeader, ok := clientMessage.(*ibctm.Header) + suite.Require().True(ok) + suite.Require().Equal(path.EndpointA.GetClientState().GetLatestHeight(), tmHeader.GetHeight()) + + prevClientState = path.EndpointA.GetClientState() + prevConsensusState = path.EndpointA.GetConsensusState(tmHeader.GetHeight()) + }, + func() { + clientState := path.EndpointA.GetClientState() + suite.Require().Equal(clientState, prevClientState) + suite.Require().True(clientState.GetLatestHeight().EQ(consensusHeights[0])) + + tmHeader, ok := clientMessage.(*ibctm.Header) + suite.Require().True(ok) + suite.Require().Equal(path.EndpointA.GetConsensusState(tmHeader.GetHeight()), prevConsensusState) + }, true, + }, + { + "success with pruned consensus state", func() { + // this height will be expired and pruned + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + pruneHeight = path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + + // Increment the time by a week + suite.coordinator.IncrementTimeBy(7 * 24 * time.Hour) + + // create the consensus state that can be used as trusted height for next update + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + // 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) + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + // ensure counterparty state is committed + suite.coordinator.CommitBlock(suite.chainB) + clientMessage, err = path.EndpointA.Chain.ConstructUpdateTMClientHeader(path.EndpointA.Counterparty.Chain, path.EndpointA.ClientID) + suite.Require().NoError(err) + }, + func() { + tmHeader, ok := clientMessage.(*ibctm.Header) + suite.Require().True(ok) + + clientState := path.EndpointA.GetClientState() + suite.Require().True(clientState.GetLatestHeight().EQ(tmHeader.GetHeight())) // new update, updated client state should have changed + suite.Require().True(clientState.GetLatestHeight().EQ(consensusHeights[0])) + + // ensure consensus state was pruned + _, found := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, pruneHeight) + suite.Require().False(found) + }, true, + }, + { + "invalid ClientMessage type", func() { + clientMessage = &ibctm.Misbehaviour{} + }, + func() {}, + false, + }, + } + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() // reset + pruneHeight = clienttypes.ZeroHeight() + path = ibctesting.NewPath(suite.chainA, suite.chainB) + + err := path.EndpointA.CreateClient() + suite.Require().NoError(err) + + // ensure counterparty state is committed + suite.coordinator.CommitBlock(suite.chainB) + clientMessage, err = path.EndpointA.Chain.ConstructUpdateTMClientHeader(path.EndpointA.Counterparty.Chain, path.EndpointA.ClientID) + suite.Require().NoError(err) + + tc.malleate() + + clientState := path.EndpointA.GetClientState() + clientStore = suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + + if tc.expPass { + consensusHeights = clientState.UpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, clientMessage) + + header := clientMessage.(*ibctm.Header) + expConsensusState := &ibctm.ConsensusState{ + Timestamp: header.GetTime(), + Root: commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), + NextValidatorsHash: header.Header.NextValidatorsHash, + } + + bz := clientStore.Get(host.ConsensusStateKey(header.GetHeight())) + updatedConsensusState := clienttypes.MustUnmarshalConsensusState(suite.chainA.App.AppCodec(), bz) + + suite.Require().Equal(expConsensusState, updatedConsensusState) + + } else { + suite.Require().Panics(func() { + clientState.UpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, clientMessage) + }) + } + + // perform custom checks + tc.expResult() + }) + } +} + +func (suite *TendermintTestSuite) TestPruneConsensusState() { + // create path and setup clients + path := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupClients(path) + + // 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) + + // this height will be expired but not pruned + path.EndpointA.UpdateClient() + expiredHeight := path.EndpointA.GetClientState().GetLatestHeight() + + // expected values that must still remain in store after pruning + expectedConsState, ok := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, expiredHeight) + suite.Require().True(ok) + ctx = path.EndpointA.Chain.GetContext() + clientStore = path.EndpointA.Chain.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) + expectedProcessTime, ok := ibctm.GetProcessedTime(clientStore, expiredHeight) + suite.Require().True(ok) + expectedProcessHeight, ok := ibctm.GetProcessedHeight(clientStore, expiredHeight) + suite.Require().True(ok) + expectedConsKey := ibctm.GetIterationKey(clientStore, expiredHeight) + suite.Require().NotNil(expectedConsKey) + + // Increment the time by a week + suite.coordinator.IncrementTimeBy(7 * 24 * time.Hour) + + // create the consensus state that can be used as trusted height for next update + path.EndpointA.UpdateClient() + + // 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) + path.EndpointA.UpdateClient() + + ctx = path.EndpointA.Chain.GetContext() + clientStore = path.EndpointA.Chain.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) + + // check that the first expired consensus state got deleted along with all associated metadata + consState, ok := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, pruneHeight) + suite.Require().Nil(consState, "expired consensus state not pruned") + suite.Require().False(ok) + // check processed time metadata is pruned + processTime, ok := ibctm.GetProcessedTime(clientStore, pruneHeight) + suite.Require().Equal(uint64(0), processTime, "processed time metadata not pruned") + suite.Require().False(ok) + processHeight, ok := ibctm.GetProcessedHeight(clientStore, pruneHeight) + suite.Require().Nil(processHeight, "processed height metadata not pruned") + suite.Require().False(ok) + + // check iteration key metadata is pruned + consKey := ibctm.GetIterationKey(clientStore, pruneHeight) + suite.Require().Nil(consKey, "iteration key not pruned") + + // check that second expired consensus state doesn't get deleted + // this ensures that there is a cap on gas cost of UpdateClient + consState, ok = path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, expiredHeight) + suite.Require().Equal(expectedConsState, consState, "consensus state incorrectly pruned") + suite.Require().True(ok) + // check processed time metadata is not pruned + processTime, ok = ibctm.GetProcessedTime(clientStore, expiredHeight) + suite.Require().Equal(expectedProcessTime, processTime, "processed time metadata incorrectly pruned") + suite.Require().True(ok) + + // check processed height metadata is not pruned + processHeight, ok = ibctm.GetProcessedHeight(clientStore, expiredHeight) + suite.Require().Equal(expectedProcessHeight, processHeight, "processed height metadata incorrectly pruned") + suite.Require().True(ok) + + // check iteration key metadata is not pruned + consKey = ibctm.GetIterationKey(clientStore, expiredHeight) + suite.Require().Equal(expectedConsKey, consKey, "iteration key incorrectly pruned") +} + +func (suite *TendermintTestSuite) TestCheckForMisbehaviour() { + var ( + path *ibctesting.Path + clientMessage exported.ClientMessage + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "valid update no misbehaviour", + func() {}, + false, + }, + { + "consensus state already exists, already updated", + func() { + header, ok := clientMessage.(*ibctm.Header) + suite.Require().True(ok) + + consensusState := &ibctm.ConsensusState{ + Timestamp: header.GetTime(), + Root: commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), + NextValidatorsHash: header.Header.NextValidatorsHash, + } + + tmHeader, ok := clientMessage.(*ibctm.Header) + suite.Require().True(ok) + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), path.EndpointA.ClientID, tmHeader.GetHeight(), consensusState) + }, + false, + }, + { + "consensus state already exists, app hash mismatch", + func() { + header, ok := clientMessage.(*ibctm.Header) + suite.Require().True(ok) + + consensusState := &ibctm.ConsensusState{ + Timestamp: header.GetTime(), + Root: commitmenttypes.NewMerkleRoot([]byte{}), // empty bytes + NextValidatorsHash: header.Header.NextValidatorsHash, + } + + tmHeader, ok := clientMessage.(*ibctm.Header) + suite.Require().True(ok) + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), path.EndpointA.ClientID, tmHeader.GetHeight(), consensusState) + }, + true, + }, + { + "previous consensus state exists and header time is before previous consensus state time", + func() { + header, ok := clientMessage.(*ibctm.Header) + suite.Require().True(ok) + + // offset header timestamp before previous consensus state timestamp + header.Header.Time = header.GetTime().Add(-time.Hour) + }, + true, + }, + { + "next consensus state exists and header time is after next consensus state time", + func() { + header, ok := clientMessage.(*ibctm.Header) + suite.Require().True(ok) + + // commit block and update client, adding a new consensus state + suite.coordinator.CommitBlock(suite.chainB) + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + // increase timestamp of current header + header.Header.Time = header.Header.Time.Add(time.Hour) + }, + true, + }, + { + "valid fork misbehaviour returns true", + func() { + header1, err := path.EndpointA.Chain.ConstructUpdateTMClientHeader(path.EndpointA.Counterparty.Chain, path.EndpointA.ClientID) + suite.Require().NoError(err) + + // commit block and update client + suite.coordinator.CommitBlock(suite.chainB) + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + header2, err := path.EndpointA.Chain.ConstructUpdateTMClientHeader(path.EndpointA.Counterparty.Chain, path.EndpointA.ClientID) + suite.Require().NoError(err) + + // assign the same height, each header will have a different commit hash + header1.Header.Height = header2.Header.Height + + clientMessage = &ibctm.Misbehaviour{ + Header1: header1, + Header2: header2, + ClientId: path.EndpointA.ClientID, + } + }, + true, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + // reset suite to create fresh application state + suite.SetupTest() + path = ibctesting.NewPath(suite.chainA, suite.chainB) + + err := path.EndpointA.CreateClient() + suite.Require().NoError(err) + + // ensure counterparty state is committed + suite.coordinator.CommitBlock(suite.chainB) + clientMessage, err = path.EndpointA.Chain.ConstructUpdateTMClientHeader(path.EndpointA.Counterparty.Chain, path.EndpointA.ClientID) + suite.Require().NoError(err) + + tc.malleate() + + clientState := path.EndpointA.GetClientState() + clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + + foundMisbehaviour := clientState.CheckForMisbehaviour( + suite.chainA.GetContext(), + suite.chainA.App.AppCodec(), + clientStore, // pass in clientID prefixed clientStore + clientMessage, + ) + + if tc.expPass { + suite.Require().True(foundMisbehaviour) + } else { + suite.Require().False(foundMisbehaviour) + } + }) + } +} + +func (suite *TendermintTestSuite) TestUpdateStateOnMisbehaviour() { + var ( + path *ibctesting.Path + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + // reset suite to create fresh application state + suite.SetupTest() + path = ibctesting.NewPath(suite.chainA, suite.chainB) + + err := path.EndpointA.CreateClient() + suite.Require().NoError(err) + + tc.malleate() + + clientState := path.EndpointA.GetClientState() + clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + + clientState.UpdateStateOnMisbehaviour(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, nil) + + if tc.expPass { + clientStateBz := clientStore.Get(host.ClientStateKey()) + suite.Require().NotEmpty(clientStateBz) + + newClientState := clienttypes.MustUnmarshalClientState(suite.chainA.Codec, clientStateBz) + suite.Require().Equal(frozenHeight, newClientState.(*ibctm.ClientState).FrozenHeight) + } + }) + } +} diff --git a/modules/light-clients/07-tendermint/types/upgrade.go b/modules/light-clients/07-tendermint/upgrade.go similarity index 78% rename from modules/light-clients/07-tendermint/types/upgrade.go rename to modules/light-clients/07-tendermint/upgrade.go index 07ce9823d2e..277ced61273 100644 --- a/modules/light-clients/07-tendermint/types/upgrade.go +++ b/modules/light-clients/07-tendermint/upgrade.go @@ -1,4 +1,4 @@ -package types +package tendermint import ( "fmt" @@ -14,11 +14,11 @@ import ( ) // VerifyUpgradeAndUpdateState checks if the upgraded client has been committed by the current client -// It will zero out all client-specific fields (e.g. TrustingPeriod and verify all data +// It will zero out all client-specific fields (e.g. TrustingPeriod) and verify all data // in client state that must be the same across all valid Tendermint clients for the new chain. // VerifyUpgrade will return an error if: // - the upgradedClient is not a Tendermint ClientState -// - the lastest height of the client state does not have the same revision number or has a greater +// - the latest height of the client state does not have the same revision number or has a greater // height than the committed client. // - the height of upgraded client is not greater than that of current client // - the latest height of the new client does not match or is greater than the height in committed client @@ -28,16 +28,16 @@ func (cs ClientState) VerifyUpgradeAndUpdateState( ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, upgradedClient exported.ClientState, upgradedConsState exported.ConsensusState, proofUpgradeClient, proofUpgradeConsState []byte, -) (exported.ClientState, exported.ConsensusState, error) { +) error { if len(cs.UpgradePath) == 0 { - return nil, nil, sdkerrors.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade client, no upgrade path set") + return sdkerrors.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade client, no upgrade path set") } // last height of current counterparty chain must be client's latest height lastHeight := cs.GetLatestHeight() if !upgradedClient.GetLatestHeight().GT(lastHeight) { - return nil, nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidHeight, "upgraded client height %s must be at greater than current client height %s", + return sdkerrors.Wrapf(sdkerrors.ErrInvalidHeight, "upgraded client height %s must be at greater than current client height %s", upgradedClient.GetLatestHeight(), lastHeight) } @@ -46,52 +46,52 @@ func (cs ClientState) VerifyUpgradeAndUpdateState( // counterparty must also commit to the upgraded consensus state at a sub-path under the upgrade path specified tmUpgradeClient, ok := upgradedClient.(*ClientState) if !ok { - return nil, nil, sdkerrors.Wrapf(clienttypes.ErrInvalidClientType, "upgraded client must be Tendermint client. expected: %T got: %T", + return sdkerrors.Wrapf(clienttypes.ErrInvalidClientType, "upgraded client must be Tendermint client. expected: %T got: %T", &ClientState{}, upgradedClient) } tmUpgradeConsState, ok := upgradedConsState.(*ConsensusState) if !ok { - return nil, nil, sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "upgraded consensus state must be Tendermint consensus state. expected %T, got: %T", + return sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "upgraded consensus state must be Tendermint consensus state. expected %T, got: %T", &ConsensusState{}, upgradedConsState) } // unmarshal proofs var merkleProofClient, merkleProofConsState commitmenttypes.MerkleProof if err := cdc.Unmarshal(proofUpgradeClient, &merkleProofClient); err != nil { - return nil, nil, sdkerrors.Wrapf(commitmenttypes.ErrInvalidProof, "could not unmarshal client merkle proof: %v", err) + return sdkerrors.Wrapf(commitmenttypes.ErrInvalidProof, "could not unmarshal client merkle proof: %v", err) } if err := cdc.Unmarshal(proofUpgradeConsState, &merkleProofConsState); err != nil { - return nil, nil, sdkerrors.Wrapf(commitmenttypes.ErrInvalidProof, "could not unmarshal consensus state merkle proof: %v", err) + return sdkerrors.Wrapf(commitmenttypes.ErrInvalidProof, "could not unmarshal consensus state merkle proof: %v", err) } // Must prove against latest consensus state to ensure we are verifying against latest upgrade plan // This verifies that upgrade is intended for the provided revision, since committed client must exist // at this consensus state - consState, err := GetConsensusState(clientStore, cdc, lastHeight) - if err != nil { - return nil, nil, sdkerrors.Wrap(err, "could not retrieve consensus state for lastHeight") + consState, found := GetConsensusState(clientStore, cdc, lastHeight) + if !found { + return sdkerrors.Wrap(clienttypes.ErrConsensusStateNotFound, "could not retrieve consensus state for lastHeight") } // Verify client proof - bz, err := cdc.MarshalInterface(upgradedClient) + bz, err := cdc.MarshalInterface(upgradedClient.ZeroCustomFields()) if err != nil { - return nil, nil, sdkerrors.Wrapf(clienttypes.ErrInvalidClient, "could not marshal client state: %v", err) + return sdkerrors.Wrapf(clienttypes.ErrInvalidClient, "could not marshal client state: %v", err) } // construct clientState Merkle path upgradeClientPath := constructUpgradeClientMerklePath(cs.UpgradePath, lastHeight) if err := merkleProofClient.VerifyMembership(cs.ProofSpecs, consState.GetRoot(), upgradeClientPath, bz); err != nil { - return nil, nil, sdkerrors.Wrapf(err, "client state proof failed. Path: %s", upgradeClientPath.Pretty()) + return sdkerrors.Wrapf(err, "client state proof failed. Path: %s", upgradeClientPath.Pretty()) } // Verify consensus state proof bz, err = cdc.MarshalInterface(upgradedConsState) if err != nil { - return nil, nil, sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "could not marshal consensus state: %v", err) + return sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "could not marshal consensus state: %v", err) } // construct consensus state Merkle path upgradeConsStatePath := constructUpgradeConsStateMerklePath(cs.UpgradePath, lastHeight) if err := merkleProofConsState.VerifyMembership(cs.ProofSpecs, consState.GetRoot(), upgradeConsStatePath, bz); err != nil { - return nil, nil, sdkerrors.Wrapf(err, "consensus state proof failed. Path: %s", upgradeConsStatePath.Pretty()) + return sdkerrors.Wrapf(err, "consensus state proof failed. Path: %s", upgradeConsStatePath.Pretty()) } // Construct new client state and consensus state @@ -105,7 +105,7 @@ func (cs ClientState) VerifyUpgradeAndUpdateState( ) if err := newClientState.Validate(); err != nil { - return nil, nil, sdkerrors.Wrap(err, "updated client state failed basic validation") + return sdkerrors.Wrap(err, "updated client state failed basic validation") } // The new consensus state is merely used as a trusted kernel against which headers on the new @@ -119,10 +119,11 @@ func (cs ClientState) VerifyUpgradeAndUpdateState( tmUpgradeConsState.Timestamp, commitmenttypes.NewMerkleRoot([]byte(SentinelRoot)), tmUpgradeConsState.NextValidatorsHash, ) - // set metadata for this consensus state + setClientState(clientStore, cdc, newClientState) + setConsensusState(clientStore, cdc, newConsState, newClientState.LatestHeight) setConsensusMetadata(ctx, clientStore, tmUpgradeClient.LatestHeight) - return newClientState, newConsState, nil + return nil } // construct MerklePath for the committed client from upgradePath diff --git a/modules/light-clients/07-tendermint/types/upgrade_test.go b/modules/light-clients/07-tendermint/upgrade_test.go similarity index 93% rename from modules/light-clients/07-tendermint/types/upgrade_test.go rename to modules/light-clients/07-tendermint/upgrade_test.go index fb21057a1e7..301b64288c9 100644 --- a/modules/light-clients/07-tendermint/types/upgrade_test.go +++ b/modules/light-clients/07-tendermint/upgrade_test.go @@ -1,4 +1,4 @@ -package types_test +package tendermint_test import ( upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" @@ -6,14 +6,13 @@ import ( clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" "github.com/cosmos/ibc-go/v5/modules/core/exported" - "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v5/testing" ) -var newChainId = "newChainId-1" - func (suite *TendermintTestSuite) TestVerifyUpgrade() { var ( + newChainID string upgradedClient exported.ClientState upgradedConsState exported.ConsensusState lastHeight clienttypes.Height @@ -55,9 +54,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { { name: "successful upgrade to same revision", setup: func() { - upgradedHeight := clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+2)) - // don't use -1 suffix in chain id - upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, upgradedHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) + upgradedClient = ibctm.NewClientState(suite.chainB.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, clienttypes.NewHeight(clienttypes.ParseChainID(suite.chainB.ChainID), upgradedClient.GetLatestHeight().GetRevisionHeight()+10), commitmenttypes.GetSDKSpecs(), upgradePath, false, false) upgradedClient = upgradedClient.ZeroCustomFields() upgradedClientBz, err = clienttypes.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient) suite.Require().NoError(err) @@ -112,7 +109,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { name: "unsuccessful upgrade: committed client does not have zeroed custom fields", setup: func() { // non-zeroed upgrade client - upgradedClient = types.NewClientState(newChainId, types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) + upgradedClient = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) upgradedClientBz, err = clienttypes.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient) suite.Require().NoError(err) @@ -148,7 +145,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) // change upgradedClient client-specified parameters - upgradedClient = types.NewClientState("wrongchainID", types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, true, true) + upgradedClient = ibctm.NewClientState("wrongchainID", ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, true, true) suite.coordinator.CommitBlock(suite.chainB) err := path.EndpointA.UpdateClient() @@ -170,7 +167,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) // change upgradedClient client-specified parameters - upgradedClient = types.NewClientState(newChainId, types.DefaultTrustLevel, ubdPeriod, ubdPeriod+trustingPeriod, maxClockDrift+5, lastHeight, commitmenttypes.GetSDKSpecs(), upgradePath, true, false) + upgradedClient = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, ubdPeriod, ubdPeriod+trustingPeriod, maxClockDrift+5, lastHeight, commitmenttypes.GetSDKSpecs(), upgradePath, true, false) suite.coordinator.CommitBlock(suite.chainB) err := path.EndpointA.UpdateClient() @@ -195,7 +192,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) // change submitted upgradedConsensusState - upgradedConsState = &types.ConsensusState{ + upgradedConsState = &ibctm.ConsensusState{ NextValidatorsHash: []byte("maliciousValidators"), } @@ -299,7 +296,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) // SetClientState with empty upgrade path - tmClient, _ := cs.(*types.ClientState) + tmClient, _ := cs.(*ibctm.ClientState) tmClient.UpgradePath = []string{""} suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID, tmClient) }, @@ -401,7 +398,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { name: "unsuccessful upgrade: final client is not valid", setup: func() { // new client has smaller unbonding period such that old trusting period is no longer valid - upgradedClient = types.NewClientState(newChainId, types.DefaultTrustLevel, trustingPeriod, trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) + upgradedClient = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, trustingPeriod, trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) upgradedClientBz, err = clienttypes.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient) suite.Require().NoError(err) @@ -436,12 +433,20 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { path = ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(path) - upgradedClient = types.NewClientState(newChainId, types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) + + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) + revisionNumber := clienttypes.ParseChainID(clientState.ChainId) + + var err error + newChainID, err = clienttypes.SetRevisionNumber(clientState.ChainId, revisionNumber+1) + suite.Require().NoError(err) + + upgradedClient = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, clienttypes.NewHeight(revisionNumber+1, clientState.GetLatestHeight().GetRevisionHeight()+1), commitmenttypes.GetSDKSpecs(), upgradePath, false, false) upgradedClient = upgradedClient.ZeroCustomFields() upgradedClientBz, err = clienttypes.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient) suite.Require().NoError(err) - upgradedConsState = &types.ConsensusState{ + upgradedConsState = &ibctm.ConsensusState{ NextValidatorsHash: []byte("nextValsHash"), } upgradedConsStateBz, err = clienttypes.MarshalConsensusState(suite.chainA.App.AppCodec(), upgradedConsState) @@ -455,7 +460,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { // Call ZeroCustomFields on upgraded clients to clear any client-chosen parameters in test-case upgradedClient upgradedClient = upgradedClient.ZeroCustomFields() - clientState, consensusState, err := cs.VerifyUpgradeAndUpdateState( + err = cs.VerifyUpgradeAndUpdateState( suite.chainA.GetContext(), suite.cdc, clientStore, @@ -467,14 +472,15 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { if tc.expPass { suite.Require().NoError(err, "verify upgrade failed on valid case: %s", tc.name) + + clientState := suite.chainA.GetClientState(path.EndpointA.ClientID) suite.Require().NotNil(clientState, "verify upgrade failed on valid case: %s", tc.name) + + consensusState, found := suite.chainA.GetConsensusState(path.EndpointA.ClientID, clientState.GetLatestHeight()) suite.Require().NotNil(consensusState, "verify upgrade failed on valid case: %s", tc.name) + suite.Require().True(found) } else { suite.Require().Error(err, "verify upgrade passed on invalid case: %s", tc.name) - suite.Require().Nil(clientState, "verify upgrade passed on invalid case: %s", tc.name) - - suite.Require().Nil(consensusState, "verify upgrade passed on invalid case: %s", tc.name) - } } } diff --git a/modules/light-clients/09-localhost/doc.go b/modules/light-clients/09-localhost/doc.go deleted file mode 100644 index 40a0f060867..00000000000 --- a/modules/light-clients/09-localhost/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -/* -Package localhost implements a concrete `ConsensusState`, `Header`, -`Misbehaviour` and `Equivocation` types for the loop-back client. -*/ -package localhost diff --git a/modules/light-clients/09-localhost/module.go b/modules/light-clients/09-localhost/module.go deleted file mode 100644 index cf1615a8023..00000000000 --- a/modules/light-clients/09-localhost/module.go +++ /dev/null @@ -1,10 +0,0 @@ -package localhost - -import ( - "github.com/cosmos/ibc-go/v5/modules/light-clients/09-localhost/types" -) - -// Name returns the IBC client name -func Name() string { - return types.SubModuleName -} diff --git a/modules/light-clients/09-localhost/types/client_state.go b/modules/light-clients/09-localhost/types/client_state.go deleted file mode 100644 index ceda52b2354..00000000000 --- a/modules/light-clients/09-localhost/types/client_state.go +++ /dev/null @@ -1,340 +0,0 @@ -package types - -import ( - "bytes" - "encoding/binary" - "reflect" - "strings" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v5/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v5/modules/core/24-host" - "github.com/cosmos/ibc-go/v5/modules/core/exported" -) - -var _ exported.ClientState = (*ClientState)(nil) - -// NewClientState creates a new ClientState instance -func NewClientState(chainID string, height clienttypes.Height) *ClientState { - return &ClientState{ - ChainId: chainID, - Height: height, - } -} - -// GetChainID returns an empty string -func (cs ClientState) GetChainID() string { - return cs.ChainId -} - -// ClientType is localhost. -func (cs ClientState) ClientType() string { - return exported.Localhost -} - -// GetLatestHeight returns the latest height stored. -func (cs ClientState) GetLatestHeight() exported.Height { - return cs.Height -} - -// Status always returns Active. The localhost status cannot be changed. -func (cs ClientState) Status(_ sdk.Context, _ sdk.KVStore, _ codec.BinaryCodec, -) exported.Status { - return exported.Active -} - -// Validate performs a basic validation of the client state fields. -func (cs ClientState) Validate() error { - if strings.TrimSpace(cs.ChainId) == "" { - return sdkerrors.Wrap(sdkerrors.ErrInvalidChainID, "chain id cannot be blank") - } - if cs.Height.RevisionHeight == 0 { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidHeight, "local revision height cannot be zero") - } - return nil -} - -// ZeroCustomFields returns the same client state since there are no custom fields in localhost -func (cs ClientState) ZeroCustomFields() exported.ClientState { - return &cs -} - -// Initialize ensures that initial consensus state for localhost is nil -func (cs ClientState) Initialize(_ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, consState exported.ConsensusState) error { - if consState != nil { - return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "initial consensus state for localhost must be nil.") - } - return nil -} - -// ExportMetadata is a no-op for localhost client -func (cs ClientState) ExportMetadata(_ sdk.KVStore) []exported.GenesisMetadata { - return nil -} - -// CheckHeaderAndUpdateState updates the localhost client. It only needs access to the context -func (cs *ClientState) CheckHeaderAndUpdateState( - ctx sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, _ exported.Header, -) (exported.ClientState, exported.ConsensusState, error) { - // use the chain ID from context since the localhost client is from the running chain (i.e self). - cs.ChainId = ctx.ChainID() - revision := clienttypes.ParseChainID(cs.ChainId) - cs.Height = clienttypes.NewHeight(revision, uint64(ctx.BlockHeight())) - return cs, nil, nil -} - -// CheckMisbehaviourAndUpdateState implements ClientState -// Since localhost is the client of the running chain, misbehaviour cannot be submitted to it -// Thus, CheckMisbehaviourAndUpdateState returns an error for localhost -func (cs ClientState) CheckMisbehaviourAndUpdateState( - _ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, _ exported.Misbehaviour, -) (exported.ClientState, error) { - return nil, sdkerrors.Wrap(clienttypes.ErrInvalidMisbehaviour, "cannot submit misbehaviour to localhost client") -} - -// CheckSubstituteAndUpdateState returns an error. The localhost cannot be modified by -// proposals. -func (cs ClientState) CheckSubstituteAndUpdateState( - ctx sdk.Context, _ codec.BinaryCodec, _, _ sdk.KVStore, - _ exported.ClientState, -) (exported.ClientState, error) { - return nil, sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "cannot update localhost client with a proposal") -} - -// VerifyUpgradeAndUpdateState returns an error since localhost cannot be upgraded -func (cs ClientState) VerifyUpgradeAndUpdateState( - _ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, - _ exported.ClientState, _ exported.ConsensusState, _, _ []byte, -) (exported.ClientState, exported.ConsensusState, error) { - return nil, nil, sdkerrors.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade localhost client") -} - -// VerifyClientState verifies that the localhost client state is stored locally -func (cs ClientState) VerifyClientState( - store sdk.KVStore, cdc codec.BinaryCodec, - _ exported.Height, _ exported.Prefix, _ string, _ []byte, clientState exported.ClientState, -) error { - path := host.KeyClientState - bz := store.Get([]byte(path)) - if bz == nil { - return sdkerrors.Wrapf(clienttypes.ErrFailedClientStateVerification, - "not found for path: %s", path) - } - - selfClient := clienttypes.MustUnmarshalClientState(cdc, bz) - - if !reflect.DeepEqual(selfClient, clientState) { - return sdkerrors.Wrapf(clienttypes.ErrFailedClientStateVerification, - "stored clientState != provided clientState: \n%v\n≠\n%v", - selfClient, clientState, - ) - } - return nil -} - -// VerifyClientConsensusState returns nil since a local host client does not store consensus -// states. -func (cs ClientState) VerifyClientConsensusState( - sdk.KVStore, codec.BinaryCodec, - exported.Height, string, exported.Height, exported.Prefix, - []byte, exported.ConsensusState, -) error { - return nil -} - -// VerifyConnectionState verifies a proof of the connection state of the -// specified connection end stored locally. -func (cs ClientState) VerifyConnectionState( - store sdk.KVStore, - cdc codec.BinaryCodec, - _ exported.Height, - _ exported.Prefix, - _ []byte, - connectionID string, - connectionEnd exported.ConnectionI, -) error { - path := host.ConnectionKey(connectionID) - bz := store.Get(path) - if bz == nil { - return sdkerrors.Wrapf(clienttypes.ErrFailedConnectionStateVerification, "not found for path %s", path) - } - - var prevConnection connectiontypes.ConnectionEnd - err := cdc.Unmarshal(bz, &prevConnection) - if err != nil { - return err - } - - if !reflect.DeepEqual(&prevConnection, connectionEnd) { - return sdkerrors.Wrapf( - clienttypes.ErrFailedConnectionStateVerification, - "connection end ≠ previous stored connection: \n%v\n≠\n%v", connectionEnd, prevConnection, - ) - } - - return nil -} - -// VerifyChannelState verifies a proof of the channel state of the specified -// channel end, under the specified port, stored on the local machine. -func (cs ClientState) VerifyChannelState( - store sdk.KVStore, - cdc codec.BinaryCodec, - _ exported.Height, - prefix exported.Prefix, - _ []byte, - portID, - channelID string, - channel exported.ChannelI, -) error { - path := host.ChannelKey(portID, channelID) - bz := store.Get(path) - if bz == nil { - return sdkerrors.Wrapf(clienttypes.ErrFailedChannelStateVerification, "not found for path %s", path) - } - - var prevChannel channeltypes.Channel - err := cdc.Unmarshal(bz, &prevChannel) - if err != nil { - return err - } - - if !reflect.DeepEqual(&prevChannel, channel) { - return sdkerrors.Wrapf( - clienttypes.ErrFailedChannelStateVerification, - "channel end ≠ previous stored channel: \n%v\n≠\n%v", channel, prevChannel, - ) - } - - return nil -} - -// VerifyPacketCommitment verifies a proof of an outgoing packet commitment at -// the specified port, specified channel, and specified sequence. -func (cs ClientState) VerifyPacketCommitment( - ctx sdk.Context, - store sdk.KVStore, - _ codec.BinaryCodec, - _ exported.Height, - _ uint64, - _ uint64, - _ exported.Prefix, - _ []byte, - portID, - channelID string, - sequence uint64, - commitmentBytes []byte, -) error { - path := host.PacketCommitmentKey(portID, channelID, sequence) - - data := store.Get(path) - if len(data) == 0 { - return sdkerrors.Wrapf(clienttypes.ErrFailedPacketCommitmentVerification, "not found for path %s", path) - } - - if !bytes.Equal(data, commitmentBytes) { - return sdkerrors.Wrapf( - clienttypes.ErrFailedPacketCommitmentVerification, - "commitment ≠ previous commitment: \n%X\n≠\n%X", commitmentBytes, data, - ) - } - - return nil -} - -// VerifyPacketAcknowledgement verifies a proof of an incoming packet -// acknowledgement at the specified port, specified channel, and specified sequence. -func (cs ClientState) VerifyPacketAcknowledgement( - ctx sdk.Context, - store sdk.KVStore, - _ codec.BinaryCodec, - _ exported.Height, - _ uint64, - _ uint64, - _ exported.Prefix, - _ []byte, - portID, - channelID string, - sequence uint64, - acknowledgement []byte, -) error { - path := host.PacketAcknowledgementKey(portID, channelID, sequence) - - data := store.Get(path) - if len(data) == 0 { - return sdkerrors.Wrapf(clienttypes.ErrFailedPacketAckVerification, "not found for path %s", path) - } - - if !bytes.Equal(data, acknowledgement) { - return sdkerrors.Wrapf( - clienttypes.ErrFailedPacketAckVerification, - "ak bytes ≠ previous ack: \n%X\n≠\n%X", acknowledgement, data, - ) - } - - return nil -} - -// VerifyPacketReceiptAbsence verifies a proof of the absence of an -// incoming packet receipt at the specified port, specified channel, and -// specified sequence. -func (cs ClientState) VerifyPacketReceiptAbsence( - ctx sdk.Context, - store sdk.KVStore, - _ codec.BinaryCodec, - _ exported.Height, - _ uint64, - _ uint64, - _ exported.Prefix, - _ []byte, - portID, - channelID string, - sequence uint64, -) error { - path := host.PacketReceiptKey(portID, channelID, sequence) - - data := store.Get(path) - if data != nil { - return sdkerrors.Wrap(clienttypes.ErrFailedPacketReceiptVerification, "expected no packet receipt") - } - - return nil -} - -// VerifyNextSequenceRecv verifies a proof of the next sequence number to be -// received of the specified channel at the specified port. -func (cs ClientState) VerifyNextSequenceRecv( - ctx sdk.Context, - store sdk.KVStore, - _ codec.BinaryCodec, - _ exported.Height, - _ uint64, - _ uint64, - _ exported.Prefix, - _ []byte, - portID, - channelID string, - nextSequenceRecv uint64, -) error { - path := host.NextSequenceRecvKey(portID, channelID) - - data := store.Get(path) - if len(data) == 0 { - return sdkerrors.Wrapf(clienttypes.ErrFailedNextSeqRecvVerification, "not found for path %s", path) - } - - prevSequenceRecv := binary.BigEndian.Uint64(data) - if prevSequenceRecv != nextSequenceRecv { - return sdkerrors.Wrapf( - clienttypes.ErrFailedNextSeqRecvVerification, - "next sequence receive ≠ previous stored sequence (%d ≠ %d)", nextSequenceRecv, prevSequenceRecv, - ) - } - - return nil -} diff --git a/modules/light-clients/09-localhost/types/client_state_test.go b/modules/light-clients/09-localhost/types/client_state_test.go deleted file mode 100644 index 83eb0e8ea51..00000000000 --- a/modules/light-clients/09-localhost/types/client_state_test.go +++ /dev/null @@ -1,526 +0,0 @@ -package types_test - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - - clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v5/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v5/modules/core/24-host" - "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" - "github.com/cosmos/ibc-go/v5/modules/light-clients/09-localhost/types" -) - -const ( - testConnectionID = "connectionid" - testPortID = "testportid" - testChannelID = "testchannelid" - testSequence = 1 -) - -func (suite *LocalhostTestSuite) TestStatus() { - clientState := types.NewClientState("chainID", clienttypes.NewHeight(3, 10)) - - // localhost should always return active - status := clientState.Status(suite.ctx, nil, nil) - suite.Require().Equal(exported.Active, status) -} - -func (suite *LocalhostTestSuite) TestValidate() { - testCases := []struct { - name string - clientState *types.ClientState - expPass bool - }{ - { - name: "valid client", - clientState: types.NewClientState("chainID", clienttypes.NewHeight(3, 10)), - expPass: true, - }, - { - name: "invalid chain id", - clientState: types.NewClientState(" ", clienttypes.NewHeight(3, 10)), - expPass: false, - }, - { - name: "invalid height", - clientState: types.NewClientState("chainID", clienttypes.ZeroHeight()), - expPass: false, - }, - } - - for _, tc := range testCases { - err := tc.clientState.Validate() - if tc.expPass { - suite.Require().NoError(err, tc.name) - } else { - suite.Require().Error(err, tc.name) - } - } -} - -func (suite *LocalhostTestSuite) TestInitialize() { - testCases := []struct { - name string - consState exported.ConsensusState - expPass bool - }{ - { - "valid initialization", - nil, - true, - }, - { - "invalid consenus state", - &ibctmtypes.ConsensusState{}, - false, - }, - } - - clientState := types.NewClientState("chainID", clienttypes.NewHeight(3, 10)) - - for _, tc := range testCases { - err := clientState.Initialize(suite.ctx, suite.cdc, suite.store, tc.consState) - - if tc.expPass { - suite.Require().NoError(err, "valid testcase: %s failed", tc.name) - } else { - suite.Require().Error(err, "invalid testcase: %s passed", tc.name) - } - } -} - -func (suite *LocalhostTestSuite) TestVerifyClientState() { - clientState := types.NewClientState("chainID", clientHeight) - invalidClient := types.NewClientState("chainID", clienttypes.NewHeight(0, 12)) - - testCases := []struct { - name string - clientState *types.ClientState - malleate func() - counterparty *types.ClientState - expPass bool - }{ - { - name: "proof verification success", - clientState: clientState, - malleate: func() { - bz := clienttypes.MustMarshalClientState(suite.cdc, clientState) - suite.store.Set(host.ClientStateKey(), bz) - }, - counterparty: clientState, - expPass: true, - }, - { - name: "proof verification failed: invalid client", - clientState: clientState, - malleate: func() { - bz := clienttypes.MustMarshalClientState(suite.cdc, clientState) - suite.store.Set(host.ClientStateKey(), bz) - }, - counterparty: invalidClient, - expPass: false, - }, - { - name: "proof verification failed: client not stored", - clientState: clientState, - malleate: func() {}, - counterparty: clientState, - expPass: false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() - tc.malleate() - - err := tc.clientState.VerifyClientState( - suite.store, suite.cdc, clienttypes.NewHeight(0, 10), nil, "", []byte{}, tc.counterparty, - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -func (suite *LocalhostTestSuite) TestVerifyClientConsensusState() { - clientState := types.NewClientState("chainID", clientHeight) - err := clientState.VerifyClientConsensusState( - nil, nil, nil, "", nil, nil, nil, nil, - ) - suite.Require().NoError(err) -} - -func (suite *LocalhostTestSuite) TestCheckHeaderAndUpdateState() { - clientState := types.NewClientState("chainID", clientHeight) - cs, _, err := clientState.CheckHeaderAndUpdateState(suite.ctx, nil, nil, nil) - suite.Require().NoError(err) - suite.Require().Equal(uint64(0), cs.GetLatestHeight().GetRevisionNumber()) - suite.Require().Equal(suite.ctx.BlockHeight(), int64(cs.GetLatestHeight().GetRevisionHeight())) - suite.Require().Equal(suite.ctx.BlockHeader().ChainID, clientState.ChainId) -} - -func (suite *LocalhostTestSuite) TestMisbehaviourAndUpdateState() { - clientState := types.NewClientState("chainID", clientHeight) - cs, err := clientState.CheckMisbehaviourAndUpdateState(suite.ctx, nil, nil, nil) - suite.Require().Error(err) - suite.Require().Nil(cs) -} - -func (suite *LocalhostTestSuite) TestProposedHeaderAndUpdateState() { - clientState := types.NewClientState("chainID", clientHeight) - cs, err := clientState.CheckSubstituteAndUpdateState(suite.ctx, nil, nil, nil, nil) - suite.Require().Error(err) - suite.Require().Nil(cs) -} - -func (suite *LocalhostTestSuite) TestVerifyConnectionState() { - counterparty := connectiontypes.NewCounterparty("clientB", testConnectionID, commitmenttypes.NewMerklePrefix([]byte("ibc"))) - conn1 := connectiontypes.NewConnectionEnd(connectiontypes.OPEN, "clientA", counterparty, []*connectiontypes.Version{connectiontypes.NewVersion("1", nil)}, 0) - conn2 := connectiontypes.NewConnectionEnd(connectiontypes.OPEN, "clientA", counterparty, []*connectiontypes.Version{connectiontypes.NewVersion("2", nil)}, 0) - - testCases := []struct { - name string - clientState *types.ClientState - malleate func() - connection connectiontypes.ConnectionEnd - expPass bool - }{ - { - name: "proof verification success", - clientState: types.NewClientState("chainID", clientHeight), - malleate: func() { - bz, err := suite.cdc.Marshal(&conn1) - suite.Require().NoError(err) - suite.store.Set(host.ConnectionKey(testConnectionID), bz) - }, - connection: conn1, - expPass: true, - }, - { - name: "proof verification failed: connection not stored", - clientState: types.NewClientState("chainID", clientHeight), - malleate: func() {}, - connection: conn1, - expPass: false, - }, - { - name: "proof verification failed: unmarshal error", - clientState: types.NewClientState("chainID", clientHeight), - malleate: func() { - suite.store.Set(host.ConnectionKey(testConnectionID), []byte("connection")) - }, - connection: conn1, - expPass: false, - }, - { - name: "proof verification failed: different connection stored", - clientState: types.NewClientState("chainID", clientHeight), - malleate: func() { - bz, err := suite.cdc.Marshal(&conn2) - suite.Require().NoError(err) - suite.store.Set(host.ConnectionKey(testConnectionID), bz) - }, - connection: conn1, - expPass: false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() - tc.malleate() - - err := tc.clientState.VerifyConnectionState( - suite.store, suite.cdc, clientHeight, nil, []byte{}, testConnectionID, &tc.connection, - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -func (suite *LocalhostTestSuite) TestVerifyChannelState() { - counterparty := channeltypes.NewCounterparty(testPortID, testChannelID) - ch1 := channeltypes.NewChannel(channeltypes.OPEN, channeltypes.ORDERED, counterparty, []string{testConnectionID}, "1.0.0") - ch2 := channeltypes.NewChannel(channeltypes.OPEN, channeltypes.ORDERED, counterparty, []string{testConnectionID}, "2.0.0") - - testCases := []struct { - name string - clientState *types.ClientState - malleate func() - channel channeltypes.Channel - expPass bool - }{ - { - name: "proof verification success", - clientState: types.NewClientState("chainID", clientHeight), - malleate: func() { - bz, err := suite.cdc.Marshal(&ch1) - suite.Require().NoError(err) - suite.store.Set(host.ChannelKey(testPortID, testChannelID), bz) - }, - channel: ch1, - expPass: true, - }, - { - name: "proof verification failed: channel not stored", - clientState: types.NewClientState("chainID", clientHeight), - malleate: func() {}, - channel: ch1, - expPass: false, - }, - { - name: "proof verification failed: unmarshal failed", - clientState: types.NewClientState("chainID", clientHeight), - malleate: func() { - suite.store.Set(host.ChannelKey(testPortID, testChannelID), []byte("channel")) - }, - channel: ch1, - expPass: false, - }, - { - name: "proof verification failed: different channel stored", - clientState: types.NewClientState("chainID", clientHeight), - malleate: func() { - bz, err := suite.cdc.Marshal(&ch2) - suite.Require().NoError(err) - suite.store.Set(host.ChannelKey(testPortID, testChannelID), bz) - }, - channel: ch1, - expPass: false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() - tc.malleate() - - err := tc.clientState.VerifyChannelState( - suite.store, suite.cdc, clientHeight, nil, []byte{}, testPortID, testChannelID, &tc.channel, - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -func (suite *LocalhostTestSuite) TestVerifyPacketCommitment() { - testCases := []struct { - name string - clientState *types.ClientState - malleate func() - commitment []byte - expPass bool - }{ - { - name: "proof verification success", - clientState: types.NewClientState("chainID", clientHeight), - malleate: func() { - suite.store.Set( - host.PacketCommitmentKey(testPortID, testChannelID, testSequence), []byte("commitment"), - ) - }, - commitment: []byte("commitment"), - expPass: true, - }, - { - name: "proof verification failed: different commitment stored", - clientState: types.NewClientState("chainID", clientHeight), - malleate: func() { - suite.store.Set( - host.PacketCommitmentKey(testPortID, testChannelID, testSequence), []byte("different"), - ) - }, - commitment: []byte("commitment"), - expPass: false, - }, - { - name: "proof verification failed: no commitment stored", - clientState: types.NewClientState("chainID", clientHeight), - malleate: func() {}, - commitment: []byte{}, - expPass: false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() - tc.malleate() - - err := tc.clientState.VerifyPacketCommitment( - suite.ctx, suite.store, suite.cdc, clientHeight, 0, 0, nil, []byte{}, testPortID, testChannelID, testSequence, tc.commitment, - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -func (suite *LocalhostTestSuite) TestVerifyPacketAcknowledgement() { - testCases := []struct { - name string - clientState *types.ClientState - malleate func() - ack []byte - expPass bool - }{ - { - name: "proof verification success", - clientState: types.NewClientState("chainID", clientHeight), - malleate: func() { - suite.store.Set( - host.PacketAcknowledgementKey(testPortID, testChannelID, testSequence), []byte("acknowledgement"), - ) - }, - ack: []byte("acknowledgement"), - expPass: true, - }, - { - name: "proof verification failed: different ack stored", - clientState: types.NewClientState("chainID", clientHeight), - malleate: func() { - suite.store.Set( - host.PacketAcknowledgementKey(testPortID, testChannelID, testSequence), []byte("different"), - ) - }, - ack: []byte("acknowledgement"), - expPass: false, - }, - { - name: "proof verification failed: no commitment stored", - clientState: types.NewClientState("chainID", clientHeight), - malleate: func() {}, - ack: []byte{}, - expPass: false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() - tc.malleate() - - err := tc.clientState.VerifyPacketAcknowledgement( - suite.ctx, suite.store, suite.cdc, clientHeight, 0, 0, nil, []byte{}, testPortID, testChannelID, testSequence, tc.ack, - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -func (suite *LocalhostTestSuite) TestVerifyPacketReceiptAbsence() { - clientState := types.NewClientState("chainID", clientHeight) - - err := clientState.VerifyPacketReceiptAbsence( - suite.ctx, suite.store, suite.cdc, clientHeight, 0, 0, nil, nil, testPortID, testChannelID, testSequence, - ) - - suite.Require().NoError(err, "receipt absence failed") - - suite.store.Set(host.PacketReceiptKey(testPortID, testChannelID, testSequence), []byte("receipt")) - - err = clientState.VerifyPacketReceiptAbsence( - suite.ctx, suite.store, suite.cdc, clientHeight, 0, 0, nil, nil, testPortID, testChannelID, testSequence, - ) - suite.Require().Error(err, "receipt exists in store") -} - -func (suite *LocalhostTestSuite) TestVerifyNextSeqRecv() { - nextSeqRecv := uint64(5) - - testCases := []struct { - name string - clientState *types.ClientState - malleate func() - nextSeqRecv uint64 - expPass bool - }{ - { - name: "proof verification success", - clientState: types.NewClientState("chainID", clientHeight), - malleate: func() { - suite.store.Set( - host.NextSequenceRecvKey(testPortID, testChannelID), - sdk.Uint64ToBigEndian(nextSeqRecv), - ) - }, - nextSeqRecv: nextSeqRecv, - expPass: true, - }, - { - name: "proof verification failed: different nextSeqRecv stored", - clientState: types.NewClientState("chainID", clientHeight), - malleate: func() { - suite.store.Set( - host.NextSequenceRecvKey(testPortID, testChannelID), - sdk.Uint64ToBigEndian(3), - ) - }, - nextSeqRecv: nextSeqRecv, - expPass: false, - }, - { - name: "proof verification failed: no nextSeqRecv stored", - clientState: types.NewClientState("chainID", clientHeight), - malleate: func() {}, - nextSeqRecv: nextSeqRecv, - expPass: false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() - tc.malleate() - - err := tc.clientState.VerifyNextSequenceRecv( - suite.ctx, suite.store, suite.cdc, clientHeight, 0, 0, nil, []byte{}, testPortID, testChannelID, nextSeqRecv, - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} diff --git a/modules/light-clients/09-localhost/types/codec.go b/modules/light-clients/09-localhost/types/codec.go deleted file mode 100644 index 0e0a31d31d7..00000000000 --- a/modules/light-clients/09-localhost/types/codec.go +++ /dev/null @@ -1,16 +0,0 @@ -package types - -import ( - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - - "github.com/cosmos/ibc-go/v5/modules/core/exported" -) - -// RegisterInterfaces register the ibc interfaces submodule implementations to protobuf -// Any. -func RegisterInterfaces(registry codectypes.InterfaceRegistry) { - registry.RegisterImplementations( - (*exported.ClientState)(nil), - &ClientState{}, - ) -} diff --git a/modules/light-clients/09-localhost/types/errors.go b/modules/light-clients/09-localhost/types/errors.go deleted file mode 100644 index 57ad7c1f6a6..00000000000 --- a/modules/light-clients/09-localhost/types/errors.go +++ /dev/null @@ -1,10 +0,0 @@ -package types - -import ( - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -// Localhost sentinel errors -var ( - ErrConsensusStatesNotStored = sdkerrors.Register(SubModuleName, 2, "localhost does not store consensus states") -) diff --git a/modules/light-clients/09-localhost/types/keys.go b/modules/light-clients/09-localhost/types/keys.go deleted file mode 100644 index 2fe7c7e48f5..00000000000 --- a/modules/light-clients/09-localhost/types/keys.go +++ /dev/null @@ -1,6 +0,0 @@ -package types - -const ( - // SubModuleName for the localhost (loopback) client - SubModuleName = "localhost" -) diff --git a/modules/light-clients/09-localhost/types/localhost.pb.go b/modules/light-clients/09-localhost/types/localhost.pb.go deleted file mode 100644 index 7c674191e64..00000000000 --- a/modules/light-clients/09-localhost/types/localhost.pb.go +++ /dev/null @@ -1,369 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: ibc/lightclients/localhost/v1/localhost.proto - -package types - -import ( - fmt "fmt" - types "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/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 - -// ClientState defines a loopback (localhost) client. It requires (read-only) -// access to keys outside the client prefix. -type ClientState struct { - // self chain ID - ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty" yaml:"chain_id"` - // self latest block height - Height types.Height `protobuf:"bytes,2,opt,name=height,proto3" json:"height"` -} - -func (m *ClientState) Reset() { *m = ClientState{} } -func (m *ClientState) String() string { return proto.CompactTextString(m) } -func (*ClientState) ProtoMessage() {} -func (*ClientState) Descriptor() ([]byte, []int) { - return fileDescriptor_acd9f5b22d41bf6d, []int{0} -} -func (m *ClientState) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ClientState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ClientState.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 *ClientState) XXX_Merge(src proto.Message) { - xxx_messageInfo_ClientState.Merge(m, src) -} -func (m *ClientState) XXX_Size() int { - return m.Size() -} -func (m *ClientState) XXX_DiscardUnknown() { - xxx_messageInfo_ClientState.DiscardUnknown(m) -} - -var xxx_messageInfo_ClientState proto.InternalMessageInfo - -func init() { - proto.RegisterType((*ClientState)(nil), "ibc.lightclients.localhost.v1.ClientState") -} - -func init() { - proto.RegisterFile("ibc/lightclients/localhost/v1/localhost.proto", fileDescriptor_acd9f5b22d41bf6d) -} - -var fileDescriptor_acd9f5b22d41bf6d = []byte{ - // 288 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0xcd, 0x4c, 0x4a, 0xd6, - 0xcf, 0xc9, 0x4c, 0xcf, 0x28, 0x49, 0xce, 0xc9, 0x4c, 0xcd, 0x2b, 0x29, 0xd6, 0xcf, 0xc9, 0x4f, - 0x4e, 0xcc, 0xc9, 0xc8, 0x2f, 0x2e, 0xd1, 0x2f, 0x33, 0x44, 0x70, 0xf4, 0x0a, 0x8a, 0xf2, 0x4b, - 0xf2, 0x85, 0x64, 0x33, 0x93, 0x92, 0xf5, 0x90, 0x95, 0xeb, 0x21, 0x54, 0x94, 0x19, 0x4a, 0x89, - 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0x55, 0xea, 0x83, 0x58, 0x10, 0x4d, 0x52, 0xf2, 0x20, 0x3b, 0x92, - 0xf3, 0x8b, 0x52, 0xf5, 0x21, 0x9a, 0x40, 0x06, 0x43, 0x58, 0x10, 0x05, 0x4a, 0xb5, 0x5c, 0xdc, - 0xce, 0x60, 0x7e, 0x70, 0x49, 0x62, 0x49, 0xaa, 0x90, 0x1e, 0x17, 0x47, 0x72, 0x46, 0x62, 0x66, - 0x5e, 0x7c, 0x66, 0x8a, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0xa7, 0x93, 0xf0, 0xa7, 0x7b, 0xf2, 0xfc, - 0x95, 0x89, 0xb9, 0x39, 0x56, 0x4a, 0x30, 0x19, 0xa5, 0x20, 0x76, 0x30, 0xd3, 0x33, 0x45, 0xc8, - 0x82, 0x8b, 0x2d, 0x23, 0x15, 0xe4, 0x26, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x6e, 0x23, 0x29, 0x3d, - 0x90, 0x2b, 0x41, 0x16, 0xea, 0x41, 0xad, 0x29, 0x33, 0xd4, 0xf3, 0x00, 0xab, 0x70, 0x62, 0x39, - 0x71, 0x4f, 0x9e, 0x21, 0x08, 0xaa, 0xde, 0x8a, 0xa5, 0x63, 0x81, 0x3c, 0x83, 0x53, 0xdc, 0x89, - 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, - 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0xb9, 0xa4, 0x67, 0x96, 0x64, 0x94, 0x26, - 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x27, 0xe7, 0x17, 0xe7, 0xe6, 0x17, 0xeb, 0x67, 0x26, 0x25, 0xeb, - 0xa6, 0xe7, 0xeb, 0x97, 0x99, 0xea, 0xe7, 0xe6, 0xa7, 0x94, 0xe6, 0xa4, 0x16, 0x43, 0x42, 0x4f, - 0x17, 0x16, 0x7c, 0x06, 0x96, 0xba, 0x88, 0x10, 0x2c, 0xa9, 0x2c, 0x48, 0x2d, 0x4e, 0x62, 0x03, - 0xfb, 0xd2, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x75, 0xe7, 0x2e, 0x11, 0x6c, 0x01, 0x00, 0x00, -} - -func (m *ClientState) 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 *ClientState) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ClientState) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - { - size, err := m.Height.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintLocalhost(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - if len(m.ChainId) > 0 { - i -= len(m.ChainId) - copy(dAtA[i:], m.ChainId) - i = encodeVarintLocalhost(dAtA, i, uint64(len(m.ChainId))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintLocalhost(dAtA []byte, offset int, v uint64) int { - offset -= sovLocalhost(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *ClientState) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.ChainId) - if l > 0 { - n += 1 + l + sovLocalhost(uint64(l)) - } - l = m.Height.Size() - n += 1 + l + sovLocalhost(uint64(l)) - return n -} - -func sovLocalhost(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozLocalhost(x uint64) (n int) { - return sovLocalhost(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *ClientState) 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 ErrIntOverflowLocalhost - } - 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: ClientState: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ClientState: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowLocalhost - } - 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 ErrInvalidLengthLocalhost - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthLocalhost - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ChainId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - 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 ErrIntOverflowLocalhost - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthLocalhost - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthLocalhost - } - 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 := skipLocalhost(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthLocalhost - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipLocalhost(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, ErrIntOverflowLocalhost - } - 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, ErrIntOverflowLocalhost - } - 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, ErrIntOverflowLocalhost - } - 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, ErrInvalidLengthLocalhost - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupLocalhost - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthLocalhost - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthLocalhost = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowLocalhost = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupLocalhost = fmt.Errorf("proto: unexpected end of group") -) diff --git a/modules/light-clients/09-localhost/types/localhost_test.go b/modules/light-clients/09-localhost/types/localhost_test.go deleted file mode 100644 index 50bfdcb62f9..00000000000 --- a/modules/light-clients/09-localhost/types/localhost_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package types_test - -import ( - "testing" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/suite" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - - clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v5/modules/core/exported" - "github.com/cosmos/ibc-go/v5/testing/simapp" -) - -const ( - height = 4 -) - -var clientHeight = clienttypes.NewHeight(0, 10) - -type LocalhostTestSuite struct { - suite.Suite - - cdc codec.Codec - ctx sdk.Context - store sdk.KVStore -} - -func (suite *LocalhostTestSuite) SetupTest() { - isCheckTx := false - app := simapp.Setup(isCheckTx) - - suite.cdc = app.AppCodec() - suite.ctx = app.BaseApp.NewContext(isCheckTx, tmproto.Header{Height: 1, ChainID: "ibc-chain"}) - suite.store = app.IBCKeeper.ClientKeeper.ClientStore(suite.ctx, exported.Localhost) -} - -func TestLocalhostTestSuite(t *testing.T) { - suite.Run(t, new(LocalhostTestSuite)) -} diff --git a/proto/ibc/core/client/v1/tx.proto b/proto/ibc/core/client/v1/tx.proto index 8e716226d95..27f81917e4c 100644 --- a/proto/ibc/core/client/v1/tx.proto +++ b/proto/ibc/core/client/v1/tx.proto @@ -40,15 +40,15 @@ message MsgCreateClient { message MsgCreateClientResponse {} // MsgUpdateClient defines an sdk.Msg to update a IBC client state using -// the given header. +// the given client message. message MsgUpdateClient { option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; // client unique identifier string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; - // header to update the light client - google.protobuf.Any header = 2; + // client message to update the light client + google.protobuf.Any client_message = 2; // signer address string signer = 3; } @@ -82,16 +82,17 @@ message MsgUpgradeClientResponse {} // MsgSubmitMisbehaviour defines an sdk.Msg type that submits Evidence for // light client misbehaviour. +// Warning: DEPRECATED message MsgSubmitMisbehaviour { option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; // client unique identifier - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; + string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\"", deprecated = true]; // misbehaviour used for freezing the light client - google.protobuf.Any misbehaviour = 2; + google.protobuf.Any misbehaviour = 2 [deprecated = true]; // signer address - string signer = 3; + string signer = 3 [deprecated = true]; } // MsgSubmitMisbehaviourResponse defines the Msg/SubmitMisbehaviour response diff --git a/proto/ibc/lightclients/localhost/v1/localhost.proto b/proto/ibc/lightclients/localhost/v1/localhost.proto deleted file mode 100644 index 909c4ebcef5..00000000000 --- a/proto/ibc/lightclients/localhost/v1/localhost.proto +++ /dev/null @@ -1,18 +0,0 @@ -syntax = "proto3"; - -package ibc.lightclients.localhost.v1; - -option go_package = "github.com/cosmos/ibc-go/v5/modules/light-clients/09-localhost/types"; - -import "gogoproto/gogo.proto"; -import "ibc/core/client/v1/client.proto"; - -// ClientState defines a loopback (localhost) client. It requires (read-only) -// access to keys outside the client prefix. -message ClientState { - option (gogoproto.goproto_getters) = false; - // self chain ID - string chain_id = 1 [(gogoproto.moretags) = "yaml:\"chain_id\""]; - // self latest block height - ibc.core.client.v1.Height height = 2 [(gogoproto.nullable) = false]; -} diff --git a/proto/ibc/lightclients/solomachine/v2/solomachine.proto b/proto/ibc/lightclients/solomachine/v2/solomachine.proto index 61dcc45b2d7..5cc5ba9c551 100644 --- a/proto/ibc/lightclients/solomachine/v2/solomachine.proto +++ b/proto/ibc/lightclients/solomachine/v2/solomachine.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.lightclients.solomachine.v2; -option go_package = "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine/types"; +option go_package = "github.com/cosmos/ibc-go/v5/modules/core/02-client/migrations/v6"; import "ibc/core/connection/v1/connection.proto"; import "ibc/core/channel/v1/channel.proto"; diff --git a/proto/ibc/lightclients/solomachine/v3/solomachine.proto b/proto/ibc/lightclients/solomachine/v3/solomachine.proto new file mode 100644 index 00000000000..5475a16bd93 --- /dev/null +++ b/proto/ibc/lightclients/solomachine/v3/solomachine.proto @@ -0,0 +1,103 @@ +syntax = "proto3"; + +package ibc.lightclients.solomachine.v3; + +option go_package = "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine;solomachine"; + +import "gogoproto/gogo.proto"; +import "google/protobuf/any.proto"; + +// ClientState defines a solo machine client that tracks the current consensus +// state and if the client is frozen. +message ClientState { + option (gogoproto.goproto_getters) = false; + // latest sequence of the client state + uint64 sequence = 1; + // frozen sequence of the solo machine + bool is_frozen = 2 [(gogoproto.moretags) = "yaml:\"is_frozen\""]; + ConsensusState consensus_state = 3 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; + // when set to true, will allow governance to update a solo machine client. + // The client will be unfrozen if it is frozen. + bool allow_update_after_proposal = 4 [(gogoproto.moretags) = "yaml:\"allow_update_after_proposal\""]; +} + +// ConsensusState defines a solo machine consensus state. The sequence of a +// consensus state is contained in the "height" key used in storing the +// consensus state. +message ConsensusState { + option (gogoproto.goproto_getters) = false; + // public key of the solo machine + google.protobuf.Any public_key = 1 [(gogoproto.moretags) = "yaml:\"public_key\""]; + // diversifier allows the same public key to be re-used across different solo + // machine clients (potentially on different chains) without being considered + // misbehaviour. + string diversifier = 2; + uint64 timestamp = 3; +} + +// Header defines a solo machine consensus header +message Header { + option (gogoproto.goproto_getters) = false; + // sequence to update solo machine public key at + 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\""]; +} + +// Misbehaviour defines misbehaviour for a solo machine which consists +// of a sequence and two signatures over different messages at that sequence. +message Misbehaviour { + option (gogoproto.goproto_getters) = false; + + // ClientID is deprecated + string client_id = 1 [deprecated = true, (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\""]; +} + +// SignatureAndData contains a signature and the data signed over to create that +// signature. +message SignatureAndData { + option (gogoproto.goproto_getters) = false; + bytes signature = 1; + bytes path = 2; + bytes data = 3; + uint64 timestamp = 4; +} + +// TimestampedSignatureData contains the signature data and the timestamp of the +// signature. +message TimestampedSignatureData { + option (gogoproto.goproto_getters) = false; + bytes signature_data = 1 [(gogoproto.moretags) = "yaml:\"signature_data\""]; + uint64 timestamp = 2; +} + +// SignBytes defines the signed bytes used for signature verification. +message SignBytes { + option (gogoproto.goproto_getters) = false; + + // the sequence number + uint64 sequence = 1; + // the proof timestamp + uint64 timestamp = 2; + // the public key diversifier + string diversifier = 3; + // the standardised path bytes + bytes path = 4; + // the marshaled data bytes + bytes data = 5; +} + +// HeaderData returns the SignBytes data for update verification. +message HeaderData { + option (gogoproto.goproto_getters) = false; + + // header public key + google.protobuf.Any new_pub_key = 1 [(gogoproto.moretags) = "yaml:\"new_pub_key\""]; + // header diversifier + string new_diversifier = 2 [(gogoproto.moretags) = "yaml:\"new_diversifier\""]; +} diff --git a/proto/ibc/lightclients/tendermint/v1/tendermint.proto b/proto/ibc/lightclients/tendermint/v1/tendermint.proto index 48b47aee6cb..27c5c909460 100644 --- a/proto/ibc/lightclients/tendermint/v1/tendermint.proto +++ b/proto/ibc/lightclients/tendermint/v1/tendermint.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.lightclients.tendermint.v1; -option go_package = "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types"; +option go_package = "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint;tendermint"; import "tendermint/types/validator.proto"; import "tendermint/types/types.proto"; @@ -79,7 +79,8 @@ message ConsensusState { message Misbehaviour { option (gogoproto.goproto_getters) = false; - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; + // ClientID is deprecated + string client_id = 1 [deprecated = true, (gogoproto.moretags) = "yaml:\"client_id\""]; Header header_1 = 2 [(gogoproto.customname) = "Header1", (gogoproto.moretags) = "yaml:\"header_1\""]; Header header_2 = 3 [(gogoproto.customname) = "Header2", (gogoproto.moretags) = "yaml:\"header_2\""]; } diff --git a/testing/README.md b/testing/README.md index c682ba9ed8e..a488ffa42f1 100644 --- a/testing/README.md +++ b/testing/README.md @@ -255,8 +255,8 @@ import ( "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" - "github.com/cosmos/ibc-go/v4/modules/apps/transfer/simapp" - ibctesting "github.com/cosmos/ibc-go/v4/testing" + "github.com/cosmos/ibc-go/v5/modules/apps/transfer/simapp" + ibctesting "github.com/cosmos/ibc-go/v5/testing" ) func SetupTransferTestingApp() (ibctesting.TestingApp, map[string]json.RawMessage) { diff --git a/testing/chain.go b/testing/chain.go index ab7f707007c..9e01513e66b 100644 --- a/testing/chain.go +++ b/testing/chain.go @@ -30,7 +30,7 @@ import ( host "github.com/cosmos/ibc-go/v5/modules/core/24-host" "github.com/cosmos/ibc-go/v5/modules/core/exported" "github.com/cosmos/ibc-go/v5/modules/core/types" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" "github.com/cosmos/ibc-go/v5/testing/mock" "github.com/cosmos/ibc-go/v5/testing/simapp" ) @@ -53,8 +53,8 @@ type TestChain struct { Coordinator *Coordinator App TestingApp ChainID string - LastHeader *ibctmtypes.Header // header for last block height committed - CurrentHeader tmproto.Header // header for current block height + LastHeader *ibctm.Header // header for last block height committed + CurrentHeader tmproto.Header // header for current block height QueryServer types.QueryServer TxConfig client.TxConfig Codec codec.BinaryCodec @@ -200,11 +200,18 @@ func (chain *TestChain) QueryProof(key []byte) ([]byte, clienttypes.Height) { return chain.QueryProofAtHeight(key, chain.App.LastBlockHeight()) } -// QueryProof performs an abci query with the given key and returns the proto encoded merkle proof -// for the query and the height at which the proof will succeed on a tendermint verifier. +// QueryProofAtHeight performs an abci query with the given key and returns the proto encoded merkle proof +// for the query and the height at which the proof will succeed on a tendermint verifier. Only the IBC +// store is supported func (chain *TestChain) QueryProofAtHeight(key []byte, height int64) ([]byte, clienttypes.Height) { + return chain.QueryProofForStore(host.StoreKey, key, height) +} + +// QueryProofForStore performs an abci query with the given key and returns the proto encoded merkle proof +// for the query and the height at which the proof will succeed on a tendermint verifier. +func (chain *TestChain) QueryProofForStore(storeKey string, key []byte, height int64) ([]byte, clienttypes.Height) { res := chain.App.Query(abci.RequestQuery{ - Path: fmt.Sprintf("store/%s/key", host.StoreKey), + Path: fmt.Sprintf("store/%s/key", storeKey), Height: height - 1, Data: key, Prove: true, @@ -385,13 +392,13 @@ func (chain *TestChain) GetPrefix() commitmenttypes.MerklePrefix { // ConstructUpdateTMClientHeader will construct a valid 07-tendermint Header to update the // light client on the source chain. -func (chain *TestChain) ConstructUpdateTMClientHeader(counterparty *TestChain, clientID string) (*ibctmtypes.Header, error) { +func (chain *TestChain) ConstructUpdateTMClientHeader(counterparty *TestChain, clientID string) (*ibctm.Header, error) { return chain.ConstructUpdateTMClientHeaderWithTrustedHeight(counterparty, clientID, clienttypes.ZeroHeight()) } // ConstructUpdateTMClientHeader will construct a valid 07-tendermint Header to update the // light client on the source chain. -func (chain *TestChain) ConstructUpdateTMClientHeaderWithTrustedHeight(counterparty *TestChain, clientID string, trustedHeight clienttypes.Height) (*ibctmtypes.Header, error) { +func (chain *TestChain) ConstructUpdateTMClientHeaderWithTrustedHeight(counterparty *TestChain, clientID string, trustedHeight clienttypes.Height) (*ibctm.Header, error) { header := counterparty.LastHeader // Relayer must query for LatestHeight on client to get TrustedHeight if the trusted height is not set if trustedHeight.IsZero() { @@ -413,7 +420,7 @@ func (chain *TestChain) ConstructUpdateTMClientHeaderWithTrustedHeight(counterpa // NextValidatorsHash tmTrustedVals, ok = counterparty.GetValsAtHeight(int64(trustedHeight.RevisionHeight + 1)) if !ok { - return nil, sdkerrors.Wrapf(ibctmtypes.ErrInvalidHeaderHeight, "could not retrieve trusted validators at trustedHeight: %d", trustedHeight) + return nil, sdkerrors.Wrapf(ibctm.ErrInvalidHeaderHeight, "could not retrieve trusted validators at trustedHeight: %d", trustedHeight) } } // inject trusted fields into last header @@ -437,13 +444,13 @@ func (chain *TestChain) ExpireClient(amount time.Duration) { // CurrentTMClientHeader creates a TM header using the current header parameters // on the chain. The trusted fields in the header are set to nil. -func (chain *TestChain) CurrentTMClientHeader() *ibctmtypes.Header { +func (chain *TestChain) CurrentTMClientHeader() *ibctm.Header { return chain.CreateTMClientHeader(chain.ChainID, chain.CurrentHeader.Height, clienttypes.Height{}, chain.CurrentHeader.Time, chain.Vals, chain.NextVals, nil, chain.Signers) } // CreateTMClientHeader creates a TM header to update the TM client. Args are passed in to allow // caller flexibility to use params that differ from the chain. -func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, trustedHeight clienttypes.Height, timestamp time.Time, tmValSet, nextVals, tmTrustedVals *tmtypes.ValidatorSet, signers map[string]tmtypes.PrivValidator) *ibctmtypes.Header { +func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, trustedHeight clienttypes.Height, timestamp time.Time, tmValSet, nextVals, tmTrustedVals *tmtypes.ValidatorSet, signers map[string]tmtypes.PrivValidator) *ibctm.Header { var ( valSet *tmproto.ValidatorSet trustedVals *tmproto.ValidatorSet @@ -502,7 +509,7 @@ func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, // The trusted fields may be nil. They may be filled before relaying messages to a client. // The relayer is responsible for querying client and injecting appropriate trusted fields. - return &ibctmtypes.Header{ + return &ibctm.Header{ SignedHeader: signedHeader, ValidatorSet: valSet, TrustedHeight: trustedHeight, diff --git a/testing/config.go b/testing/config.go index 2090681a53e..768aa968708 100644 --- a/testing/config.go +++ b/testing/config.go @@ -6,7 +6,7 @@ import ( connectiontypes "github.com/cosmos/ibc-go/v5/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" "github.com/cosmos/ibc-go/v5/testing/mock" ) @@ -15,7 +15,7 @@ type ClientConfig interface { } type TendermintConfig struct { - TrustLevel ibctmtypes.Fraction + TrustLevel ibctm.Fraction TrustingPeriod time.Duration UnbondingPeriod time.Duration MaxClockDrift time.Duration diff --git a/testing/coordinator.go b/testing/coordinator.go index f2cc49f9a91..6374a17b170 100644 --- a/testing/coordinator.go +++ b/testing/coordinator.go @@ -11,7 +11,9 @@ import ( ) var ( - ChainIDPrefix = "testchain" + ChainIDPrefix = "testchain" + // to disable revision format, set ChainIDSuffix to "" + ChainIDSuffix = "-1" globalStartTime = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) TimeIncrement = time.Second * 5 ) @@ -173,7 +175,7 @@ func (coord *Coordinator) GetChain(chainID string) *TestChain { // GetChainID returns the chainID used for the provided index. func GetChainID(index int) string { - return ChainIDPrefix + strconv.Itoa(index) + return ChainIDPrefix + strconv.Itoa(index) + ChainIDSuffix } // CommitBlock commits a block on the provided indexes and then increments the global time. diff --git a/testing/endpoint.go b/testing/endpoint.go index b44fcad035f..8331980da93 100644 --- a/testing/endpoint.go +++ b/testing/endpoint.go @@ -2,6 +2,7 @@ package ibctesting import ( "fmt" + "strings" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" @@ -12,7 +13,7 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" host "github.com/cosmos/ibc-go/v5/modules/core/24-host" "github.com/cosmos/ibc-go/v5/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" ) // Endpoint is a which represents a channel endpoint and its associated @@ -91,7 +92,7 @@ func (endpoint *Endpoint) CreateClient() (err error) { require.True(endpoint.Chain.T, ok) height := endpoint.Counterparty.Chain.LastHeader.GetHeight().(clienttypes.Height) - clientState = ibctmtypes.NewClientState( + clientState = ibctm.NewClientState( endpoint.Counterparty.Chain.ChainID, tmConfig.TrustLevel, tmConfig.TrustingPeriod, tmConfig.UnbondingPeriod, tmConfig.MaxClockDrift, height, commitmenttypes.GetSDKSpecs(), UpgradePath, tmConfig.AllowUpdateAfterExpiry, tmConfig.AllowUpdateAfterMisbehaviour, ) @@ -131,7 +132,7 @@ func (endpoint *Endpoint) UpdateClient() (err error) { // ensure counterparty has committed state endpoint.Chain.Coordinator.CommitBlock(endpoint.Counterparty.Chain) - var header exported.Header + var header exported.ClientMessage switch endpoint.ClientConfig.GetClientType() { case exported.Tendermint: @@ -154,6 +155,59 @@ func (endpoint *Endpoint) UpdateClient() (err error) { return endpoint.Chain.sendMsgs(msg) } +// UpgradeChain will upgrade a chain's chainID to the next revision number. +// It will also update the counterparty client. +// TODO: implement actual upgrade chain functionality via scheduling an upgrade +// and upgrading the client via MsgUpgradeClient +// see reference https://github.com/cosmos/ibc-go/pull/1169 +func (endpoint *Endpoint) UpgradeChain() error { + if strings.TrimSpace(endpoint.Counterparty.ClientID) == "" { + return fmt.Errorf("cannot upgrade chain if there is no counterparty client") + } + + clientState := endpoint.Counterparty.GetClientState().(*ibctm.ClientState) + + // increment revision number in chainID + + oldChainID := clientState.ChainId + if !clienttypes.IsRevisionFormat(oldChainID) { + return fmt.Errorf("cannot upgrade chain which is not of revision format: %s", oldChainID) + } + + revisionNumber := clienttypes.ParseChainID(oldChainID) + newChainID, err := clienttypes.SetRevisionNumber(oldChainID, revisionNumber+1) + if err != nil { + return err + } + + // update chain + endpoint.Chain.ChainID = newChainID + endpoint.Chain.CurrentHeader.ChainID = newChainID + endpoint.Chain.NextBlock() // commit changes + + // update counterparty client manually + clientState.ChainId = newChainID + clientState.LatestHeight = clienttypes.NewHeight(revisionNumber+1, clientState.LatestHeight.GetRevisionHeight()+1) + endpoint.Counterparty.SetClientState(clientState) + + consensusState := &ibctm.ConsensusState{ + Timestamp: endpoint.Chain.LastHeader.GetTime(), + Root: commitmenttypes.NewMerkleRoot(endpoint.Chain.LastHeader.Header.GetAppHash()), + NextValidatorsHash: endpoint.Chain.LastHeader.Header.NextValidatorsHash, + } + endpoint.Counterparty.SetConsensusState(consensusState, clientState.GetLatestHeight()) + + // ensure the next update isn't identical to the one set in state + endpoint.Chain.Coordinator.IncrementTime() + endpoint.Chain.NextBlock() + + if err = endpoint.Counterparty.UpdateClient(); err != nil { + return err + } + + return nil +} + // ConnOpenInit will construct and execute a MsgConnectionOpenInit on the associated endpoint. func (endpoint *Endpoint) ConnOpenInit() error { msg := connectiontypes.NewMsgConnectionOpenInit( diff --git a/testing/solomachine.go b/testing/solomachine.go index 50974e58268..d22e67afd24 100644 --- a/testing/solomachine.go +++ b/testing/solomachine.go @@ -16,7 +16,7 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" host "github.com/cosmos/ibc-go/v5/modules/core/24-host" "github.com/cosmos/ibc-go/v5/modules/core/exported" - solomachinetypes "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine/types" + solomachinetypes "github.com/cosmos/ibc-go/v5/modules/light-clients/06-solomachine" ) // Solomachine is a testing helper used to simulate a counterparty @@ -107,7 +107,8 @@ func (solo *Solomachine) GetHeight() exported.Height { // CreateHeader generates a new private/public key pair and creates the // necessary signature to construct a valid solo machine header. -func (solo *Solomachine) CreateHeader() *solomachinetypes.Header { +// A new diversifier will be used as well +func (solo *Solomachine) CreateHeader(newDiversifier string) *solomachinetypes.Header { // generate new private keys and signature for header newPrivKeys, newPubKeys, newPubKey := GenerateKeys(solo.t, uint64(len(solo.PrivateKeys))) @@ -116,7 +117,7 @@ func (solo *Solomachine) CreateHeader() *solomachinetypes.Header { data := &solomachinetypes.HeaderData{ NewPubKey: publicKey, - NewDiversifier: solo.Diversifier, + NewDiversifier: newDiversifier, } dataBz, err := solo.cdc.Marshal(data) @@ -126,7 +127,7 @@ func (solo *Solomachine) CreateHeader() *solomachinetypes.Header { Sequence: solo.Sequence, Timestamp: solo.Time, Diversifier: solo.Diversifier, - DataType: solomachinetypes.HEADER, + Path: []byte{}, Data: dataBz, } @@ -140,7 +141,7 @@ func (solo *Solomachine) CreateHeader() *solomachinetypes.Header { Timestamp: solo.Time, Signature: sig, NewPublicKey: publicKey, - NewDiversifier: solo.Diversifier, + NewDiversifier: newDiversifier, } // assumes successful header update @@ -148,6 +149,7 @@ func (solo *Solomachine) CreateHeader() *solomachinetypes.Header { solo.PrivateKeys = newPrivKeys solo.PublicKeys = newPubKeys solo.PublicKey = newPubKey + solo.Diversifier = newDiversifier return header } @@ -155,20 +157,19 @@ func (solo *Solomachine) CreateHeader() *solomachinetypes.Header { // CreateMisbehaviour constructs testing misbehaviour for the solo machine client // by signing over two different data bytes at the same sequence. func (solo *Solomachine) CreateMisbehaviour() *solomachinetypes.Misbehaviour { - path := solo.GetClientStatePath("counterparty") - dataOne, err := solomachinetypes.ClientStateDataBytes(solo.cdc, path, solo.ClientState()) + merklePath := solo.GetClientStatePath("counterparty") + path, err := solo.cdc.Marshal(&merklePath) require.NoError(solo.t, err) - path = solo.GetConsensusStatePath("counterparty", clienttypes.NewHeight(0, 1)) - dataTwo, err := solomachinetypes.ConsensusStateDataBytes(solo.cdc, path, solo.ConsensusState()) + data, err := solo.cdc.Marshal(solo.ClientState()) require.NoError(solo.t, err) signBytes := &solomachinetypes.SignBytes{ Sequence: solo.Sequence, Timestamp: solo.Time, Diversifier: solo.Diversifier, - DataType: solomachinetypes.CLIENT, - Data: dataOne, + Path: path, + Data: data, } bz, err := solo.cdc.Marshal(signBytes) @@ -177,20 +178,27 @@ func (solo *Solomachine) CreateMisbehaviour() *solomachinetypes.Misbehaviour { sig := solo.GenerateSignature(bz) signatureOne := solomachinetypes.SignatureAndData{ Signature: sig, - DataType: solomachinetypes.CLIENT, - Data: dataOne, + Path: path, + Data: data, Timestamp: solo.Time, } // misbehaviour signaturess can have different timestamps solo.Time++ + merklePath = solo.GetConsensusStatePath("counterparty", clienttypes.NewHeight(0, 1)) + path, err = solo.cdc.Marshal(&merklePath) + require.NoError(solo.t, err) + + data, err = solo.cdc.Marshal(solo.ConsensusState()) + require.NoError(solo.t, err) + signBytes = &solomachinetypes.SignBytes{ Sequence: solo.Sequence, Timestamp: solo.Time, Diversifier: solo.Diversifier, - DataType: solomachinetypes.CONSENSUS, - Data: dataTwo, + Path: path, + Data: data, } bz, err = solo.cdc.Marshal(signBytes) @@ -199,8 +207,8 @@ func (solo *Solomachine) CreateMisbehaviour() *solomachinetypes.Misbehaviour { sig = solo.GenerateSignature(bz) signatureTwo := solomachinetypes.SignatureAndData{ Signature: sig, - DataType: solomachinetypes.CONSENSUS, - Data: dataTwo, + Path: path, + Data: data, Timestamp: solo.Time, } diff --git a/testing/values.go b/testing/values.go index 46df3b5ba27..e60de189e03 100644 --- a/testing/values.go +++ b/testing/values.go @@ -12,7 +12,7 @@ import ( ibctransfertypes "github.com/cosmos/ibc-go/v5/modules/apps/transfer/types" connectiontypes "github.com/cosmos/ibc-go/v5/modules/core/03-connection/types" commitmenttypes "github.com/cosmos/ibc-go/v5/modules/core/23-commitment/types" - ibctmtypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types" + ibctm "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint" "github.com/cosmos/ibc-go/v5/testing/mock" "github.com/cosmos/ibc-go/v5/testing/simapp" ) @@ -47,7 +47,7 @@ var ( DefaultOpenInitVersion *connectiontypes.Version // DefaultTrustLevel sets params variables used to create a TM client - DefaultTrustLevel = ibctmtypes.DefaultTrustLevel + DefaultTrustLevel = ibctm.DefaultTrustLevel TestCoin = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) UpgradePath = []string{"upgrade", "upgradedIBCState"}