x/ibc: IBC alpha (#5277)

* IBC alpha

* ICS 23 Implementation (#4515)

* add mapping

* rm unused mapping/*, rm interfaces

* rm unused code

* mv mapping -> state, rm x/ibc

* rm GetIfExists

* add key

* rm custom encoding/decoding in enum/bool

* fix lint

* rm tests

* add commitment

* newtyped remote values

* newtyped context

* revert context newtype

* add README, keypath

* reflect downstream ics

* add merkle

* add test for proving

* soft coded root keypath

* add update

* remove RootUpdate

* separate keypath and keuprefix

* add codec

* separate root/path

* add path to codec

* add docs in progre

* add comments

* add comments

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* add comments in progress

* add comments

* fix comment

* add comments in progress

* recover IntEncoding scheme for integer

* add uint tests, don't use codec in custom types

* finalize merge

* add godoc

* reformat test

* rm XXX

* add godoc

* add query

* update query.go

* update query.go

* add Query to boolean.go

* fix key

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* merge from ics04 branch

* merge from ics04 branch

* fix lint

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* applying review in progress

* apply review - make querier interface

* fix dependency

* revise querier interface to work both on cli & store

* rm commented lines

* rename Path -> Prefix

* Store accessor upstream changes (#5119)

* Store accessor upstream changes (#5119)

* add comments, reformat merkle querier

* rm merkle/utils

* ICS 23 upstream changes (#5120)

* ICS 23 upstream changes (#5120)

* update Value

* remove Mapping

* remove store accessors

* refactor ICS23

* cleanup types

* implement batch verification

* gosimple suggestion

* alias

* add tests

* ICS 24 Implementation (#5229)

* add validation functions

* validate path in ics-23

* address @fede comments

* move errors into host package

* flatten ICS23 structure

* fix ApplyPrefix

* complete types testing

* delete empty test file

* remove ibc errors from core error package

* start batch-verify tests

* minor changes on commitment types

* use testsuite

* upstream changes

* context changes

* ICS 02 Implementation (#4516)

* add mapping

* rm unused mapping/*, rm interfaces

* rm unused code

* mv mapping -> state, rm x/ibc

* rm GetIfExists

* add key

* rm custom encoding/decoding in enum/bool

* fix lint

* rm tests

* add commitment

* newtyped remote values

* newtyped context

* revert context newtype

* add README, keypath

* reflect downstream ics

* add merkle

* add test for proving

* soft coded root keypath

* add update

* remove RootUpdate

* separate keypath and keuprefix

* add codec

* separate root/path

* add path to codec

* add client

* add counterpartymanager

* fix manager

* add Is() to counterobject

* add readme, reflect ICS02 revision

* reflect downstream ics

* test in progress

* add test

* in progres

* fin rebase

* in progress

* fin rebase

* add CLIObject in progress

* cli in progress

* add CLIObject

* separate testing from tendermint

* add key to node

* add root and storekey to tests/node, add codec

* rm cli/query.go

* fix test

* fix lint

* fix lint

* add handler/msgs/client

* rm relay

* finalize rebase on 23 root/path sep

* fix lint, fix syntax

* rm freebase, reformat query

* add docs in progre

* add comments

* add comments

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* add comments in progress

* add comments

* fix comment

* add comments in progress

* recover IntEncoding scheme for integer

* add uint tests, don't use codec in custom types

* finalize merge

* add godoc

* add godoc in progress

* reformat test

* rm XXX

* add godoc

* modify store

* add query

* update query.go

* update query.go

* cli refactor in progress

* cli refactor in progress

* add Query to boolean.go

* fix key

* fix cli / merkle test

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* merge from ics04 branch

* merge from ics04 branch

* merge from ics04 branch

* fix lint

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* applying review in progress

* apply review - make querier interface

* fix dependency

* fix dependency

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* reflect downstream change

* fix cli

* rm commented lines

* address review in progress

* rename Path -> Prefix

* Store accessor upstream changes (#5119)

* Store accessor upstream changes (#5119)

* add comments, reformat merkle querier

* rm merkle/utils

* ICS 23 upstream changes (#5120)

* ICS 23 upstream changes (#5120)

* update Value

* update test

* fix

* ICS 02 upstream changes (#5122)

* ICS 02 upstream changes (#5122)

* cleanup types and submodule

* more cleanup and godocs

* remove counterPartyManager/State and cleanup

* implement SubmitMisbehaviour and refactor

* errors

* events

* fix test

* refactors

* remove Mapping

* remove store accessors

* proposed refactor

* remove store accessors from ICS02

* refactor queriers, handler and clean keeper

* logger and tx long description

* ineffassign

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* add verification functions

* ICS02 module.go

* top level x/ibc structure

* Update x/ibc/02-client/client/cli/query.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Update x/ibc/02-client/types/tendermint/consensus_state.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* address some of the review comments

* minor UX improvements

* rename pkg

* fixes

* refactor ICS23

* cleanup types

* implement batch verification

* gosimple suggestion

* various fixes; remove legacy tests; remove commitment path query

* alias

* minor updates from ICS23

* renaming

* update verification and rename root funcs

* move querier to x/ibc

* update query.go to use 'custom/...' query path

* add tests

* ICS 24 Implementation (#5229)

* add validation functions

* validate path in ics-23

* address @fede comments

* move errors into host package

* flatten ICS23 structure

* fix ApplyPrefix

* updates from ICS23 and ICS24

* msg.ValidateBasic and ADR09 evidence interface

* complete types testing

* delete empty test file

* remove ibc errors from core error package

* custom JSON marshaling

* start batch-verify tests

* minor changes on commitment types

* R4R - Store consensus state correctly (#5242)

* store consensus state correctly

* fix client example

* update alias

* use testsuite

* Integrate Evidence Implementation into ICS-02 (#5258)

* implement evidence in ics-02

* fix build errors and import cycles

* address fede comments

* remove unnecessary pubkey and fix init

* add tests

* finish tendermint tests

* complete merge

* Add tests for msgs

* upstream changes

* fix

* upstream changes

* fix cons state

* context changes

* ICS 03 Implementation (#4517)

* add test

* in progres

* fin rebase

* in progress

* fin rebase

* add CLIObject in progress

* cli in progress

* add CLIObject

* separate testing from tendermint

* add key to node

* add root and storekey to tests/node, add codec

* rm cli/query.go

* fix test

* fix lint

* fix lint

* add handler/msgs/client

* rm relay

* finalize rebase on 23 root/path sep

* fix lint, fix syntax

* fix querying

* extract out context withstore

* fix 02-client test

* fix 23-commitment test

* add query in progress

* rm freebase, reformat query

* add cli/handler/msg in progress

* add cli/msg/handler

* add CLIQuery, fix tests

* fix golangci

* add docs in progre

* add comments

* add comments

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* add comments in progress

* add comments

* fix comment

* add comments in progress

* recover IntEncoding scheme for integer

* add uint tests, don't use codec in custom types

* finalize merge

* add godoc

* add godoc in progress

* reformat test

* rm XXX

* add godoc

* modify store

* add query

* update query.go

* update query.go

* cli refactor in progress

* cli refactor in progress

* add Query to boolean.go

* fix key

* fix cli / merkle test

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* fix test

* fix client

* merge from ics04 branch

* merge from ics04 branch

* merge from ics04 branch

* merge from ics04 branch

* fix lint

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* applying review in progress

* apply review - make querier interface

* fix dependency

* fix dependency

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* reflect downstream change

* fix cli

* reflect downstream changes

* rm commented lines

* address review in progress

* address review, rm cleanup/closing

* rename Path -> Prefix

* Store accessor upstream changes (#5119)

* Store accessor upstream changes (#5119)

* add comments, reformat merkle querier

* rm merkle/utils

* ICS 23 upstream changes (#5120)

* ICS 23 upstream changes (#5120)

* update Value

* update test

* fix

* ICS 02 upstream changes (#5122)

* ICS 02 upstream changes (#5122)

* ICS 03 upstream changes (#5123)

* ICS 03 upstream changes (#5123)

* cleanup types and submodule

* more cleanup and godocs

* remove counterPartyManager/State and cleanup

* implement SubmitMisbehaviour and refactor

* errors

* events

* fix test

* refactors

* WIP refactor ICS03

* remove Mapping

* remove store accessors

* proposed refactor

* remove store accessors from ICS02

* refactor queriers, handler and clean keeper

* logger and tx long description

* ineffassign

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* remove store accessors

* refactor handshake to update it to the latest ICS03 spec

* update handler and msgs

* add verification functions

* update verification

* ICS02 module.go

* top level x/ibc structure

* update connection queries

* update connection tx

* remove extra files

* update expected client keeper and export verification funcs

* Update x/ibc/02-client/client/cli/query.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Update x/ibc/02-client/types/tendermint/consensus_state.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* address some of the review comments

* resolve some TODOs and address comments from review

* update connection versioning

* minor error updates

* minor UX improvements

* rename pkg

* fixes

* refactor ICS23

* cleanup types

* rename pkg and fix import

* implement batch verification

* gosimple suggestion

* various fixes; remove legacy tests; remove commitment path query

* alias

* minor updates from ICS23

* renaming

* update verification and rename root funcs

* move querier to x/ibc

* update query.go to use 'custom/...' query path

* add tests

* ICS 24 Implementation (#5229)

* add validation functions

* validate path in ics-23

* address @fede comments

* move errors into host package

* flatten ICS23 structure

* fix ApplyPrefix

* updates from ICS23 and ICS24

* msg.ValidateBasic and ADR09 evidence interface

* complete types testing

* delete empty test file

* remove ibc errors from core error package

* custom JSON marshaling; msg.ValidateBasic; renaming of variables

* minor update

* custom JSON marshaling

* start batch-verify tests

* minor changes on commitment types

* R4R - Store consensus state correctly (#5242)

* store consensus state correctly

* fix client example

* update alias

* update alias

* use testsuite

* Integrate Evidence Implementation into ICS-02 (#5258)

* implement evidence in ics-02

* fix build errors and import cycles

* address fede comments

* remove unnecessary pubkey and fix init

* add tests

* finish tendermint tests

* complete merge

* Add tests for msgs

* upstream changes

* fix

* upstream changes

* fix cons state

* context changes

* fix cli tx

* upstream changes

* fix

* ICS 05 implementation (#5193)

* fix lint

* fix lint

* add handler/msgs/client

* rm relay

* finalize rebase on 23 root/path sep

* fix lint, fix syntax

* fix querying

* extract out context withstore

* fix 02-client test

* fix 23-commitment test

* add query in progress

* rm freebase, reformat query

* add cli/handler/msg in progress

* add cli/msg/handler

* add CLIQuery, fix tests

* fix golangci

* add docs in progre

* add comments

* add comments

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* add comments in progress

* add comments

* fix comment

* add comments in progress

* recover IntEncoding scheme for integer

* add uint tests, don't use codec in custom types

* finalize merge

* add godoc

* add godoc in progress

* reformat test

* rm XXX

* add godoc

* modify store

* add query

* update query.go

* update query.go

* cli refactor in progress

* cli refactor in progress

* add Query to boolean.go

* fix key

* fix cli / merkle test

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* fix test

* fix client

* merge from ics04 branch

* merge from ics04 branch

* merge from ics04 branch

* merge from ics04 branch

* fix lint

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* applying review in progress

* apply review - make querier interface

* fix dependency

* fix dependency

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* reflect downstream change

* fix cli

* reflect downstream changes

* rm commented lines

* address review in progress

* address review, rm cleanup/closing

* rename Path -> Prefix

* Store accessor upstream changes (#5119)

* Store accessor upstream changes (#5119)

* add comments, reformat merkle querier

* rm merkle/utils

* ICS 23 upstream changes (#5120)

* ICS 23 upstream changes (#5120)

* update Value

* update test

* fix

* ICS 02 upstream changes (#5122)

* ICS 02 upstream changes (#5122)

* ICS 03 upstream changes (#5123)

* ICS 03 upstream changes (#5123)

* cleanup types and submodule

* more cleanup and godocs

* remove counterPartyManager/State and cleanup

* implement SubmitMisbehaviour and refactor

* errors

* events

* fix test

* refactors

* WIP refactor ICS03

* remove Mapping

* remove store accessors

* proposed refactor

* remove store accessors from ICS02

* refactor queriers, handler and clean keeper

* logger and tx long description

* ineffassign

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* remove store accessors

* refactor handshake to update it to the latest ICS03 spec

* update handler and msgs

* add verification functions

* update verification

* ICS02 module.go

* top level x/ibc structure

* update connection queries

* update connection tx

* remove extra files

* update expected client keeper and export verification funcs

* ICS 05 Implementation

* release port and godocs

* Update x/ibc/02-client/client/cli/query.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Update x/ibc/02-client/types/tendermint/consensus_state.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* address some of the review comments

* resolve some TODOs and address comments from review

* update connection versioning

* minor error updates

* update errors and add port Keeper to ibc Keeper

* minor UX improvements

* rename pkg

* fixes

* refactor ICS23

* cleanup types

* ICS 5 updates (#5222)

* Validate port identifiers

* Refactor to static bind

* Add comments

* Add 'GetPorts' query function

* rename pkg and fix import

* implement batch verification

* gosimple suggestion

* various fixes; remove legacy tests; remove commitment path query

* alias

* minor updates from ICS23

* renaming

* update verification and rename root funcs

* move querier to x/ibc

* update query.go to use 'custom/...' query path

* add tests

* ICS 24 Implementation (#5229)

* add validation functions

* validate path in ics-23

* address @fede comments

* move errors into host package

* flatten ICS23 structure

* fix ApplyPrefix

* updates from ICS23 and ICS24

* msg.ValidateBasic and ADR09 evidence interface

* complete types testing

* delete empty test file

* remove ibc errors from core error package

* custom JSON marshaling; msg.ValidateBasic; renaming of variables

* minor update

* custom JSON marshaling

* use host validation for port ids

* start batch-verify tests

* minor changes on commitment types

* R4R - Store consensus state correctly (#5242)

* store consensus state correctly

* fix client example

* update alias

* update alias

* update alias and keeper.GetPort()

* use testsuite

* Integrate Evidence Implementation into ICS-02 (#5258)

* implement evidence in ics-02

* fix build errors and import cycles

* address fede comments

* remove unnecessary pubkey and fix init

* add tests

* finish tendermint tests

* complete merge

* Add tests for msgs

* upstream changes

* fix

* upstream changes

* fix cons state

* context changes

* fix cli tx

* upstream changes

* upstream changes

* ICS 04 Implementation (#4548)

* merge from ics04 branch

* merge from ics04 branch

* fix lint

* add port

* fix test

* add mocks

* fix connid -> portid in handshake.go

* add mock

* add ibc module.go, finalize mock

* add keeper

* add StoreKey const

* fix test

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* applying review in progress

* apply review - make querier interface

* fix cli errors

* fix dependency

* fix dependency

* reflect method name change

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* reflect downstream change

* fix cli

* reflect downstream changes

* reflect downstream changes

* fix from address in tx cli

* fix cli in progress(squash later)

* fix cli

* remove timeout, add channel cli

* fix golangci

* fix cli

* Clean up

* fix mock cli in progress

* finalize cleanup, mock cli wip

* add cli for mocksend

* fix handler

* rm commented lines

* address review in progress

* address review, rm cleanup/closing

* rename mock packages

* fix interface for gaia

* rename Path -> Prefix

* Store accessor upstream changes (#5119)

* Store accessor upstream changes (#5119)

* add comments, reformat merkle querier

* rm merkle/utils

* ICS 23 upstream changes (#5120)

* ICS 23 upstream changes (#5120)

* update Value

* update test

* fix

* ICS 02 upstream changes (#5122)

* ICS 02 upstream changes (#5122)

* ICS 03 upstream changes (#5123)

* ICS 03 upstream changes (#5123)

* update test

* cleanup types and submodule

* more cleanup and godocs

* remove counterPartyManager/State and cleanup

* implement SubmitMisbehaviour and refactor

* errors

* events

* fix test

* refactors

* WIP refactor ICS03

* remove Mapping

* remove store accessors

* proposed refactor

* remove store accessors from ICS02

* refactor queriers, handler and clean keeper

* logger and tx long description

* ineffassign

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* remove store accessors

* refactor handshake to update it to the latest ICS03 spec

* update handler and msgs

* add verification functions

* update verification

* ICS02 module.go

* top level x/ibc structure

* update connection queries

* update connection tx

* remove extra files

* refactor: remove store accessors, update keeper and types to match spec (WIP)

* update handshake and packet

* implement packet timeouts

* implement send and receive packet

* implement packet ACK

* update handler

* add channel errors

* channel querier

* update expected client keeper and export verification funcs

* ICS 05 Implementation

* release port and godocs

* Update x/ibc/02-client/client/cli/query.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Update x/ibc/02-client/types/tendermint/consensus_state.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* address some of the review comments

* resolve some TODOs and address comments from review

* update connection versioning

* minor error updates

* update ICS04 with downstream changes

* Implement tx cli actions

* add MsgSendPacket handler; msg validation, errors and events

* update errors and add port Keeper to ibc Keeper

* minor UX improvements

* rename pkg

* fixes

* refactor ICS23

* cleanup types

* ICS 5 updates (#5222)

* Validate port identifiers

* Refactor to static bind

* Add comments

* Add 'GetPorts' query function

* rename pkg and fix import

* implement batch verification

* gosimple suggestion

* various fixes; remove legacy tests; remove commitment path query

* alias

* minor updates from ICS23

* renaming

* update verification and rename root funcs

* rm legacy tests; add query proofs support

* remove capability key generation and authentication logic

* move querier to x/ibc

* update query.go to use 'custom/...' query path

* add tests

* ICS 24 Implementation (#5229)

* add validation functions

* validate path in ics-23

* address @fede comments

* move errors into host package

* flatten ICS23 structure

* fix ApplyPrefix

* updates from ICS23 and ICS24

* msg.ValidateBasic and ADR09 evidence interface

* complete types testing

* delete empty test file

* remove ibc errors from core error package

* custom JSON marshaling; msg.ValidateBasic; renaming of variables

* minor update

* custom JSON marshaling

* use host validation for port ids

* downstream changes; custom marshal JSON; msg validation, and update errors

* update errors and aliases

* start batch-verify tests

* update msg validation and CLI UX

* minor changes on commitment types

* fix channel and packet check (#5243)

* R4R - Store consensus state correctly (#5242)

* store consensus state correctly

* fix client example

* update alias

* update alias

* update alias and keeper.GetPort()

* authenticate port ID; remove send packet msg from CLI

* comment out handlers

* use testsuite

* Integrate Evidence Implementation into ICS-02 (#5258)

* implement evidence in ics-02

* fix build errors and import cycles

* address fede comments

* remove unnecessary pubkey and fix init

* add tests

* finish tendermint tests

* complete merge

* Add tests for msgs

* upstream changes

* fix

* upstream changes

* fix cons state

* context changes

* fix cli tx

* upstream changes

* upstream changes

* upstream changes

* IBC v1.0.0 (#5245)

* applying review in progress

* apply review - make querier interface

* fix cli errors

* fix dependency

* fix dependency

* reflect method name change

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* reflect downstream change

* fix cli

* reflect downstream changes

* reflect downstream changes

* fix from address in tx cli

* fix cli in progress(squash later)

* fix cli

* remove timeout, add channel cli

* fix golangci

* fix cli

* Clean up

* fix mock cli in progress

* finalize cleanup, mock cli wip

* add cli for mocksend

* fix handler

* rm commented lines

* address review in progress

* address review, rm cleanup/closing

* rename mock packages

* fix interface for gaia

* rename Path -> Prefix

* Store accessor upstream changes (#5119)

* Store accessor upstream changes (#5119)

* add comments, reformat merkle querier

* rm merkle/utils

* ICS 23 upstream changes (#5120)

* ICS 23 upstream changes (#5120)

* update Value

* update test

* fix

* ICS 02 upstream changes (#5122)

* ICS 02 upstream changes (#5122)

* ICS 03 upstream changes (#5123)

* ICS 03 upstream changes (#5123)

* update test

* cleanup types and submodule

* more cleanup and godocs

* remove counterPartyManager/State and cleanup

* implement SubmitMisbehaviour and refactor

* errors

* events

* fix test

* refactors

* WIP refactor ICS03

* remove Mapping

* remove store accessors

* proposed refactor

* remove store accessors from ICS02

* refactor queriers, handler and clean keeper

* logger and tx long description

* ineffassign

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* remove store accessors

* refactor handshake to update it to the latest ICS03 spec

* update handler and msgs

* add verification functions

* update verification

* ICS02 module.go

* top level x/ibc structure

* update connection queries

* update connection tx

* remove extra files

* refactor: remove store accessors, update keeper and types to match spec (WIP)

* update handshake and packet

* implement packet timeouts

* implement send and receive packet

* implement packet ACK

* update handler

* add channel errors

* channel querier

* update expected client keeper and export verification funcs

* ICS 05 Implementation

* release port and godocs

* Update x/ibc/02-client/client/cli/query.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Update x/ibc/02-client/types/tendermint/consensus_state.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* address some of the review comments

* resolve some TODOs and address comments from review

* update connection versioning

* minor error updates

* update ICS04 with downstream changes

* Implement tx cli actions

* add MsgSendPacket handler; msg validation, errors and events

* update errors and add port Keeper to ibc Keeper

* minor UX improvements

* rename pkg

* fixes

* refactor ICS23

* cleanup types

* ICS 5 updates (#5222)

* Validate port identifiers

* Refactor to static bind

* Add comments

* Add 'GetPorts' query function

* rename pkg and fix import

* implement batch verification

* gosimple suggestion

* various fixes; remove legacy tests; remove commitment path query

* alias

* minor updates from ICS23

* renaming

* update verification and rename root funcs

* rm legacy tests; add query proofs support

* remove capability key generation and authentication logic

* move querier to x/ibc

* update query.go to use 'custom/...' query path

* add tests

* ICS 24 Implementation (#5229)

* add validation functions

* validate path in ics-23

* address @fede comments

* move errors into host package

* flatten ICS23 structure

* fix ApplyPrefix

* updates from ICS23 and ICS24

* msg.ValidateBasic and ADR09 evidence interface

* complete types testing

* delete empty test file

* remove ibc errors from core error package

* custom JSON marshaling; msg.ValidateBasic; renaming of variables

* minor update

* custom JSON marshaling

* use host validation for port ids

* downstream changes; custom marshal JSON; msg validation, and update errors

* update errors and aliases

* start batch-verify tests

* update msg validation and CLI UX

* minor changes on commitment types

* fix channel and packet check (#5243)

* R4R - Store consensus state correctly (#5242)

* store consensus state correctly

* fix client example

* update alias

* update alias

* update alias and keeper.GetPort()

* authenticate port ID; remove send packet msg from CLI

* comment out handlers

* add ibc module to simapp

* ICS20 implementation (#5204)

* add ibc bank mock

* modify handler

* import channel

* add receiving logic

* add cli proof handling

* modify cli

* modify receiver type

* modify errcode

* optimize codes

* add denom prefix when source is true

* refactor code

* error return

* switch ibc antehandler to decorator pattern

* fix name/comment

* ICS 20 implementation (#5250)

* move ics20 code to 20-transfer

* clean code

* fix compiling error

* add transfer module

* address ICS20 comments from review

* add routing callbacks

* clean code

* add missing err return

* modify err type

* modify err type

* add supply handling

* modify proof type

* add comments for msg and packet data

* add timeout supply handling

* modify module account name

* use supply keeper for burn and mint coins

* restructure keeper

* update alias and module.go

* golangci linter

* add ics20 handler to IBC handler

* update callbacks

* update ICS20 escrow address

* fix querier routes

* fix create client cli

* minor updates

* ibc querier test

* Refactor ibc/mock/bank into ICS 20 (#5264)

* Most of code port from mock module to ICS 20

* A few minor fixes

* Apply suggestions from code review

Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>

* Fix suggestions from autolinter

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* Fix order of messages

* Add invalid height error code, check non-nil proof

* Fix linter error

* Return the underlying error

* Tendermint starts at height 1

* Apply suggestions from code review

* setup ics20 test suite

* add event to MsgRecvPacket

* update ibc keeper test to use test suite

* Add handshake commands

* WIP connection handshake

* WIP Connection Handshake

* use testsuite

* Add cliCtx.WaitForNBlocks

* fix connection handshake in progress

* fix connection handshake in progress

* Integrate Evidence Implementation into ICS-02 (#5258)

* implement evidence in ics-02

* fix build errors and import cycles

* address fede comments

* remove unnecessary pubkey and fix init

* add tests

* finish tendermint tests

* complete merge

* Add tests for msgs

* upstream changes

* fix

* upstream changes

* fix cons state

* context changes

* fix cli tx

* upstream changes

* upstream changes

* upstream changes

* upstream changes

* IBC demo fixes (#5267)

* WIP refactor ICS03

* remove Mapping

* remove store accessors

* proposed refactor

* remove store accessors from ICS02

* refactor queriers, handler and clean keeper

* logger and tx long description

* ineffassign

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* remove store accessors

* refactor handshake to update it to the latest ICS03 spec

* update handler and msgs

* add verification functions

* update verification

* ICS02 module.go

* top level x/ibc structure

* update connection queries

* update connection tx

* remove extra files

* refactor: remove store accessors, update keeper and types to match spec (WIP)

* update handshake and packet

* implement packet timeouts

* implement send and receive packet

* implement packet ACK

* update handler

* add channel errors

* channel querier

* update expected client keeper and export verification funcs

* ICS 05 Implementation

* release port and godocs

* Update x/ibc/02-client/client/cli/query.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Update x/ibc/02-client/types/tendermint/consensus_state.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* address some of the review comments

* resolve some TODOs and address comments from review

* update connection versioning

* minor error updates

* update ICS04 with downstream changes

* Implement tx cli actions

* add MsgSendPacket handler; msg validation, errors and events

* update errors and add port Keeper to ibc Keeper

* minor UX improvements

* rename pkg

* fixes

* refactor ICS23

* cleanup types

* ICS 5 updates (#5222)

* Validate port identifiers

* Refactor to static bind

* Add comments

* Add 'GetPorts' query function

* rename pkg and fix import

* implement batch verification

* gosimple suggestion

* various fixes; remove legacy tests; remove commitment path query

* alias

* minor updates from ICS23

* renaming

* update verification and rename root funcs

* rm legacy tests; add query proofs support

* remove capability key generation and authentication logic

* move querier to x/ibc

* update query.go to use 'custom/...' query path

* add tests

* ICS 24 Implementation (#5229)

* add validation functions

* validate path in ics-23

* address @fede comments

* move errors into host package

* flatten ICS23 structure

* fix ApplyPrefix

* updates from ICS23 and ICS24

* msg.ValidateBasic and ADR09 evidence interface

* complete types testing

* delete empty test file

* remove ibc errors from core error package

* custom JSON marshaling; msg.ValidateBasic; renaming of variables

* minor update

* custom JSON marshaling

* use host validation for port ids

* downstream changes; custom marshal JSON; msg validation, and update errors

* update errors and aliases

* start batch-verify tests

* update msg validation and CLI UX

* minor changes on commitment types

* fix channel and packet check (#5243)

* R4R - Store consensus state correctly (#5242)

* store consensus state correctly

* fix client example

* update alias

* update alias

* update alias and keeper.GetPort()

* authenticate port ID; remove send packet msg from CLI

* comment out handlers

* add ibc module to simapp

* ICS20 implementation (#5204)

* add ibc bank mock

* modify handler

* import channel

* add receiving logic

* add cli proof handling

* modify cli

* modify receiver type

* modify errcode

* optimize codes

* add denom prefix when source is true

* refactor code

* error return

* switch ibc antehandler to decorator pattern

* fix name/comment

* ICS 20 implementation (#5250)

* move ics20 code to 20-transfer

* clean code

* fix compiling error

* add transfer module

* address ICS20 comments from review

* add routing callbacks

* clean code

* add missing err return

* modify err type

* modify err type

* add supply handling

* modify proof type

* add comments for msg and packet data

* add timeout supply handling

* modify module account name

* use supply keeper for burn and mint coins

* restructure keeper

* update alias and module.go

* golangci linter

* add ics20 handler to IBC handler

* update callbacks

* update ICS20 escrow address

* fix querier routes

* fix create client cli

* minor updates

* ibc querier test

* Refactor ibc/mock/bank into ICS 20 (#5264)

* Most of code port from mock module to ICS 20

* A few minor fixes

* Apply suggestions from code review

Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>

* Fix suggestions from autolinter

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* Fix order of messages

* Add invalid height error code, check non-nil proof

* Fix linter error

* Return the underlying error

* Tendermint starts at height 1

* Apply suggestions from code review

* setup ics20 test suite

* add event to MsgRecvPacket

* update ibc keeper test to use test suite

* Add handshake commands

* WIP connection handshake

* WIP Connection Handshake

* use testsuite

* Add cliCtx.WaitForNBlocks

* fix connection handshake in progress

* fix connection handshake in progress

* Add print debugging (old-school)

* Add log line

* More debugging

* Set prove flag to true

* More debugging

* Use store query

* Fix query, hopefully

* Fix query path

* Hmm

* Fix context bug

* Generate & return & use consensus state proof

* Print debugging

* Add debugging

* Begin working on the channel creation command

* remove submodule prefix from keypath, fix addConnectionToClients to treat nil as empty array

* fix OpenConfirm, rm debugging code

* WIP channel shake 🕺

* WIP channel shake 🕺

* WIP channel shake 🕺

* WIP channel shake 🕺

* WIP channel shake 🕺

* WIP channel shake 🕺

* WIP channel shake 🕺

* Update bound port

* Add from flag to ICS 20 commands

* Undefine flag

* add debug

* Uncomment channel message handlers

* fix validatebasic identifier failure

* Fix printing

* add debug code

* CLI debugging

* fix counterpartyHops, channel handshake working w/o port

* Fix compilation error

* Push channel query command update

* Remove unused code

* Add gaiacli keys test

* Update error

* Add printf

* fix token restriciton

* comment out port

* fix querier to retrieve the next sequence

* Alter command to take arguments

* Name it packet-sequence

* add packet query utils

* Use the querier

* Packet is JSON

* printf the value

* fix query packet

* fix packet receive in progress

* lol

* export Packet fields, rename Packet.XXX() -> Packet.GetXXX()

* fix route

* add debug

* comment out port logic from packet.go

* token transfer now working

* fix client tx

* Integrate Evidence Implementation into ICS-02 (#5258)

* implement evidence in ics-02

* fix build errors and import cycles

* address fede comments

* remove unnecessary pubkey and fix init

* add tests

* Apply suggestions from code review

* clean up

* finish tendermint tests

* complete merge

* Add tests for msgs

* ICS02 changes

* upstream changes

* fix

* upstream changes

* fix cons state

* context changes

* fix cli tx

* upstream changes

* upstream changes

* upstream changes

* upstream changes

* more cleanup

* Add unit tests for ICS03 (#5275)

* add Is() to counterobject

* add readme, reflect ICS02 revision

* reflect downstream ics

* test in progress

* add test

* in progres

* fin rebase

* in progress

* fin rebase

* add CLIObject in progress

* cli in progress

* add CLIObject

* separate testing from tendermint

* add key to node

* add root and storekey to tests/node, add codec

* rm cli/query.go

* fix test

* fix lint

* fix lint

* add handler/msgs/client

* rm relay

* finalize rebase on 23 root/path sep

* fix lint, fix syntax

* fix querying

* extract out context withstore

* fix 02-client test

* fix 23-commitment test

* add query in progress

* rm freebase, reformat query

* add cli/handler/msg in progress

* add cli/msg/handler

* add CLIQuery, fix tests

* fix golangci

* add docs in progre

* add comments

* add comments

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* add comments in progress

* add comments

* fix comment

* add comments in progress

* recover IntEncoding scheme for integer

* add uint tests, don't use codec in custom types

* finalize merge

* add godoc

* add godoc in progress

* reformat test

* rm XXX

* add godoc

* modify store

* add query

* update query.go

* update query.go

* cli refactor in progress

* cli refactor in progress

* add Query to boolean.go

* fix key

* fix cli / merkle test

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* fix test

* fix client

* merge from ics04 branch

* merge from ics04 branch

* merge from ics04 branch

* merge from ics04 branch

* fix lint

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* applying review in progress

* apply review - make querier interface

* fix dependency

* fix dependency

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* reflect downstream change

* fix cli

* reflect downstream changes

* rm commented lines

* address review in progress

* address review, rm cleanup/closing

* rename Path -> Prefix

* Store accessor upstream changes (#5119)

* Store accessor upstream changes (#5119)

* add comments, reformat merkle querier

* rm merkle/utils

* ICS 23 upstream changes (#5120)

* ICS 23 upstream changes (#5120)

* update Value

* update test

* fix

* ICS 02 upstream changes (#5122)

* ICS 02 upstream changes (#5122)

* ICS 03 upstream changes (#5123)

* ICS 03 upstream changes (#5123)

* cleanup types and submodule

* more cleanup and godocs

* remove counterPartyManager/State and cleanup

* implement SubmitMisbehaviour and refactor

* errors

* events

* fix test

* refactors

* WIP refactor ICS03

* remove Mapping

* remove store accessors

* proposed refactor

* remove store accessors from ICS02

* refactor queriers, handler and clean keeper

* logger and tx long description

* ineffassign

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* remove store accessors

* refactor handshake to update it to the latest ICS03 spec

* update handler and msgs

* add verification functions

* update verification

* ICS02 module.go

* top level x/ibc structure

* update connection queries

* update connection tx

* remove extra files

* update expected client keeper and export verification funcs

* Update x/ibc/02-client/client/cli/query.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Update x/ibc/02-client/types/tendermint/consensus_state.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* address some of the review comments

* resolve some TODOs and address comments from review

* update connection versioning

* minor error updates

* minor UX improvements

* rename pkg

* fixes

* refactor ICS23

* cleanup types

* rename pkg and fix import

* implement batch verification

* gosimple suggestion

* various fixes; remove legacy tests; remove commitment path query

* alias

* minor updates from ICS23

* renaming

* update verification and rename root funcs

* move querier to x/ibc

* update query.go to use 'custom/...' query path

* add tests

* ICS 24 Implementation (#5229)

* add validation functions

* validate path in ics-23

* address @fede comments

* move errors into host package

* flatten ICS23 structure

* fix ApplyPrefix

* updates from ICS23 and ICS24

* msg.ValidateBasic and ADR09 evidence interface

* complete types testing

* delete empty test file

* remove ibc errors from core error package

* custom JSON marshaling; msg.ValidateBasic; renaming of variables

* minor update

* custom JSON marshaling

* minor changes on commitment types

* R4R - Store consensus state correctly (#5242)

* store consensus state correctly

* fix client example

* update alias

* update alias

* implement ics25

* update comment

* refactor method name

* fix file name

* add test case

* refactor code

* refactor code

* blocked the consensusState check

* refactor code

* fix golangci comments

* refactor testcase

* replace rootMultiStore with simApp

* remove unless code

* remove unless code & refactor test case

* refactor testcase

* goimports code

* clean up

* Add unit tests for ICS04 (#5286)

* fix test

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* applying review in progress

* apply review - make querier interface

* fix cli errors

* fix dependency

* fix dependency

* reflect method name change

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* reflect downstream change

* fix cli

* reflect downstream changes

* reflect downstream changes

* fix from address in tx cli

* fix cli in progress(squash later)

* fix cli

* remove timeout, add channel cli

* fix golangci

* fix cli

* Clean up

* fix mock cli in progress

* finalize cleanup, mock cli wip

* add cli for mocksend

* fix handler

* rm commented lines

* address review in progress

* address review, rm cleanup/closing

* rename mock packages

* fix interface for gaia

* rename Path -> Prefix

* Store accessor upstream changes (#5119)

* Store accessor upstream changes (#5119)

* add comments, reformat merkle querier

* rm merkle/utils

* ICS 23 upstream changes (#5120)

* ICS 23 upstream changes (#5120)

* update Value

* update test

* fix

* ICS 02 upstream changes (#5122)

* ICS 02 upstream changes (#5122)

* ICS 03 upstream changes (#5123)

* ICS 03 upstream changes (#5123)

* update test

* cleanup types and submodule

* more cleanup and godocs

* remove counterPartyManager/State and cleanup

* implement SubmitMisbehaviour and refactor

* errors

* events

* fix test

* refactors

* WIP refactor ICS03

* remove Mapping

* remove store accessors

* proposed refactor

* remove store accessors from ICS02

* refactor queriers, handler and clean keeper

* logger and tx long description

* ineffassign

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* remove store accessors

* refactor handshake to update it to the latest ICS03 spec

* update handler and msgs

* add verification functions

* update verification

* ICS02 module.go

* top level x/ibc structure

* update connection queries

* update connection tx

* remove extra files

* refactor: remove store accessors, update keeper and types to match spec (WIP)

* update handshake and packet

* implement packet timeouts

* implement send and receive packet

* implement packet ACK

* update handler

* add channel errors

* channel querier

* update expected client keeper and export verification funcs

* ICS 05 Implementation

* release port and godocs

* Update x/ibc/02-client/client/cli/query.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Update x/ibc/02-client/types/tendermint/consensus_state.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* address some of the review comments

* resolve some TODOs and address comments from review

* update connection versioning

* minor error updates

* update ICS04 with downstream changes

* Implement tx cli actions

* add MsgSendPacket handler; msg validation, errors and events

* update errors and add port Keeper to ibc Keeper

* minor UX improvements

* rename pkg

* fixes

* refactor ICS23

* cleanup types

* ICS 5 updates (#5222)

* Validate port identifiers

* Refactor to static bind

* Add comments

* Add 'GetPorts' query function

* rename pkg and fix import

* implement batch verification

* gosimple suggestion

* various fixes; remove legacy tests; remove commitment path query

* alias

* minor updates from ICS23

* renaming

* update verification and rename root funcs

* rm legacy tests; add query proofs support

* remove capability key generation and authentication logic

* move querier to x/ibc

* update query.go to use 'custom/...' query path

* add tests

* ICS 24 Implementation (#5229)

* add validation functions

* validate path in ics-23

* address @fede comments

* move errors into host package

* flatten ICS23 structure

* fix ApplyPrefix

* updates from ICS23 and ICS24

* msg.ValidateBasic and ADR09 evidence interface

* complete types testing

* delete empty test file

* remove ibc errors from core error package

* custom JSON marshaling; msg.ValidateBasic; renaming of variables

* minor update

* custom JSON marshaling

* use host validation for port ids

* downstream changes; custom marshal JSON; msg validation, and update errors

* update errors and aliases

* update msg validation and CLI UX

* minor changes on commitment types

* fix channel and packet check (#5243)

* R4R - Store consensus state correctly (#5242)

* store consensus state correctly

* fix client example

* update alias

* update alias

* update alias and keeper.GetPort()

* authenticate port ID; remove send packet msg from CLI

* comment out handlers

* add ibc module to simapp

* ICS20 implementation (#5204)

* add ibc bank mock

* modify handler

* import channel

* add receiving logic

* add cli proof handling

* modify cli

* modify receiver type

* modify errcode

* optimize codes

* add denom prefix when source is true

* refactor code

* error return

* switch ibc antehandler to decorator pattern

* fix name/comment

* ICS 20 implementation (#5250)

* move ics20 code to 20-transfer

* clean code

* fix compiling error

* add transfer module

* address ICS20 comments from review

* add routing callbacks

* clean code

* add missing err return

* modify err type

* modify err type

* add supply handling

* modify proof type

* add comments for msg and packet data

* add timeout supply handling

* modify module account name

* use supply keeper for burn and mint coins

* restructure keeper

* update alias and module.go

* golangci linter

* add ics20 handler to IBC handler

* update callbacks

* update ICS20 escrow address

* fix querier routes

* fix create client cli

* minor updates

* ibc querier test

* Refactor ibc/mock/bank into ICS 20 (#5264)

* Most of code port from mock module to ICS 20

* A few minor fixes

* Apply suggestions from code review

Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>

* Fix suggestions from autolinter

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* Fix order of messages

* Add invalid height error code, check non-nil proof

* Fix linter error

* Return the underlying error

* Tendermint starts at height 1

* Apply suggestions from code review

* setup ics20 test suite

* add event to MsgRecvPacket

* update ibc keeper test to use test suite

* Add handshake commands

* WIP connection handshake

* WIP Connection Handshake

* Add cliCtx.WaitForNBlocks

* fix connection handshake in progress

* fix connection handshake in progress

* add channel unit test

* add more channel tests

* fix channel test

* refactor channel test

* add capability test for channel

* make channel testing work

* optimize channel test

* delete types/errors.go

* modify capability test

* uncomment

* add msg tests for channel

* fix port capability store

* fix channel test

* use simapp

* modify channel test

* refactor channel msg test

* go fmt

* IBC alpha general cleanup (#5291)

* remove prefix from keeper; update client queries; address ICS02 comments from @cwgoes

* add proof for root query

* golangci

* remove hardcoded bind port logic

* space

* WIP: register errors

* register errors; make format

* use new instead of register; unescape path

* golangci

* Fix codec issue in ics23

* Modify codec registration style to match previous working state

* write port tests

* ICS-02: Keeper Tests (#5329)

* add keeper tests

* fix tendermint tests

* Fix proof verification; remove store key prefixes; add additional path validations (#5313)

* fix poof verify

* minor cleanup

* fix tests

* remove key prefixes

* fix tests

* Add ICS20 tests (#5308)

* add ics20 test

* delete debug

* fix ics20 test

* revert and modify

* optimize test

* add ics20 msg test

* fix test

* add packet tests and more msgs tests

* add ReceivePacket and callbacks tests

* fix callbacks test

* add handler tests for ics20

* fix handler tests

* minor cleanup

* test all positive amounts

* update test suite NotNil to Error

* fix ics20 tests

* expected error

* Add IBC REST endpoints (#5310)

* add rest framework

* add rest endpoints for ibc connection

* add rest endpoints for ibc client

* add rest endpoints for ibc channel

* modify ibc rest api

* add rest endpoints for ibc transfer

* fix query route

* fix receive packet

* fix query client state api

* use sub module name instead of icsxx

* use const for prove judgement

* modify ibc rest api

* add api docs to swagger

* add ibc config

* fix proof path in swagger

* return query result proof

* update swagger docs

* parse prove

* clean up

* fix ibc rest api and swagger docs

* fix host validate

* fix typo

* add submitMisbehaviour error response in swagger

* fix rest queryRoot and swagger doc

* add response comments for each REST functions

* fix rest function comments

* fix IBC proofs (#5351)

* fix ICS02 proofs

* fix ICS03 proofs

* fix ICS04 proofs

* fix ICS20 proofs

* make format

* fix build; comment handshakes

* ICS-2 Implement Misbehavior (#5321)

* ibc client evidence route

* split evidence from misbehaviour

* clean up client events

* test misbehaviour and evidence

* remove comments

* remove frozen comments from demo

* Update x/ibc/02-client/types/tendermint/evidence_test.go

Co-Authored-By: Aditya <adityasripal@gmail.com>

* change evidence to detect malicious chain

* remove unnecessary sort

* fix evidence and persist committers to check misbehaviour

* minor fixes and remove incorrect tests

* add evidence tests

* remove debug statements

* cleanup evidence test

* start misbehaviour tests

* fix nondeterministic bug

* add same height and next height checks in misbehaviour

* fix bugs

* apply fede review suggestions

* finish code review changes

* fix GetCommitter and write keeper-level misbehaviour tests

* remove incorrect special case checking

* save

* final fixes

* save

* fix conflict

* fix conflicts and add back submit misbehaviour msg

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* save

* add godocs and fix test

* fix test panics in other modules

* Update x/ibc/02-client/keeper/client.go

Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>

* add back aliases

* Misc ibc fixes (#5357)

* fix cli ExactArgs

* remove full handshakes

* rm dup flag

* fix error handling

* Implement Query Committer methods in ICS-02 (#5402)

* add query methods for committers in ICS-02

* Update x/ibc/02-client/keeper/keeper.go

* add REST docs

* fix test

* IBC UX improvements (#5364)

* ICS02 iterators

* ICS03 iterators

* ICS04 iterators

* ICS02 client updates

* CLI connections

* setup queriers

* clean up queriers

* add tests

* IBC top-level querier tests

* update ICS02 keys

* update ICS03 keys

* make format

* update ICS04 keys

* fix a few tests

* fix ICS20 tests

* update keys

* fix ICS02 queries (#5425)

* fix CLI JSON param unmarshaling (#5431)

* Fix inconsistent string lookup functions (#5437)

* fix inconsistent string lookup functions

* test client type and ordering

* channel and connection state tests

* address golangcibot comments

* fix test

* Update x/ibc error handling (#5462)

* Merge PR #5428: Add mod, exponentiation for uint

* Modified examples in distribution module (#5441)

* Merge PR #5442: Remove of the client/alias.go

* Merge PR #5445: Mock rpcclient in tests for votes pagination

* Merge PR #5435: Added iterator that allows to read only requested values

* Merge PR #5427: Remove code duplication in x/auth/client/cli

* Merge PR #5421: Refactor Error Handling

* update x/ibc error handling

* update ICS24 and ICS02 errors

* ICS03, ICS23 and common errors

* updates from master and errors from ICS04

* build

* fix ics20 tests

* fix tests

* golangcibot fixes

Co-authored-by: Kevin Davis <karzak@users.noreply.github.com>
Co-authored-by: kaustubhkapatral <54210167+kaustubhkapatral@users.noreply.github.com>
Co-authored-by: Ferenc Fabian <qwer.kocka@gmail.com>
Co-authored-by: Dmitry Shulyak <yashulyak@gmail.com>
Co-authored-by: Alessio Treglia <quadrispro@ubuntu.com>
Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com>

* ADR 015 Implementation (#5401)

* implement in progress

* rm unneccessary change under simapp, modify baseapp for codetxbreak

* fix test in progress

* fix test error

* fix golangci

* address minor comments

* mv antehandler to ante/, address comments

* fix GetCommitment => GetData, fix syntax

* checkout types/ to ibc-alpha

* checkout to origin/ibc-alpha

* fix branch problem

* fix syntax error

* recover PacketI interface

* mv recvpacket rest from 20 -> 04

* address minor comments

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* rm wrong files

* Apply suggestions from code review

* PacketDataI field is now named, not embed

* add acknowledgement hashing

* rename finalization functiosn

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* Rename GetCommitment() to GetBytes()

* Add recv sequence incr to RecvPacket()

* Revert but where is PacketExecuted() called

* Call PacketExecuted(), check seq in RecvPacket()

* The port is called "bank"

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* Update simapp/app.go

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* Remove omitempty

* Add godoc

* Move events

* set ProofVerificationDecorator on AnteHandler

* Apply suggestions from code review

Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>

* format

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: Christopher Goes <cwgoes@pluranimity.org>
Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>

* IBC alpha

* ICS 23 Implementation (#4515)

* add mapping

* rm unused mapping/*, rm interfaces

* rm unused code

* mv mapping -> state, rm x/ibc

* rm GetIfExists

* add key

* rm custom encoding/decoding in enum/bool

* fix lint

* rm tests

* add commitment

* newtyped remote values

* newtyped context

* revert context newtype

* add README, keypath

* reflect downstream ics

* add merkle

* add test for proving

* soft coded root keypath

* add update

* remove RootUpdate

* separate keypath and keuprefix

* add codec

* separate root/path

* add path to codec

* add docs in progre

* add comments

* add comments

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* add comments in progress

* add comments

* fix comment

* add comments in progress

* recover IntEncoding scheme for integer

* add uint tests, don't use codec in custom types

* finalize merge

* add godoc

* reformat test

* rm XXX

* add godoc

* add query

* update query.go

* update query.go

* add Query to boolean.go

* fix key

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* merge from ics04 branch

* merge from ics04 branch

* fix lint

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* applying review in progress

* apply review - make querier interface

* fix dependency

* revise querier interface to work both on cli & store

* rm commented lines

* rename Path -> Prefix

* Store accessor upstream changes (#5119)

* Store accessor upstream changes (#5119)

* add comments, reformat merkle querier

* rm merkle/utils

* ICS 23 upstream changes (#5120)

* ICS 23 upstream changes (#5120)

* update Value

* remove Mapping

* remove store accessors

* refactor ICS23

* cleanup types

* implement batch verification

* gosimple suggestion

* alias

* add tests

* ICS 24 Implementation (#5229)

* add validation functions

* validate path in ics-23

* address @fede comments

* move errors into host package

* flatten ICS23 structure

* fix ApplyPrefix

* complete types testing

* delete empty test file

* remove ibc errors from core error package

* start batch-verify tests

* minor changes on commitment types

* use testsuite

* upstream changes

* context changes

* ICS 02 Implementation (#4516)

* add mapping

* rm unused mapping/*, rm interfaces

* rm unused code

* mv mapping -> state, rm x/ibc

* rm GetIfExists

* add key

* rm custom encoding/decoding in enum/bool

* fix lint

* rm tests

* add commitment

* newtyped remote values

* newtyped context

* revert context newtype

* add README, keypath

* reflect downstream ics

* add merkle

* add test for proving

* soft coded root keypath

* add update

* remove RootUpdate

* separate keypath and keuprefix

* add codec

* separate root/path

* add path to codec

* add client

* add counterpartymanager

* fix manager

* add Is() to counterobject

* add readme, reflect ICS02 revision

* reflect downstream ics

* test in progress

* add test

* in progres

* fin rebase

* in progress

* fin rebase

* add CLIObject in progress

* cli in progress

* add CLIObject

* separate testing from tendermint

* add key to node

* add root and storekey to tests/node, add codec

* rm cli/query.go

* fix test

* fix lint

* fix lint

* add handler/msgs/client

* rm relay

* finalize rebase on 23 root/path sep

* fix lint, fix syntax

* rm freebase, reformat query

* add docs in progre

* add comments

* add comments

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* add comments in progress

* add comments

* fix comment

* add comments in progress

* recover IntEncoding scheme for integer

* add uint tests, don't use codec in custom types

* finalize merge

* add godoc

* add godoc in progress

* reformat test

* rm XXX

* add godoc

* modify store

* add query

* update query.go

* update query.go

* cli refactor in progress

* cli refactor in progress

* add Query to boolean.go

* fix key

* fix cli / merkle test

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* merge from ics04 branch

* merge from ics04 branch

* merge from ics04 branch

* fix lint

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* applying review in progress

* apply review - make querier interface

* fix dependency

* fix dependency

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* reflect downstream change

* fix cli

* rm commented lines

* address review in progress

* rename Path -> Prefix

* Store accessor upstream changes (#5119)

* Store accessor upstream changes (#5119)

* add comments, reformat merkle querier

* rm merkle/utils

* ICS 23 upstream changes (#5120)

* ICS 23 upstream changes (#5120)

* update Value

* update test

* fix

* ICS 02 upstream changes (#5122)

* ICS 02 upstream changes (#5122)

* cleanup types and submodule

* more cleanup and godocs

* remove counterPartyManager/State and cleanup

* implement SubmitMisbehaviour and refactor

* errors

* events

* fix test

* refactors

* remove Mapping

* remove store accessors

* proposed refactor

* remove store accessors from ICS02

* refactor queriers, handler and clean keeper

* logger and tx long description

* ineffassign

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* add verification functions

* ICS02 module.go

* top level x/ibc structure

* Update x/ibc/02-client/client/cli/query.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Update x/ibc/02-client/types/tendermint/consensus_state.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* address some of the review comments

* minor UX improvements

* rename pkg

* fixes

* refactor ICS23

* cleanup types

* implement batch verification

* gosimple suggestion

* various fixes; remove legacy tests; remove commitment path query

* alias

* minor updates from ICS23

* renaming

* update verification and rename root funcs

* move querier to x/ibc

* update query.go to use 'custom/...' query path

* add tests

* ICS 24 Implementation (#5229)

* add validation functions

* validate path in ics-23

* address @fede comments

* move errors into host package

* flatten ICS23 structure

* fix ApplyPrefix

* updates from ICS23 and ICS24

* msg.ValidateBasic and ADR09 evidence interface

* complete types testing

* delete empty test file

* remove ibc errors from core error package

* custom JSON marshaling

* start batch-verify tests

* minor changes on commitment types

* R4R - Store consensus state correctly (#5242)

* store consensus state correctly

* fix client example

* update alias

* use testsuite

* Integrate Evidence Implementation into ICS-02 (#5258)

* implement evidence in ics-02

* fix build errors and import cycles

* address fede comments

* remove unnecessary pubkey and fix init

* add tests

* finish tendermint tests

* complete merge

* Add tests for msgs

* upstream changes

* fix

* upstream changes

* fix cons state

* context changes

* ICS 03 Implementation (#4517)

* add test

* in progres

* fin rebase

* in progress

* fin rebase

* add CLIObject in progress

* cli in progress

* add CLIObject

* separate testing from tendermint

* add key to node

* add root and storekey to tests/node, add codec

* rm cli/query.go

* fix test

* fix lint

* fix lint

* add handler/msgs/client

* rm relay

* finalize rebase on 23 root/path sep

* fix lint, fix syntax

* fix querying

* extract out context withstore

* fix 02-client test

* fix 23-commitment test

* add query in progress

* rm freebase, reformat query

* add cli/handler/msg in progress

* add cli/msg/handler

* add CLIQuery, fix tests

* fix golangci

* add docs in progre

* add comments

* add comments

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* add comments in progress

* add comments

* fix comment

* add comments in progress

* recover IntEncoding scheme for integer

* add uint tests, don't use codec in custom types

* finalize merge

* add godoc

* add godoc in progress

* reformat test

* rm XXX

* add godoc

* modify store

* add query

* update query.go

* update query.go

* cli refactor in progress

* cli refactor in progress

* add Query to boolean.go

* fix key

* fix cli / merkle test

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* fix test

* fix client

* merge from ics04 branch

* merge from ics04 branch

* merge from ics04 branch

* merge from ics04 branch

* fix lint

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* applying review in progress

* apply review - make querier interface

* fix dependency

* fix dependency

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* reflect downstream change

* fix cli

* reflect downstream changes

* rm commented lines

* address review in progress

* address review, rm cleanup/closing

* rename Path -> Prefix

* Store accessor upstream changes (#5119)

* Store accessor upstream changes (#5119)

* add comments, reformat merkle querier

* rm merkle/utils

* ICS 23 upstream changes (#5120)

* ICS 23 upstream changes (#5120)

* update Value

* update test

* fix

* ICS 02 upstream changes (#5122)

* ICS 02 upstream changes (#5122)

* ICS 03 upstream changes (#5123)

* ICS 03 upstream changes (#5123)

* cleanup types and submodule

* more cleanup and godocs

* remove counterPartyManager/State and cleanup

* implement SubmitMisbehaviour and refactor

* errors

* events

* fix test

* refactors

* WIP refactor ICS03

* remove Mapping

* remove store accessors

* proposed refactor

* remove store accessors from ICS02

* refactor queriers, handler and clean keeper

* logger and tx long description

* ineffassign

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* remove store accessors

* refactor handshake to update it to the latest ICS03 spec

* update handler and msgs

* add verification functions

* update verification

* ICS02 module.go

* top level x/ibc structure

* update connection queries

* update connection tx

* remove extra files

* update expected client keeper and export verification funcs

* Update x/ibc/02-client/client/cli/query.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Update x/ibc/02-client/types/tendermint/consensus_state.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* address some of the review comments

* resolve some TODOs and address comments from review

* update connection versioning

* minor error updates

* minor UX improvements

* rename pkg

* fixes

* refactor ICS23

* cleanup types

* rename pkg and fix import

* implement batch verification

* gosimple suggestion

* various fixes; remove legacy tests; remove commitment path query

* alias

* minor updates from ICS23

* renaming

* update verification and rename root funcs

* move querier to x/ibc

* update query.go to use 'custom/...' query path

* add tests

* ICS 24 Implementation (#5229)

* add validation functions

* validate path in ics-23

* address @fede comments

* move errors into host package

* flatten ICS23 structure

* fix ApplyPrefix

* updates from ICS23 and ICS24

* msg.ValidateBasic and ADR09 evidence interface

* complete types testing

* delete empty test file

* remove ibc errors from core error package

* custom JSON marshaling; msg.ValidateBasic; renaming of variables

* minor update

* custom JSON marshaling

* start batch-verify tests

* minor changes on commitment types

* R4R - Store consensus state correctly (#5242)

* store consensus state correctly

* fix client example

* update alias

* update alias

* use testsuite

* Integrate Evidence Implementation into ICS-02 (#5258)

* implement evidence in ics-02

* fix build errors and import cycles

* address fede comments

* remove unnecessary pubkey and fix init

* add tests

* finish tendermint tests

* complete merge

* Add tests for msgs

* upstream changes

* fix

* upstream changes

* fix cons state

* context changes

* fix cli tx

* upstream changes

* fix

* ICS 05 implementation (#5193)

* fix lint

* fix lint

* add handler/msgs/client

* rm relay

* finalize rebase on 23 root/path sep

* fix lint, fix syntax

* fix querying

* extract out context withstore

* fix 02-client test

* fix 23-commitment test

* add query in progress

* rm freebase, reformat query

* add cli/handler/msg in progress

* add cli/msg/handler

* add CLIQuery, fix tests

* fix golangci

* add docs in progre

* add comments

* add comments

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* add comments in progress

* add comments

* fix comment

* add comments in progress

* recover IntEncoding scheme for integer

* add uint tests, don't use codec in custom types

* finalize merge

* add godoc

* add godoc in progress

* reformat test

* rm XXX

* add godoc

* modify store

* add query

* update query.go

* update query.go

* cli refactor in progress

* cli refactor in progress

* add Query to boolean.go

* fix key

* fix cli / merkle test

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* fix test

* fix client

* merge from ics04 branch

* merge from ics04 branch

* merge from ics04 branch

* merge from ics04 branch

* fix lint

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* applying review in progress

* apply review - make querier interface

* fix dependency

* fix dependency

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* reflect downstream change

* fix cli

* reflect downstream changes

* rm commented lines

* address review in progress

* address review, rm cleanup/closing

* rename Path -> Prefix

* Store accessor upstream changes (#5119)

* Store accessor upstream changes (#5119)

* add comments, reformat merkle querier

* rm merkle/utils

* ICS 23 upstream changes (#5120)

* ICS 23 upstream changes (#5120)

* update Value

* update test

* fix

* ICS 02 upstream changes (#5122)

* ICS 02 upstream changes (#5122)

* ICS 03 upstream changes (#5123)

* ICS 03 upstream changes (#5123)

* cleanup types and submodule

* more cleanup and godocs

* remove counterPartyManager/State and cleanup

* implement SubmitMisbehaviour and refactor

* errors

* events

* fix test

* refactors

* WIP refactor ICS03

* remove Mapping

* remove store accessors

* proposed refactor

* remove store accessors from ICS02

* refactor queriers, handler and clean keeper

* logger and tx long description

* ineffassign

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* remove store accessors

* refactor handshake to update it to the latest ICS03 spec

* update handler and msgs

* add verification functions

* update verification

* ICS02 module.go

* top level x/ibc structure

* update connection queries

* update connection tx

* remove extra files

* update expected client keeper and export verification funcs

* ICS 05 Implementation

* release port and godocs

* Update x/ibc/02-client/client/cli/query.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Update x/ibc/02-client/types/tendermint/consensus_state.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* address some of the review comments

* resolve some TODOs and address comments from review

* update connection versioning

* minor error updates

* update errors and add port Keeper to ibc Keeper

* minor UX improvements

* rename pkg

* fixes

* refactor ICS23

* cleanup types

* ICS 5 updates (#5222)

* Validate port identifiers

* Refactor to static bind

* Add comments

* Add 'GetPorts' query function

* rename pkg and fix import

* implement batch verification

* gosimple suggestion

* various fixes; remove legacy tests; remove commitment path query

* alias

* minor updates from ICS23

* renaming

* update verification and rename root funcs

* move querier to x/ibc

* update query.go to use 'custom/...' query path

* add tests

* ICS 24 Implementation (#5229)

* add validation functions

* validate path in ics-23

* address @fede comments

* move errors into host package

* flatten ICS23 structure

* fix ApplyPrefix

* updates from ICS23 and ICS24

* msg.ValidateBasic and ADR09 evidence interface

* complete types testing

* delete empty test file

* remove ibc errors from core error package

* custom JSON marshaling; msg.ValidateBasic; renaming of variables

* minor update

* custom JSON marshaling

* use host validation for port ids

* start batch-verify tests

* minor changes on commitment types

* R4R - Store consensus state correctly (#5242)

* store consensus state correctly

* fix client example

* update alias

* update alias

* update alias and keeper.GetPort()

* use testsuite

* Integrate Evidence Implementation into ICS-02 (#5258)

* implement evidence in ics-02

* fix build errors and import cycles

* address fede comments

* remove unnecessary pubkey and fix init

* add tests

* finish tendermint tests

* complete merge

* Add tests for msgs

* upstream changes

* fix

* upstream changes

* fix cons state

* context changes

* fix cli tx

* upstream changes

* upstream changes

* ICS 04 Implementation (#4548)

* merge from ics04 branch

* merge from ics04 branch

* fix lint

* add port

* fix test

* add mocks

* fix connid -> portid in handshake.go

* add mock

* add ibc module.go, finalize mock

* add keeper

* add StoreKey const

* fix test

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* applying review in progress

* apply review - make querier interface

* fix cli errors

* fix dependency

* fix dependency

* reflect method name change

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* reflect downstream change

* fix cli

* reflect downstream changes

* reflect downstream changes

* fix from address in tx cli

* fix cli in progress(squash later)

* fix cli

* remove timeout, add channel cli

* fix golangci

* fix cli

* Clean up

* fix mock cli in progress

* finalize cleanup, mock cli wip

* add cli for mocksend

* fix handler

* rm commented lines

* address review in progress

* address review, rm cleanup/closing

* rename mock packages

* fix interface for gaia

* rename Path -> Prefix

* Store accessor upstream changes (#5119)

* Store accessor upstream changes (#5119)

* add comments, reformat merkle querier

* rm merkle/utils

* ICS 23 upstream changes (#5120)

* ICS 23 upstream changes (#5120)

* update Value

* update test

* fix

* ICS 02 upstream changes (#5122)

* ICS 02 upstream changes (#5122)

* ICS 03 upstream changes (#5123)

* ICS 03 upstream changes (#5123)

* update test

* cleanup types and submodule

* more cleanup and godocs

* remove counterPartyManager/State and cleanup

* implement SubmitMisbehaviour and refactor

* errors

* events

* fix test

* refactors

* WIP refactor ICS03

* remove Mapping

* remove store accessors

* proposed refactor

* remove store accessors from ICS02

* refactor queriers, handler and clean keeper

* logger and tx long description

* ineffassign

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* remove store accessors

* refactor handshake to update it to the latest ICS03 spec

* update handler and msgs

* add verification functions

* update verification

* ICS02 module.go

* top level x/ibc structure

* update connection queries

* update connection tx

* remove extra files

* refactor: remove store accessors, update keeper and types to match spec (WIP)

* update handshake and packet

* implement packet timeouts

* implement send and receive packet

* implement packet ACK

* update handler

* add channel errors

* channel querier

* update expected client keeper and export verification funcs

* ICS 05 Implementation

* release port and godocs

* Update x/ibc/02-client/client/cli/query.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Update x/ibc/02-client/types/tendermint/consensus_state.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* address some of the review comments

* resolve some TODOs and address comments from review

* update connection versioning

* minor error updates

* update ICS04 with downstream changes

* Implement tx cli actions

* add MsgSendPacket handler; msg validation, errors and events

* update errors and add port Keeper to ibc Keeper

* minor UX improvements

* rename pkg

* fixes

* refactor ICS23

* cleanup types

* ICS 5 updates (#5222)

* Validate port identifiers

* Refactor to static bind

* Add comments

* Add 'GetPorts' query function

* rename pkg and fix import

* implement batch verification

* gosimple suggestion

* various fixes; remove legacy tests; remove commitment path query

* alias

* minor updates from ICS23

* renaming

* update verification and rename root funcs

* rm legacy tests; add query proofs support

* remove capability key generation and authentication logic

* move querier to x/ibc

* update query.go to use 'custom/...' query path

* add tests

* ICS 24 Implementation (#5229)

* add validation functions

* validate path in ics-23

* address @fede comments

* move errors into host package

* flatten ICS23 structure

* fix ApplyPrefix

* updates from ICS23 and ICS24

* msg.ValidateBasic and ADR09 evidence interface

* complete types testing

* delete empty test file

* remove ibc errors from core error package

* custom JSON marshaling; msg.ValidateBasic; renaming of variables

* minor update

* custom JSON marshaling

* use host validation for port ids

* downstream changes; custom marshal JSON; msg validation, and update errors

* update errors and aliases

* start batch-verify tests

* update msg validation and CLI UX

* minor changes on commitment types

* fix channel and packet check (#5243)

* R4R - Store consensus state correctly (#5242)

* store consensus state correctly

* fix client example

* update alias

* update alias

* update alias and keeper.GetPort()

* authenticate port ID; remove send packet msg from CLI

* comment out handlers

* use testsuite

* Integrate Evidence Implementation into ICS-02 (#5258)

* implement evidence in ics-02

* fix build errors and import cycles

* address fede comments

* remove unnecessary pubkey and fix init

* add tests

* finish tendermint tests

* complete merge

* Add tests for msgs

* upstream changes

* fix

* upstream changes

* fix cons state

* context changes

* fix cli tx

* upstream changes

* upstream changes

* upstream changes

* IBC v1.0.0 (#5245)

* applying review in progress

* apply review - make querier interface

* fix cli errors

* fix dependency

* fix dependency

* reflect method name change

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* reflect downstream change

* fix cli

* reflect downstream changes

* reflect downstream changes

* fix from address in tx cli

* fix cli in progress(squash later)

* fix cli

* remove timeout, add channel cli

* fix golangci

* fix cli

* Clean up

* fix mock cli in progress

* finalize cleanup, mock cli wip

* add cli for mocksend

* fix handler

* rm commented lines

* address review in progress

* address review, rm cleanup/closing

* rename mock packages

* fix interface for gaia

* rename Path -> Prefix

* Store accessor upstream changes (#5119)

* Store accessor upstream changes (#5119)

* add comments, reformat merkle querier

* rm merkle/utils

* ICS 23 upstream changes (#5120)

* ICS 23 upstream changes (#5120)

* update Value

* update test

* fix

* ICS 02 upstream changes (#5122)

* ICS 02 upstream changes (#5122)

* ICS 03 upstream changes (#5123)

* ICS 03 upstream changes (#5123)

* update test

* cleanup types and submodule

* more cleanup and godocs

* remove counterPartyManager/State and cleanup

* implement SubmitMisbehaviour and refactor

* errors

* events

* fix test

* refactors

* WIP refactor ICS03

* remove Mapping

* remove store accessors

* proposed refactor

* remove store accessors from ICS02

* refactor queriers, handler and clean keeper

* logger and tx long description

* ineffassign

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* remove store accessors

* refactor handshake to update it to the latest ICS03 spec

* update handler and msgs

* add verification functions

* update verification

* ICS02 module.go

* top level x/ibc structure

* update connection queries

* update connection tx

* remove extra files

* refactor: remove store accessors, update keeper and types to match spec (WIP)

* update handshake and packet

* implement packet timeouts

* implement send and receive packet

* implement packet ACK

* update handler

* add channel errors

* channel querier

* update expected client keeper and export verification funcs

* ICS 05 Implementation

* release port and godocs

* Update x/ibc/02-client/client/cli/query.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Update x/ibc/02-client/types/tendermint/consensus_state.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* address some of the review comments

* resolve some TODOs and address comments from review

* update connection versioning

* minor error updates

* update ICS04 with downstream changes

* Implement tx cli actions

* add MsgSendPacket handler; msg validation, errors and events

* update errors and add port Keeper to ibc Keeper

* minor UX improvements

* rename pkg

* fixes

* refactor ICS23

* cleanup types

* ICS 5 updates (#5222)

* Validate port identifiers

* Refactor to static bind

* Add comments

* Add 'GetPorts' query function

* rename pkg and fix import

* implement batch verification

* gosimple suggestion

* various fixes; remove legacy tests; remove commitment path query

* alias

* minor updates from ICS23

* renaming

* update verification and rename root funcs

* rm legacy tests; add query proofs support

* remove capability key generation and authentication logic

* move querier to x/ibc

* update query.go to use 'custom/...' query path

* add tests

* ICS 24 Implementation (#5229)

* add validation functions

* validate path in ics-23

* address @fede comments

* move errors into host package

* flatten ICS23 structure

* fix ApplyPrefix

* updates from ICS23 and ICS24

* msg.ValidateBasic and ADR09 evidence interface

* complete types testing

* delete empty test file

* remove ibc errors from core error package

* custom JSON marshaling; msg.ValidateBasic; renaming of variables

* minor update

* custom JSON marshaling

* use host validation for port ids

* downstream changes; custom marshal JSON; msg validation, and update errors

* update errors and aliases

* start batch-verify tests

* update msg validation and CLI UX

* minor changes on commitment types

* fix channel and packet check (#5243)

* R4R - Store consensus state correctly (#5242)

* store consensus state correctly

* fix client example

* update alias

* update alias

* update alias and keeper.GetPort()

* authenticate port ID; remove send packet msg from CLI

* comment out handlers

* add ibc module to simapp

* ICS20 implementation (#5204)

* add ibc bank mock

* modify handler

* import channel

* add receiving logic

* add cli proof handling

* modify cli

* modify receiver type

* modify errcode

* optimize codes

* add denom prefix when source is true

* refactor code

* error return

* switch ibc antehandler to decorator pattern

* fix name/comment

* ICS 20 implementation (#5250)

* move ics20 code to 20-transfer

* clean code

* fix compiling error

* add transfer module

* address ICS20 comments from review

* add routing callbacks

* clean code

* add missing err return

* modify err type

* modify err type

* add supply handling

* modify proof type

* add comments for msg and packet data

* add timeout supply handling

* modify module account name

* use supply keeper for burn and mint coins

* restructure keeper

* update alias and module.go

* golangci linter

* add ics20 handler to IBC handler

* update callbacks

* update ICS20 escrow address

* fix querier routes

* fix create client cli

* minor updates

* ibc querier test

* Refactor ibc/mock/bank into ICS 20 (#5264)

* Most of code port from mock module to ICS 20

* A few minor fixes

* Apply suggestions from code review

Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>

* Fix suggestions from autolinter

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* Fix order of messages

* Add invalid height error code, check non-nil proof

* Fix linter error

* Return the underlying error

* Tendermint starts at height 1

* Apply suggestions from code review

* setup ics20 test suite

* add event to MsgRecvPacket

* update ibc keeper test to use test suite

* Add handshake commands

* WIP connection handshake

* WIP Connection Handshake

* use testsuite

* Add cliCtx.WaitForNBlocks

* fix connection handshake in progress

* fix connection handshake in progress

* Integrate Evidence Implementation into ICS-02 (#5258)

* implement evidence in ics-02

* fix build errors and import cycles

* address fede comments

* remove unnecessary pubkey and fix init

* add tests

* finish tendermint tests

* complete merge

* Add tests for msgs

* upstream changes

* fix

* upstream changes

* fix cons state

* context changes

* fix cli tx

* upstream changes

* upstream changes

* upstream changes

* upstream changes

* IBC demo fixes (#5267)

* WIP refactor ICS03

* remove Mapping

* remove store accessors

* proposed refactor

* remove store accessors from ICS02

* refactor queriers, handler and clean keeper

* logger and tx long description

* ineffassign

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* remove store accessors

* refactor handshake to update it to the latest ICS03 spec

* update handler and msgs

* add verification functions

* update verification

* ICS02 module.go

* top level x/ibc structure

* update connection queries

* update connection tx

* remove extra files

* refactor: remove store accessors, update keeper and types to match spec (WIP)

* update handshake and packet

* implement packet timeouts

* implement send and receive packet

* implement packet ACK

* update handler

* add channel errors

* channel querier

* update expected client keeper and export verification funcs

* ICS 05 Implementation

* release port and godocs

* Update x/ibc/02-client/client/cli/query.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Update x/ibc/02-client/types/tendermint/consensus_state.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* address some of the review comments

* resolve some TODOs and address comments from review

* update connection versioning

* minor error updates

* update ICS04 with downstream changes

* Implement tx cli actions

* add MsgSendPacket handler; msg validation, errors and events

* update errors and add port Keeper to ibc Keeper

* minor UX improvements

* rename pkg

* fixes

* refactor ICS23

* cleanup types

* ICS 5 updates (#5222)

* Validate port identifiers

* Refactor to static bind

* Add comments

* Add 'GetPorts' query function

* rename pkg and fix import

* implement batch verification

* gosimple suggestion

* various fixes; remove legacy tests; remove commitment path query

* alias

* minor updates from ICS23

* renaming

* update verification and rename root funcs

* rm legacy tests; add query proofs support

* remove capability key generation and authentication logic

* move querier to x/ibc

* update query.go to use 'custom/...' query path

* add tests

* ICS 24 Implementation (#5229)

* add validation functions

* validate path in ics-23

* address @fede comments

* move errors into host package

* flatten ICS23 structure

* fix ApplyPrefix

* updates from ICS23 and ICS24

* msg.ValidateBasic and ADR09 evidence interface

* complete types testing

* delete empty test file

* remove ibc errors from core error package

* custom JSON marshaling; msg.ValidateBasic; renaming of variables

* minor update

* custom JSON marshaling

* use host validation for port ids

* downstream changes; custom marshal JSON; msg validation, and update errors

* update errors and aliases

* start batch-verify tests

* update msg validation and CLI UX

* minor changes on commitment types

* fix channel and packet check (#5243)

* R4R - Store consensus state correctly (#5242)

* store consensus state correctly

* fix client example

* update alias

* update alias

* update alias and keeper.GetPort()

* authenticate port ID; remove send packet msg from CLI

* comment out handlers

* add ibc module to simapp

* ICS20 implementation (#5204)

* add ibc bank mock

* modify handler

* import channel

* add receiving logic

* add cli proof handling

* modify cli

* modify receiver type

* modify errcode

* optimize codes

* add denom prefix when source is true

* refactor code

* error return

* switch ibc antehandler to decorator pattern

* fix name/comment

* ICS 20 implementation (#5250)

* move ics20 code to 20-transfer

* clean code

* fix compiling error

* add transfer module

* address ICS20 comments from review

* add routing callbacks

* clean code

* add missing err return

* modify err type

* modify err type

* add supply handling

* modify proof type

* add comments for msg and packet data

* add timeout supply handling

* modify module account name

* use supply keeper for burn and mint coins

* restructure keeper

* update alias and module.go

* golangci linter

* add ics20 handler to IBC handler

* update callbacks

* update ICS20 escrow address

* fix querier routes

* fix create client cli

* minor updates

* ibc querier test

* Refactor ibc/mock/bank into ICS 20 (#5264)

* Most of code port from mock module to ICS 20

* A few minor fixes

* Apply suggestions from code review

Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>

* Fix suggestions from autolinter

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* Fix order of messages

* Add invalid height error code, check non-nil proof

* Fix linter error

* Return the underlying error

* Tendermint starts at height 1

* Apply suggestions from code review

* setup ics20 test suite

* add event to MsgRecvPacket

* update ibc keeper test to use test suite

* Add handshake commands

* WIP connection handshake

* WIP Connection Handshake

* use testsuite

* Add cliCtx.WaitForNBlocks

* fix connection handshake in progress

* fix connection handshake in progress

* Add print debugging (old-school)

* Add log line

* More debugging

* Set prove flag to true

* More debugging

* Use store query

* Fix query, hopefully

* Fix query path

* Hmm

* Fix context bug

* Generate & return & use consensus state proof

* Print debugging

* Add debugging

* Begin working on the channel creation command

* remove submodule prefix from keypath, fix addConnectionToClients to treat nil as empty array

* fix OpenConfirm, rm debugging code

* WIP channel shake 🕺

* WIP channel shake 🕺

* WIP channel shake 🕺

* WIP channel shake 🕺

* WIP channel shake 🕺

* WIP channel shake 🕺

* WIP channel shake 🕺

* Update bound port

* Add from flag to ICS 20 commands

* Undefine flag

* add debug

* Uncomment channel message handlers

* fix validatebasic identifier failure

* Fix printing

* add debug code

* CLI debugging

* fix counterpartyHops, channel handshake working w/o port

* Fix compilation error

* Push channel query command update

* Remove unused code

* Add gaiacli keys test

* Update error

* Add printf

* fix token restriciton

* comment out port

* fix querier to retrieve the next sequence

* Alter command to take arguments

* Name it packet-sequence

* add packet query utils

* Use the querier

* Packet is JSON

* printf the value

* fix query packet

* fix packet receive in progress

* lol

* export Packet fields, rename Packet.XXX() -> Packet.GetXXX()

* fix route

* add debug

* comment out port logic from packet.go

* token transfer now working

* fix client tx

* Integrate Evidence Implementation into ICS-02 (#5258)

* implement evidence in ics-02

* fix build errors and import cycles

* address fede comments

* remove unnecessary pubkey and fix init

* add tests

* Apply suggestions from code review

* clean up

* finish tendermint tests

* complete merge

* Add tests for msgs

* ICS02 changes

* upstream changes

* fix

* upstream changes

* fix cons state

* context changes

* fix cli tx

* upstream changes

* upstream changes

* upstream changes

* upstream changes

* more cleanup

* Add unit tests for ICS03 (#5275)

* add Is() to counterobject

* add readme, reflect ICS02 revision

* reflect downstream ics

* test in progress

* add test

* in progres

* fin rebase

* in progress

* fin rebase

* add CLIObject in progress

* cli in progress

* add CLIObject

* separate testing from tendermint

* add key to node

* add root and storekey to tests/node, add codec

* rm cli/query.go

* fix test

* fix lint

* fix lint

* add handler/msgs/client

* rm relay

* finalize rebase on 23 root/path sep

* fix lint, fix syntax

* fix querying

* extract out context withstore

* fix 02-client test

* fix 23-commitment test

* add query in progress

* rm freebase, reformat query

* add cli/handler/msg in progress

* add cli/msg/handler

* add CLIQuery, fix tests

* fix golangci

* add docs in progre

* add comments

* add comments

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* add comments in progress

* add comments

* fix comment

* add comments in progress

* recover IntEncoding scheme for integer

* add uint tests, don't use codec in custom types

* finalize merge

* add godoc

* add godoc in progress

* reformat test

* rm XXX

* add godoc

* modify store

* add query

* update query.go

* update query.go

* cli refactor in progress

* cli refactor in progress

* add Query to boolean.go

* fix key

* fix cli / merkle test

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* godoc cleanup

* fix test

* fix client

* merge from ics04 branch

* merge from ics04 branch

* merge from ics04 branch

* merge from ics04 branch

* fix lint

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* applying review in progress

* apply review - make querier interface

* fix dependency

* fix dependency

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* reflect downstream change

* fix cli

* reflect downstream changes

* rm commented lines

* address review in progress

* address review, rm cleanup/closing

* rename Path -> Prefix

* Store accessor upstream changes (#5119)

* Store accessor upstream changes (#5119)

* add comments, reformat merkle querier

* rm merkle/utils

* ICS 23 upstream changes (#5120)

* ICS 23 upstream changes (#5120)

* update Value

* update test

* fix

* ICS 02 upstream changes (#5122)

* ICS 02 upstream changes (#5122)

* ICS 03 upstream changes (#5123)

* ICS 03 upstream changes (#5123)

* cleanup types and submodule

* more cleanup and godocs

* remove counterPartyManager/State and cleanup

* implement SubmitMisbehaviour and refactor

* errors

* events

* fix test

* refactors

* WIP refactor ICS03

* remove Mapping

* remove store accessors

* proposed refactor

* remove store accessors from ICS02

* refactor queriers, handler and clean keeper

* logger and tx long description

* ineffassign

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* remove store accessors

* refactor handshake to update it to the latest ICS03 spec

* update handler and msgs

* add verification functions

* update verification

* ICS02 module.go

* top level x/ibc structure

* update connection queries

* update connection tx

* remove extra files

* update expected client keeper and export verification funcs

* Update x/ibc/02-client/client/cli/query.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Update x/ibc/02-client/types/tendermint/consensus_state.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* address some of the review comments

* resolve some TODOs and address comments from review

* update connection versioning

* minor error updates

* minor UX improvements

* rename pkg

* fixes

* refactor ICS23

* cleanup types

* rename pkg and fix import

* implement batch verification

* gosimple suggestion

* various fixes; remove legacy tests; remove commitment path query

* alias

* minor updates from ICS23

* renaming

* update verification and rename root funcs

* move querier to x/ibc

* update query.go to use 'custom/...' query path

* add tests

* ICS 24 Implementation (#5229)

* add validation functions

* validate path in ics-23

* address @fede comments

* move errors into host package

* flatten ICS23 structure

* fix ApplyPrefix

* updates from ICS23 and ICS24

* msg.ValidateBasic and ADR09 evidence interface

* complete types testing

* delete empty test file

* remove ibc errors from core error package

* custom JSON marshaling; msg.ValidateBasic; renaming of variables

* minor update

* custom JSON marshaling

* minor changes on commitment types

* R4R - Store consensus state correctly (#5242)

* store consensus state correctly

* fix client example

* update alias

* update alias

* implement ics25

* update comment

* refactor method name

* fix file name

* add test case

* refactor code

* refactor code

* blocked the consensusState check

* refactor code

* fix golangci comments

* refactor testcase

* replace rootMultiStore with simApp

* remove unless code

* remove unless code & refactor test case

* refactor testcase

* goimports code

* clean up

* Add unit tests for ICS04 (#5286)

* fix test

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* applying review in progress

* apply review - make querier interface

* fix cli errors

* fix dependency

* fix dependency

* reflect method name change

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* revise querier interface to work both on cli & store

* reflect downstream change

* fix cli

* reflect downstream changes

* reflect downstream changes

* fix from address in tx cli

* fix cli in progress(squash later)

* fix cli

* remove timeout, add channel cli

* fix golangci

* fix cli

* Clean up

* fix mock cli in progress

* finalize cleanup, mock cli wip

* add cli for mocksend

* fix handler

* rm commented lines

* address review in progress

* address review, rm cleanup/closing

* rename mock packages

* fix interface for gaia

* rename Path -> Prefix

* Store accessor upstream changes (#5119)

* Store accessor upstream changes (#5119)

* add comments, reformat merkle querier

* rm merkle/utils

* ICS 23 upstream changes (#5120)

* ICS 23 upstream changes (#5120)

* update Value

* update test

* fix

* ICS 02 upstream changes (#5122)

* ICS 02 upstream changes (#5122)

* ICS 03 upstream changes (#5123)

* ICS 03 upstream changes (#5123)

* update test

* cleanup types and submodule

* more cleanup and godocs

* remove counterPartyManager/State and cleanup

* implement SubmitMisbehaviour and refactor

* errors

* events

* fix test

* refactors

* WIP refactor ICS03

* remove Mapping

* remove store accessors

* proposed refactor

* remove store accessors from ICS02

* refactor queriers, handler and clean keeper

* logger and tx long description

* ineffassign

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* remove store accessors

* refactor handshake to update it to the latest ICS03 spec

* update handler and msgs

* add verification functions

* update verification

* ICS02 module.go

* top level x/ibc structure

* update connection queries

* update connection tx

* remove extra files

* refactor: remove store accessors, update keeper and types to match spec (WIP)

* update handshake and packet

* implement packet timeouts

* implement send and receive packet

* implement packet ACK

* update handler

* add channel errors

* channel querier

* update expected client keeper and export verification funcs

* ICS 05 Implementation

* release port and godocs

* Update x/ibc/02-client/client/cli/query.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* Update x/ibc/02-client/types/tendermint/consensus_state.go

Co-Authored-By: Jack Zampolin <jack.zampolin@gmail.com>

* address some of the review comments

* resolve some TODOs and address comments from review

* update connection versioning

* minor error updates

* update ICS04 with downstream changes

* Implement tx cli actions

* add MsgSendPacket handler; msg validation, errors and events

* update errors and add port Keeper to ibc Keeper

* minor UX improvements

* rename pkg

* fixes

* refactor ICS23

* cleanup types

* ICS 5 updates (#5222)

* Validate port identifiers

* Refactor to static bind

* Add comments

* Add 'GetPorts' query function

* rename pkg and fix import

* implement batch verification

* gosimple suggestion

* various fixes; remove legacy tests; remove commitment path query

* alias

* minor updates from ICS23

* renaming

* update verification and rename root funcs

* rm legacy tests; add query proofs support

* remove capability key generation and authentication logic

* move querier to x/ibc

* update query.go to use 'custom/...' query path

* add tests

* ICS 24 Implementation (#5229)

* add validation functions

* validate path in ics-23

* address @fede comments

* move errors into host package

* flatten ICS23 structure

* fix ApplyPrefix

* updates from ICS23 and ICS24

* msg.ValidateBasic and ADR09 evidence interface

* complete types testing

* delete empty test file

* remove ibc errors from core error package

* custom JSON marshaling; msg.ValidateBasic; renaming of variables

* minor update

* custom JSON marshaling

* use host validation for port ids

* downstream changes; custom marshal JSON; msg validation, and update errors

* update errors and aliases

* update msg validation and CLI UX

* minor changes on commitment types

* fix channel and packet check (#5243)

* R4R - Store consensus state correctly (#5242)

* store consensus state correctly

* fix client example

* update alias

* update alias

* update alias and keeper.GetPort()

* authenticate port ID; remove send packet msg from CLI

* comment out handlers

* add ibc module to simapp

* ICS20 implementation (#5204)

* add ibc bank mock

* modify handler

* import channel

* add receiving logic

* add cli proof handling

* modify cli

* modify receiver type

* modify errcode

* optimize codes

* add denom prefix when source is true

* refactor code

* error return

* switch ibc antehandler to decorator pattern

* fix name/comment

* ICS 20 implementation (#5250)

* move ics20 code to 20-transfer

* clean code

* fix compiling error

* add transfer module

* address ICS20 comments from review

* add routing callbacks

* clean code

* add missing err return

* modify err type

* modify err type

* add supply handling

* modify proof type

* add comments for msg and packet data

* add timeout supply handling

* modify module account name

* use supply keeper for burn and mint coins

* restructure keeper

* update alias and module.go

* golangci linter

* add ics20 handler to IBC handler

* update callbacks

* update ICS20 escrow address

* fix querier routes

* fix create client cli

* minor updates

* ibc querier test

* Refactor ibc/mock/bank into ICS 20 (#5264)

* Most of code port from mock module to ICS 20

* A few minor fixes

* Apply suggestions from code review

Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>

* Fix suggestions from autolinter

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* Fix order of messages

* Add invalid height error code, check non-nil proof

* Fix linter error

* Return the underlying error

* Tendermint starts at height 1

* Apply suggestions from code review

* setup ics20 test suite

* add event to MsgRecvPacket

* update ibc keeper test to use test suite

* Add handshake commands

* WIP connection handshake

* WIP Connection Handshake

* Add cliCtx.WaitForNBlocks

* fix connection handshake in progress

* fix connection handshake in progress

* add channel unit test

* add more channel tests

* fix channel test

* refactor channel test

* add capability test for channel

* make channel testing work

* optimize channel test

* delete types/errors.go

* modify capability test

* uncomment

* add msg tests for channel

* fix port capability store

* fix channel test

* use simapp

* modify channel test

* refactor channel msg test

* go fmt

* IBC alpha general cleanup (#5291)

* remove prefix from keeper; update client queries; address ICS02 comments from @cwgoes

* add proof for root query

* golangci

* remove hardcoded bind port logic

* space

* WIP: register errors

* register errors; make format

* use new instead of register; unescape path

* golangci

* Fix codec issue in ics23

* Modify codec registration style to match previous working state

* write port tests

* ICS-02: Keeper Tests (#5329)

* add keeper tests

* fix tendermint tests

* Fix proof verification; remove store key prefixes; add additional path validations (#5313)

* fix poof verify

* minor cleanup

* fix tests

* remove key prefixes

* fix tests

* Add ICS20 tests (#5308)

* add ics20 test

* delete debug

* fix ics20 test

* revert and modify

* optimize test

* add ics20 msg test

* fix test

* add packet tests and more msgs tests

* add ReceivePacket and callbacks tests

* fix callbacks test

* add handler tests for ics20

* fix handler tests

* minor cleanup

* test all positive amounts

* update test suite NotNil to Error

* fix ics20 tests

* expected error

* Add IBC REST endpoints (#5310)

* add rest framework

* add rest endpoints for ibc connection

* add rest endpoints for ibc client

* add rest endpoints for ibc channel

* modify ibc rest api

* add rest endpoints for ibc transfer

* fix query route

* fix receive packet

* fix query client state api

* use sub module name instead of icsxx

* use const for prove judgement

* modify ibc rest api

* add api docs to swagger

* add ibc config

* fix proof path in swagger

* return query result proof

* update swagger docs

* parse prove

* clean up

* fix ibc rest api and swagger docs

* fix host validate

* fix typo

* add submitMisbehaviour error response in swagger

* fix rest queryRoot and swagger doc

* add response comments for each REST functions

* fix rest function comments

* fix IBC proofs (#5351)

* fix ICS02 proofs

* fix ICS03 proofs

* fix ICS04 proofs

* fix ICS20 proofs

* make format

* fix build; comment handshakes

* ICS-2 Implement Misbehavior (#5321)

* ibc client evidence route

* split evidence from misbehaviour

* clean up client events

* test misbehaviour and evidence

* remove comments

* remove frozen comments from demo

* Update x/ibc/02-client/types/tendermint/evidence_test.go

Co-Authored-By: Aditya <adityasripal@gmail.com>

* change evidence to detect malicious chain

* remove unnecessary sort

* fix evidence and persist committers to check misbehaviour

* minor fixes and remove incorrect tests

* add evidence tests

* remove debug statements

* cleanup evidence test

* start misbehaviour tests

* fix nondeterministic bug

* add same height and next height checks in misbehaviour

* fix bugs

* apply fede review suggestions

* finish code review changes

* fix GetCommitter and write keeper-level misbehaviour tests

* remove incorrect special case checking

* save

* final fixes

* save

* fix conflict

* fix conflicts and add back submit misbehaviour msg

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* save

* add godocs and fix test

* fix test panics in other modules

* Update x/ibc/02-client/keeper/client.go

Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>

* add back aliases

* Misc ibc fixes (#5357)

* fix cli ExactArgs

* remove full handshakes

* rm dup flag

* fix error handling

* Implement Query Committer methods in ICS-02 (#5402)

* add query methods for committers in ICS-02

* Update x/ibc/02-client/keeper/keeper.go

* add REST docs

* fix test

* IBC UX improvements (#5364)

* ICS02 iterators

* ICS03 iterators

* ICS04 iterators

* ICS02 client updates

* CLI connections

* setup queriers

* clean up queriers

* add tests

* IBC top-level querier tests

* update ICS02 keys

* update ICS03 keys

* make format

* update ICS04 keys

* fix a few tests

* fix ICS20 tests

* update keys

* fix ICS02 queries (#5425)

* fix CLI JSON param unmarshaling (#5431)

* Fix inconsistent string lookup functions (#5437)

* fix inconsistent string lookup functions

* test client type and ordering

* channel and connection state tests

* address golangcibot comments

* fix test

* Update x/ibc error handling (#5462)

* Merge PR #5428: Add mod, exponentiation for uint

* Modified examples in distribution module (#5441)

* Merge PR #5442: Remove of the client/alias.go

* Merge PR #5445: Mock rpcclient in tests for votes pagination

* Merge PR #5435: Added iterator that allows to read only requested values

* Merge PR #5427: Remove code duplication in x/auth/client/cli

* Merge PR #5421: Refactor Error Handling

* update x/ibc error handling

* update ICS24 and ICS02 errors

* ICS03, ICS23 and common errors

* updates from master and errors from ICS04

* build

* fix ics20 tests

* fix tests

* golangcibot fixes

Co-authored-by: Kevin Davis <karzak@users.noreply.github.com>
Co-authored-by: kaustubhkapatral <54210167+kaustubhkapatral@users.noreply.github.com>
Co-authored-by: Ferenc Fabian <qwer.kocka@gmail.com>
Co-authored-by: Dmitry Shulyak <yashulyak@gmail.com>
Co-authored-by: Alessio Treglia <quadrispro@ubuntu.com>
Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com>

* ADR 015 Implementation (#5401)

* implement in progress

* rm unneccessary change under simapp, modify baseapp for codetxbreak

* fix test in progress

* fix test error

* fix golangci

* address minor comments

* mv antehandler to ante/, address comments

* fix GetCommitment => GetData, fix syntax

* checkout types/ to ibc-alpha

* checkout to origin/ibc-alpha

* fix branch problem

* fix syntax error

* recover PacketI interface

* mv recvpacket rest from 20 -> 04

* address minor comments

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* rm wrong files

* Apply suggestions from code review

* PacketDataI field is now named, not embed

* add acknowledgement hashing

* rename finalization functiosn

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* Rename GetCommitment() to GetBytes()

* Add recv sequence incr to RecvPacket()

* Revert but where is PacketExecuted() called

* Call PacketExecuted(), check seq in RecvPacket()

* The port is called "bank"

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* Update simapp/app.go

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* Remove omitempty

* Add godoc

* Move events

* set ProofVerificationDecorator on AnteHandler

* Apply suggestions from code review

Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>

* format

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: Christopher Goes <cwgoes@pluranimity.org>
Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>

* Fix build errors

* remove tmcmn instance

* remove tmcmn instance

* Fix compliation errors

* Fix build errors

* Fix build errors

* ICS07 Tendermint Client implementation (#5485)

* implement ICS07

* build

* update tests and cleanup

* x/ibc/02-client/types: remove misbehaviour in favor of evidence

* remove root query, update queriers, implement verification funcs

* remove committer; cleanup

* move keys to ibc/types

* fix paths

* update ICS03 connection verification

* move order and states to exported pkg

* update ICS04 to latest spec

* fix build

* move ics02 types/errors package to /types

* update a few tests

* update tests; fix codec registration

* minor changes from code review

* ibc/client/types: fix tests

* ibc/02-client/keeper: fix tests

* ibc/03-connection/keeper: begin tests for verify.go

* ibc/23-commitment: add IsEmpty() to Prefix, Path and Proof

* address comments from review

* add tests for evidence

* x/ibc/07-tendermint: add tests for consensus state, header and update

* ibc/07-tendermint: fix verification panic and add tests

* ibc/07-tendermint: add failure test cases

* x/ibc/03-connection/keeper: add verification tests for failing cases

* remove unused queriers

* Update ICS 7 tests (#5556)

* Update ICS 7 tests

* Fix one problem

* Also set consensus state for height 1

* Apply same fixes to ICS 4 tests

* Remove unnecessary change

* Fix ante tests; remove printfs

* Remove printf

* Update x/ibc/ante/ante_test.go

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* add TODOs for ADR 03 dynamic store

* add tests for msgs and packet (#5559)

* Add skeleton for ValidateBasic tests

* Move tests; basic one passes

* Add more ValidateBasic tests

* Add more ValidateBasic testcases

* Fix minor typo

* Add `ValidateBasic` tests for Packet

* Move to packet_test.go

* use app.Commit for tests

* update verify.go

* Fix all ICS 07 Tests (#5565)

* ICS 07 Debugging

* WIP Debugging

* Foo bar baz, baz bar foo, 🤷‍♂️

* cleanup print statements

* cleanup verification test

* add return err for proof verification

* cleanup; start handshake testing

* connection handshake tests

* scopelint

* WIP Test refactor

* fix ICS03 tests

* fix ICS04 tests

* nolint

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* cleanup comments and add a few tests

* typo

Co-authored-by: Christopher Goes <cwgoes@pluranimity.org>
Co-authored-by: Jack Zampolin <jack.zampolin@gmail.com>

* fix build

* IBC historical info support (#5475)

* implement GetConsensusState

* introspect past consensus states on ICS03 handshake

* implement ToTmValidator staking util function

* add test cases

* update tests

* Fix various compile erros

* fix historical info

* fix dep cycle

* Fix golint issues

* Fix proto docs lint fail

* move consensus state query downstream to ICS03

* remove unused funcs on expected keeper

* update tests and move get consensus state to ICS03

* increase cov for verification funcs

* fix tests

* interfacer fix

* fix expected keeper

* remove TODOs

Co-authored-by: Jack Zampolin <jack.zampolin@gmail.com>

* cleanup ibc-alpha diff with master

* Add bank alias for gaia

* Moar bank alias gaia

* Moar bank alias gaia

* Fix query all clients

* update to current Tendermint master

* TxSearchMock: add orderBy field to TxSearch method

* fix build errors

* Small changes for compilation of gaia

* Small changes for compilation of gaia

* Add 07-tm.Header.ConsensusState() to make conversions easy

* Add additional IBC Channel Tests (#5578)

* Add stubbed out tests

* one working testcase and mocked packet types

* Finish TestSendPacket

* Move mocked proofs to ibc/types and finish TestRecvPacket

* Implement TestPacketExecuted

* WIP TestAckPacket

* Start on timeout tests, 1 passing

* WIP Tests

* first cleanup

* test send transfer

* add packet tests

* fixes and more tests

* finish tests

* Update x/ibc/04-channel/keeper/packet.go

* golangcibot fixes

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: Christopher Goes <cwgoes@pluranimity.org>

* merge master

* ICS07 follow up changes (#5606)

* ADR07 follow up changes

* add assertion checks

* update ICS02 tests

* update ICS07 tests

* add trusting and ubd period to msg

* tests

* more test updates

* ICS07 follow ups (#5631)

* refactor tendermint package to move msgs here

* fix rest of package to accomadate 07 refactor

* added GetHeight to ConsensusState and moved clientstate struct creation to 07-tendermint

* start work on making misbehavior retrieve consensusState LTE misbehavior

* allow misbehavior submission at height not equal to persisted consensusState

* optimize submitMisbehavior by erroring earlier

* cleanup misbehavior and propose lazy fix

* fix bug

* Update x/ibc/02-client/keeper/client.go

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* address fede review

* add chain-id into clientstate

* address necessary fede review

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

Co-authored-by: Aditya <adityasripal@gmail.com>

* IBC SDK specification (#5426)

* IBC SDK specification

* update events

* add implementation mapping

* minor additions to readme

* fix conflicts

* add missing ADRs, modules and ICS

* fix build

* Merge PR #5670: Fix Packet Timeout Bug

* add destination height to MsgSendTransger

* quick fix

* Add defensive checks before setting param keytables in keeprs

* ICS 20 Cleanup and Tests (#5577)

* Add comments, remove unused code and attempt to point to places where the spec is being implemented

* close channel when transfer fails

* rename packer data transfer to align to spec; refactor table tests

* ICS 20 implementation cleanup work (#5602)

* Simulation docs (#5033)

* simulation docs

* update docs with the latest simulation changes

* minor imporvments

* clean up of simulation.md

* expand section on weights

* minor reword

* minor wording fix

Co-authored-by: Marko <marbar3778@yahoo.com>

* Merge PR #5597: Include Amount in Complete Unbonding/Redelegation Events

* Add bank alias for gaia

* Moar bank alias gaia

* Moar bank alias gaia

* Call `TimeoutExecuted`, add wrappers

* Remove unused `MsgRecvPacket`

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: Marko <marbar3778@yahoo.com>
Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com>
Co-authored-by: Jack Zampolin <jack.zampolin@gmail.com>

* Merge PR #5603: Remove acknowledgement interface in favour of []byte

* fixes and cleanup

* spec compliance

* refactor relay prefixes and tests

* Fix test compilation

* cleanup; add notes and additional test case

* Receive transfer test

* Apply suggestions from code review

Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>

* Fix autolinter application

* Add testcase with incorrect prefix

* golangcibot fixes

* delete extra comment

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: Christopher Goes <cwgoes@pluranimity.org>
Co-authored-by: Marko <marbar3778@yahoo.com>
Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com>
Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>

* Merge PR #5666: Use Tendermint lite client verification

* Disambiguate error codes

* Fix binary marshalling for state storage

* readd MsgSubmitClientMisbehaviour

* Fix double flag registration

* ICS23 refactor (#5710)

* ICS23 restructure directories

* more fixes

* format

* Merge PR #5711: Switch mock proofs to real proofs

* Add key, path, value to mock proofs

* Also alter mock types (why are there duplicates)

* Remove mock proofs from handshake_test.go

* Use actual proofs

* Try to fix historical info, no luck

* Have test-cases produce consensus heights

* Fix consensus height / proof height difference in verifyClientConsensusState

* Bug fixes contd.

* Fix some identifier issues

* `TestConnOpenConfirm` now works

* further on proof

* fix debugger print statement

* IT PASSES

* revert identifier changes

* refactor query proof to generate proofs from either chain

* fix ack and confirm

* Remove temporary break

* fix connection and channel verify tests

* fix everything but verify client consensusstate

* fix all verify tests

* fix ics07 tests

* fix handshake tests

* fix packet tests

* fix timeout tests

Co-authored-by: Aditya Sripal <adityasripal@gmail.com>
Co-authored-by: Federico Kunze <federico.kunze94@gmail.com>

* Try to fix store decoding issue

* Sim issue update

* add error in msg

* remove next validator set from ibctmtypes.Header

* remove warning msg

* Make IBC updating more robust

* blh

* bump tm dependency

* remove redundant clockdrift correction

* remove blh commit

* fix test build failures

* Change time from PST to UTC

* Merge PR #5770: Update error message in connection keeper

* Merge PR #5774: Debug timestamp issues

* Merge PR #5786: Fix MsgTransfer routing

* Fix test-case

* register MsgPacket

* Flip boolean

* emit packet event on SendPacket

* Fix attribute setting

* Implement in-memory KVStore

* Start keeper and types

* Add codec

* Add keys logic

* Update types

* Update keeper

* Implement NewCapability

* Implement InitializeAndSeal

* Update simapp

* Implement GetCapability

* Add logging for new and claimed caps

* Call InitializeAndSeal in SimApp

* Update keeper semantics + unit tests

* Use big endian

* More unit tests

* Increase keeper test coverage

* Remove TODO

* Add module doc

* Update doc

* Apply suggestions from code review

Co-Authored-By: Aditya <adityasripal@gmail.com>

* Update NewCapability godoc

* Clarify owner

* Add forgery test case to TestAuthenticateCapability

* Format doc

* Update to tm@v0.33.2

* Update ADR

* Explicitly take pointer in FwdCapabilityKey

* Update set to be logn

* Update app module

* Lint

* Fix broken test after packet format changed

* Add stub and unit tests for ReleaseCapability

* Finish implementation

* Add test case to TestAuthenticateCapability for releasing a cap

* remove swagger files from ibc module (#5893)

* Move IBC packet data interpretation to the application module (#5890)

* fix: move IBC packet data interpretation to the application module

This also adds a channelexported.NewOpaquePacketData(rawBytes)
implementation to assist apps in being able to manipulate the
raw packet data using the codec layer.

* feat: use an internal-to-module PacketDataI type

This one only has a GetBytes() method, which is implemented by
OpaquePacketData.

* fix: remove OpaquePacketData

No need to wrap the []byte packet.GetData().  If the caller wants
it, they can use it directly.

* docs: update adr-015

* fix: put the TimeoutHeight back into the packet commitment

* refactor: simplify unmarshalling of transfer packet

* docs: update for new unmarshal steps

* fix: clean up usage of sdkerrors.Wrapf

* Apply suggestions from code review

Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* chore: remove unnecessary "encoding/binary" import

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* fix ibc-alpha sims (#5909)

* fix some simulations

* fix HistoricalInfo sim decoders

* add staking sim decoder test case for HistInfo

* Merge PR #5901: Add & update IBC queriers for relayer use

* Add identifier to connection responses (ref #5829)

* Update querier as well

* Fix test-case

* Update for consistency

* Add querier for connection channels; fix linter

* Fix build (?)

* Add JSON & Yaml tags

* Add tags

* Add identifiers to channels as well

* fix test

* Merge PR #5914: x/capability: Fix Object Capability Model

* Merge PR #5918: Remove source field from ICS 20 packet & message types per latest spec

* fix ics20 client args (#5924)

* Merge PR #5930: Add GetChainID to ClientState interface

* Merge PR #5925: Add additional events to x/ibc

* Migrate x/capability to Protobuf (#5926)

* migrate x/capability to protobuf

* fixes

* format

* remove capability from codec std

* return pointer for getOwners

* remove &

* Update x/capability/keeper/keeper.go

Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>

* rename remove Capability interface; rename CapabilityKey -> Capaility; cc @cwgoes

* x/capability: remove RegisterCapabilityTypeCodec and seal amino cdc

Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com>
Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>

* Merge PR #5939: Unmarshal packets as JSON

* Merge PR #5888: Dynamic Capabilities with Routing

* cleanup ibc-alpha (#5945)

* cleanup ibc-alpha

* remove HasKeyTable()

* add preexisting checks

* undo remove checks

* x/staking: import and export HistoricalInfo

* staking/types: add HistoricalInfo to GenesisState

* changelog

* add staking module to app BeginBlockers

* remove JSON files

* address comments from review

* cleanup ibc-alpha

* fix ibc-alpha lint (#5959)

* x/ibc: changelog (#5960)

* x/ibc: changelog

* add reference to the spec

* Merge PR #5954: Bind Transfer Port on InitChain

* Bind transfer port in InitChain

* push fixes

* address @fedekunze review

* Apply suggestions from code review

* lint

Co-authored-by: Jack Zampolin <jack.zampolin@gmail.com>
Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: Federico Kunze <federico.kunze94@gmail.com>

Co-authored-by: Joon <torecursedivine@gmail.com>
Co-authored-by: Christopher Goes <cwgoes@pluranimity.org>
Co-authored-by: vincent <vincent.ch.cn@gmail.com>
Co-authored-by: Jack Zampolin <jack.zampolin@gmail.com>
Co-authored-by: Aditya Sripal <adityasripal@gmail.com>
Co-authored-by: Kevin Davis <karzak@users.noreply.github.com>
Co-authored-by: kaustubhkapatral <54210167+kaustubhkapatral@users.noreply.github.com>
Co-authored-by: Ferenc Fabian <qwer.kocka@gmail.com>
Co-authored-by: Dmitry Shulyak <yashulyak@gmail.com>
Co-authored-by: Alessio Treglia <quadrispro@ubuntu.com>
Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com>
Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>
Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
Co-authored-by: Marko <marbar3778@yahoo.com>
Co-authored-by: Aleksandr Bezobchuk <aleks.bezobchuk@gmail.com>
Co-authored-by: Michael FIG <michael+github@fig.org>
Co-authored-by: Segue <huoda.china@163.com>
This commit is contained in:
Federico Kunze 2020-04-08 20:57:52 -04:00 committed by GitHub
parent 8eb4808b0e
commit b5a6587291
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
211 changed files with 23566 additions and 155 deletions

View File

@ -79,17 +79,27 @@ to now accept a `codec.JSONMarshaler` for modular serialization of genesis state
* (crypto) [\#5880](https://github.com/cosmos/cosmos-sdk/pull/5880) Merge `crypto/keys/mintkey` into `crypto`.
* (crypto/hd) [\#5904](https://github.com/cosmos/cosmos-sdk/pull/5904) `crypto/keys/hd` moved to `crypto/hd`.
* (crypto/keyring):
- [\#5866](https://github.com/cosmos/cosmos-sdk/pull/5866) Rename `crypto/keys/` to `crypto/keyring/`.
- [\#5904](https://github.com/cosmos/cosmos-sdk/pull/5904) `Keybase` -> `Keyring` interfaces migration. `LegacyKeybase` interface is added in order
* [\#5866](https://github.com/cosmos/cosmos-sdk/pull/5866) Rename `crypto/keys/` to `crypto/keyring/`.
* [\#5904](https://github.com/cosmos/cosmos-sdk/pull/5904) `Keybase` -> `Keyring` interfaces migration. `LegacyKeybase` interface is added in order
to guarantee limited backward compatibility with the old Keybase interface for the sole purpose of migrating keys across the new keyring backends. `NewLegacy`
constructor is provided [\#5889](https://github.com/cosmos/cosmos-sdk/pull/5889) to allow for smooth migration of keys from the legacy LevelDB based implementation
to new keyring backends. Plus, the package and the new keyring no longer depends on the sdk.Config singleton. Please consult the package documentation for more
information on how to implement the new `Keyring` interface.
- [\#5858](https://github.com/cosmos/cosmos-sdk/pull/5858) Make Keyring store keys by name and address's hexbytes representation.
* [\#5858](https://github.com/cosmos/cosmos-sdk/pull/5858) Make Keyring store keys by name and address's hexbytes representation.
### Features
* (x/ibc) [\#5588](https://github.com/cosmos/cosmos-sdk/pull/5588) Add [ICS 024 - Host State Machine Requirements](https://github.com/cosmos/ics/tree/master/spec/ics-024-host-requirements) subpackage to `x/ibc` module.
* (x/ibc) [\#5277](https://github.com/cosmos/cosmos-sdk/pull/5277) `x/ibc` changes from IBC alpha. For more details check the the [`x/ibc/spec`](https://github.com/cosmos/tree/master/x/ibc/spec) directory:
* [ICS 002 - Client Semantics](https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics) subpackage
* [ICS 003 - Connection Semantics](https://github.com/cosmos/ics/blob/master/spec/ics-003-connection-semantics) subpackage
* [ICS 004 - Channel and Packet Semantics](https://github.com/cosmos/ics/blob/master/spec/ics-004-channel-and-packet-semantics) subpackage
* [ICS 005 - Port Allocation](https://github.com/cosmos/ics/blob/master/spec/ics-005-port-allocation) subpackage
* [ICS 007 - Tendermint Client](https://github.com/cosmos/ics/blob/master/spec/ics-007-tendermint-client) subpackage
* [ICS 020 - Fungible Token Transfer](https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer) module
* [ICS 023 - Vector Commitments](https://github.com/cosmos/ics/tree/master/spec/ics-023-vector-commitments) subpackage
* (ibc/ante) Implement IBC `AnteHandler` as per [ADR 15 - IBC Packet Receiver](https://github.com/cosmos/tree/master/docs/architecture/adr-015-ibc-packet-receiver.md).
* (x/capability) [\#5828](https://github.com/cosmos/cosmos-sdk/pull/5828) Capability module integration as outlined in [ADR 3 - Dynamic Capability Store](https://github.com/cosmos/tree/master/docs/architecture/adr-003-dynamic-capability-store.md).
### Bug Fixes

View File

@ -103,8 +103,7 @@ func (ctx CLIContext) queryABCI(req abci.RequestQuery) (abci.ResponseQuery, erro
return result.Response, nil
}
err = ctx.verifyProof(req.Path, result.Response)
if err != nil {
if err = ctx.verifyProof(req.Path, result.Response); err != nil {
return abci.ResponseQuery{}, err
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@
## Changelog
- 12 December 2019: Initial version
- 02 April 2020: Memory Store Revisions
## Context
@ -15,20 +16,33 @@ At present, the Cosmos SDK does not have the ability to do this. Object-capabili
and passed to Keepers as fixed arguments ([example](https://github.com/cosmos/gaia/blob/dcbddd9f04b3086c0ad07ee65de16e7adedc7da4/app/app.go#L160)). Keepers cannot create or store capability keys during transaction execution — although they could call `NewKVStoreKey` and take the memory address
of the returned struct, storing this in the Merklised store would result in a consensus fault, since the memory address will be different on each machine (this is intentional — were this not the case, the keys would be predictable and couldn't serve as object capabilities).
Keepers need a way to keep a private map of store keys which can be altered during transacton execution, along with a suitable mechanism for regenerating the unique memory addresses (capability keys) in this map whenever the application is started or restarted.
Keepers need a way to keep a private map of store keys which can be altered during transaction execution, along with a suitable mechanism for regenerating the unique memory addresses (capability keys) in this map whenever the application is started or restarted.
This ADR proposes such an interface & mechanism.
## Decision
The SDK will include a new `CapabilityKeeper` abstraction, which is responsible for provisioning, tracking, and authenticating capabilities at runtime. During application initialisation in `app.go`, the `CapabilityKeeper` will
be hooked up to modules through unique function references (by calling `ScopeToModule`, defined below) so that it can identify the calling module when later invoked. When the initial state is loaded from disk, the `CapabilityKeeper`'s `Initialise` function will create new capability keys
for all previously allocated capability identifiers (allocated during execution of past transactions and assigned to particular modes), and keep them in a memory-only store while the chain is running. The SDK will include a new `MemoryStore` store type, similar
to the existing `TransientStore` but without erasure on `Commit()`, which this `CapabilityKeeper` will use to privately store capability keys.
The SDK will include a new `CapabilityKeeper` abstraction, which is responsible for provisioning,
tracking, and authenticating capabilities at runtime. During application initialisation in `app.go`,
the `CapabilityKeeper` will be hooked up to modules through unique function references
(by calling `ScopeToModule`, defined below) so that it can identify the calling module when later
invoked.
The `CapabilityKeeper` will use two stores: a regular, persistent `KVStore`, which will track what capabilities have been created by each module, and an in-memory `MemoryStore` (described below), which will
store the actual capabilities. The `CapabilityKeeper` will define the following types & functions:
When the initial state is loaded from disk, the `CapabilityKeeper`'s `Initialise` function will create
new capability keys for all previously allocated capability identifiers (allocated during execution of
past transactions and assigned to particular modes), and keep them in a memory-only store while the
chain is running.
The `Capability` interface is similar to `StoreKey`, but has a globally unique `Index()` instead of a name. A `String()` method is provided for debugging.
The `CapabilityKeeper` will include an ephemeral in-memory `CapabilityStore`, which internally maintains
two maps, one for forward mappings that map from module name, capability tuples to capability names and
one for reverse mappings that map from module name, capability name to capabilities. The reverse
mapping contains the actual capability objects by reference.
In addition to the `CapabilityStore`, the `CapabilityKeeper` will use a persistent `KVStore`, which
will track what capabilities have been created by each module. The `CapabilityKeeper` will define the
following types & functions:
The `Capability` interface is similar to `StoreKey`, but has a globally unique `Index()` instead of
a name. A `String()` method is provided for debugging.
```golang
type Capability interface {
@ -50,25 +64,28 @@ A `CapabilityKeeper` contains a persistent store key, memory store key, and mapp
```golang
type CapabilityKeeper struct {
persistentKey StoreKey
memoryKey MemoryStoreKey
moduleNames map[string]interface{}
sealed bool
capStore CapabilityStore
moduleNames map[string]interface{}
sealed bool
}
```
The `CapabilityKeeper` provides the ability to create *scoped* sub-keepers which are tied to a particular module name. These `ScopedCapabilityKeeper`s must be created at application
initialisation and passed to modules, which can then use them to claim capabilities they receive and retrieve capabilities which they own by name, in addition
to creating new capabilities & authenticating capabilities passed by other modules.
The `CapabilityKeeper` provides the ability to create *scoped* sub-keepers which are tied to a
particular module name. These `ScopedCapabilityKeeper`s must be created at application initialisation
and passed to modules, which can then use them to claim capabilities they receive and retrieve
capabilities which they own by name, in addition to creating new capabilities & authenticating capabilities
passed by other modules.
```golang
type ScopedCapabilityKeeper struct {
persistentKey StoreKey
memoryKey MemoryStoreKey
moduleName string
capStore CapabilityStore
moduleName string
}
```
`ScopeToModule` is used to create a scoped sub-keeper with a particular name, which must be unique. It MUST be called before `InitialiseAndSeal`.
`ScopeToModule` is used to create a scoped sub-keeper with a particular name, which must be unique.
It MUST be called before `InitialiseAndSeal`.
```golang
func (ck CapabilityKeeper) ScopeToModule(moduleName string) ScopedCapabilityKeeper {
@ -78,35 +95,41 @@ func (ck CapabilityKeeper) ScopeToModule(moduleName string) ScopedCapabilityKeep
if _, present := ck.moduleNames[moduleName]; present {
panic("cannot create multiple scoped capability keepers for the same module name")
}
ck.moduleNames[moduleName] = struct{}{}
return ScopedCapabilityKeeper{
persistentKey: ck.persistentKey,
memoryKey: ck.memoryKey,
moduleName: moduleName
capStore: ck.capStore,
moduleName: moduleName,
}
}
```
`InitialiseAndSeal` MUST be called exactly once, after loading the initial state and creating all necessary `ScopedCapabilityKeeper`s,
in order to populate the memory store with newly-created capability keys in accordance with the keys previously claimed by particular modules
and prevent the creation of any new `ScopedCapabilityKeeper`s.
`InitialiseAndSeal` MUST be called exactly once, after loading the initial state and creating all
necessary `ScopedCapabilityKeeper`s, in order to populate the memory store with newly-created
capability keys in accordance with the keys previously claimed by particular modules and prevent the
creation of any new `ScopedCapabilityKeeper`s.
```golang
func (ck CapabilityKeeper) InitialiseAndSeal(ctx Context) {
if ck.sealed {
panic("capability keeper is sealed")
}
persistentStore := ctx.KVStore(ck.persistentKey)
memoryStore := ctx.KVStore(ck.memoryKey)
// initialise memory store for all names in persistent store
for index, value := range persistentStore.Iter() {
capability = &CapabilityKey{index: index}
for moduleAndCapability := range value {
moduleName, capabilityName := moduleAndCapability.Split("/")
memoryStore.Set(moduleName + "/fwd/" + capability, capabilityName)
memoryStore.Set(moduleName + "/rev/" + capabilityName, capability)
capStore.Set(moduleName + "/fwd/" + capability, capabilityName)
capStore.Set(moduleName + "/rev/" + capabilityName, capability)
}
}
ck.sealed = true
}
```
@ -117,24 +140,30 @@ call `ClaimCapability`.
```golang
func (sck ScopedCapabilityKeeper) NewCapability(ctx Context, name string) (Capability, error) {
memoryStore := ctx.KVStore(sck.memoryKey)
// check name not taken in memory store
if memoryStore.Get("rev/" + name) != nil {
if capStore.Get("rev/" + name) != nil {
return nil, errors.New("name already taken")
}
// fetch the current index
index := persistentStore.Get("index")
// create a new capability
capability := &CapabilityKey{index: index}
// set persistent store
persistentStore.Set(index, Set.singleton(sck.moduleName + "/" + name))
// update the index
index++
persistentStore.Set("index", index)
// set forward mapping in memory store from capability to name
memoryStore.Set(sck.moduleName + "/fwd/" + capability, name)
capStore.Set(sck.moduleName + "/fwd/" + capability, name)
// set reverse mapping in memory store from name to capability
memoryStore.Set(sck.moduleName + "/rev/" + name, capability)
capStore.Set(sck.moduleName + "/rev/" + name, capability)
// return the newly created capability
return capability
}
@ -146,24 +175,28 @@ with which the calling module previously associated it.
```golang
func (sck ScopedCapabilityKeeper) AuthenticateCapability(name string, capability Capability) bool {
memoryStore := ctx.KVStore(sck.memoryKey)
// return whether forward mapping in memory store matches name
return memoryStore.Get(sck.moduleName + "/fwd/" + capability) === name
return capStore.Get(sck.moduleName + "/fwd/" + capability) === name
}
```
`ClaimCapability` allows a module to claim a capability key which it has received from another module so that future `GetCapability` calls will succeed.
`ClaimCapability` allows a module to claim a capability key which it has received from another module
so that future `GetCapability` calls will succeed.
`ClaimCapability` MUST be called if a module which receives a capability wishes to access it by name in the future. Capabilities are multi-owner, so if multiple modules have a single `Capability` reference, they will all own it.
`ClaimCapability` MUST be called if a module which receives a capability wishes to access it by name
in the future. Capabilities are multi-owner, so if multiple modules have a single `Capability` reference,
they will all own it.
```golang
func (sck ScopedCapabilityKeeper) ClaimCapability(ctx Context, capability Capability, name string) error {
persistentStore := ctx.KVStore(sck.persistentKey)
memoryStore := ctx.KVStore(sck.memoryKey)
// set forward mapping in memory store from capability to name
memoryStore.Set(sck.moduleName + "/fwd/" + capability, name)
capStore.Set(sck.moduleName + "/fwd/" + capability, name)
// set reverse mapping in memory store from name to capability
memoryStore.Set(sck.moduleName + "/rev/" + name, capability)
capStore.Set(sck.moduleName + "/rev/" + name, capability)
// update owner set in persistent store
owners := persistentStore.Get(capability.Index())
owners.add(sck.moduleName + "/" + name)
@ -171,33 +204,37 @@ func (sck ScopedCapabilityKeeper) ClaimCapability(ctx Context, capability Capabi
}
```
`GetCapability` allows a module to fetch a capability which it has previously claimed by name. The module is not allowed to retrieve capabilities which it does not own. If another module
claims a capability, the previously owning module will no longer be able to claim it.
`GetCapability` allows a module to fetch a capability which it has previously claimed by name.
The module is not allowed to retrieve capabilities which it does not own.
```golang
func (sck ScopedCapabilityKeeper) GetCapability(ctx Context, name string) (Capability, error) {
memoryStore := ctx.KVStore(sck.memoryKey)
// fetch capability from memory store
capability := memoryStore.Get(sck.moduleName + "/rev/" + name)
capability := capStore.Get(sck.moduleName + "/rev/" + name)
// return the capability
return capability
}
```
`ReleaseCapability` allows a module to release a capability which it had previously claimed. If no more owners exist, the capability will be deleted globally.
`ReleaseCapability` allows a module to release a capability which it had previously claimed. If no
more owners exist, the capability will be deleted globally.
```golang
func (sck ScopedCapabilityKeeper) ReleaseCapability(ctx Context, capability Capability) err {
persistentStore := ctx.KVStore(sck.persistentKey)
memoryStore := ctx.KVStore(sck.memoryKey)
name := memoryStore.Get(sck.moduleName + "/fwd/" + capability)
name := capStore.Get(sck.moduleName + "/fwd/" + capability)
if name == nil {
return error("capability not owned by module")
}
// delete forward mapping in memory store
memoryStore.Delete(sck.moduleName + "/fwd/" + capability, name)
// delete reverse mapping in memory store
memoryStore.Delete(sck.moduleName + "/rev/" + name, capability)
// update owner set in persistent store
owners := persistentStore.Get(capability.Index())
owners.remove(sck.moduleName + "/" + name)
@ -211,14 +248,6 @@ func (sck ScopedCapabilityKeeper) ReleaseCapability(ctx Context, capability Capa
}
```
### Memory store
A new store key type, `MemoryStoreKey`, will be added to the `store` package. The `MemoryStoreKey`s work just like `StoreKey`s.
The memory store will work just like the current transient store, except that it will not create a new `dbadapter.Store` when `Commit()` is called, but instead retain the current one (so that state will persist across blocks).
Initially the memory store will only be used by the `CapabilityKeeper`, but it could be used by other modules in the future.
### Usage patterns
#### Initialisation

View File

@ -192,22 +192,7 @@ func NewAnteHandler(
}
```
The implementation of this ADR will also change the `Data` field of the `Packet` type from `[]byte` (i.e. arbitrary data) to `PacketDataI`. We want to make application modules be able to register custom packet data type which is automatically unmarshaled at `TxDecoder` time and can be simply type switched inside the application handler. Also, by having `GetCommitment()` method instead of manually generate the commitment inside the IBC keeper, the applications can define their own commitment method, including bare bytes, hashing, etc.
This also removes the `Timeout` field from the `Packet` struct. This is because the `PacketDataI` interface now contains this information. You can see details about this in [ICS04](https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#definitions).
The `PacketDataI` is the application specific interface that provides information for the execution of the application packet. In the case of ICS20 this would be `denom`, `amount` and `address`
```go
// PacketDataI defines the standard interface for IBC packet data
type PacketDataI interface {
GetCommitment() []byte // Commitment form that will be stored in the state.
GetTimeoutHeight() uint64
ValidateBasic() error
Type() string
}
```
The implementation of this ADR will also create a `Data` field of the `Packet` of type `[]byte`, which can be deserialised by the receiving module into its own private type. It is up to the application modules to do this according to their own interpretation, not by the IBC keeper. This is crucial for dynamic IBC.
Example application-side usage:
@ -234,15 +219,17 @@ func NewHandler(k Keeper) Handler {
case MsgTransfer:
return handleMsgTransfer(ctx, k, msg)
case ibc.MsgPacket:
switch data := msg.Packet.Data.(type) {
case PacketDataTransfer: // i.e fulfills the PacketDataI interface
return handlePacketDataTransfer(ctx, k, msg.Packet, data)
var data PacketDataTransfer
if err := types.ModuleCodec.UnmarshalBinaryBare(msg.GetData(), &data); err != nil {
return err
}
case ibc.MsgTimeoutPacket:
switch packet := msg.Packet.Data.(type) {
case PacketDataTransfer: // i.e fulfills the PacketDataI interface
return handleTimeoutPacketDataTransfer(ctx, k, msg.Packet)
return handlePacketDataTransfer(ctx, k, msg, data)
case ibc.MsgTimeoutPacket:
var data PacketDataTransfer
if err := types.ModuleCodec.UnmarshalBinaryBare(msg.GetData(), &data); err != nil {
return err
}
return handleTimeoutPacketDataTransfer(ctx, k, packet)
// interface { PortID() string; ChannelID() string; Channel() ibc.Channel }
// MsgChanInit, MsgChanTry implements ibc.MsgChannelOpen
case ibc.MsgChannelOpen:

View File

@ -10661,4 +10661,4 @@
"integrity": "sha1-4Se9nmb9hGvl6rSME5SIL3wOT5g="
}
}
}
}

View File

@ -1,3 +0,0 @@
# Cosmos Inter-Blockchain Communication (IBC) Protocol
__Disclaimer__ This module has been removed from the repository for the time being. If you would like to follow the process of IBC, go to [ICS repo](https://github.com/cosmos/ics), there you will find the standard and updates.

View File

@ -18,11 +18,16 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/capability"
"github.com/cosmos/cosmos-sdk/x/crisis"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/evidence"
"github.com/cosmos/cosmos-sdk/x/genutil"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/ibc"
ibcclient "github.com/cosmos/cosmos-sdk/x/ibc/02-client"
port "github.com/cosmos/cosmos-sdk/x/ibc/05-port"
transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/params"
paramsclient "github.com/cosmos/cosmos-sdk/x/params/client"
@ -51,6 +56,7 @@ var (
supply.AppModuleBasic{},
genutil.AppModuleBasic{},
bank.AppModuleBasic{},
capability.AppModuleBasic{},
staking.AppModuleBasic{},
mint.AppModuleBasic{},
distr.AppModuleBasic{},
@ -60,18 +66,21 @@ var (
params.AppModuleBasic{},
crisis.AppModuleBasic{},
slashing.AppModuleBasic{},
ibc.AppModuleBasic{},
upgrade.AppModuleBasic{},
evidence.AppModuleBasic{},
transfer.AppModuleBasic{},
)
// module account permissions
maccPerms = map[string][]string{
auth.FeeCollectorName: nil,
distr.ModuleName: nil,
mint.ModuleName: {supply.Minter},
staking.BondedPoolName: {supply.Burner, supply.Staking},
staking.NotBondedPoolName: {supply.Burner, supply.Staking},
gov.ModuleName: {supply.Burner},
auth.FeeCollectorName: nil,
distr.ModuleName: nil,
mint.ModuleName: {supply.Minter},
staking.BondedPoolName: {supply.Burner, supply.Staking},
staking.NotBondedPoolName: {supply.Burner, supply.Staking},
gov.ModuleName: {supply.Burner},
transfer.GetModuleAccountName(): {supply.Minter, supply.Burner},
}
// module accounts that are allowed to receive tokens
@ -99,18 +108,25 @@ type SimApp struct {
subspaces map[string]params.Subspace
// keepers
AccountKeeper auth.AccountKeeper
BankKeeper bank.Keeper
SupplyKeeper supply.Keeper
StakingKeeper staking.Keeper
SlashingKeeper slashing.Keeper
MintKeeper mint.Keeper
DistrKeeper distr.Keeper
GovKeeper gov.Keeper
CrisisKeeper crisis.Keeper
UpgradeKeeper upgrade.Keeper
ParamsKeeper params.Keeper
EvidenceKeeper evidence.Keeper
AccountKeeper auth.AccountKeeper
BankKeeper bank.Keeper
CapabilityKeeper *capability.Keeper
SupplyKeeper supply.Keeper
StakingKeeper staking.Keeper
SlashingKeeper slashing.Keeper
MintKeeper mint.Keeper
DistrKeeper distr.Keeper
GovKeeper gov.Keeper
CrisisKeeper crisis.Keeper
UpgradeKeeper upgrade.Keeper
ParamsKeeper params.Keeper
IBCKeeper *ibc.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly
EvidenceKeeper evidence.Keeper
TransferKeeper transfer.Keeper
// make scoped keepers public for test purposes
ScopedIBCKeeper capability.ScopedKeeper
ScopedTransferKeeper capability.ScopedKeeper
// the module manager
mm *module.Manager
@ -136,7 +152,8 @@ func NewSimApp(
keys := sdk.NewKVStoreKeys(
bam.MainStoreKey, auth.StoreKey, bank.StoreKey, staking.StoreKey,
supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey,
gov.StoreKey, params.StoreKey, upgrade.StoreKey, evidence.StoreKey,
gov.StoreKey, params.StoreKey, ibc.StoreKey, upgrade.StoreKey,
evidence.StoreKey, transfer.StoreKey, capability.StoreKey,
)
tkeys := sdk.NewTransientStoreKeys(params.TStoreKey)
@ -161,6 +178,11 @@ func NewSimApp(
app.subspaces[crisis.ModuleName] = app.ParamsKeeper.Subspace(crisis.DefaultParamspace)
app.subspaces[evidence.ModuleName] = app.ParamsKeeper.Subspace(evidence.DefaultParamspace)
// add capability keeper and ScopeToModule for ibc module
app.CapabilityKeeper = capability.NewKeeper(appCodec, keys[capability.StoreKey])
scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibc.ModuleName)
scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(transfer.ModuleName)
// add keepers
app.AccountKeeper = auth.NewAccountKeeper(
appCodec, keys[auth.StoreKey], app.subspaces[auth.ModuleName], auth.ProtoBaseAccount,
@ -190,15 +212,6 @@ func NewSimApp(
)
app.UpgradeKeeper = upgrade.NewKeeper(skipUpgradeHeights, keys[upgrade.StoreKey], appCodec, homePath)
// create evidence keeper with router
evidenceKeeper := evidence.NewKeeper(
appCodec, keys[evidence.StoreKey], app.subspaces[evidence.ModuleName], &app.StakingKeeper, app.SlashingKeeper,
)
evidenceRouter := evidence.NewRouter()
// TODO: Register evidence routes.
evidenceKeeper.SetRouter(evidenceRouter)
app.EvidenceKeeper = *evidenceKeeper
// register the proposal types
govRouter := gov.NewRouter()
govRouter.AddRoute(gov.RouterKey, gov.ProposalHandler).
@ -216,12 +229,42 @@ func NewSimApp(
staking.NewMultiStakingHooks(app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks()),
)
// Create IBC Keeper
app.IBCKeeper = ibc.NewKeeper(
app.cdc, keys[ibc.StoreKey], app.StakingKeeper, scopedIBCKeeper,
)
// Create Transfer Keepers
app.TransferKeeper = transfer.NewKeeper(
app.cdc, keys[transfer.StoreKey],
app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper,
app.BankKeeper, app.SupplyKeeper,
scopedTransferKeeper,
)
transferModule := transfer.NewAppModule(app.TransferKeeper)
// Create static IBC router, add transfer route, then set and seal it
ibcRouter := port.NewRouter()
ibcRouter.AddRoute(transfer.ModuleName, transferModule)
app.IBCKeeper.SetRouter(ibcRouter)
// create evidence keeper with router
evidenceKeeper := evidence.NewKeeper(
appCodec, keys[evidence.StoreKey], app.subspaces[evidence.ModuleName], &app.StakingKeeper, app.SlashingKeeper,
)
evidenceRouter := evidence.NewRouter().
AddRoute(ibcclient.RouterKey, ibcclient.HandlerClientMisbehaviour(app.IBCKeeper.ClientKeeper))
evidenceKeeper.SetRouter(evidenceRouter)
app.EvidenceKeeper = *evidenceKeeper
// NOTE: Any module instantiated in the module manager that is later modified
// must be passed by reference here.
app.mm = module.NewManager(
genutil.NewAppModule(app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx),
auth.NewAppModule(app.AccountKeeper, app.SupplyKeeper),
bank.NewAppModule(app.BankKeeper, app.AccountKeeper),
capability.NewAppModule(*app.CapabilityKeeper),
crisis.NewAppModule(&app.CrisisKeeper),
supply.NewAppModule(app.SupplyKeeper, app.BankKeeper, app.AccountKeeper),
gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper),
@ -231,6 +274,8 @@ func NewSimApp(
staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper),
upgrade.NewAppModule(app.UpgradeKeeper),
evidence.NewAppModule(app.EvidenceKeeper),
ibc.NewAppModule(app.IBCKeeper),
transferModule,
)
// During begin block slashing happens after distr.BeginBlocker so that
@ -244,7 +289,8 @@ func NewSimApp(
app.mm.SetOrderInitGenesis(
auth.ModuleName, distr.ModuleName, staking.ModuleName, bank.ModuleName,
slashing.ModuleName, gov.ModuleName, mint.ModuleName, supply.ModuleName,
crisis.ModuleName, genutil.ModuleName, evidence.ModuleName,
crisis.ModuleName, ibc.ModuleName, genutil.ModuleName, evidence.ModuleName,
transfer.ModuleName,
)
app.mm.RegisterInvariants(&app.CrisisKeeper)
@ -275,7 +321,12 @@ func NewSimApp(
// initialize BaseApp
app.SetInitChainer(app.InitChainer)
app.SetBeginBlocker(app.BeginBlocker)
app.SetAnteHandler(ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, auth.DefaultSigVerificationGasConsumer))
app.SetAnteHandler(
ante.NewAnteHandler(
app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper,
ante.DefaultSigVerificationGasConsumer,
),
)
app.SetEndBlocker(app.EndBlocker)
if loadLatest {
@ -285,6 +336,15 @@ func NewSimApp(
}
}
// Initialize and seal the capability keeper so all persistent capabilities
// are loaded in-memory and prevent any further modules from creating scoped
// sub-keepers.
ctx := app.BaseApp.NewContext(true, abci.Header{})
app.CapabilityKeeper.InitializeAndSeal(ctx)
app.ScopedIBCKeeper = scopedIBCKeeper
app.ScopedTransferKeeper = scopedTransferKeeper
return app
}

View File

@ -169,12 +169,13 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error {
// load each Store (note this doesn't panic on unmounted keys now)
var newStores = make(map[types.StoreKey]types.CommitKVStore)
for key, storeParams := range rs.storesParams {
// Load it
store, err := rs.loadCommitStoreFromParams(key, rs.getCommitID(infos, key.Name()), storeParams)
if err != nil {
return errors.Wrap(err, "failed to load store")
}
newStores[key] = store
// If it was deleted, remove all data

View File

@ -275,6 +275,24 @@ const (
StoreTypeTransient
)
func (st StoreType) String() string {
switch st {
case StoreTypeMulti:
return "StoreTypeMulti"
case StoreTypeDB:
return "StoreTypeDB"
case StoreTypeIAVL:
return "StoreTypeIAVL"
case StoreTypeTransient:
return "StoreTypeTransient"
}
return "unknown store type"
}
//----------------------------------------
// Keys for accessing substores

View File

@ -580,8 +580,8 @@ func (coins Coins) Sort() Coins {
// Parsing
var (
// Denominations can be 3 ~ 32 characters long.
reDnmString = `[a-z][a-z0-9/]{2,31}`
// Denominations can be 3 ~ 64 characters long.
reDnmString = `[a-z][a-z0-9/]{2,63}`
reAmt = `[[:digit:]]+`
reDecAmt = `[[:digit:]]*\.[[:digit:]]+`
reSpc = `[[:space:]]*`

View File

@ -99,6 +99,7 @@ func NewKVStoreKeys(names ...string) map[string]*KVStoreKey {
for _, name := range names {
keys[name] = NewKVStoreKey(name)
}
return keys
}
@ -115,6 +116,7 @@ func NewTransientStoreKeys(names ...string) map[string]*TransientStoreKey {
for _, name := range names {
keys[name] = NewTransientStoreKey(name)
}
return keys
}

View File

@ -49,6 +49,16 @@ func Uint64ToBigEndian(i uint64) []byte {
return b
}
// BigEndianToUint64 returns an uint64 from big endian encoded bytes. If encoding
// is empty, zero is returned.
func BigEndianToUint64(bz []byte) uint64 {
if len(bz) == 0 {
return 0
}
return binary.BigEndian.Uint64(bz)
}
// Slight modification of the RFC3339Nano but it right pads all zeros and drops the time zone info
const SortableTimeFormat = "2006-01-02T15:04:05.000000000"

View File

@ -87,7 +87,7 @@ func TestUint64ToBigEndian(t *testing.T) {
func TestFormatTimeBytes(t *testing.T) {
t.Parallel()
tm, err := time.Parse("Jan 2, 2006 at 3:04pm (MST)", "Mar 3, 2020 at 7:54pm (PST)")
tm, err := time.Parse("Jan 2, 2006 at 3:04pm (MST)", "Mar 3, 2020 at 7:54pm (UTC)")
require.NoError(t, err)
require.Equal(t, "2020-03-03T19:54:00.000000000", string(sdk.FormatTimeBytes(tm)))
}

View File

@ -4,12 +4,17 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/keeper"
"github.com/cosmos/cosmos-sdk/x/auth/types"
ibcante "github.com/cosmos/cosmos-sdk/x/ibc/ante"
ibckeeper "github.com/cosmos/cosmos-sdk/x/ibc/keeper"
)
// NewAnteHandler returns an AnteHandler that checks and increments sequence
// numbers, checks signatures & account numbers, and deducts fees from the first
// signer.
func NewAnteHandler(ak keeper.AccountKeeper, supplyKeeper types.SupplyKeeper, sigGasConsumer SignatureVerificationGasConsumer) sdk.AnteHandler {
func NewAnteHandler(
ak keeper.AccountKeeper, supplyKeeper types.SupplyKeeper, ibcKeeper ibckeeper.Keeper,
sigGasConsumer SignatureVerificationGasConsumer,
) sdk.AnteHandler {
return sdk.ChainAnteDecorators(
NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
NewMempoolFeeDecorator(),
@ -21,6 +26,7 @@ func NewAnteHandler(ak keeper.AccountKeeper, supplyKeeper types.SupplyKeeper, si
NewDeductFeeDecorator(ak, supplyKeeper),
NewSigGasConsumeDecorator(ak, sigGasConsumer),
NewSigVerificationDecorator(ak),
NewIncrementSequenceDecorator(ak), // innermost AnteDecorator
NewIncrementSequenceDecorator(ak),
ibcante.NewProofVerificationDecorator(ibcKeeper.ClientKeeper, ibcKeeper.ChannelKeeper), // innermost AnteDecorator
)
}

View File

@ -38,7 +38,7 @@ func TestSimulateGasCost(t *testing.T) {
// setup
app, ctx := createTestApp(true)
ctx = ctx.WithBlockHeight(1)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer)
// keys and addresses
priv1, _, addr1 := types.KeyTestPubAddr()
@ -92,7 +92,7 @@ func TestSimulateGasCost(t *testing.T) {
func TestAnteHandlerSigErrors(t *testing.T) {
// setup
app, ctx := createTestApp(true)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer)
// keys and addresses
priv1, _, addr1 := types.KeyTestPubAddr()
@ -142,7 +142,7 @@ func TestAnteHandlerAccountNumbers(t *testing.T) {
// setup
app, ctx := createTestApp(false)
ctx = ctx.WithBlockHeight(1)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer)
// keys and addresses
priv1, _, addr1 := types.KeyTestPubAddr()
@ -201,7 +201,7 @@ func TestAnteHandlerAccountNumbersAtBlockHeightZero(t *testing.T) {
// setup
app, ctx := createTestApp(false)
ctx = ctx.WithBlockHeight(0)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer)
// keys and addresses
priv1, _, addr1 := types.KeyTestPubAddr()
@ -259,7 +259,7 @@ func TestAnteHandlerSequences(t *testing.T) {
// setup
app, ctx := createTestApp(false)
ctx = ctx.WithBlockHeight(1)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer)
// keys and addresses
priv1, _, addr1 := types.KeyTestPubAddr()
@ -335,7 +335,7 @@ func TestAnteHandlerSequences(t *testing.T) {
func TestAnteHandlerFees(t *testing.T) {
// setup
app, ctx := createTestApp(true)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer)
// keys and addresses
priv1, _, addr1 := types.KeyTestPubAddr()
@ -377,7 +377,7 @@ func TestAnteHandlerMemoGas(t *testing.T) {
// setup
app, ctx := createTestApp(true)
ctx = ctx.WithBlockHeight(1)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer)
// keys and addresses
priv1, _, addr1 := types.KeyTestPubAddr()
@ -417,7 +417,7 @@ func TestAnteHandlerMultiSigner(t *testing.T) {
// setup
app, ctx := createTestApp(false)
ctx = ctx.WithBlockHeight(1)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer)
// keys and addresses
priv1, _, addr1 := types.KeyTestPubAddr()
@ -467,7 +467,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
// setup
app, ctx := createTestApp(true)
ctx = ctx.WithBlockHeight(1)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer)
// keys and addresses
priv1, _, addr1 := types.KeyTestPubAddr()
@ -544,7 +544,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
// setup
app, ctx := createTestApp(true)
ctx = ctx.WithBlockHeight(1)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer)
// keys and addresses
priv1, _, addr1 := types.KeyTestPubAddr()
@ -662,7 +662,7 @@ func TestAnteHandlerSigLimitExceeded(t *testing.T) {
// setup
app, ctx := createTestApp(true)
ctx = ctx.WithBlockHeight(1)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer)
// keys and addresses
priv1, _, addr1 := types.KeyTestPubAddr()
@ -703,7 +703,7 @@ func TestCustomSignatureVerificationGasConsumer(t *testing.T) {
app, ctx := createTestApp(true)
ctx = ctx.WithBlockHeight(1)
// setup an ante handler that only accepts PubKeyEd25519
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, func(meter sdk.GasMeter, sig []byte, pubkey crypto.PubKey, params types.Params) error {
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, func(meter sdk.GasMeter, sig []byte, pubkey crypto.PubKey, params types.Params) error {
switch pubkey := pubkey.(type) {
case ed25519.PubKeyEd25519:
meter.ConsumeGas(params.SigVerifyCostED25519, "ante verify: ed25519")
@ -761,7 +761,7 @@ func TestAnteHandlerReCheck(t *testing.T) {
app.AccountKeeper.SetAccount(ctx, acc1)
app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins())
antehandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer)
antehandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer)
// test that operations skipped on recheck do not run

View File

@ -31,11 +31,16 @@ func NewAccountKeeper(
cdc types.Codec, key sdk.StoreKey, paramstore paramtypes.Subspace, proto func() exported.Account,
) AccountKeeper {
// set KeyTable if it has not already been set
if !paramstore.HasKeyTable() {
paramstore = paramstore.WithKeyTable(types.ParamKeyTable())
}
return AccountKeeper{
key: key,
proto: proto,
cdc: cdc,
paramSubspace: paramstore.WithKeyTable(types.ParamKeyTable()),
paramSubspace: paramstore,
}
}

View File

@ -12,7 +12,7 @@ const (
// QueryAccountParams defines the params for querying accounts.
type QueryAccountParams struct {
Address sdk.AccAddress
Address sdk.AccAddress `json:"account"`
}
// NewQueryAccountParams creates a new instance of QueryAccountParams.

View File

@ -38,11 +38,15 @@ func NewBaseKeeper(
cdc codec.Marshaler, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace paramtypes.Subspace, blacklistedAddrs map[string]bool,
) BaseKeeper {
ps := paramSpace.WithKeyTable(types.ParamKeyTable())
// set KeyTable if it has not already been set
if !paramSpace.HasKeyTable() {
paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable())
}
return BaseKeeper{
BaseSendKeeper: NewBaseSendKeeper(cdc, storeKey, ak, ps, blacklistedAddrs),
BaseSendKeeper: NewBaseSendKeeper(cdc, storeKey, ak, paramSpace, blacklistedAddrs),
ak: ak,
paramSpace: ps,
paramSpace: paramSpace,
}
}

42
x/capability/alias.go Normal file
View File

@ -0,0 +1,42 @@
package capability
import (
"github.com/cosmos/cosmos-sdk/x/capability/keeper"
"github.com/cosmos/cosmos-sdk/x/capability/types"
)
// DONTCOVER
// nolint
const (
ModuleName = types.ModuleName
StoreKey = types.StoreKey
MemStoreKey = types.MemStoreKey
)
// nolint
var (
NewKeeper = keeper.NewKeeper
NewCapability = types.NewCapability
RevCapabilityKey = types.RevCapabilityKey
FwdCapabilityKey = types.FwdCapabilityKey
KeyIndex = types.KeyIndex
KeyPrefixIndexCapability = types.KeyPrefixIndexCapability
ErrCapabilityTaken = types.ErrCapabilityTaken
ErrOwnerClaimed = types.ErrOwnerClaimed
ErrCapabilityNotOwned = types.ErrCapabilityNotOwned
RegisterCodec = types.RegisterCodec
ModuleCdc = types.ModuleCdc
NewOwner = types.NewOwner
NewCapabilityOwners = types.NewCapabilityOwners
NewCapabilityStore = types.NewCapabilityStore
)
// nolint
type (
Keeper = keeper.Keeper
ScopedKeeper = keeper.ScopedKeeper
Capability = types.Capability
CapabilityOwners = types.CapabilityOwners
CapabilityStore = types.CapabilityStore
)

View File

@ -0,0 +1,89 @@
# x/capability
## Abstract
`x/capability` is an implementation of a Cosmos SDK module, per [ADR 003](./../../../docs/architecture/adr-003-dynamic-capability-store.md),
that allows for provisioning, tracking, and authenticating multi-owner capabilities
at runtime.
The keeper maintains two states: persistent and ephemeral in-memory. The persistent
store maintains a globally unique auto-incrementing index and a mapping from
capability index to a set of capability owners that are defined as a module and
capability name tuple. The in-memory ephemeral state keeps track of the actual
capabilities, represented as addresses in local memory, with both forward and reverse indexes.
The forward index maps module name and capability tuples to the capability name. The
reverse index maps between the module and capability name and the capability itself.
The keeper allows the creation of "scoped" sub-keepers which are tied to a particular
module by name. Scoped keepers must be created at application initialization and
passed to modules, which can then use them to claim capabilities they receive and
retrieve capabilities which they own by name, in addition to creating new capabilities
& authenticating capabilities passed by other modules. A scoped keeper cannot escape its scope,
so a module cannot interfere with or inspect capabilities owned by other modules.
The keeper provides no other core functionality that can be found in other modules
like queriers, REST and CLI handlers, and genesis state.
## Initialization
During application initialization, the keeper must be instantiated with a persistent
store key and an in-memory store key.
```go
type App struct {
// ...
capabilityKeeper *capability.Keeper
}
func NewApp(...) *App {
// ...
app.capabilityKeeper = capability.NewKeeper(codec, persistentStoreKey, memStoreKey)
}
```
After the keeper is created, it can be used to create scoped sub-keepers which
are passed to other modules that can create, authenticate, and claim capabilities.
After all the necessary scoped keepers are created and the state is loaded, the
main capability keeper must be initialized and sealed to populate the in-memory
state and to prevent further scoped keepers from being created.
```go
func NewApp(...) *App {
// ...
// Initialize and seal the capability keeper so all persistent capabilities
// are loaded in-memory and prevent any further modules from creating scoped
// sub-keepers.
ctx := app.BaseApp.NewContext(true, abci.Header{})
app.capabilityKeeper.InitializeAndSeal(ctx)
return app
}
```
## Capabilities
Capabilities are multi-owner. A scoped keeper can create a capability via `NewCapability`
which creates a new unique, unforgeable object-capability reference. The newly
created capability is automatically persisted; the calling module need not call
`ClaimCapability`. Calling `NewCapability` will create the capability with the
calling module and name as a tuple to be treated the capabilities first owner.
Capabilities can be claimed by other modules which add them as owners. `ClaimCapability`
allows a module to claim a capability key which it has received from another
module so that future `GetCapability` calls will succeed. `ClaimCapability` MUST
be called if a module which receives a capability wishes to access it by name in
the future. Again, capabilities are multi-owner, so if multiple modules have a
single Capability reference, they will all own it. If a module receives a capability
from another module but does not call `ClaimCapability`, it may use it in the executing
transaction but will not be able to access it afterwards.
`AuthenticateCapability` can be called by any module to check that a capability
does in fact correspond to a particular name (the name can be un-trusted user input)
with which the calling module previously associated it.
`GetCapability` allows a module to fetch a capability which it has previously
claimed by name. The module is not allowed to retrieve capabilities which it does
not own.

View File

@ -0,0 +1,325 @@
package keeper
import (
"fmt"
"github.com/tendermint/tendermint/libs/log"
"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"
"github.com/cosmos/cosmos-sdk/x/capability/types"
)
type (
// Keeper defines the capability module's keeper. It is responsible for provisioning,
// tracking, and authenticating capabilities at runtime. During application
// initialization, the keeper can be hooked up to modules through unique function
// references so that it can identify the calling module when later invoked.
//
// When the initial state is loaded from disk, the keeper allows the ability to
// create new capability keys for all previously allocated capability identifiers
// (allocated during execution of past transactions and assigned to particular modes),
// and keep them in a memory-only store while the chain is running.
//
// The keeper allows the ability to create scoped sub-keepers which are tied to
// a single specific module.
Keeper struct {
cdc codec.Marshaler
storeKey sdk.StoreKey
capStore types.CapabilityStore
scopedModules map[string]struct{}
sealed bool
}
// ScopedKeeper defines a scoped sub-keeper which is tied to a single specific
// module provisioned by the capability keeper. Scoped keepers must be created
// at application initialization and passed to modules, which can then use them
// to claim capabilities they receive and retrieve capabilities which they own
// by name, in addition to creating new capabilities & authenticating capabilities
// passed by other modules.
ScopedKeeper struct {
cdc codec.Marshaler
storeKey sdk.StoreKey
capStore types.CapabilityStore // shared amongst all scoped keepers
module string
}
)
func NewKeeper(cdc codec.Marshaler, storeKey sdk.StoreKey) *Keeper {
return &Keeper{
cdc: cdc,
storeKey: storeKey,
capStore: types.NewCapabilityStore(),
scopedModules: make(map[string]struct{}),
sealed: false,
}
}
// ScopeToModule attempts to create and return a ScopedKeeper for a given module
// by name. It will panic if the keeper is already sealed or if the module name
// already has a ScopedKeeper.
func (k *Keeper) ScopeToModule(moduleName string) ScopedKeeper {
if k.sealed {
panic("cannot scope to module via a sealed capability keeper")
}
if _, ok := k.scopedModules[moduleName]; ok {
panic(fmt.Sprintf("cannot create multiple scoped keepers for the same module name: %s", moduleName))
}
k.scopedModules[moduleName] = struct{}{}
return ScopedKeeper{
cdc: k.cdc,
storeKey: k.storeKey,
capStore: k.capStore,
module: moduleName,
}
}
// InitializeAndSeal loads all capabilities from the persistent KVStore into the
// in-memory store and seals the keeper to prevent further modules from creating
// a scoped keeper. InitializeAndSeal must be called once after the application
// state is loaded.
func (k *Keeper) InitializeAndSeal(ctx sdk.Context) {
if k.sealed {
panic("cannot initialize and seal an already sealed capability keeper")
}
prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixIndexCapability)
iterator := sdk.KVStorePrefixIterator(prefixStore, nil)
// initialize the in-memory store for all persisted capabilities
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
index := types.IndexFromKey(iterator.Key())
cap := types.NewCapability(index)
var capOwners types.CapabilityOwners
k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &capOwners)
for _, owner := range capOwners.Owners {
// Set the forward mapping between the module and capability tuple and the
// capability name in the in-memory store.
k.capStore.SetCapabilityName(owner.Module, owner.Name, cap)
// Set the reverse mapping between the module and capability name and the
// capability in the in-memory store.
k.capStore.SetCapability(owner.Module, owner.Name, cap)
}
}
k.sealed = true
}
// GetLatestIndex returns the latest index of the CapabilityKeeper
func (k Keeper) GetLatestIndex(ctx sdk.Context) uint64 {
store := ctx.KVStore(k.storeKey)
return types.IndexFromKey(store.Get(types.KeyIndex))
}
// NewCapability attempts to create a new capability with a given name. If the
// capability already exists in the in-memory store, an error will be returned.
// Otherwise, a new capability is created with the current global unique index.
// The newly created capability has the scoped module name and capability name
// tuple set as the initial owner. Finally, the global index is incremented along
// with forward and reverse indexes set in the in-memory store.
//
// Note, namespacing is completely local, which is safe since records are prefixed
// with the module name and no two ScopedKeeper can have the same module name.
func (sk ScopedKeeper) NewCapability(ctx sdk.Context, name string) (*types.Capability, error) {
store := ctx.KVStore(sk.storeKey)
if cap := sk.capStore.GetCapability(sk.module, name); cap != nil {
return nil, sdkerrors.Wrapf(types.ErrCapabilityTaken, fmt.Sprintf("module: %s, name: %s", sk.module, name))
}
// create new capability with the current global index
index := types.IndexFromKey(store.Get(types.KeyIndex))
cap := types.NewCapability(index)
// update capability owner set
if err := sk.addOwner(ctx, cap, name); err != nil {
return nil, err
}
// increment global index
store.Set(types.KeyIndex, types.IndexToKey(index+1))
// Set the forward mapping between the module and capability tuple and the
// capability name in the in-memory store.
sk.capStore.SetCapabilityName(sk.module, name, cap)
// Set the reverse mapping between the module and capability name and the
// capability in the in-memory store.
sk.capStore.SetCapability(sk.module, name, cap)
logger(ctx).Info("created new capability", "module", sk.module, "name", name)
return cap, nil
}
// AuthenticateCapability attempts to authenticate a given capability and name
// from a caller. It allows for a caller to check that a capability does in fact
// correspond to a particular name. The scoped keeper will lookup the capability
// from the internal in-memory store and check against the provided name. It returns
// true upon success and false upon failure.
//
// Note, the capability's forward mapping is indexed by a string which should
// contain its unique memory reference.
func (sk ScopedKeeper) AuthenticateCapability(ctx sdk.Context, cap *types.Capability, name string) bool {
return sk.capStore.GetCapabilityName(sk.module, cap) == name
}
// ClaimCapability attempts to claim a given Capability. The provided name and
// the scoped module's name tuple are treated as the owner. It will attempt
// to add the owner to the persistent set of capability owners for the capability
// index. If the owner already exists, it will return an error. Otherwise, it will
// also set a forward and reverse index for the capability and capability name.
func (sk ScopedKeeper) ClaimCapability(ctx sdk.Context, cap *types.Capability, name string) error {
// update capability owner set
if err := sk.addOwner(ctx, cap, name); err != nil {
return err
}
// Set the forward mapping between the module and capability tuple and the
// capability name in the in-memory store.
sk.capStore.SetCapabilityName(sk.module, name, cap)
// Set the reverse mapping between the module and capability name and the
// capability in the in-memory store.
sk.capStore.SetCapability(sk.module, name, cap)
logger(ctx).Info("claimed capability", "module", sk.module, "name", name, "capability", cap.GetIndex())
return nil
}
// ReleaseCapability allows a scoped module to release a capability which it had
// previously claimed or created. After releasing the capability, if no more
// owners exist, the capability will be globally removed.
func (sk ScopedKeeper) ReleaseCapability(ctx sdk.Context, cap *types.Capability) error {
name := sk.capStore.GetCapabilityName(sk.module, cap)
if len(name) == 0 {
return sdkerrors.Wrap(types.ErrCapabilityNotOwned, sk.module)
}
// Remove the forward mapping between the module and capability tuple and the
// capability name in the in-memory store.
sk.capStore.DeleteCapabilityName(sk.module, cap)
// Remove the reverse mapping between the module and capability name and the
// capability in the in-memory store.
sk.capStore.DeleteCapability(sk.module, name)
// remove owner
capOwners := sk.getOwners(ctx, cap)
capOwners.Remove(types.NewOwner(sk.module, name))
prefixStore := prefix.NewStore(ctx.KVStore(sk.storeKey), types.KeyPrefixIndexCapability)
indexKey := types.IndexToKey(cap.GetIndex())
if len(capOwners.Owners) == 0 {
// remove capability owner set
prefixStore.Delete(indexKey)
} else {
// update capability owner set
prefixStore.Set(indexKey, sk.cdc.MustMarshalBinaryBare(capOwners))
}
return nil
}
// GetCapability allows a module to fetch a capability which it previously claimed
// by name. The module is not allowed to retrieve capabilities which it does not
// own.
func (sk ScopedKeeper) GetCapability(ctx sdk.Context, name string) (*types.Capability, bool) {
cap := sk.capStore.GetCapability(sk.module, name)
if cap == nil {
return nil, false
}
return cap, true
}
// Get all the Owners that own the capability associated with the name this ScopedKeeper uses
// to refer to the capability
func (sk ScopedKeeper) GetOwners(ctx sdk.Context, name string) (*types.CapabilityOwners, bool) {
cap, ok := sk.GetCapability(ctx, name)
if !ok {
return nil, false
}
prefixStore := prefix.NewStore(ctx.KVStore(sk.storeKey), types.KeyPrefixIndexCapability)
indexKey := types.IndexToKey(cap.GetIndex())
var capOwners types.CapabilityOwners
bz := prefixStore.Get(indexKey)
if len(bz) == 0 {
return nil, false
}
sk.cdc.MustUnmarshalBinaryBare(bz, &capOwners)
return &capOwners, true
}
// LookupModules returns all the module owners for a given capability
// as a string array, the capability is also returned along with a boolean success flag
func (sk ScopedKeeper) LookupModules(ctx sdk.Context, name string) ([]string, *types.Capability, bool) {
cap, ok := sk.GetCapability(ctx, name)
if !ok {
return nil, nil, false
}
capOwners, ok := sk.GetOwners(ctx, name)
if !ok {
return nil, nil, false
}
mods := make([]string, len(capOwners.Owners))
for i, co := range capOwners.Owners {
mods[i] = co.Module
}
return mods, cap, true
}
func (sk ScopedKeeper) addOwner(ctx sdk.Context, cap *types.Capability, name string) error {
prefixStore := prefix.NewStore(ctx.KVStore(sk.storeKey), types.KeyPrefixIndexCapability)
indexKey := types.IndexToKey(cap.GetIndex())
capOwners := sk.getOwners(ctx, cap)
if err := capOwners.Set(types.NewOwner(sk.module, name)); err != nil {
return err
}
// update capability owner set
prefixStore.Set(indexKey, sk.cdc.MustMarshalBinaryBare(capOwners))
return nil
}
func (sk ScopedKeeper) getOwners(ctx sdk.Context, cap *types.Capability) *types.CapabilityOwners {
prefixStore := prefix.NewStore(ctx.KVStore(sk.storeKey), types.KeyPrefixIndexCapability)
indexKey := types.IndexToKey(cap.GetIndex())
bz := prefixStore.Get(indexKey)
var owners *types.CapabilityOwners
if len(bz) == 0 {
owners = types.NewCapabilityOwners()
} else {
var capOwners types.CapabilityOwners
sk.cdc.MustUnmarshalBinaryBare(bz, &capOwners)
owners = &capOwners
}
return owners
}
func logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
}

View File

@ -0,0 +1,245 @@
package keeper_test
import (
"fmt"
"testing"
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/capability"
"github.com/cosmos/cosmos-sdk/x/capability/keeper"
"github.com/cosmos/cosmos-sdk/x/capability/types"
"github.com/cosmos/cosmos-sdk/x/staking"
)
type KeeperTestSuite struct {
suite.Suite
ctx sdk.Context
keeper *keeper.Keeper
}
func (suite *KeeperTestSuite) SetupTest() {
checkTx := false
app := simapp.Setup(checkTx)
cdc := codec.NewHybridCodec(app.Codec())
// create new keeper so we can define custom scoping before init and seal
keeper := keeper.NewKeeper(cdc, app.GetKey(capability.StoreKey))
suite.ctx = app.BaseApp.NewContext(checkTx, abci.Header{Height: 1})
suite.keeper = keeper
}
func (suite *KeeperTestSuite) TestInitializeAndSeal() {
sk := suite.keeper.ScopeToModule(bank.ModuleName)
caps := make([]*types.Capability, 5)
// Get Latest Index before creating new ones to sychronize indices correctly
prevIndex := suite.keeper.GetLatestIndex(suite.ctx)
for i := range caps {
cap, err := sk.NewCapability(suite.ctx, fmt.Sprintf("transfer-%d", i))
suite.Require().NoError(err)
suite.Require().NotNil(cap)
suite.Require().Equal(uint64(i)+prevIndex, cap.GetIndex())
caps[i] = cap
}
suite.Require().NotPanics(func() {
suite.keeper.InitializeAndSeal(suite.ctx)
})
for i, cap := range caps {
got, ok := sk.GetCapability(suite.ctx, fmt.Sprintf("transfer-%d", i))
suite.Require().True(ok)
suite.Require().Equal(cap, got)
suite.Require().Equal(uint64(i)+prevIndex, got.GetIndex())
}
suite.Require().Panics(func() {
suite.keeper.InitializeAndSeal(suite.ctx)
})
suite.Require().Panics(func() {
_ = suite.keeper.ScopeToModule(staking.ModuleName)
})
}
func (suite *KeeperTestSuite) TestNewCapability() {
sk := suite.keeper.ScopeToModule(bank.ModuleName)
cap, err := sk.NewCapability(suite.ctx, "transfer")
suite.Require().NoError(err)
suite.Require().NotNil(cap)
got, ok := sk.GetCapability(suite.ctx, "transfer")
suite.Require().True(ok)
suite.Require().Equal(cap, got)
suite.Require().True(cap == got, "expected memory addresses to be equal")
got, ok = sk.GetCapability(suite.ctx, "invalid")
suite.Require().False(ok)
suite.Require().Nil(got)
cap, err = sk.NewCapability(suite.ctx, "transfer")
suite.Require().Error(err)
suite.Require().Nil(cap)
}
func (suite *KeeperTestSuite) TestAuthenticateCapability() {
sk1 := suite.keeper.ScopeToModule(bank.ModuleName)
sk2 := suite.keeper.ScopeToModule(staking.ModuleName)
cap1, err := sk1.NewCapability(suite.ctx, "transfer")
suite.Require().NoError(err)
suite.Require().NotNil(cap1)
forgedCap := types.NewCapability(0) // index should be the same index as the first capability
suite.Require().False(sk2.AuthenticateCapability(suite.ctx, forgedCap, "transfer"))
cap2, err := sk2.NewCapability(suite.ctx, "bond")
suite.Require().NoError(err)
suite.Require().NotNil(cap2)
got, ok := sk1.GetCapability(suite.ctx, "transfer")
suite.Require().True(ok)
suite.Require().True(sk1.AuthenticateCapability(suite.ctx, cap1, "transfer"))
suite.Require().True(sk1.AuthenticateCapability(suite.ctx, got, "transfer"))
suite.Require().False(sk1.AuthenticateCapability(suite.ctx, cap1, "invalid"))
suite.Require().False(sk1.AuthenticateCapability(suite.ctx, cap2, "transfer"))
suite.Require().True(sk2.AuthenticateCapability(suite.ctx, cap2, "bond"))
suite.Require().False(sk2.AuthenticateCapability(suite.ctx, cap2, "invalid"))
suite.Require().False(sk2.AuthenticateCapability(suite.ctx, cap1, "bond"))
sk2.ReleaseCapability(suite.ctx, cap2)
suite.Require().False(sk2.AuthenticateCapability(suite.ctx, cap2, "bond"))
badCap := types.NewCapability(100)
suite.Require().False(sk1.AuthenticateCapability(suite.ctx, badCap, "transfer"))
suite.Require().False(sk2.AuthenticateCapability(suite.ctx, badCap, "bond"))
}
func (suite *KeeperTestSuite) TestClaimCapability() {
sk1 := suite.keeper.ScopeToModule(bank.ModuleName)
sk2 := suite.keeper.ScopeToModule(staking.ModuleName)
cap, err := sk1.NewCapability(suite.ctx, "transfer")
suite.Require().NoError(err)
suite.Require().NotNil(cap)
suite.Require().Error(sk1.ClaimCapability(suite.ctx, cap, "transfer"))
suite.Require().NoError(sk2.ClaimCapability(suite.ctx, cap, "transfer"))
got, ok := sk1.GetCapability(suite.ctx, "transfer")
suite.Require().True(ok)
suite.Require().Equal(cap, got)
got, ok = sk2.GetCapability(suite.ctx, "transfer")
suite.Require().True(ok)
suite.Require().Equal(cap, got)
}
func (suite *KeeperTestSuite) TestGetOwners() {
sk1 := suite.keeper.ScopeToModule(bank.ModuleName)
sk2 := suite.keeper.ScopeToModule(staking.ModuleName)
sk3 := suite.keeper.ScopeToModule("foo")
sks := []keeper.ScopedKeeper{sk1, sk2, sk3}
cap, err := sk1.NewCapability(suite.ctx, "transfer")
suite.Require().NoError(err)
suite.Require().NotNil(cap)
suite.Require().NoError(sk2.ClaimCapability(suite.ctx, cap, "transfer"))
suite.Require().NoError(sk3.ClaimCapability(suite.ctx, cap, "transfer"))
expectedOrder := []string{bank.ModuleName, "foo", staking.ModuleName}
// Ensure all scoped keepers can get owners
for _, sk := range sks {
owners, ok := sk.GetOwners(suite.ctx, "transfer")
mods, cap, mok := sk.LookupModules(suite.ctx, "transfer")
suite.Require().True(ok, "could not retrieve owners")
suite.Require().NotNil(owners, "owners is nil")
suite.Require().True(mok, "could not retrieve modules")
suite.Require().NotNil(cap, "capability is nil")
suite.Require().NotNil(mods, "modules is nil")
suite.Require().Equal(len(expectedOrder), len(owners.Owners), "length of owners is unexpected")
for i, o := range owners.Owners {
// Require owner is in expected position
suite.Require().Equal(expectedOrder[i], o.Module, "module is unexpected")
suite.Require().Equal(expectedOrder[i], mods[i], "module in lookup is unexpected")
}
}
// foo module releases capability
err = sk3.ReleaseCapability(suite.ctx, cap)
suite.Require().Nil(err, "could not release capability")
// new expected order and scoped capabilities
expectedOrder = []string{bank.ModuleName, staking.ModuleName}
sks = []keeper.ScopedKeeper{sk1, sk2}
// Ensure all scoped keepers can get owners
for _, sk := range sks {
owners, ok := sk.GetOwners(suite.ctx, "transfer")
mods, cap, mok := sk.LookupModules(suite.ctx, "transfer")
suite.Require().True(ok, "could not retrieve owners")
suite.Require().NotNil(owners, "owners is nil")
suite.Require().True(mok, "could not retrieve modules")
suite.Require().NotNil(cap, "capability is nil")
suite.Require().NotNil(mods, "modules is nil")
suite.Require().Equal(len(expectedOrder), len(owners.Owners), "length of owners is unexpected")
for i, o := range owners.Owners {
// Require owner is in expected position
suite.Require().Equal(expectedOrder[i], o.Module, "module is unexpected")
suite.Require().Equal(expectedOrder[i], mods[i], "module in lookup is unexpected")
}
}
}
func (suite *KeeperTestSuite) TestReleaseCapability() {
sk1 := suite.keeper.ScopeToModule(bank.ModuleName)
sk2 := suite.keeper.ScopeToModule(staking.ModuleName)
cap1, err := sk1.NewCapability(suite.ctx, "transfer")
suite.Require().NoError(err)
suite.Require().NotNil(cap1)
suite.Require().NoError(sk2.ClaimCapability(suite.ctx, cap1, "transfer"))
cap2, err := sk2.NewCapability(suite.ctx, "bond")
suite.Require().NoError(err)
suite.Require().NotNil(cap2)
suite.Require().Error(sk1.ReleaseCapability(suite.ctx, cap2))
suite.Require().NoError(sk2.ReleaseCapability(suite.ctx, cap1))
got, ok := sk2.GetCapability(suite.ctx, "transfer")
suite.Require().False(ok)
suite.Require().Nil(got)
suite.Require().NoError(sk1.ReleaseCapability(suite.ctx, cap1))
got, ok = sk1.GetCapability(suite.ctx, "transfer")
suite.Require().False(ok)
suite.Require().Nil(got)
}
func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}

117
x/capability/module.go Normal file
View File

@ -0,0 +1,117 @@
package capability
import (
"encoding/json"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
abci "github.com/tendermint/tendermint/abci/types"
)
var (
_ module.AppModule = AppModule{}
_ module.AppModuleBasic = AppModuleBasic{}
// TODO: Enable simulation once concrete types are defined.
// _ module.AppModuleSimulation = AppModuleSimulation{}
)
// ----------------------------------------------------------------------------
// AppModuleBasic
// ----------------------------------------------------------------------------
// AppModuleBasic implements the AppModuleBasic interface for the capability module.
type AppModuleBasic struct {
}
func NewAppModuleBasic() AppModuleBasic {
return AppModuleBasic{}
}
// Name returns the capability module's name.
func (AppModuleBasic) Name() string {
return ModuleName
}
// RegisterCodec registers the capability module's types to the provided codec.
func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {
RegisterCodec(cdc)
}
// DefaultGenesis returns the capability module's default genesis state.
func (AppModuleBasic) DefaultGenesis(_ codec.JSONMarshaler) json.RawMessage { return []byte("{}") }
// ValidateGenesis performs genesis state validation for the capability module.
func (AppModuleBasic) ValidateGenesis(_ codec.JSONMarshaler, _ json.RawMessage) error { return nil }
// RegisterRESTRoutes registers the capability module's REST service handlers.
func (a AppModuleBasic) RegisterRESTRoutes(_ context.CLIContext, _ *mux.Router) {}
// GetTxCmd returns the capability module's root tx command.
func (a AppModuleBasic) GetTxCmd(_ *codec.Codec) *cobra.Command { return nil }
// GetTxCmd returns the capability module's root query command.
func (AppModuleBasic) GetQueryCmd(_ *codec.Codec) *cobra.Command { return nil }
// ----------------------------------------------------------------------------
// AppModule
// ----------------------------------------------------------------------------
// AppModule implements the AppModule interface for the capability module.
type AppModule struct {
AppModuleBasic
keeper Keeper
}
func NewAppModule(keeper Keeper) AppModule {
return AppModule{
AppModuleBasic: NewAppModuleBasic(),
keeper: keeper,
}
}
// Name returns the capability module's name.
func (am AppModule) Name() string {
return am.AppModuleBasic.Name()
}
// Route returns the capability module's message routing key.
func (AppModule) Route() string { return "" }
// QuerierRoute returns the capability module's query routing key.
func (AppModule) QuerierRoute() string { return "" }
// NewHandler returns the capability module's message Handler.
func (am AppModule) NewHandler() sdk.Handler { return nil }
// NewQuerierHandler returns the capability module's Querier.
func (am AppModule) NewQuerierHandler() sdk.Querier { return nil }
// RegisterInvariants registers the capability module's invariants.
func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {}
// InitGenesis performs the capability module's genesis initialization It returns
// no validator updates.
func (am AppModule) InitGenesis(_ sdk.Context, _ codec.JSONMarshaler, _ json.RawMessage) []abci.ValidatorUpdate {
return []abci.ValidatorUpdate{}
}
// ExportGenesis returns the capability module's exported genesis state as raw JSON bytes.
func (am AppModule) ExportGenesis(_ sdk.Context, cdc codec.JSONMarshaler) json.RawMessage {
return am.DefaultGenesis(cdc)
}
// BeginBlock executes all ABCI BeginBlock logic respective to the capability module.
func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {}
// EndBlock executes all ABCI EndBlock logic respective to the capability module. It
// returns no validator updates.
func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
return []abci.ValidatorUpdate{}
}

View File

@ -0,0 +1,30 @@
package types
import (
"github.com/cosmos/cosmos-sdk/codec"
)
// RegisterCodec registers all the necessary types and interfaces for the
// capability module.
func RegisterCodec(cdc *codec.Codec) {
cdc.RegisterConcrete(&Capability{}, "cosmos-sdk/Capability", nil)
cdc.RegisterConcrete(Owner{}, "cosmos-sdk/Owner", nil)
cdc.RegisterConcrete(&CapabilityOwners{}, "cosmos-sdk/CapabilityOwners", nil)
}
var (
amino = codec.New()
// ModuleCdc references the global x/capability module codec. Note, the codec should
// ONLY be used in certain instances of tests and for JSON encoding as Amino is
// still used for that purpose.
//
// The actual codec used for serialization should be provided to x/capability and
// defined at the application level.
ModuleCdc = codec.NewHybridCodec(amino)
)
func init() {
RegisterCodec(amino)
amino.Seal()
}

View File

@ -0,0 +1,14 @@
package types
// DONTCOVER
import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// x/capability module sentinel errors
var (
ErrCapabilityTaken = sdkerrors.Register(ModuleName, 2, "capability name already taken")
ErrOwnerClaimed = sdkerrors.Register(ModuleName, 3, "given owner already claimed capability")
ErrCapabilityNotOwned = sdkerrors.Register(ModuleName, 4, "capability not owned by module")
)

View File

@ -0,0 +1,51 @@
package types
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
)
const (
// ModuleName defines the module name
ModuleName = "capability"
// StoreKey defines the primary module store key
StoreKey = ModuleName
// MemStoreKey defines the in-memory store key
MemStoreKey = "mem_capability"
)
var (
// KeyIndex defines the key that stores the current globally unique capability
// index.
KeyIndex = []byte("index")
// KeyPrefixIndexCapability defines a key prefix that stores index to capability
// name mappings.
KeyPrefixIndexCapability = []byte("capability_index")
)
// RevCapabilityKey returns a reverse lookup key for a given module and capability
// name.
func RevCapabilityKey(module, name string) []byte {
return []byte(fmt.Sprintf("%s/rev/%s", module, name))
}
// FwdCapabilityKey returns a forward lookup key for a given module and capability
// reference.
func FwdCapabilityKey(module string, cap *Capability) []byte {
return []byte(fmt.Sprintf("%s/fwd/%p", module, cap))
}
// IndexToKey returns bytes to be used as a key for a given capability index.
func IndexToKey(index uint64) []byte {
return sdk.Uint64ToBigEndian(index)
}
// IndexFromKey returns an index from a call to IndexToKey for a given capability
// index.
func IndexFromKey(key []byte) uint64 {
return sdk.BigEndianToUint64(key)
}

View File

@ -0,0 +1,29 @@
package types_test
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/x/capability/types"
)
func TestRevCapabilityKey(t *testing.T) {
expected := []byte("bank/rev/send")
require.Equal(t, expected, types.RevCapabilityKey("bank", "send"))
}
func TestFwdCapabilityKey(t *testing.T) {
cap := types.NewCapability(23)
expected := []byte(fmt.Sprintf("bank/fwd/%p", cap))
require.Equal(t, expected, types.FwdCapabilityKey("bank", cap))
}
func TestIndexToKey(t *testing.T) {
require.Equal(t, []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x5a}, types.IndexToKey(3162))
}
func TestIndexFromKey(t *testing.T) {
require.Equal(t, uint64(3162), types.IndexFromKey([]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x5a}))
}

View File

@ -0,0 +1,56 @@
package types
// CapabilityStore defines an ephemeral in-memory object capability store.
type CapabilityStore struct {
revMemStore map[string]*Capability
fwdMemStore map[string]string
}
func NewCapabilityStore() CapabilityStore {
return CapabilityStore{
revMemStore: make(map[string]*Capability),
fwdMemStore: make(map[string]string),
}
}
// GetCapability returns a Capability by module and name tuple. If no Capability
// exists, nil will be returned.
func (cs CapabilityStore) GetCapability(module, name string) *Capability {
key := RevCapabilityKey(module, name)
return cs.revMemStore[string(key)]
}
// GetCapabilityName returns a Capability name by module and Capability tuple. If
// no Capability name exists for the given tuple, an empty string is returned.
func (cs CapabilityStore) GetCapabilityName(module string, cap *Capability) string {
key := FwdCapabilityKey(module, cap)
return cs.fwdMemStore[string(key)]
}
// SetCapability sets the reverse mapping between the module and capability name
// and the capability in the in-memory store.
func (cs CapabilityStore) SetCapability(module, name string, cap *Capability) {
key := RevCapabilityKey(module, name)
cs.revMemStore[string(key)] = cap
}
// SetCapabilityName sets the forward mapping between the module and capability
// tuple and the capability name in the in-memory store.
func (cs CapabilityStore) SetCapabilityName(module, name string, cap *Capability) {
key := FwdCapabilityKey(module, cap)
cs.fwdMemStore[string(key)] = name
}
// DeleteCapability removes the reverse mapping between the module and capability
// name and the capability in the in-memory store.
func (cs CapabilityStore) DeleteCapability(module, name string) {
key := RevCapabilityKey(module, name)
delete(cs.revMemStore, string(key))
}
// DeleteCapabilityName removes the forward mapping between the module and capability
// tuple and the capability name in the in-memory store.
func (cs CapabilityStore) DeleteCapabilityName(module string, cap *Capability) {
key := FwdCapabilityKey(module, cap)
delete(cs.fwdMemStore, string(key))
}

View File

@ -0,0 +1,87 @@
package types
import (
"fmt"
"sort"
"gopkg.in/yaml.v2"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// NewCapability returns a reference to a new Capability to be used as an
// actual capability.
func NewCapability(index uint64) *Capability {
return &Capability{Index: index}
}
// String returns the string representation of a Capability. The string contains
// the Capability's memory reference as the string is to be used in a composite
// key and to authenticate capabilities.
func (ck *Capability) String() string {
return fmt.Sprintf("Capability{%p, %d}", ck, ck.Index)
}
func NewOwner(module, name string) Owner {
return Owner{Module: module, Name: name}
}
// Key returns a composite key for an Owner.
func (o Owner) Key() string {
return fmt.Sprintf("%s/%s", o.Module, o.Name)
}
func (o Owner) String() string {
bz, _ := yaml.Marshal(o)
return string(bz)
}
func NewCapabilityOwners() *CapabilityOwners {
return &CapabilityOwners{Owners: make([]Owner, 0)}
}
// Set attempts to add a given owner to the CapabilityOwners. If the owner
// already exists, an error will be returned. Set runs in O(log n) average time
// and O(n) in the worst case.
func (co *CapabilityOwners) Set(owner Owner) error {
i, ok := co.Get(owner)
if ok {
// owner already exists at co.Owners[i]
return sdkerrors.Wrapf(ErrOwnerClaimed, owner.String())
}
// owner does not exist in the set of owners, so we insert at position i
co.Owners = append(co.Owners, Owner{}) // expand by 1 in amortized O(1) / O(n) worst case
copy(co.Owners[i+1:], co.Owners[i:])
co.Owners[i] = owner
return nil
}
// Remove removes a provided owner from the CapabilityOwners if it exists. If the
// owner does not exist, Remove is considered a no-op.
func (co *CapabilityOwners) Remove(owner Owner) {
if len(co.Owners) == 0 {
return
}
i, ok := co.Get(owner)
if ok {
// owner exists at co.Owners[i]
co.Owners = append(co.Owners[:i], co.Owners[i+1:]...)
}
}
// Get returns (i, true) of the provided owner in the CapabilityOwners if the
// owner exists, where i indicates the owner's index in the set. Otherwise
// (i, false) where i indicates where in the set the owner should be added.
func (co *CapabilityOwners) Get(owner Owner) (int, bool) {
// find smallest index s.t. co.Owners[i] >= owner in O(log n) time
i := sort.Search(len(co.Owners), func(i int) bool { return co.Owners[i].Key() >= owner.Key() })
if i < len(co.Owners) && co.Owners[i].Key() == owner.Key() {
// owner exists at co.Owners[i]
return i, true
}
return i, false
}

View File

@ -0,0 +1,710 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: x/capability/types/types.proto
package types
import (
fmt "fmt"
_ "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
// Capability defines an implementation of an object capability. The index provided to
// a Capability must be globally unique.
type Capability struct {
Index uint64 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty" yaml:"index"`
}
func (m *Capability) Reset() { *m = Capability{} }
func (*Capability) ProtoMessage() {}
func (*Capability) Descriptor() ([]byte, []int) {
return fileDescriptor_d73d5c48b3550cdd, []int{0}
}
func (m *Capability) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *Capability) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_Capability.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 *Capability) XXX_Merge(src proto.Message) {
xxx_messageInfo_Capability.Merge(m, src)
}
func (m *Capability) XXX_Size() int {
return m.Size()
}
func (m *Capability) XXX_DiscardUnknown() {
xxx_messageInfo_Capability.DiscardUnknown(m)
}
var xxx_messageInfo_Capability proto.InternalMessageInfo
func (m *Capability) GetIndex() uint64 {
if m != nil {
return m.Index
}
return 0
}
// Owner defines a single capability owner. An owner is defined by the name of
// capability and the module name.
type Owner struct {
Module string `protobuf:"bytes,1,opt,name=module,proto3" json:"module,omitempty" yaml:"module"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty" yaml:"name"`
}
func (m *Owner) Reset() { *m = Owner{} }
func (*Owner) ProtoMessage() {}
func (*Owner) Descriptor() ([]byte, []int) {
return fileDescriptor_d73d5c48b3550cdd, []int{1}
}
func (m *Owner) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *Owner) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_Owner.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 *Owner) XXX_Merge(src proto.Message) {
xxx_messageInfo_Owner.Merge(m, src)
}
func (m *Owner) XXX_Size() int {
return m.Size()
}
func (m *Owner) XXX_DiscardUnknown() {
xxx_messageInfo_Owner.DiscardUnknown(m)
}
var xxx_messageInfo_Owner proto.InternalMessageInfo
// CapabilityOwners defines a set of owners of a single Capability. The set of
// owners must be unique.
type CapabilityOwners struct {
Owners []Owner `protobuf:"bytes,1,rep,name=owners,proto3" json:"owners"`
}
func (m *CapabilityOwners) Reset() { *m = CapabilityOwners{} }
func (m *CapabilityOwners) String() string { return proto.CompactTextString(m) }
func (*CapabilityOwners) ProtoMessage() {}
func (*CapabilityOwners) Descriptor() ([]byte, []int) {
return fileDescriptor_d73d5c48b3550cdd, []int{2}
}
func (m *CapabilityOwners) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *CapabilityOwners) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_CapabilityOwners.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 *CapabilityOwners) XXX_Merge(src proto.Message) {
xxx_messageInfo_CapabilityOwners.Merge(m, src)
}
func (m *CapabilityOwners) XXX_Size() int {
return m.Size()
}
func (m *CapabilityOwners) XXX_DiscardUnknown() {
xxx_messageInfo_CapabilityOwners.DiscardUnknown(m)
}
var xxx_messageInfo_CapabilityOwners proto.InternalMessageInfo
func (m *CapabilityOwners) GetOwners() []Owner {
if m != nil {
return m.Owners
}
return nil
}
func init() {
proto.RegisterType((*Capability)(nil), "cosmos_sdk.x.capability.v1.Capability")
proto.RegisterType((*Owner)(nil), "cosmos_sdk.x.capability.v1.Owner")
proto.RegisterType((*CapabilityOwners)(nil), "cosmos_sdk.x.capability.v1.CapabilityOwners")
}
func init() { proto.RegisterFile("x/capability/types/types.proto", fileDescriptor_d73d5c48b3550cdd) }
var fileDescriptor_d73d5c48b3550cdd = []byte{
// 308 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xab, 0xd0, 0x4f, 0x4e,
0x2c, 0x48, 0x4c, 0xca, 0xcc, 0xc9, 0x2c, 0xa9, 0xd4, 0x2f, 0xa9, 0x2c, 0x48, 0x2d, 0x86, 0x90,
0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0x52, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xf1, 0xc5,
0x29, 0xd9, 0x7a, 0x15, 0x7a, 0x08, 0xa5, 0x7a, 0x65, 0x86, 0x52, 0x6a, 0x25, 0x19, 0x99, 0x45,
0x29, 0xf1, 0x05, 0x89, 0x45, 0x25, 0x95, 0xfa, 0x60, 0xe5, 0xfa, 0xe9, 0xf9, 0xe9, 0xf9, 0x08,
0x16, 0xc4, 0x0c, 0x25, 0x2b, 0x2e, 0x2e, 0x67, 0xb8, 0x46, 0x21, 0x35, 0x2e, 0xd6, 0xcc, 0xbc,
0x94, 0xd4, 0x0a, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x16, 0x27, 0x81, 0x4f, 0xf7, 0xe4, 0x79, 0x2a,
0x13, 0x73, 0x73, 0xac, 0x94, 0xc0, 0xc2, 0x4a, 0x41, 0x10, 0x69, 0x2b, 0x96, 0x19, 0x0b, 0xe4,
0x19, 0x94, 0x12, 0xb9, 0x58, 0xfd, 0xcb, 0xf3, 0x52, 0x8b, 0x84, 0x34, 0xb9, 0xd8, 0x72, 0xf3,
0x53, 0x4a, 0x73, 0x52, 0xc1, 0xfa, 0x38, 0x9d, 0x04, 0x3f, 0xdd, 0x93, 0xe7, 0x85, 0xe8, 0x83,
0x88, 0x2b, 0x05, 0x41, 0x15, 0x08, 0x29, 0x73, 0xb1, 0xe4, 0x25, 0xe6, 0xa6, 0x4a, 0x30, 0x81,
0x15, 0xf2, 0x7f, 0xba, 0x27, 0xcf, 0x0d, 0x51, 0x08, 0x12, 0x55, 0x0a, 0x02, 0x4b, 0x5a, 0x71,
0x74, 0x2c, 0x90, 0x67, 0x00, 0x5b, 0x11, 0xcc, 0x25, 0x80, 0x70, 0x1e, 0xd8, 0xb2, 0x62, 0x21,
0x7b, 0x2e, 0xb6, 0x7c, 0x30, 0x4b, 0x82, 0x51, 0x81, 0x59, 0x83, 0xdb, 0x48, 0x51, 0x0f, 0x77,
0x38, 0xe8, 0x81, 0xf5, 0x38, 0xb1, 0x9c, 0xb8, 0x27, 0xcf, 0x10, 0x04, 0xd5, 0xe6, 0xe4, 0x79,
0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7,
0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0xfa, 0xe9, 0x99, 0x25, 0x19, 0xa5,
0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0x10, 0x43, 0xa1, 0x94, 0x6e, 0x71, 0x4a, 0xb6, 0x3e, 0x66,
0x74, 0x24, 0xb1, 0x81, 0x43, 0xd1, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x0b, 0x14, 0xb2, 0xaf,
0xab, 0x01, 0x00, 0x00,
}
func (m *Capability) 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 *Capability) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *Capability) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.Index != 0 {
i = encodeVarintTypes(dAtA, i, uint64(m.Index))
i--
dAtA[i] = 0x8
}
return len(dAtA) - i, nil
}
func (m *Owner) 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 *Owner) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *Owner) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.Name) > 0 {
i -= len(m.Name)
copy(dAtA[i:], m.Name)
i = encodeVarintTypes(dAtA, i, uint64(len(m.Name)))
i--
dAtA[i] = 0x12
}
if len(m.Module) > 0 {
i -= len(m.Module)
copy(dAtA[i:], m.Module)
i = encodeVarintTypes(dAtA, i, uint64(len(m.Module)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *CapabilityOwners) 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 *CapabilityOwners) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *CapabilityOwners) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.Owners) > 0 {
for iNdEx := len(m.Owners) - 1; iNdEx >= 0; iNdEx-- {
{
size, err := m.Owners[iNdEx].MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintTypes(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
}
}
return len(dAtA) - i, nil
}
func encodeVarintTypes(dAtA []byte, offset int, v uint64) int {
offset -= sovTypes(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return base
}
func (m *Capability) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.Index != 0 {
n += 1 + sovTypes(uint64(m.Index))
}
return n
}
func (m *Owner) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Module)
if l > 0 {
n += 1 + l + sovTypes(uint64(l))
}
l = len(m.Name)
if l > 0 {
n += 1 + l + sovTypes(uint64(l))
}
return n
}
func (m *CapabilityOwners) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if len(m.Owners) > 0 {
for _, e := range m.Owners {
l = e.Size()
n += 1 + l + sovTypes(uint64(l))
}
}
return n
}
func sovTypes(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
func sozTypes(x uint64) (n int) {
return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *Capability) 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 ErrIntOverflowTypes
}
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: Capability: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Capability: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType)
}
m.Index = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Index |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipTypes(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthTypes
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthTypes
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *Owner) 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 ErrIntOverflowTypes
}
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: Owner: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Owner: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Module", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
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 ErrInvalidLengthTypes
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthTypes
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Module = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
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 ErrInvalidLengthTypes
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthTypes
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Name = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipTypes(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthTypes
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthTypes
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *CapabilityOwners) 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 ErrIntOverflowTypes
}
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: CapabilityOwners: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: CapabilityOwners: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Owners", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthTypes
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthTypes
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Owners = append(m.Owners, Owner{})
if err := m.Owners[len(m.Owners)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipTypes(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthTypes
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthTypes
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipTypes(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, ErrIntOverflowTypes
}
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, ErrIntOverflowTypes
}
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, ErrIntOverflowTypes
}
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, ErrInvalidLengthTypes
}
iNdEx += length
case 3:
depth++
case 4:
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupTypes
}
depth--
case 5:
iNdEx += 4
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthTypes
}
if depth == 0 {
return iNdEx, nil
}
}
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group")
)

View File

@ -0,0 +1,33 @@
syntax = "proto3";
package cosmos_sdk.x.capability.v1;
option go_package = "github.com/cosmos/cosmos-sdk/x/capability/types";
import "third_party/proto/gogoproto/gogo.proto";
// Capability defines an implementation of an object capability. The index provided to
// a Capability must be globally unique.
message Capability {
option (gogoproto.goproto_stringer) = false;
uint64 index = 1 [(gogoproto.moretags) = "yaml:\"index\""];
}
// Owner defines a single capability owner. An owner is defined by the name of
// capability and the module name.
message Owner {
option (gogoproto.goproto_stringer) = false;
option (gogoproto.goproto_getters) = false;
string module = 1 [(gogoproto.moretags) = "yaml:\"module\""];
string name = 2 [(gogoproto.moretags) = "yaml:\"name\""];
}
// CapabilityOwners defines a set of owners of a single Capability. The set of
// owners must be unique.
message CapabilityOwners {
repeated Owner owners = 1 [
(gogoproto.nullable) = false
];
}

View File

@ -0,0 +1,69 @@
package types_test
import (
"fmt"
"sort"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/x/capability/types"
)
func TestCapabilityKey(t *testing.T) {
idx := uint64(3162)
cap := types.NewCapability(idx)
require.Equal(t, idx, cap.GetIndex())
require.Equal(t, fmt.Sprintf("Capability{%p, %d}", cap, idx), cap.String())
}
func TestOwner(t *testing.T) {
o := types.NewOwner("bank", "send")
require.Equal(t, "bank/send", o.Key())
require.Equal(t, "module: bank\nname: send\n", o.String())
}
func TestCapabilityOwners_Set(t *testing.T) {
co := types.NewCapabilityOwners()
owners := make([]types.Owner, 1024)
for i := range owners {
var owner types.Owner
if i%2 == 0 {
owner = types.NewOwner("bank", fmt.Sprintf("send-%d", i))
} else {
owner = types.NewOwner("slashing", fmt.Sprintf("slash-%d", i))
}
owners[i] = owner
require.NoError(t, co.Set(owner))
}
sort.Slice(owners, func(i, j int) bool { return owners[i].Key() < owners[j].Key() })
require.Equal(t, owners, co.Owners)
for _, owner := range owners {
require.Error(t, co.Set(owner))
}
}
func TestCapabilityOwners_Remove(t *testing.T) {
co := types.NewCapabilityOwners()
co.Remove(types.NewOwner("bank", "send-0"))
require.Len(t, co.Owners, 0)
for i := 0; i < 5; i++ {
require.NoError(t, co.Set(types.NewOwner("bank", fmt.Sprintf("send-%d", i))))
}
require.Len(t, co.Owners, 5)
for i := 0; i < 5; i++ {
co.Remove(types.NewOwner("bank", fmt.Sprintf("send-%d", i)))
require.Len(t, co.Owners, 5-(i+1))
}
require.Len(t, co.Owners, 0)
}

View File

@ -28,9 +28,14 @@ func NewKeeper(
feeCollectorName string,
) Keeper {
// set KeyTable if it has not already been set
if !paramSpace.HasKeyTable() {
paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable())
}
return Keeper{
routes: make([]types.InvarRoute, 0),
paramSpace: paramSpace.WithKeyTable(types.ParamKeyTable()),
paramSpace: paramSpace,
invCheckPeriod: invCheckPeriod,
supplyKeeper: supplyKeeper,
feeCollectorName: feeCollectorName,

View File

@ -15,11 +15,17 @@ type Evidence interface {
Hash() tmbytes.HexBytes
ValidateBasic() error
// The consensus address of the malicious validator at time of infraction
GetConsensusAddress() sdk.ConsAddress
// Height at which the infraction occurred
GetHeight() int64
}
// ValidatorEvidence extends Evidence interface to define contract
// for evidence against malicious validators
type ValidatorEvidence interface {
Evidence
// The consensus address of the malicious validator at time of infraction
GetConsensusAddress() sdk.ConsAddress
// The total power of the malicious validator at time of infraction
GetValidatorPower() int64

51
x/ibc/02-client/alias.go Normal file
View File

@ -0,0 +1,51 @@
package client
// nolint
// autogenerated code using github.com/rigelrozanski/multitool
// aliases generated for the following subdirectories:
// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/02-client/keeper
// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/02-client/types
import (
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/keeper"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
)
const (
AttributeKeyClientID = types.AttributeKeyClientID
AttrbuteKeyClientType = types.AttributeKeyClientType
SubModuleName = types.SubModuleName
RouterKey = types.RouterKey
QuerierRoute = types.QuerierRoute
QueryAllClients = types.QueryAllClients
QueryClientState = types.QueryClientState
QueryConsensusState = types.QueryConsensusState
)
var (
// functions aliases
NewKeeper = keeper.NewKeeper
QuerierClients = keeper.QuerierClients
RegisterCodec = types.RegisterCodec
ErrClientExists = types.ErrClientExists
ErrClientNotFound = types.ErrClientNotFound
ErrClientFrozen = types.ErrClientFrozen
ErrConsensusStateNotFound = types.ErrConsensusStateNotFound
ErrInvalidConsensus = types.ErrInvalidConsensus
ErrClientTypeNotFound = types.ErrClientTypeNotFound
ErrInvalidClientType = types.ErrInvalidClientType
ErrRootNotFound = types.ErrRootNotFound
ErrInvalidHeader = types.ErrInvalidHeader
ErrInvalidEvidence = types.ErrInvalidEvidence
// variable aliases
SubModuleCdc = types.SubModuleCdc
EventTypeCreateClient = types.EventTypeCreateClient
EventTypeUpdateClient = types.EventTypeUpdateClient
AttributeValueCategory = types.AttributeValueCategory
)
type (
Keeper = keeper.Keeper
StakingKeeper = types.StakingKeeper
)

View File

@ -0,0 +1,28 @@
package cli
import (
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
)
// GetQueryCmd returns the query commands for IBC clients
func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
ics02ClientQueryCmd := &cobra.Command{
Use: "client",
Short: "IBC client query subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
}
ics02ClientQueryCmd.AddCommand(flags.GetCommands(
GetCmdQueryClientStates(queryRoute, cdc),
GetCmdQueryClientState(queryRoute, cdc),
GetCmdQueryConsensusState(queryRoute, cdc),
GetCmdQueryHeader(cdc),
GetCmdNodeConsensusState(queryRoute, cdc),
GetCmdQueryPath(queryRoute, cdc),
)...)
return ics02ClientQueryCmd
}

View File

@ -0,0 +1,180 @@
package cli
import (
"errors"
"fmt"
"strconv"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/client/utils"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
)
// GetCmdQueryClientStates defines the command to query all the light clients
// that this chain mantains.
func GetCmdQueryClientStates(queryRoute string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "states",
Short: "Query all available light clients",
Long: strings.TrimSpace(
fmt.Sprintf(`Query all available light clients
Example:
$ %s query ibc client states
`, version.ClientName),
),
Example: fmt.Sprintf("%s query ibc client states", version.ClientName),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
page := viper.GetInt(flags.FlagPage)
limit := viper.GetInt(flags.FlagLimit)
clientStates, _, err := utils.QueryAllClientStates(cliCtx, page, limit)
if err != nil {
return err
}
return cliCtx.PrintOutput(clientStates)
},
}
cmd.Flags().Int(flags.FlagPage, 1, "pagination page of light clients to to query for")
cmd.Flags().Int(flags.FlagLimit, 100, "pagination limit of light clients to query for")
return cmd
}
// GetCmdQueryClientState defines the command to query the state of a client with
// a given id as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#query
func GetCmdQueryClientState(queryRoute string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "state [client-id]",
Short: "Query a client state",
Long: strings.TrimSpace(
fmt.Sprintf(`Query stored client state
Example:
$ %s query ibc client state [client-id]
`, version.ClientName),
),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
clientID := args[0]
if strings.TrimSpace(clientID) == "" {
return errors.New("client ID can't be blank")
}
prove := viper.GetBool(flags.FlagProve)
clientStateRes, err := utils.QueryClientState(cliCtx, clientID, prove)
if err != nil {
return err
}
return cliCtx.PrintOutput(clientStateRes)
},
}
cmd.Flags().Bool(flags.FlagProve, true, "show proofs for the query results")
return cmd
}
// GetCmdQueryConsensusState defines the command to query the consensus state of
// the chain as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#query
func GetCmdQueryConsensusState(queryRoute string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "consensus-state [client-id] [height]",
Short: "Query the consensus state of a client at a given height",
Long: "Query the consensus state for a particular light client at a given height",
Example: fmt.Sprintf("%s query ibc client consensus-state [client-id] [height]", version.ClientName),
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
clientID := args[0]
if strings.TrimSpace(clientID) == "" {
return errors.New("client ID can't be blank")
}
height, err := strconv.ParseUint(args[1], 10, 64)
if err != nil {
return fmt.Errorf("expected integer height, got: %s", args[1])
}
prove := viper.GetBool(flags.FlagProve)
csRes, err := utils.QueryConsensusState(cliCtx, clientID, height, prove)
if err != nil {
return err
}
return cliCtx.PrintOutput(csRes)
},
}
cmd.Flags().Bool(flags.FlagProve, true, "show proofs for the query results")
return cmd
}
// GetCmdQueryHeader defines the command to query the latest header on the chain
func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "header",
Short: "Query the latest header of the running chain",
Long: "Query the latest Tendermint header of the running chain",
Example: fmt.Sprintf("%s query ibc client header", version.ClientName),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
header, _, err := utils.QueryTendermintHeader(cliCtx)
if err != nil {
return err
}
return cliCtx.PrintOutput(header)
},
}
}
// GetCmdNodeConsensusState defines the command to query the latest consensus state of a node
// The result is feed to client creation
func GetCmdNodeConsensusState(queryRoute string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "node-state",
Short: "Query a node consensus state",
Long: strings.TrimSpace(
fmt.Sprintf(`Query a node consensus state. This result is feed to the client creation transaction.
Example:
$ %s query ibc client node-state
`, version.ClientName),
),
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
state, _, err := utils.QueryNodeConsensusState(cliCtx)
if err != nil {
return err
}
return cliCtx.PrintOutput(state)
},
}
}
// GetCmdQueryPath defines the command to query the commitment path.
func GetCmdQueryPath(storeName string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "path",
Short: "Query the commitment path of the running chain",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCLIContext().WithCodec(cdc)
path := commitmenttypes.NewMerklePrefix([]byte("ibc"))
return ctx.PrintOutput(path)
},
}
}

View File

@ -0,0 +1,172 @@
package rest
import (
"fmt"
"net/http"
"strconv"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/types/rest"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/client/utils"
)
func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) {
r.HandleFunc("/ibc/clients", queryAllClientStatesFn(cliCtx)).Methods("GET")
r.HandleFunc(fmt.Sprintf("/ibc/clients/{%s}/client-state", RestClientID), queryClientStateHandlerFn(cliCtx)).Methods("GET")
r.HandleFunc(fmt.Sprintf("/ibc/clients/{%s}/consensus-state", RestClientID), queryConsensusStateHandlerFn(cliCtx)).Methods("GET")
r.HandleFunc("/ibc/header", queryHeaderHandlerFn(cliCtx)).Methods("GET")
r.HandleFunc("/ibc/node-state", queryNodeConsensusStateHandlerFn(cliCtx)).Methods("GET")
}
// queryAllClientStatesFn queries all available light clients
//
// @Summary Query client states
// @Tags IBC
// @Produce json
// @Param page query int false "The page number to query" default(1)
// @Param limit query int false "The number of results per page" default(100)
// @Success 200 {object} QueryClientState "OK"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/clients [get]
func queryAllClientStatesFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
_, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
clients, height, err := utils.QueryAllClientStates(cliCtx, page, limit)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
cliCtx = cliCtx.WithHeight(height)
rest.PostProcessResponse(w, cliCtx, clients)
}
}
// queryClientStateHandlerFn implements a client state querying route
//
// @Summary Query client state
// @Tags IBC
// @Produce json
// @Param client-id path string true "Client ID"
// @Param prove query boolean false "Proof of result"
// @Success 200 {object} QueryClientState "OK"
// @Failure 400 {object} rest.ErrorResponse "Invalid client id"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/clients/{client-id}/client-state [get]
func queryClientStateHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
clientID := vars[RestClientID]
prove := rest.ParseQueryParamBool(r, flags.FlagProve)
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
clientStateRes, err := utils.QueryClientState(cliCtx, clientID, prove)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
cliCtx = cliCtx.WithHeight(int64(clientStateRes.ProofHeight))
rest.PostProcessResponse(w, cliCtx, clientStateRes)
}
}
// queryConsensusStateHandlerFn implements a consensus state querying route
//
// @Summary Query cliet consensus-state
// @Tags IBC
// @Produce json
// @Param client-id path string true "Client ID"
// @Param height path number true "Height"
// @Param prove query boolean false "Proof of result"
// @Success 200 {object} QueryConsensusState "OK"
// @Failure 400 {object} rest.ErrorResponse "Invalid client id"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/clients/{client-id}/consensus-state [get]
func queryConsensusStateHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
clientID := vars[RestClientID]
height, err := strconv.ParseUint(vars[RestRootHeight], 10, 64)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
prove := rest.ParseQueryParamBool(r, flags.FlagProve)
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
csRes, err := utils.QueryConsensusState(cliCtx, clientID, height, prove)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
cliCtx = cliCtx.WithHeight(int64(csRes.ProofHeight))
rest.PostProcessResponse(w, cliCtx, csRes)
}
}
// queryHeaderHandlerFn implements a header querying route
//
// @Summary Query header
// @Tags IBC
// @Produce json
// @Success 200 {object} QueryHeader "OK"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/header [get]
func queryHeaderHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
header, height, err := utils.QueryTendermintHeader(cliCtx)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
res := cliCtx.Codec.MustMarshalJSON(header)
cliCtx = cliCtx.WithHeight(height)
rest.PostProcessResponse(w, cliCtx, res)
}
}
// queryNodeConsensusStateHandlerFn implements a node consensus state querying route
//
// @Summary Query node consensus-state
// @Tags IBC
// @Produce json
// @Success 200 {object} QueryNodeConsensusState "OK"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/node-state [get]
func queryNodeConsensusStateHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
state, height, err := utils.QueryNodeConsensusState(cliCtx)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
}
res := cliCtx.Codec.MustMarshalJSON(state)
cliCtx = cliCtx.WithHeight(height)
rest.PostProcessResponse(w, cliCtx, res)
}
}

View File

@ -0,0 +1,18 @@
package rest
import (
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
)
// REST client flags
const (
RestClientID = "client-id"
RestRootHeight = "height"
)
// RegisterRoutes - Central function to define routes that get registered by the main application
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) {
registerQueryRoutes(cliCtx, r)
}

View File

@ -0,0 +1,157 @@
package utils
import (
"fmt"
abci "github.com/tendermint/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types"
)
// QueryAllClientStates returns all the light client states. It _does not_ return
// any merkle proof.
func QueryAllClientStates(cliCtx context.CLIContext, page, limit int) ([]exported.ClientState, int64, error) {
params := types.NewQueryAllClientsParams(page, limit)
bz, err := cliCtx.Codec.MarshalJSON(params)
if err != nil {
return nil, 0, fmt.Errorf("failed to marshal query params: %w", err)
}
route := fmt.Sprintf("custom/%s/%s/%s", "ibc", types.QuerierRoute, types.QueryAllClients)
res, height, err := cliCtx.QueryWithData(route, bz)
if err != nil {
return nil, 0, err
}
var clients []exported.ClientState
err = cliCtx.Codec.UnmarshalJSON(res, &clients)
if err != nil {
return nil, 0, fmt.Errorf("failed to unmarshal light clients: %w", err)
}
return clients, height, nil
}
// QueryClientState queries the store to get the light client state and a merkle
// proof.
func QueryClientState(
cliCtx context.CLIContext, clientID string, prove bool,
) (types.StateResponse, error) {
req := abci.RequestQuery{
Path: "store/ibc/key",
Data: ibctypes.KeyClientState(clientID),
Prove: prove,
}
res, err := cliCtx.QueryABCI(req)
if err != nil {
return types.StateResponse{}, err
}
var clientState exported.ClientState
if err := cliCtx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &clientState); err != nil {
return types.StateResponse{}, err
}
clientStateRes := types.NewClientStateResponse(clientID, clientState, res.Proof, res.Height)
return clientStateRes, nil
}
// QueryConsensusState queries the store to get the consensus state and a merkle
// proof.
func QueryConsensusState(
cliCtx context.CLIContext, clientID string, height uint64, prove bool,
) (types.ConsensusStateResponse, error) {
var conStateRes types.ConsensusStateResponse
req := abci.RequestQuery{
Path: "store/ibc/key",
Data: ibctypes.KeyConsensusState(clientID, height),
Prove: prove,
}
res, err := cliCtx.QueryABCI(req)
if err != nil {
return conStateRes, err
}
var cs exported.ConsensusState
if err := cliCtx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &cs); err != nil {
return conStateRes, err
}
return types.NewConsensusStateResponse(clientID, cs, res.Proof, res.Height), nil
}
// QueryTendermintHeader takes a client context and returns the appropriate
// tendermint header
func QueryTendermintHeader(cliCtx context.CLIContext) (ibctmtypes.Header, int64, error) {
node, err := cliCtx.GetNode()
if err != nil {
return ibctmtypes.Header{}, 0, err
}
info, err := node.ABCIInfo()
if err != nil {
return ibctmtypes.Header{}, 0, err
}
height := info.Response.LastBlockHeight
commit, err := node.Commit(&height)
if err != nil {
return ibctmtypes.Header{}, 0, err
}
validators, err := node.Validators(&height, 0, 10000)
if err != nil {
return ibctmtypes.Header{}, 0, err
}
header := ibctmtypes.Header{
SignedHeader: commit.SignedHeader,
ValidatorSet: tmtypes.NewValidatorSet(validators.Validators),
}
return header, height, nil
}
// QueryNodeConsensusState takes a client context and returns the appropriate
// tendermint consensus state
func QueryNodeConsensusState(cliCtx context.CLIContext) (ibctmtypes.ConsensusState, int64, error) {
node, err := cliCtx.GetNode()
if err != nil {
return ibctmtypes.ConsensusState{}, 0, err
}
info, err := node.ABCIInfo()
if err != nil {
return ibctmtypes.ConsensusState{}, 0, err
}
height := info.Response.LastBlockHeight
commit, err := node.Commit(&height)
if err != nil {
return ibctmtypes.ConsensusState{}, 0, err
}
validators, err := node.Validators(&height, 0, 10000)
if err != nil {
return ibctmtypes.ConsensusState{}, 0, err
}
state := ibctmtypes.ConsensusState{
Timestamp: commit.Time,
Root: commitmenttypes.NewMerkleRoot(commit.AppHash),
ValidatorSet: tmtypes.NewValidatorSet(validators.Validators),
}
return state, height, nil
}

10
x/ibc/02-client/doc.go Normal file
View File

@ -0,0 +1,10 @@
/*
Package client implements the ICS 02 - Client Semantics specification
https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics. This
concrete implementations defines types and method to store and update light
clients which tracks on other chain's state.
The main type is `Client`, which provides `commitment.Root` to verify state proofs and `ConsensusState` to
verify header proofs.
*/
package client

View File

@ -0,0 +1,193 @@
package exported
import (
"encoding/json"
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/codec"
evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported"
connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported"
channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported"
commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported"
)
// ClientState defines the required common functions for light clients.
type ClientState interface {
GetID() string
GetChainID() string
ClientType() ClientType
GetLatestHeight() uint64
IsFrozen() bool
// State verification functions
VerifyClientConsensusState(
cdc *codec.Codec,
root commitmentexported.Root,
height uint64,
counterpartyClientIdentifier string,
consensusHeight uint64,
prefix commitmentexported.Prefix,
proof commitmentexported.Proof,
consensusState ConsensusState,
) error
VerifyConnectionState(
cdc *codec.Codec,
height uint64,
prefix commitmentexported.Prefix,
proof commitmentexported.Proof,
connectionID string,
connectionEnd connectionexported.ConnectionI,
consensusState ConsensusState,
) error
VerifyChannelState(
cdc *codec.Codec,
height uint64,
prefix commitmentexported.Prefix,
proof commitmentexported.Proof,
portID,
channelID string,
channel channelexported.ChannelI,
consensusState ConsensusState,
) error
VerifyPacketCommitment(
height uint64,
prefix commitmentexported.Prefix,
proof commitmentexported.Proof,
portID,
channelID string,
sequence uint64,
commitmentBytes []byte,
consensusState ConsensusState,
) error
VerifyPacketAcknowledgement(
height uint64,
prefix commitmentexported.Prefix,
proof commitmentexported.Proof,
portID,
channelID string,
sequence uint64,
acknowledgement []byte,
consensusState ConsensusState,
) error
VerifyPacketAcknowledgementAbsence(
height uint64,
prefix commitmentexported.Prefix,
proof commitmentexported.Proof,
portID,
channelID string,
sequence uint64,
consensusState ConsensusState,
) error
VerifyNextSequenceRecv(
height uint64,
prefix commitmentexported.Prefix,
proof commitmentexported.Proof,
portID,
channelID string,
nextSequenceRecv uint64,
consensusState ConsensusState,
) error
}
// ConsensusState is the state of the consensus process
type ConsensusState interface {
ClientType() ClientType // Consensus kind
// GetHeight returns the height of the consensus state
GetHeight() uint64
// GetRoot returns the commitment root of the consensus state,
// which is used for key-value pair verification.
GetRoot() commitmentexported.Root
ValidateBasic() error
}
// Misbehaviour defines a specific consensus kind and an evidence
type Misbehaviour interface {
evidenceexported.Evidence
ClientType() ClientType
GetClientID() string
}
// Header is the consensus state update information
type Header interface {
ClientType() ClientType
GetHeight() uint64
}
// MsgCreateClient defines the msg interface that the
// CreateClient Handler expects
type MsgCreateClient interface {
sdk.Msg
GetClientID() string
GetClientType() string
GetConsensusState() ConsensusState
}
// MsgUpdateClient defines the msg interface that the
// UpdateClient Handler expects
type MsgUpdateClient interface {
sdk.Msg
GetClientID() string
GetHeader() Header
}
// ClientType defines the type of the consensus algorithm
type ClientType byte
// available client types
const (
Tendermint ClientType = iota + 1 // 1
)
// string representation of the client types
const (
ClientTypeTendermint string = "tendermint"
)
func (ct ClientType) String() string {
switch ct {
case Tendermint:
return ClientTypeTendermint
default:
return ""
}
}
// MarshalJSON marshal to JSON using string.
func (ct ClientType) MarshalJSON() ([]byte, error) {
return json.Marshal(ct.String())
}
// UnmarshalJSON decodes from JSON.
func (ct *ClientType) UnmarshalJSON(data []byte) error {
var s string
err := json.Unmarshal(data, &s)
if err != nil {
return err
}
clientType := ClientTypeFromString(s)
if clientType == 0 {
return fmt.Errorf("invalid client type '%s'", s)
}
*ct = clientType
return nil
}
// ClientTypeFromString returns a byte that corresponds to the registered client
// type. It returns 0 if the type is not found/registered.
func ClientTypeFromString(clientType string) ClientType {
switch clientType {
case ClientTypeTendermint:
return Tendermint
default:
return 0
}
}

View File

@ -0,0 +1,49 @@
package exported
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestClientTypeString(t *testing.T) {
cases := []struct {
msg string
name string
clientType ClientType
}{
{"tendermint client", ClientTypeTendermint, Tendermint},
{"empty type", "", 0},
}
for _, tt := range cases {
tt := tt
require.Equal(t, tt.clientType, ClientTypeFromString(tt.name), tt.msg)
require.Equal(t, tt.name, tt.clientType.String(), tt.msg)
}
}
func TestClientTypeMarshalJSON(t *testing.T) {
cases := []struct {
msg string
name string
clientType ClientType
expectPass bool
}{
{"tendermint client should have passed", ClientTypeTendermint, Tendermint, true},
{"empty type should have failed", "", 0, false},
}
for _, tt := range cases {
tt := tt
bz, err := tt.clientType.MarshalJSON()
require.NoError(t, err)
var ct ClientType
if tt.expectPass {
require.NoError(t, ct.UnmarshalJSON(bz), tt.msg)
require.Equal(t, tt.name, ct.String(), tt.msg)
} else {
require.Error(t, ct.UnmarshalJSON(bz), tt.msg)
}
}
}

104
x/ibc/02-client/handler.go Normal file
View File

@ -0,0 +1,104 @@
package client
import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/evidence"
evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
)
// HandleMsgCreateClient defines the sdk.Handler for MsgCreateClient
func HandleMsgCreateClient(ctx sdk.Context, k Keeper, msg exported.MsgCreateClient) (*sdk.Result, error) {
clientType := exported.ClientTypeFromString(msg.GetClientType())
var clientState exported.ClientState
switch clientType {
case 0:
return nil, sdkerrors.Wrap(ErrInvalidClientType, msg.GetClientType())
case exported.Tendermint:
tmMsg, ok := msg.(ibctmtypes.MsgCreateClient)
if !ok {
return nil, sdkerrors.Wrap(ErrInvalidClientType, "Msg is not a Tendermint CreateClient msg")
}
var err error
clientState, err = ibctmtypes.InitializeFromMsg(tmMsg)
if err != nil {
return nil, err
}
default:
return nil, sdkerrors.Wrap(ErrInvalidClientType, msg.GetClientType())
}
_, err := k.CreateClient(
ctx, clientState, msg.GetConsensusState(),
)
if err != nil {
return nil, err
}
attributes := make([]sdk.Attribute, len(msg.GetSigners())+1)
attributes[0] = sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory)
for i, signer := range msg.GetSigners() {
attributes[i+1] = sdk.NewAttribute(sdk.AttributeKeySender, signer.String())
}
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
EventTypeCreateClient,
sdk.NewAttribute(AttributeKeyClientID, msg.GetClientID()),
sdk.NewAttribute(AttrbuteKeyClientType, msg.GetClientType()),
),
sdk.NewEvent(
sdk.EventTypeMessage,
attributes...,
),
})
return &sdk.Result{
Events: ctx.EventManager().Events().ToABCIEvents(),
}, nil
}
// HandleMsgUpdateClient defines the sdk.Handler for MsgUpdateClient
func HandleMsgUpdateClient(ctx sdk.Context, k Keeper, msg exported.MsgUpdateClient) (*sdk.Result, error) {
if err := k.UpdateClient(ctx, msg.GetClientID(), msg.GetHeader()); err != nil {
return nil, err
}
attributes := make([]sdk.Attribute, len(msg.GetSigners())+1)
attributes[0] = sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory)
for i, signer := range msg.GetSigners() {
attributes[i+1] = sdk.NewAttribute(sdk.AttributeKeySender, signer.String())
}
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
EventTypeUpdateClient,
sdk.NewAttribute(AttributeKeyClientID, msg.GetClientID()),
sdk.NewAttribute(AttrbuteKeyClientType, msg.GetHeader().ClientType().String()),
),
sdk.NewEvent(
sdk.EventTypeMessage,
attributes...,
),
})
return &sdk.Result{
Events: ctx.EventManager().Events().ToABCIEvents(),
}, nil
}
// HandlerClientMisbehaviour defines the Evidence module handler for submitting a
// light client misbehaviour.
func HandlerClientMisbehaviour(k Keeper) evidence.Handler {
return func(ctx sdk.Context, evidence evidenceexported.Evidence) error {
misbehaviour, ok := evidence.(exported.Misbehaviour)
if !ok {
return types.ErrInvalidEvidence
}
return k.CheckMisbehaviourAndUpdateState(ctx, misbehaviour)
}
}

View File

@ -0,0 +1,153 @@
package keeper
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
)
// CreateClient creates a new client state and populates it with a given consensus
// state as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create
//
// CONTRACT: ClientState was constructed correctly from given initial consensusState
func (k Keeper) CreateClient(
ctx sdk.Context, clientState exported.ClientState, consensusState exported.ConsensusState,
) (exported.ClientState, error) {
clientID := clientState.GetID()
_, found := k.GetClientState(ctx, clientID)
if found {
return nil, sdkerrors.Wrapf(types.ErrClientExists, "cannot create client with ID %s", clientID)
}
_, found = k.GetClientType(ctx, clientID)
if found {
panic(fmt.Sprintf("client type is already defined for client %s", clientID))
}
height := consensusState.GetHeight()
if consensusState != nil {
k.SetClientConsensusState(ctx, clientID, height, consensusState)
}
k.SetClientState(ctx, clientState)
k.SetClientType(ctx, clientID, clientState.ClientType())
k.Logger(ctx).Info(fmt.Sprintf("client %s created at height %d", clientID, clientState.GetLatestHeight()))
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeCreateClient,
sdk.NewAttribute(types.AttributeKeyClientID, clientID),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
),
})
return clientState, nil
}
// 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 {
clientType, found := k.GetClientType(ctx, clientID)
if !found {
return sdkerrors.Wrapf(types.ErrClientTypeNotFound, "cannot update client with ID %s", clientID)
}
// check that the header consensus matches the client one
if header.ClientType() != clientType {
return sdkerrors.Wrapf(types.ErrInvalidConsensus, "cannot update client with ID %s", clientID)
}
clientState, found := k.GetClientState(ctx, clientID)
if !found {
return sdkerrors.Wrapf(types.ErrClientNotFound, "cannot update client with ID %s", clientID)
}
// addittion to spec: prevent update if the client is frozen
if clientState.IsFrozen() {
return sdkerrors.Wrapf(types.ErrClientFrozen, "cannot update client with ID %s", clientID)
}
var (
consensusState exported.ConsensusState
err error
)
switch clientType {
case exported.Tendermint:
clientState, consensusState, err = tendermint.CheckValidityAndUpdateState(
clientState, header, ctx.BlockTime(),
)
default:
err = types.ErrInvalidClientType
}
if err != nil {
return sdkerrors.Wrapf(err, "cannot update client with ID %s", clientID)
}
k.SetClientState(ctx, clientState)
k.SetClientConsensusState(ctx, clientID, header.GetHeight(), consensusState)
k.Logger(ctx).Info(fmt.Sprintf("client %s updated to height %d", clientID, header.GetHeight()))
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeUpdateClient,
sdk.NewAttribute(types.AttributeKeyClientID, clientID),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
),
})
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.Wrap(types.ErrClientNotFound, misbehaviour.GetClientID())
}
consensusState, found := k.GetClientConsensusStateLTE(ctx, misbehaviour.GetClientID(), uint64(misbehaviour.GetHeight()))
if !found {
return sdkerrors.Wrap(types.ErrConsensusStateNotFound, misbehaviour.GetClientID())
}
var err error
switch e := misbehaviour.(type) {
case ibctmtypes.Evidence:
clientState, err = tendermint.CheckMisbehaviourAndUpdateState(
clientState, consensusState, misbehaviour, consensusState.GetHeight(), ctx.BlockTime(),
)
default:
err = sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized IBC client evidence type: %T", e)
}
if err != nil {
return err
}
k.SetClientState(ctx, clientState)
k.Logger(ctx).Info(fmt.Sprintf("client %s frozen due to misbehaviour", misbehaviour.GetClientID()))
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeSubmitMisbehaviour,
sdk.NewAttribute(types.AttributeKeyClientID, misbehaviour.GetClientID()),
sdk.NewAttribute(types.AttributeKeyClientType, misbehaviour.ClientType().String()),
),
)
return nil
}

View File

@ -0,0 +1,316 @@
package keeper_test
import (
"bytes"
"fmt"
"time"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
)
const (
invalidClientType exported.ClientType = 0
)
func (suite *KeeperTestSuite) TestCreateClient() {
suite.keeper.SetClientType(suite.ctx, testClientID2, exported.Tendermint)
cases := []struct {
msg string
clientID string
expPass bool
expPanic bool
}{
{"success", testClientID, true, false},
{"client ID exists", testClientID, false, false},
{"client type exists", testClientID2, false, true},
}
for i, tc := range cases {
tc := tc
i := i
if tc.expPanic {
suite.Require().Panics(func() {
clientState, err := ibctmtypes.Initialize(tc.clientID, trustingPeriod, ubdPeriod, suite.header)
suite.Require().NoError(err, "err on client state initialization")
suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
}, "Msg %d didn't panic: %s", i, tc.msg)
} else {
clientState, err := ibctmtypes.Initialize(tc.clientID, trustingPeriod, ubdPeriod, suite.header)
if tc.expPass {
suite.Require().NoError(err, "errored on initialization")
suite.Require().NotNil(clientState, "valid test case %d failed: %s", i, tc.msg)
}
// If we were able to initialize clientstate successfully, try persisting it to state
if err == nil {
_, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
}
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg)
}
}
}
}
func (suite *KeeperTestSuite) TestUpdateClient() {
// Must create header creation functions since suite.header gets recreated on each test case
createValidUpdateFn := func(s *KeeperTestSuite) ibctmtypes.Header {
return ibctmtypes.CreateTestHeader(testClientID, suite.header.Height+1, suite.header.Time.Add(time.Minute),
suite.valSet, []tmtypes.PrivValidator{suite.privVal})
}
createInvalidUpdateFn := func(s *KeeperTestSuite) ibctmtypes.Header {
return ibctmtypes.CreateTestHeader(testClientID, suite.header.Height-3, suite.header.Time.Add(time.Minute),
suite.valSet, []tmtypes.PrivValidator{suite.privVal})
}
var updateHeader ibctmtypes.Header
cases := []struct {
name string
malleate func() error
expPass bool
}{
{"valid update", func() error {
clientState, err := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, suite.header)
if err != nil {
return err
}
_, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
updateHeader = createValidUpdateFn(suite)
return err
}, true},
{"client type not found", func() error {
updateHeader = createValidUpdateFn(suite)
return nil
}, false},
{"client type and header type mismatch", func() error {
suite.keeper.SetClientType(suite.ctx, testClientID, invalidClientType)
updateHeader = createValidUpdateFn(suite)
return nil
}, false},
{"client state not found", func() error {
suite.keeper.SetClientType(suite.ctx, testClientID, exported.Tendermint)
updateHeader = createValidUpdateFn(suite)
return nil
}, false},
{"frozen client", func() error {
clientState := ibctmtypes.ClientState{FrozenHeight: 1, ID: testClientID, LastHeader: suite.header}
suite.keeper.SetClientState(suite.ctx, clientState)
suite.keeper.SetClientType(suite.ctx, testClientID, exported.Tendermint)
updateHeader = createValidUpdateFn(suite)
return nil
}, false},
{"invalid header", func() error {
clientState, err := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, suite.header)
if err != nil {
return err
}
_, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
if err != nil {
return err
}
updateHeader = createInvalidUpdateFn(suite)
return nil
}, false},
}
for i, tc := range cases {
tc := tc
i := i
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
suite.SetupTest()
err := tc.malleate()
suite.Require().NoError(err)
suite.ctx = suite.ctx.WithBlockTime(updateHeader.Time.Add(time.Minute))
err = suite.keeper.UpdateClient(suite.ctx, testClientID, updateHeader)
if tc.expPass {
suite.Require().NoError(err, err)
expConsensusState := ibctmtypes.ConsensusState{
Height: updateHeader.GetHeight(),
Timestamp: updateHeader.Time,
Root: commitmenttypes.NewMerkleRoot(updateHeader.AppHash),
ValidatorSet: updateHeader.ValidatorSet,
}
clientState, found := suite.keeper.GetClientState(suite.ctx, testClientID)
suite.Require().True(found, "valid test case %d failed: %s", i, tc.name)
consensusState, found := suite.keeper.GetClientConsensusState(suite.ctx, testClientID, updateHeader.GetHeight())
suite.Require().True(found, "valid test case %d failed: %s", i, tc.name)
tmConsState, ok := consensusState.(ibctmtypes.ConsensusState)
suite.Require().True(ok, "consensus state is not a tendermint consensus state")
// recalculate cached totalVotingPower field for equality check
tmConsState.ValidatorSet.TotalVotingPower()
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
suite.Require().Equal(updateHeader.GetHeight(), clientState.GetLatestHeight(), "client state height not updated correctly on case %s", tc.name)
suite.Require().Equal(expConsensusState, consensusState, "consensus state should have been updated on case %s", tc.name)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
}
})
}
}
func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
altPrivVal := tmtypes.NewMockPV()
altVal := tmtypes.NewValidator(altPrivVal.GetPubKey(), 4)
// Create bothValSet with both suite validator and altVal
bothValSet := tmtypes.NewValidatorSet(append(suite.valSet.Validators, altVal))
// 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
var bothSigners []tmtypes.PrivValidator
if bytes.Compare(altPrivVal.GetPubKey().Address(), suite.privVal.GetPubKey().Address()) == -1 {
bothSigners = []tmtypes.PrivValidator{altPrivVal, suite.privVal}
} else {
bothSigners = []tmtypes.PrivValidator{suite.privVal, altPrivVal}
}
altSigners := []tmtypes.PrivValidator{altPrivVal}
testCases := []struct {
name string
evidence ibctmtypes.Evidence
malleate func() error
expPass bool
}{
{
"trusting period misbehavior should pass",
ibctmtypes.Evidence{
Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners),
ChainID: testClientID,
ClientID: testClientID,
},
func() error {
suite.consensusState.ValidatorSet = bothValSet
clientState, err := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, suite.header)
if err != nil {
return err
}
_, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
return err
},
true,
},
{
"misbehavior at later height should pass",
ibctmtypes.Evidence{
Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight+5, suite.ctx.BlockTime(), bothValSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight+5, suite.ctx.BlockTime(), bothValSet, bothSigners),
ChainID: testClientID,
ClientID: testClientID,
},
func() error {
suite.consensusState.ValidatorSet = bothValSet
clientState, err := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, suite.header)
if err != nil {
return err
}
_, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
return err
},
true,
},
{
"client state not found",
ibctmtypes.Evidence{},
func() error { return nil },
false,
},
{
"consensus state not found",
ibctmtypes.Evidence{
Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners),
ChainID: testClientID,
ClientID: testClientID,
},
func() error {
clientState := ibctmtypes.ClientState{FrozenHeight: 1, ID: testClientID, LastHeader: suite.header}
suite.keeper.SetClientState(suite.ctx, clientState)
return nil
},
false,
},
{
"consensus state not found",
ibctmtypes.Evidence{
Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners),
ChainID: testClientID,
ClientID: testClientID,
},
func() error {
clientState := ibctmtypes.ClientState{FrozenHeight: 1, ID: testClientID, LastHeader: suite.header}
suite.keeper.SetClientState(suite.ctx, clientState)
return nil
},
false,
},
{
"misbehaviour check failed",
ibctmtypes.Evidence{
Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), altValSet, altSigners),
ChainID: testClientID,
ClientID: testClientID,
},
func() error {
clientState, err := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, suite.header)
if err != nil {
return err
}
_, 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
err := tc.malleate()
suite.Require().NoError(err)
err = suite.keeper.CheckMisbehaviourAndUpdateState(suite.ctx, tc.evidence)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
clientState, found := suite.keeper.GetClientState(suite.ctx, testClientID)
suite.Require().True(found, "valid test case %d failed: %s", i, tc.name)
suite.Require().True(clientState.IsFrozen(), "valid test case %d failed: %s", i, tc.name)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
}
})
}
}

View File

@ -0,0 +1,171 @@
package keeper
import (
"fmt"
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
// Keeper represents a type that grants read and write permissions to any client
// state information
type Keeper struct {
storeKey sdk.StoreKey
cdc *codec.Codec
stakingKeeper types.StakingKeeper
}
// NewKeeper creates a new NewKeeper instance
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, sk types.StakingKeeper) Keeper {
return Keeper{
storeKey: key,
cdc: cdc,
stakingKeeper: sk,
}
}
// Logger returns a module-specific logger.
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s/%s", ibctypes.ModuleName, types.SubModuleName))
}
// GetClientState gets a particular client from the store
func (k Keeper) GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(ibctypes.KeyClientState(clientID))
if bz == nil {
return nil, false
}
var clientState exported.ClientState
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &clientState)
return clientState, true
}
// SetClientState sets a particular Client to the store
func (k Keeper) SetClientState(ctx sdk.Context, clientState exported.ClientState) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinaryLengthPrefixed(clientState)
store.Set(ibctypes.KeyClientState(clientState.GetID()), bz)
}
// GetClientType gets the consensus type for a specific client
func (k Keeper) GetClientType(ctx sdk.Context, clientID string) (exported.ClientType, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(ibctypes.KeyClientType(clientID))
if bz == nil {
return 0, false
}
return exported.ClientType(bz[0]), true
}
// SetClientType sets the specific client consensus type to the provable store
func (k Keeper) SetClientType(ctx sdk.Context, clientID string, clientType exported.ClientType) {
store := ctx.KVStore(k.storeKey)
store.Set(ibctypes.KeyClientType(clientID), []byte{byte(clientType)})
}
// GetClientConsensusState gets the stored consensus state from a client at a given height.
func (k Keeper) GetClientConsensusState(ctx sdk.Context, clientID string, height uint64) (exported.ConsensusState, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(ibctypes.KeyConsensusState(clientID, height))
if bz == nil {
return nil, false
}
var consensusState exported.ConsensusState
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &consensusState)
return consensusState, true
}
// SetClientConsensusState sets a ConsensusState to a particular client at the given
// height
func (k Keeper) SetClientConsensusState(ctx sdk.Context, clientID string, height uint64, consensusState exported.ConsensusState) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinaryLengthPrefixed(consensusState)
store.Set(ibctypes.KeyConsensusState(clientID, height), bz)
}
// HasClientConsensusState returns if keeper has a ConsensusState for a particular
// client at the given height
func (k Keeper) HasClientConsensusState(ctx sdk.Context, clientID string, height uint64) bool {
store := ctx.KVStore(k.storeKey)
return store.Has(ibctypes.KeyConsensusState(clientID, height))
}
// GetLatestClientConsensusState gets the latest ConsensusState stored for a given client
func (k Keeper) GetLatestClientConsensusState(ctx sdk.Context, clientID string) (exported.ConsensusState, bool) {
clientState, ok := k.GetClientState(ctx, clientID)
if !ok {
return nil, false
}
return k.GetClientConsensusState(ctx, clientID, clientState.GetLatestHeight())
}
// GetClientConsensusStatelTE will get the latest ConsensusState of a particular client at the latest height
// less than or equal to the given height
func (k Keeper) GetClientConsensusStateLTE(ctx sdk.Context, clientID string, maxHeight uint64) (exported.ConsensusState, bool) {
for i := maxHeight; i > 0; i-- {
found := k.HasClientConsensusState(ctx, clientID, i)
if found {
return k.GetClientConsensusState(ctx, clientID, i)
}
}
return nil, false
}
// GetSelfConsensusState introspects the (self) past historical info at a given height
// and returns the expected consensus state at that height.
func (k Keeper) GetSelfConsensusState(ctx sdk.Context, height uint64) (exported.ConsensusState, bool) {
histInfo, found := k.stakingKeeper.GetHistoricalInfo(ctx, int64(height))
if !found {
return nil, false
}
valSet := stakingtypes.Validators(histInfo.Valset)
consensusState := ibctmtypes.ConsensusState{
Height: height,
Timestamp: histInfo.Header.Time,
Root: commitmenttypes.NewMerkleRoot(histInfo.Header.AppHash),
ValidatorSet: tmtypes.NewValidatorSet(valSet.ToTmValidators()),
}
return consensusState, true
}
// IterateClients provides an iterator over all stored light client State
// objects. For each State object, cb will be called. If the cb returns true,
// the iterator will close and stop.
func (k Keeper) IterateClients(ctx sdk.Context, cb func(exported.ClientState) bool) {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, ibctypes.KeyClientPrefix)
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
var clientState exported.ClientState
k.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &clientState)
if cb(clientState) {
break
}
}
}
// GetAllClients returns all stored light client State objects.
func (k Keeper) GetAllClients(ctx sdk.Context) (states []exported.ClientState) {
k.IterateClients(ctx, func(state exported.ClientState) bool {
states = append(states, state)
return false
})
return states
}

View File

@ -0,0 +1,188 @@
package keeper_test
import (
"math/rand"
"testing"
"time"
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/keeper"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
"github.com/cosmos/cosmos-sdk/x/staking"
)
const (
testClientID = "gaia"
testClientID2 = "ethbridge"
testClientID3 = "ethermint"
testClientHeight = 5
trustingPeriod time.Duration = time.Hour * 24 * 7 * 2
ubdPeriod time.Duration = time.Hour * 24 * 7 * 3
)
type KeeperTestSuite struct {
suite.Suite
cdc *codec.Codec
ctx sdk.Context
keeper *keeper.Keeper
consensusState ibctmtypes.ConsensusState
header ibctmtypes.Header
valSet *tmtypes.ValidatorSet
privVal tmtypes.PrivValidator
now time.Time
}
func (suite *KeeperTestSuite) SetupTest() {
isCheckTx := false
suite.now = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC)
now2 := suite.now.Add(time.Hour)
app := simapp.Setup(isCheckTx)
suite.cdc = app.Codec()
suite.ctx = app.BaseApp.NewContext(isCheckTx, abci.Header{Height: testClientHeight, ChainID: testClientID, Time: now2})
suite.keeper = &app.IBCKeeper.ClientKeeper
suite.privVal = tmtypes.NewMockPV()
validator := tmtypes.NewValidator(suite.privVal.GetPubKey(), 1)
suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
suite.header = ibctmtypes.CreateTestHeader(testClientID, testClientHeight, now2, suite.valSet, []tmtypes.PrivValidator{suite.privVal})
suite.consensusState = ibctmtypes.ConsensusState{
Height: testClientHeight,
Timestamp: suite.now,
Root: commitmenttypes.NewMerkleRoot([]byte("hash")),
ValidatorSet: suite.valSet,
}
var validators staking.Validators
for i := 1; i < 11; i++ {
privVal := tmtypes.NewMockPV()
pk := privVal.GetPubKey()
val := staking.NewValidator(sdk.ValAddress(pk.Address()), pk, staking.Description{})
val.Status = sdk.Bonded
val.Tokens = sdk.NewInt(rand.Int63())
validators = append(validators, val)
app.StakingKeeper.SetHistoricalInfo(suite.ctx, int64(i), staking.NewHistoricalInfo(suite.ctx.BlockHeader(), validators))
}
}
func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}
func (suite *KeeperTestSuite) TestSetClientState() {
clientState := ibctmtypes.NewClientState(testClientID, trustingPeriod, ubdPeriod, ibctmtypes.Header{})
suite.keeper.SetClientState(suite.ctx, clientState)
retrievedState, found := suite.keeper.GetClientState(suite.ctx, testClientID)
suite.Require().True(found, "GetClientState failed")
suite.Require().Equal(clientState, retrievedState, "Client states are not equal")
}
func (suite *KeeperTestSuite) TestSetClientType() {
suite.keeper.SetClientType(suite.ctx, testClientID, exported.Tendermint)
clientType, found := suite.keeper.GetClientType(suite.ctx, testClientID)
suite.Require().True(found, "GetClientType failed")
suite.Require().Equal(exported.Tendermint, clientType, "ClientTypes not stored correctly")
}
func (suite *KeeperTestSuite) TestSetClientConsensusState() {
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight, suite.consensusState)
retrievedConsState, found := suite.keeper.GetClientConsensusState(suite.ctx, testClientID, testClientHeight)
suite.Require().True(found, "GetConsensusState failed")
tmConsState, ok := retrievedConsState.(ibctmtypes.ConsensusState)
// recalculate cached totalVotingPower field for equality check
tmConsState.ValidatorSet.TotalVotingPower()
suite.Require().True(ok)
suite.Require().Equal(suite.consensusState, tmConsState, "ConsensusState not stored correctly")
}
func (suite KeeperTestSuite) TestGetAllClients() {
expClients := []exported.ClientState{
ibctmtypes.NewClientState(testClientID2, trustingPeriod, ubdPeriod, ibctmtypes.Header{}),
ibctmtypes.NewClientState(testClientID3, trustingPeriod, ubdPeriod, ibctmtypes.Header{}),
ibctmtypes.NewClientState(testClientID, trustingPeriod, ubdPeriod, ibctmtypes.Header{}),
}
for i := range expClients {
suite.keeper.SetClientState(suite.ctx, expClients[i])
}
clients := suite.keeper.GetAllClients(suite.ctx)
suite.Require().Len(clients, len(expClients))
suite.Require().Equal(expClients, clients)
}
func (suite KeeperTestSuite) TestGetConsensusState() {
suite.ctx = suite.ctx.WithBlockHeight(10)
cases := []struct {
name string
height uint64
expPass bool
}{
{"zero height", 0, false},
{"height > latest height", uint64(suite.ctx.BlockHeight()) + 1, false},
{"latest height - 1", uint64(suite.ctx.BlockHeight()) - 1, true},
{"latest height", uint64(suite.ctx.BlockHeight()), true},
}
for i, tc := range cases {
tc := tc
cs, found := suite.keeper.GetSelfConsensusState(suite.ctx, tc.height)
if tc.expPass {
suite.Require().True(found, "Case %d should have passed: %s", i, tc.name)
suite.Require().NotNil(cs, "Case %d should have passed: %s", i, tc.name)
} else {
suite.Require().False(found, "Case %d should have failed: %s", i, tc.name)
suite.Require().Nil(cs, "Case %d should have failed: %s", i, tc.name)
}
}
}
func (suite KeeperTestSuite) TestConsensusStateHelpers() {
// initial setup
clientState, _ := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, suite.header)
suite.keeper.SetClientState(suite.ctx, clientState)
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight, suite.consensusState)
nextState := ibctmtypes.ConsensusState{
Height: testClientHeight + 5,
Timestamp: suite.now,
Root: commitmenttypes.NewMerkleRoot([]byte("next")),
ValidatorSet: suite.valSet,
}
header := ibctmtypes.CreateTestHeader(testClientID, testClientHeight+5, suite.header.Time.Add(time.Minute), suite.valSet, []tmtypes.PrivValidator{suite.privVal})
// mock update functionality
clientState.LastHeader = header
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight+5, nextState)
suite.keeper.SetClientState(suite.ctx, clientState)
latest, ok := suite.keeper.GetLatestClientConsensusState(suite.ctx, testClientID)
// recalculate cached totalVotingPower for equality check
latest.(ibctmtypes.ConsensusState).ValidatorSet.TotalVotingPower()
suite.Require().True(ok)
suite.Require().Equal(nextState, latest, "Latest client not returned correctly")
// Should return existing consensusState at latestClientHeight
lte, ok := suite.keeper.GetClientConsensusStateLTE(suite.ctx, testClientID, testClientHeight+3)
// recalculate cached totalVotingPower for equality check
lte.(ibctmtypes.ConsensusState).ValidatorSet.TotalVotingPower()
suite.Require().True(ok)
suite.Require().Equal(suite.consensusState, lte, "LTE helper function did not return latest client state below height: %d", testClientHeight+3)
}

View File

@ -0,0 +1,37 @@
package keeper
import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
)
// QuerierClients defines the sdk.Querier to query all the light client states.
func QuerierClients(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
var params types.QueryAllClientsParams
if err := k.cdc.UnmarshalJSON(req.Data, &params); err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
}
clients := k.GetAllClients(ctx)
start, end := client.Paginate(len(clients), params.Page, params.Limit, 100)
if start < 0 || end < 0 {
clients = []exported.ClientState{}
} else {
clients = clients[start:end]
}
res, err := codec.MarshalJSONIndent(k.cdc, clients)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return res, nil
}

28
x/ibc/02-client/module.go Normal file
View File

@ -0,0 +1,28 @@
package client
import (
"fmt"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/client/cli"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/client/rest"
)
// Name returns the IBC client name
func Name() string {
return SubModuleName
}
// RegisterRESTRoutes registers the REST routes for the IBC client
func RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router, queryRoute string) {
rest.RegisterRoutes(ctx, rtr, fmt.Sprintf("%s/%s", queryRoute, SubModuleName))
}
// GetQueryCmd returns no root query command for the IBC client
func GetQueryCmd(cdc *codec.Codec, queryRoute string) *cobra.Command {
return cli.GetQueryCmd(fmt.Sprintf("%s/%s", queryRoute, SubModuleName), cdc)
}

View File

@ -0,0 +1,25 @@
package types
import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
)
// SubModuleCdc defines the IBC client codec.
var SubModuleCdc *codec.Codec
// RegisterCodec registers the IBC client interfaces and types
func RegisterCodec(cdc *codec.Codec) {
cdc.RegisterInterface((*exported.ClientState)(nil), nil)
cdc.RegisterInterface((*exported.MsgCreateClient)(nil), nil)
cdc.RegisterInterface((*exported.MsgUpdateClient)(nil), nil)
cdc.RegisterInterface((*exported.ConsensusState)(nil), nil)
cdc.RegisterInterface((*exported.Header)(nil), nil)
cdc.RegisterInterface((*exported.Misbehaviour)(nil), nil)
SetSubModuleCodec(cdc)
}
func SetSubModuleCodec(cdc *codec.Codec) {
SubModuleCdc = cdc
}

View File

@ -0,0 +1,27 @@
package types
import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// IBC client sentinel errors
var (
ErrClientExists = sdkerrors.Register(SubModuleName, 1, "light client already exists")
ErrClientNotFound = sdkerrors.Register(SubModuleName, 2, "light client not found")
ErrClientFrozen = sdkerrors.Register(SubModuleName, 3, "light client is frozen due to misbehaviour")
ErrConsensusStateNotFound = sdkerrors.Register(SubModuleName, 4, "consensus state not found")
ErrInvalidConsensus = sdkerrors.Register(SubModuleName, 5, "invalid consensus state")
ErrClientTypeNotFound = sdkerrors.Register(SubModuleName, 6, "client type not found")
ErrInvalidClientType = sdkerrors.Register(SubModuleName, 7, "invalid client type")
ErrRootNotFound = sdkerrors.Register(SubModuleName, 8, "commitment root not found")
ErrInvalidHeader = sdkerrors.Register(SubModuleName, 9, "invalid block header")
ErrInvalidEvidence = sdkerrors.Register(SubModuleName, 10, "invalid light client misbehaviour evidence")
ErrFailedClientConsensusStateVerification = sdkerrors.Register(SubModuleName, 13, "client consensus state verification failed")
ErrFailedConnectionStateVerification = sdkerrors.Register(SubModuleName, 14, "connection state verification failed")
ErrFailedChannelStateVerification = sdkerrors.Register(SubModuleName, 15, "channel state verification failed")
ErrFailedPacketCommitmentVerification = sdkerrors.Register(SubModuleName, 16, "packet commitment verification failed")
ErrFailedPacketAckVerification = sdkerrors.Register(SubModuleName, 17, "packet acknowledgement verification failed")
ErrFailedPacketAckAbsenceVerification = sdkerrors.Register(SubModuleName, 18, "packet acknowledgement absence verification failed")
ErrFailedNextSeqRecvVerification = sdkerrors.Register(SubModuleName, 19, "next sequence receive verification failed")
ErrSelfConsensusStateNotFound = sdkerrors.Register(SubModuleName, 20, "self consensus state not found")
)

View File

@ -0,0 +1,22 @@
package types
import (
"fmt"
ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types"
)
// IBC client events
const (
AttributeKeyClientID = "client_id"
AttributeKeyClientType = "client_type"
)
// IBC client events vars
var (
EventTypeCreateClient = "create_client"
EventTypeUpdateClient = "update_client"
EventTypeSubmitMisbehaviour = "client_misbehaviour"
AttributeValueCategory = fmt.Sprintf("%s_%s", ibctypes.ModuleName, SubModuleName)
)

View File

@ -0,0 +1,14 @@
package types
import (
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
// StakingKeeper expected staking keeper
type StakingKeeper interface {
GetHistoricalInfo(ctx sdk.Context, height int64) (stakingtypes.HistoricalInfo, bool)
UnbondingTime(ctx sdk.Context) time.Duration
}

View File

@ -0,0 +1,12 @@
package types
const (
// SubModuleName defines the IBC client name
SubModuleName string = "client"
// RouterKey is the message route for IBC client
RouterKey string = SubModuleName
// QuerierRoute is the querier route for IBC client
QuerierRoute string = SubModuleName
)

View File

@ -0,0 +1,75 @@
package types
import (
"strings"
"github.com/tendermint/tendermint/crypto/merkle"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types"
)
// query routes supported by the IBC client Querier
const (
QueryAllClients = "client_states"
QueryClientState = "client_state"
QueryConsensusState = "consensus_state"
)
// QueryAllClientsParams defines the parameters necessary for querying for all
// light client states.
type QueryAllClientsParams struct {
Page int `json:"page" yaml:"page"`
Limit int `json:"limit" yaml:"limit"`
}
// NewQueryAllClientsParams creates a new QueryAllClientsParams instance.
func NewQueryAllClientsParams(page, limit int) QueryAllClientsParams {
return QueryAllClientsParams{
Page: page,
Limit: limit,
}
}
// StateResponse defines the client response for a client state query.
// It includes the commitment proof and the height of the proof.
type StateResponse struct {
ClientState exported.ClientState `json:"client_state" yaml:"client_state"`
Proof commitmenttypes.MerkleProof `json:"proof,omitempty" yaml:"proof,omitempty"`
ProofPath commitmenttypes.MerklePath `json:"proof_path,omitempty" yaml:"proof_path,omitempty"`
ProofHeight uint64 `json:"proof_height,omitempty" yaml:"proof_height,omitempty"`
}
// NewClientStateResponse creates a new StateResponse instance.
func NewClientStateResponse(
clientID string, clientState exported.ClientState, proof *merkle.Proof, height int64,
) StateResponse {
return StateResponse{
ClientState: clientState,
Proof: commitmenttypes.MerkleProof{Proof: proof},
ProofPath: commitmenttypes.NewMerklePath(strings.Split(ibctypes.ClientStatePath(clientID), "/")),
ProofHeight: uint64(height),
}
}
// ConsensusStateResponse defines the client response for a Consensus state query.
// It includes the commitment proof and the height of the proof.
type ConsensusStateResponse struct {
ConsensusState exported.ConsensusState `json:"consensus_state" yaml:"consensus_state"`
Proof commitmenttypes.MerkleProof `json:"proof,omitempty" yaml:"proof,omitempty"`
ProofPath commitmenttypes.MerklePath `json:"proof_path,omitempty" yaml:"proof_path,omitempty"`
ProofHeight uint64 `json:"proof_height,omitempty" yaml:"proof_height,omitempty"`
}
// NewConsensusStateResponse creates a new ConsensusStateResponse instance.
func NewConsensusStateResponse(
clientID string, cs exported.ConsensusState, proof *merkle.Proof, height int64,
) ConsensusStateResponse {
return ConsensusStateResponse{
ConsensusState: cs,
Proof: commitmenttypes.MerkleProof{Proof: proof},
ProofPath: commitmenttypes.NewMerklePath(strings.Split(ibctypes.ConsensusStatePath(clientID, uint64(height)), "/")),
ProofHeight: uint64(height),
}
}

View File

@ -0,0 +1,72 @@
package connection
// nolint
// autogenerated code using github.com/rigelrozanski/multitool
// aliases generated for the following subdirectories:
// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/03-connection/keeper
// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types
import (
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/keeper"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
)
const (
AttributeKeyConnectionID = types.AttributeKeyConnectionID
AttributeKeyCounterpartyClientID = types.AttributeKeyCounterpartyClientID
SubModuleName = types.SubModuleName
StoreKey = types.StoreKey
RouterKey = types.RouterKey
QuerierRoute = types.QuerierRoute
QueryAllConnections = types.QueryAllConnections
QueryClientConnections = types.QueryClientConnections
)
var (
// functions aliases
NewKeeper = keeper.NewKeeper
QuerierConnections = keeper.QuerierConnections
QuerierClientConnections = keeper.QuerierClientConnections
RegisterCodec = types.RegisterCodec
NewConnectionEnd = types.NewConnectionEnd
NewCounterparty = types.NewCounterparty
ErrConnectionExists = types.ErrConnectionExists
ErrConnectionNotFound = types.ErrConnectionNotFound
ErrClientConnectionPathsNotFound = types.ErrClientConnectionPathsNotFound
ErrConnectionPath = types.ErrConnectionPath
ErrInvalidConnectionState = types.ErrInvalidConnectionState
ErrInvalidCounterparty = types.ErrInvalidCounterparty
NewMsgConnectionOpenInit = types.NewMsgConnectionOpenInit
NewMsgConnectionOpenTry = types.NewMsgConnectionOpenTry
NewMsgConnectionOpenAck = types.NewMsgConnectionOpenAck
NewMsgConnectionOpenConfirm = types.NewMsgConnectionOpenConfirm
NewConnectionResponse = types.NewConnectionResponse
NewClientConnectionsResponse = types.NewClientConnectionsResponse
NewQueryClientConnectionsParams = types.NewQueryClientConnectionsParams
GetCompatibleVersions = types.GetCompatibleVersions
LatestVersion = types.LatestVersion
PickVersion = types.PickVersion
// variable aliases
SubModuleCdc = types.SubModuleCdc
EventTypeConnectionOpenInit = types.EventTypeConnectionOpenInit
EventTypeConnectionOpenTry = types.EventTypeConnectionOpenTry
EventTypeConnectionOpenAck = types.EventTypeConnectionOpenAck
EventTypeConnectionOpenConfirm = types.EventTypeConnectionOpenConfirm
AttributeValueCategory = types.AttributeValueCategory
)
// nolint: golint
type (
Keeper = keeper.Keeper
ConnectionEnd = types.ConnectionEnd
Counterparty = types.Counterparty
ClientKeeper = types.ClientKeeper
MsgConnectionOpenInit = types.MsgConnectionOpenInit
MsgConnectionOpenTry = types.MsgConnectionOpenTry
MsgConnectionOpenAck = types.MsgConnectionOpenAck
MsgConnectionOpenConfirm = types.MsgConnectionOpenConfirm
ConnectionResponse = types.ConnectionResponse
ClientConnectionsResponse = types.ClientConnectionsResponse
QueryClientConnectionsParams = types.QueryClientConnectionsParams
)

View File

@ -0,0 +1,41 @@
package cli
import (
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
)
// GetQueryCmd returns the query commands for IBC connections
func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
ics03ConnectionQueryCmd := &cobra.Command{
Use: "connection",
Short: "IBC connection query subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
}
ics03ConnectionQueryCmd.AddCommand(flags.GetCommands(
GetCmdQueryConnections(queryRoute, cdc),
GetCmdQueryConnection(queryRoute, cdc),
)...)
return ics03ConnectionQueryCmd
}
// GetTxCmd returns the transaction commands for IBC connections
func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command {
ics03ConnectionTxCmd := &cobra.Command{
Use: "connection",
Short: "IBC connection transaction subcommands",
}
ics03ConnectionTxCmd.AddCommand(flags.PostCommands(
GetCmdConnectionOpenInit(storeKey, cdc),
GetCmdConnectionOpenTry(storeKey, cdc),
GetCmdConnectionOpenAck(storeKey, cdc),
GetCmdConnectionOpenConfirm(storeKey, cdc),
)...)
return ics03ConnectionTxCmd
}

View File

@ -0,0 +1,107 @@
package cli
import (
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/client/utils"
)
// GetCmdQueryConnections defines the command to query all the connection ends
// that this chain mantains.
func GetCmdQueryConnections(queryRoute string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "connections",
Short: "Query all available light clients",
Long: strings.TrimSpace(
fmt.Sprintf(`Query all available connections
Example:
$ %s query ibc connection connections
`, version.ClientName),
),
Example: fmt.Sprintf("%s query ibc connection connections", version.ClientName),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
page := viper.GetInt(flags.FlagPage)
limit := viper.GetInt(flags.FlagLimit)
connections, _, err := utils.QueryAllConnections(cliCtx, page, limit)
if err != nil {
return err
}
return cliCtx.PrintOutput(connections)
},
}
cmd.Flags().Int(flags.FlagPage, 1, "pagination page of light clients to to query for")
cmd.Flags().Int(flags.FlagLimit, 100, "pagination limit of light clients to query for")
return cmd
}
// GetCmdQueryConnection defines the command to query a connection end
func GetCmdQueryConnection(queryRoute string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "end [connection-id]",
Short: "Query stored connection end",
Long: strings.TrimSpace(fmt.Sprintf(`Query stored connection end
Example:
$ %s query ibc connection end [connection-id]
`, version.ClientName),
),
Example: fmt.Sprintf("%s query ibc connection end [connection-id]", version.ClientName),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
connectionID := args[0]
prove := viper.GetBool(flags.FlagProve)
connRes, err := utils.QueryConnection(cliCtx, connectionID, prove)
if err != nil {
return err
}
return cliCtx.PrintOutput(connRes)
},
}
cmd.Flags().Bool(flags.FlagProve, true, "show proofs for the query results")
return cmd
}
// GetCmdQueryClientConnections defines the command to query a client connections
func GetCmdQueryClientConnections(queryRoute string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "client [client-id]",
Short: "Query stored client connection paths",
Long: strings.TrimSpace(fmt.Sprintf(`Query stored client connection paths
Example:
$ %s query ibc connection client [client-id]
`, version.ClientName),
),
Example: fmt.Sprintf("%s query ibc connection client [client-id]", version.ClientName),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
clientID := args[0]
prove := viper.GetBool(flags.FlagProve)
connPathsRes, err := utils.QueryClientConnections(cliCtx, clientID, prove)
if err != nil {
return err
}
return cliCtx.PrintOutput(connPathsRes)
},
}
}

View File

@ -0,0 +1,251 @@
package cli
import (
"bufio"
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/client/utils"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
)
// Connection Handshake flags
const (
FlagNode1 = "node1"
FlagNode2 = "node2"
FlagFrom1 = "from1"
FlagFrom2 = "from2"
FlagChainID2 = "chain-id2"
)
// GetCmdConnectionOpenInit defines the command to initialize a connection on
// chain A with a given counterparty chain B
func GetCmdConnectionOpenInit(storeKey string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: strings.TrimSpace(`open-init [connection-id] [client-id] [counterparty-connection-id] [counterparty-client-id] [path/to/counterparty_prefix.json]`),
Short: "initialize connection on chain A",
Long: strings.TrimSpace(
fmt.Sprintf(`initialize a connection on chain A with a given counterparty chain B:
Example:
$ %s tx ibc connection open-init [connection-id] [client-id] \
[counterparty-connection-id] [counterparty-client-id] \
[path/to/counterparty_prefix.json]
`, version.ClientName),
),
Args: cobra.ExactArgs(5),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
connectionID := args[0]
clientID := args[1]
counterpartyConnectionID := args[2]
counterpartyClientID := args[3]
counterpartyPrefix, err := utils.ParsePrefix(cliCtx.Codec, args[4])
if err != nil {
return err
}
msg := types.NewMsgConnectionOpenInit(
connectionID, clientID, counterpartyConnectionID, counterpartyClientID,
counterpartyPrefix, cliCtx.GetFromAddress(),
)
if err := msg.ValidateBasic(); err != nil {
return err
}
return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
return cmd
}
// GetCmdConnectionOpenTry defines the command to relay a try open a connection on
// chain B
func GetCmdConnectionOpenTry(storeKey string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: strings.TrimSpace(`open-try [connection-id] [client-id]
[counterparty-connection-id] [counterparty-client-id] [path/to/counterparty_prefix.json]
[counterparty-versions] [path/to/proof_init.json]`),
Short: "initiate connection handshake between two chains",
Long: strings.TrimSpace(
fmt.Sprintf(`initialize a connection on chain A with a given counterparty chain B:
Example:
$ %s tx ibc connection open-try connection-id] [client-id] \
[counterparty-connection-id] [counterparty-client-id] [path/to/counterparty_prefix.json] \
[counterparty-versions] [path/to/proof_init.json]
`, version.ClientName),
),
Args: cobra.ExactArgs(7),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).
WithCodec(cdc).
WithHeight(viper.GetInt64(flags.FlagHeight))
connectionID := args[0]
clientID := args[1]
counterpartyConnectionID := args[2]
counterpartyClientID := args[3]
counterpartyPrefix, err := utils.ParsePrefix(cliCtx.Codec, args[4])
if err != nil {
return err
}
// TODO: parse strings?
counterpartyVersions := args[5]
proofInit, err := utils.ParseProof(cliCtx.Codec, args[1])
if err != nil {
return err
}
proofHeight := uint64(cliCtx.Height)
consensusHeight, err := lastHeight(cliCtx)
if err != nil {
return err
}
msg := types.NewMsgConnectionOpenTry(
connectionID, clientID, counterpartyConnectionID, counterpartyClientID,
counterpartyPrefix, []string{counterpartyVersions}, proofInit, proofInit, proofHeight,
consensusHeight, cliCtx.GetFromAddress(),
)
if err := msg.ValidateBasic(); err != nil {
return err
}
return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
return cmd
}
// GetCmdConnectionOpenAck defines the command to relay the acceptance of a
// connection open attempt from chain B to chain A
func GetCmdConnectionOpenAck(storeKey string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "open-ack [connection-id] [path/to/proof_try.json] [version]",
Short: "relay the acceptance of a connection open attempt from chain B to chain A",
Long: strings.TrimSpace(
fmt.Sprintf(`relay the acceptance of a connection open attempt from chain B to chain A:
Example:
$ %s tx ibc connection open-ack [connection-id] [path/to/proof_try.json] [version]
`, version.ClientName),
),
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
connectionID := args[0]
proofTry, err := utils.ParseProof(cliCtx.Codec, args[1])
if err != nil {
return err
}
proofHeight := uint64(cliCtx.Height)
consensusHeight, err := lastHeight(cliCtx)
if err != nil {
return err
}
version := args[4]
msg := types.NewMsgConnectionOpenAck(
connectionID, proofTry, proofTry, proofHeight,
consensusHeight, version, cliCtx.GetFromAddress(),
)
if err := msg.ValidateBasic(); err != nil {
return err
}
return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
return cmd
}
// GetCmdConnectionOpenConfirm defines the command to initialize a connection on
// chain A with a given counterparty chain B
func GetCmdConnectionOpenConfirm(storeKey string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "open-confirm [connection-id] [path/to/proof_ack.json]",
Short: "confirm to chain B that connection is open on chain A",
Long: strings.TrimSpace(
fmt.Sprintf(`confirm to chain B that connection is open on chain A:
Example:
$ %s tx ibc connection open-confirm [connection-id] [path/to/proof_ack.json]
`, version.ClientName),
),
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).
WithCodec(cdc).
WithHeight(viper.GetInt64(flags.FlagHeight))
connectionID := args[0]
proofAck, err := utils.ParseProof(cliCtx.Codec, args[1])
if err != nil {
return err
}
proofHeight := uint64(cliCtx.Height)
if err != nil {
return err
}
msg := types.NewMsgConnectionOpenConfirm(
connectionID, proofAck, proofHeight, cliCtx.GetFromAddress(),
)
if err := msg.ValidateBasic(); err != nil {
return err
}
return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
return cmd
}
// lastHeight util function to get the consensus height from the node
func lastHeight(cliCtx context.CLIContext) (uint64, error) {
node, err := cliCtx.GetNode()
if err != nil {
return 0, err
}
info, err := node.ABCIInfo()
if err != nil {
return 0, err
}
return uint64(info.Response.LastBlockHeight), nil
}

View File

@ -0,0 +1,84 @@
package rest
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/types/rest"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/client/utils"
)
func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) {
r.HandleFunc(fmt.Sprintf("/ibc/connections/{%s}", RestConnectionID), queryConnectionHandlerFn(cliCtx, queryRoute)).Methods("GET")
r.HandleFunc(fmt.Sprintf("/ibc/clients/{%s}/connections", RestClientID), queryClientConnectionsHandlerFn(cliCtx, queryRoute)).Methods("GET")
}
// queryConnectionHandlerFn implements a connection querying route
//
// @Summary Query connection
// @Tags IBC
// @Produce json
// @Param connection-id path string true "Client ID"
// @Param prove query boolean false "Proof of result"
// @Success 200 {object} QueryConnection "OK"
// @Failure 400 {object} rest.ErrorResponse "Invalid connection id"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/connections/{connection-id} [get]
func queryConnectionHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
connectionID := vars[RestConnectionID]
prove := rest.ParseQueryParamBool(r, flags.FlagProve)
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
connRes, err := utils.QueryConnection(cliCtx, connectionID, prove)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
cliCtx = cliCtx.WithHeight(int64(connRes.ProofHeight))
rest.PostProcessResponse(w, cliCtx, connRes)
}
}
// queryClientConnectionsHandlerFn implements a client connections querying route
//
// @Summary Query connections of a client
// @Tags IBC
// @Produce json
// @Param client-id path string true "Client ID"
// @Param prove query boolean false "Proof of result"
// @Success 200 {object} QueryClientConnections "OK"
// @Failure 400 {object} rest.ErrorResponse "Invalid client id"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/clients/{client-id}/connections [get]
func queryClientConnectionsHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
clientID := vars[RestClientID]
prove := rest.ParseQueryParamBool(r, flags.FlagProve)
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
connPathsRes, err := utils.QueryClientConnections(cliCtx, clientID, prove)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
cliCtx = cliCtx.WithHeight(int64(connPathsRes.ProofHeight))
rest.PostProcessResponse(w, cliCtx, connPathsRes)
}
}

View File

@ -0,0 +1,62 @@
package rest
import (
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/types/rest"
commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported"
)
const (
RestConnectionID = "connection-id"
RestClientID = "client-id"
)
// RegisterRoutes - Central function to define routes that get registered by the main application
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) {
registerQueryRoutes(cliCtx, r, queryRoute)
registerTxRoutes(cliCtx, r)
}
// ConnectionOpenInitReq defines the properties of a connection open init request's body.
type ConnectionOpenInitReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
ConnectionID string `json:"connection_id" yaml:"connection_id"`
ClientID string `json:"client_id" yaml:"client_id"`
CounterpartyClientID string `json:"counterparty_client_id" yaml:"counterparty_client_id"`
CounterpartyConnectionID string `json:"counterparty_connection_id" yaml:"counterparty_connection_id"`
CounterpartyPrefix commitmentexported.Prefix `json:"counterparty_prefix" yaml:"counterparty_prefix"`
}
// ConnectionOpenTryReq defines the properties of a connection open try request's body.
type ConnectionOpenTryReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
ConnectionID string `json:"connection_id" yaml:"connection_id"`
ClientID string `json:"client_id" yaml:"client_id"`
CounterpartyClientID string `json:"counterparty_client_id" yaml:"counterparty_client_id"`
CounterpartyConnectionID string `json:"counterparty_connection_id" yaml:"counterparty_connection_id"`
CounterpartyPrefix commitmentexported.Prefix `json:"counterparty_prefix" yaml:"counterparty_prefix"`
CounterpartyVersions []string `json:"counterparty_versions" yaml:"counterparty_versions"`
ProofInit commitmentexported.Proof `json:"proof_init" yaml:"proof_init"`
ProofConsensus commitmentexported.Proof `json:"proof_consensus" yaml:"proof_consensus"`
ProofHeight uint64 `json:"proof_height" yaml:"proof_height"`
ConsensusHeight uint64 `json:"consensus_height" yaml:"consensus_height"`
}
// ConnectionOpenAckReq defines the properties of a connection open ack request's body.
type ConnectionOpenAckReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
ProofTry commitmentexported.Proof `json:"proof_try" yaml:"proof_try"`
ProofConsensus commitmentexported.Proof `json:"proof_consensus" yaml:"proof_consensus"`
ProofHeight uint64 `json:"proof_height" yaml:"proof_height"`
ConsensusHeight uint64 `json:"consensus_height" yaml:"consensus_height"`
Version string `json:"version" yaml:"version"`
}
// ConnectionOpenConfirmReq defines the properties of a connection open confirm request's body.
type ConnectionOpenConfirmReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
ProofAck commitmentexported.Proof `json:"proof_ack" yaml:"proof_ack"`
ProofHeight uint64 `json:"proof_height" yaml:"proof_height"`
}

View File

@ -0,0 +1,204 @@
package rest
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/rest"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
)
func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) {
r.HandleFunc("/ibc/connections/open-init", connectionOpenInitHandlerFn(cliCtx)).Methods("POST")
r.HandleFunc("/ibc/connections/open-try", connectionOpenTryHandlerFn(cliCtx)).Methods("POST")
r.HandleFunc(fmt.Sprintf("/ibc/connections/{%s}/open-ack", RestConnectionID), connectionOpenAckHandlerFn(cliCtx)).Methods("POST")
r.HandleFunc(fmt.Sprintf("/ibc/connections/{%s}/open-confirm", RestConnectionID), connectionOpenConfirmHandlerFn(cliCtx)).Methods("POST")
}
// connectionOpenInitHandlerFn implements a connection open init handler
//
// @Summary Connection open-init
// @Tags IBC
// @Accept json
// @Produce json
// @Param body body rest.ConnectionOpenInitReq true "Connection open-init request body"
// @Success 200 {object} PostConnectionOpenInit "OK"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/connections/open-init [post]
func connectionOpenInitHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req ConnectionOpenInitReq
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
return
}
req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
return
}
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
// create the message
msg := types.NewMsgConnectionOpenInit(
req.ConnectionID, req.ClientID, req.CounterpartyConnectionID,
req.CounterpartyClientID, req.CounterpartyPrefix, fromAddr,
)
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg})
}
}
// connectionOpenTryHandlerFn implements a connection open try handler
//
// @Summary Connection open-try
// @Tags IBC
// @Accept json
// @Produce json
// @Param body body rest.ConnectionOpenTryReq true "Connection open-try request body"
// @Success 200 {object} PostConnectionOpenTry "OK"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/connections/open-try [post]
func connectionOpenTryHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req ConnectionOpenTryReq
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
return
}
req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
return
}
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
// create the message
msg := types.NewMsgConnectionOpenTry(
req.ConnectionID, req.ClientID, req.CounterpartyConnectionID,
req.CounterpartyClientID, req.CounterpartyPrefix, req.CounterpartyVersions,
req.ProofInit, req.ProofConsensus, req.ProofHeight,
req.ConsensusHeight, fromAddr,
)
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg})
}
}
// connectionOpenAckHandlerFn implements a connection open ack handler
//
// @Summary Connection open-ack
// @Tags IBC
// @Accept json
// @Produce json
// @Param connection-id path string true "Connection ID"
// @Param body body rest.ConnectionOpenAckReq true "Connection open-ack request body"
// @Success 200 {object} PostConnectionOpenAck "OK"
// @Failure 400 {object} rest.ErrorResponse "Invalid connection id"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/connections/{connection-id}/open-ack [post]
func connectionOpenAckHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
connectionID := vars[RestConnectionID]
var req ConnectionOpenAckReq
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
return
}
req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
return
}
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
// create the message
msg := types.NewMsgConnectionOpenAck(
connectionID, req.ProofTry, req.ProofConsensus, req.ProofHeight,
req.ConsensusHeight, req.Version, fromAddr,
)
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg})
}
}
// connectionOpenConfirmHandlerFn implements a connection open confirm handler
//
// @Summary Connection open-confirm
// @Tags IBC
// @Accept json
// @Produce json
// @Param connection-id path string true "Connection ID"
// @Param body body rest.ConnectionOpenConfirmReq true "Connection open-confirm request body"
// @Success 200 {object} PostConnectionOpenConfirm "OK"
// @Failure 400 {object} rest.ErrorResponse "Invalid connection id"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/connections/{connection-id}/open-confirm [post]
func connectionOpenConfirmHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
connectionID := vars[RestConnectionID]
var req ConnectionOpenConfirmReq
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
return
}
req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
return
}
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
// create the message
msg := types.NewMsgConnectionOpenConfirm(
connectionID, req.ProofAck, req.ProofHeight, fromAddr,
)
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg})
}
}

View File

@ -0,0 +1,124 @@
package utils
import (
"fmt"
"io/ioutil"
"github.com/pkg/errors"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types"
)
// QueryAllConnections returns all the connections. It _does not_ return
// any merkle proof.
func QueryAllConnections(cliCtx context.CLIContext, page, limit int) ([]types.IdentifiedConnectionEnd, int64, error) {
params := types.NewQueryAllConnectionsParams(page, limit)
bz, err := cliCtx.Codec.MarshalJSON(params)
if err != nil {
return nil, 0, fmt.Errorf("failed to marshal query params: %w", err)
}
route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryAllConnections)
res, height, err := cliCtx.QueryWithData(route, bz)
if err != nil {
return nil, 0, err
}
var connections []types.IdentifiedConnectionEnd
err = cliCtx.Codec.UnmarshalJSON(res, &connections)
if err != nil {
return nil, 0, fmt.Errorf("failed to unmarshal connections: %w", err)
}
return connections, height, nil
}
// QueryConnection queries the store to get a connection end and a merkle
// proof.
func QueryConnection(
cliCtx context.CLIContext, connectionID string, prove bool,
) (types.ConnectionResponse, error) {
req := abci.RequestQuery{
Path: "store/ibc/key",
Data: ibctypes.KeyConnection(connectionID),
Prove: prove,
}
res, err := cliCtx.QueryABCI(req)
if err != nil {
return types.ConnectionResponse{}, err
}
var connection types.ConnectionEnd
if err := cliCtx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &connection); err != nil {
return types.ConnectionResponse{}, err
}
connRes := types.NewConnectionResponse(connectionID, connection, res.Proof, res.Height)
return connRes, nil
}
// QueryClientConnections queries the store to get the registered connection paths
// registered for a particular client and a merkle proof.
func QueryClientConnections(
cliCtx context.CLIContext, clientID string, prove bool,
) (types.ClientConnectionsResponse, error) {
req := abci.RequestQuery{
Path: "store/ibc/key",
Data: ibctypes.KeyClientConnections(clientID),
Prove: prove,
}
res, err := cliCtx.QueryABCI(req)
if err != nil {
return types.ClientConnectionsResponse{}, err
}
var paths []string
if err := cliCtx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &paths); err != nil {
return types.ClientConnectionsResponse{}, err
}
connPathsRes := types.NewClientConnectionsResponse(clientID, paths, res.Proof, res.Height)
return connPathsRes, nil
}
// ParsePrefix unmarshals an cmd input argument from a JSON string to a commitment
// Prefix. If the input is not a JSON, it looks for a path to the JSON file.
func ParsePrefix(cdc *codec.Codec, arg string) (commitmenttypes.MerklePrefix, error) {
var prefix commitmenttypes.MerklePrefix
if err := cdc.UnmarshalJSON([]byte(arg), &prefix); err != nil {
// check for file path if JSON input is not provided
contents, err := ioutil.ReadFile(arg)
if err != nil {
return commitmenttypes.MerklePrefix{}, errors.New("neither JSON input nor path to .json file were provided")
}
if err := cdc.UnmarshalJSON(contents, &prefix); err != nil {
return commitmenttypes.MerklePrefix{}, errors.Wrap(err, "error unmarshalling commitment prefix")
}
}
return prefix, nil
}
// ParseProof unmarshals an cmd input argument from a JSON string to a commitment
// Proof. If the input is not a JSON, it looks for a path to the JSON file.
func ParseProof(cdc *codec.Codec, arg string) (commitmenttypes.MerkleProof, error) {
var proof commitmenttypes.MerkleProof
if err := cdc.UnmarshalJSON([]byte(arg), &proof); err != nil {
// check for file path if JSON input is not provided
contents, err := ioutil.ReadFile(arg)
if err != nil {
return commitmenttypes.MerkleProof{}, errors.New("neither JSON input nor path to .json file were provided")
}
if err := cdc.UnmarshalJSON(contents, &proof); err != nil {
return commitmenttypes.MerkleProof{}, errors.Wrap(err, "error unmarshalling commitment proof")
}
}
return proof, nil
}

View File

@ -0,0 +1,89 @@
package exported
import (
"encoding/json"
commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported"
)
// ConnectionI describes the required methods for a connection.
type ConnectionI interface {
GetState() State
GetClientID() string
GetCounterparty() CounterpartyI
GetVersions() []string
ValidateBasic() error
}
// CounterpartyI describes the required methods for a counterparty connection.
type CounterpartyI interface {
GetClientID() string
GetConnectionID() string
GetPrefix() commitmentexported.Prefix
ValidateBasic() error
}
// State defines the state of a connection between two disctinct
// chains
type State byte
// available connection states
const (
UNINITIALIZED State = iota // default State
INIT
TRYOPEN
OPEN
)
// string representation of the connection states
const (
StateUninitialized string = "UNINITIALIZED"
StateInit string = "INIT"
StateTryOpen string = "TRYOPEN"
StateOpen string = "OPEN"
)
// String implements the Stringer interface
func (s State) String() string {
switch s {
case INIT:
return StateInit
case TRYOPEN:
return StateTryOpen
case OPEN:
return StateOpen
default:
return StateUninitialized
}
}
// StateFromString parses a string into a connection state
func StateFromString(state string) State {
switch state {
case StateInit:
return INIT
case StateTryOpen:
return TRYOPEN
case StateOpen:
return OPEN
default:
return UNINITIALIZED
}
}
// MarshalJSON marshal to JSON using string.
func (s State) MarshalJSON() ([]byte, error) {
return json.Marshal(s.String())
}
// UnmarshalJSON decodes from JSON assuming Bech32 encoding.
func (s *State) UnmarshalJSON(data []byte) error {
var str string
err := json.Unmarshal(data, &str)
if err != nil {
return err
}
*s = StateFromString(str)
return nil
}

View File

@ -0,0 +1,46 @@
package exported
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestConnectionStateString(t *testing.T) {
cases := []struct {
name string
state State
}{
{StateUninitialized, UNINITIALIZED},
{StateInit, INIT},
{StateTryOpen, TRYOPEN},
{StateOpen, OPEN},
}
for _, tt := range cases {
tt := tt
require.Equal(t, tt.state, StateFromString(tt.name))
require.Equal(t, tt.name, tt.state.String())
}
}
func TestConnectionlStateMarshalJSON(t *testing.T) {
cases := []struct {
name string
state State
}{
{StateUninitialized, UNINITIALIZED},
{StateInit, INIT},
{StateTryOpen, TRYOPEN},
{StateOpen, OPEN},
}
for _, tt := range cases {
tt := tt
bz, err := tt.state.MarshalJSON()
require.NoError(t, err)
var state State
require.NoError(t, state.UnmarshalJSON(bz))
require.Equal(t, tt.name, state.String())
}
}

View File

@ -0,0 +1,113 @@
package connection
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
)
// HandleMsgConnectionOpenInit defines the sdk.Handler for MsgConnectionOpenInit
func HandleMsgConnectionOpenInit(ctx sdk.Context, k Keeper, msg MsgConnectionOpenInit) (*sdk.Result, error) {
if err := k.ConnOpenInit(
ctx, msg.ConnectionID, msg.ClientID, msg.Counterparty,
); err != nil {
return nil, err
}
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeConnectionOpenInit,
sdk.NewAttribute(types.AttributeKeyConnectionID, msg.ConnectionID),
sdk.NewAttribute(types.AttributeKeyClientID, msg.ClientID),
sdk.NewAttribute(types.AttributeKeyCounterpartyClientID, msg.Counterparty.ClientID),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()),
),
})
return &sdk.Result{
Events: ctx.EventManager().Events().ToABCIEvents(),
}, nil
}
// HandleMsgConnectionOpenTry defines the sdk.Handler for MsgConnectionOpenTry
func HandleMsgConnectionOpenTry(ctx sdk.Context, k Keeper, msg MsgConnectionOpenTry) (*sdk.Result, error) {
if err := k.ConnOpenTry(
ctx, msg.ConnectionID, msg.Counterparty, msg.ClientID,
msg.CounterpartyVersions, msg.ProofInit, msg.ProofConsensus,
msg.ProofHeight, msg.ConsensusHeight,
); err != nil {
return nil, err
}
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeConnectionOpenTry,
sdk.NewAttribute(types.AttributeKeyConnectionID, msg.ConnectionID),
sdk.NewAttribute(types.AttributeKeyClientID, msg.ClientID),
sdk.NewAttribute(types.AttributeKeyCounterpartyClientID, msg.Counterparty.ClientID),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()),
),
})
return &sdk.Result{
Events: ctx.EventManager().Events().ToABCIEvents(),
}, nil
}
// HandleMsgConnectionOpenAck defines the sdk.Handler for MsgConnectionOpenAck
func HandleMsgConnectionOpenAck(ctx sdk.Context, k Keeper, msg MsgConnectionOpenAck) (*sdk.Result, error) {
if err := k.ConnOpenAck(
ctx, msg.ConnectionID, msg.Version, msg.ProofTry, msg.ProofConsensus,
msg.ProofHeight, msg.ConsensusHeight,
); err != nil {
return nil, err
}
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
EventTypeConnectionOpenAck,
sdk.NewAttribute(AttributeKeyConnectionID, msg.ConnectionID),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()),
),
})
return &sdk.Result{
Events: ctx.EventManager().Events().ToABCIEvents(),
}, nil
}
// HandleMsgConnectionOpenConfirm defines the sdk.Handler for MsgConnectionOpenConfirm
func HandleMsgConnectionOpenConfirm(ctx sdk.Context, k Keeper, msg MsgConnectionOpenConfirm) (*sdk.Result, error) {
if err := k.ConnOpenConfirm(
ctx, msg.ConnectionID, msg.ProofAck, msg.ProofHeight,
); err != nil {
return nil, err
}
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
EventTypeConnectionOpenConfirm,
sdk.NewAttribute(AttributeKeyConnectionID, msg.ConnectionID),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()),
),
})
return &sdk.Result{
Events: ctx.EventManager().Events().ToABCIEvents(),
}, nil
}

View File

@ -0,0 +1,234 @@
package keeper
import (
"bytes"
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported"
ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types"
)
// ConnOpenInit initialises a connection attempt on chain A.
//
// NOTE: Identifiers are checked on msg validation.
func (k Keeper) ConnOpenInit(
ctx sdk.Context,
connectionID, // identifier
clientID string,
counterparty types.Counterparty, // desiredCounterpartyConnectionIdentifier, counterpartyPrefix, counterpartyClientIdentifier
) error {
_, found := k.GetConnection(ctx, connectionID)
if found {
return sdkerrors.Wrap(types.ErrConnectionExists, "cannot initialize connection")
}
// connection defines chain A's ConnectionEnd
connection := types.NewConnectionEnd(exported.INIT, clientID, counterparty, types.GetCompatibleVersions())
k.SetConnection(ctx, connectionID, connection)
if err := k.addConnectionToClient(ctx, clientID, connectionID); err != nil {
return sdkerrors.Wrap(err, "cannot initialize connection")
}
k.Logger(ctx).Info(fmt.Sprintf("connection %s state updated: NONE -> INIT", connectionID))
return nil
}
// ConnOpenTry relays notice of a connection attempt on chain A to chain B (this
// code is executed on chain B).
//
// NOTE:
// - Here chain A acts as the counterparty
// - Identifiers are checked on msg validation
func (k Keeper) ConnOpenTry(
ctx sdk.Context,
connectionID string, // desiredIdentifier
counterparty types.Counterparty, // counterpartyConnectionIdentifier, counterpartyPrefix and counterpartyClientIdentifier
clientID string, // clientID of chainA
counterpartyVersions []string, // supported versions of chain A
proofInit commitmentexported.Proof, // proof that chainA stored connectionEnd in state (on ConnOpenInit)
proofConsensus commitmentexported.Proof, // proof that chainA stored chainB's consensus state at consensus height
proofHeight uint64, // height at which relayer constructs proof of A storing connectionEnd in state
consensusHeight uint64, // latest height of chain B which chain A has stored in its chain B client
) error {
if consensusHeight > uint64(ctx.BlockHeight()) {
return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "invalid consensus height")
}
expectedConsensusState, found := k.clientKeeper.GetSelfConsensusState(ctx, consensusHeight)
if !found {
return clienttypes.ErrSelfConsensusStateNotFound
}
// expectedConnection defines Chain A's ConnectionEnd
// NOTE: chain A's counterparty is chain B (i.e where this code is executed)
prefix := k.GetCommitmentPrefix()
expectedCounterparty := types.NewCounterparty(clientID, connectionID, prefix)
expectedConnection := types.NewConnectionEnd(exported.INIT, counterparty.ClientID, expectedCounterparty, counterpartyVersions)
// chain B picks a version from Chain A's available versions that is compatible
// with the supported IBC versions
version := types.PickVersion(counterpartyVersions, types.GetCompatibleVersions())
// connection defines chain B's ConnectionEnd
connection := types.NewConnectionEnd(exported.UNINITIALIZED, clientID, counterparty, []string{version})
// Check that ChainA committed expectedConnectionEnd to its state
if err := k.VerifyConnectionState(
ctx, connection, proofHeight, proofInit, counterparty.ConnectionID,
expectedConnection,
); err != nil {
return err
}
// Check that ChainA stored the correct ConsensusState of chainB at the given consensusHeight
if err := k.VerifyClientConsensusState(
ctx, connection, proofHeight, consensusHeight, proofConsensus, expectedConsensusState,
); err != nil {
return err
}
// If connection already exists for connectionID, ensure that the existing connection's counterparty
// is chainA and connection is on INIT stage
// Check that existing connection version is on desired version of current handshake
previousConnection, found := k.GetConnection(ctx, connectionID)
if found && !(previousConnection.State == exported.INIT &&
previousConnection.Counterparty.ConnectionID == counterparty.ConnectionID &&
bytes.Equal(previousConnection.Counterparty.Prefix.Bytes(), counterparty.Prefix.Bytes()) &&
previousConnection.ClientID == clientID &&
previousConnection.Counterparty.ClientID == counterparty.ClientID &&
previousConnection.Versions[0] == version) {
return sdkerrors.Wrap(types.ErrInvalidConnection, "cannot relay connection attempt")
}
// Set connection state to TRYOPEN and store in chainB state
connection.State = exported.TRYOPEN
if err := k.addConnectionToClient(ctx, clientID, connectionID); err != nil {
return sdkerrors.Wrap(err, "cannot relay connection attempt")
}
k.SetConnection(ctx, connectionID, connection)
k.Logger(ctx).Info(fmt.Sprintf("connection %s state updated: NONE -> TRYOPEN ", connectionID))
return nil
}
// ConnOpenAck relays acceptance of a connection open attempt from chain B back
// to chain A (this code is executed on chain A).
//
// NOTE: Identifiers are checked on msg validation.
func (k Keeper) ConnOpenAck(
ctx sdk.Context,
connectionID string,
version string, // version that ChainB chose in ConnOpenTry
proofTry commitmentexported.Proof, // proof that connectionEnd was added to ChainB state in ConnOpenTry
proofConsensus commitmentexported.Proof, // proof that chainB has stored ConsensusState of chainA on its client
proofHeight uint64, // height that relayer constructed proofTry
consensusHeight uint64, // latest height of chainA that chainB has stored on its chainA client
) error {
// Check that chainB client hasn't stored invalid height
if consensusHeight > uint64(ctx.BlockHeight()) {
return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "invalid consensus height")
}
// Retrieve connection
connection, found := k.GetConnection(ctx, connectionID)
if !found {
return sdkerrors.Wrap(types.ErrConnectionNotFound, "cannot relay ACK of open attempt")
}
// Check connection on ChainA is on correct state: INIT
if connection.State != exported.INIT {
return sdkerrors.Wrapf(
types.ErrInvalidConnectionState,
"connection state is not INIT (got %s)", connection.State.String(),
)
}
// Check that ChainB's proposed version is one of chainA's accepted versions
if types.LatestVersion(connection.Versions) != version {
return sdkerrors.Wrapf(
ibctypes.ErrInvalidVersion,
"connection version does't match provided one (%s ≠ %s)", types.LatestVersion(connection.Versions), version,
)
}
// Retrieve chainA's consensus state at consensusheight
expectedConsensusState, found := k.clientKeeper.GetSelfConsensusState(ctx, consensusHeight)
if !found {
return clienttypes.ErrSelfConsensusStateNotFound
}
prefix := k.GetCommitmentPrefix()
expectedCounterparty := types.NewCounterparty(connection.ClientID, connectionID, prefix)
expectedConnection := types.NewConnectionEnd(exported.TRYOPEN, connection.Counterparty.ClientID, expectedCounterparty, []string{version})
// Ensure that ChainB stored expected connectionEnd in its state during ConnOpenTry
if err := k.VerifyConnectionState(
ctx, connection, proofHeight, proofTry, connection.Counterparty.ConnectionID,
expectedConnection,
); err != nil {
return err
}
// Ensure that ChainB has stored the correct ConsensusState for chainA at the consensusHeight
if err := k.VerifyClientConsensusState(
ctx, connection, proofHeight, consensusHeight, proofConsensus, expectedConsensusState,
); err != nil {
return err
}
// Update connection state to Open
connection.State = exported.OPEN
connection.Versions = []string{version}
k.SetConnection(ctx, connectionID, connection)
k.Logger(ctx).Info(fmt.Sprintf("connection %s state updated: INIT -> OPEN ", connectionID))
return nil
}
// ConnOpenConfirm confirms opening of a connection on chain A to chain B, after
// which the connection is open on both chains (this code is executed on chain B).
//
// NOTE: Identifiers are checked on msg validation.
func (k Keeper) ConnOpenConfirm(
ctx sdk.Context,
connectionID string,
proofAck commitmentexported.Proof, // proof that connection opened on ChainA during ConnOpenAck
proofHeight uint64, // height that relayer constructed proofAck
) error {
// Retrieve connection
connection, found := k.GetConnection(ctx, connectionID)
if !found {
return sdkerrors.Wrap(types.ErrConnectionNotFound, "cannot relay ACK of open attempt")
}
// Check that connection state on ChainB is on state: TRYOPEN
if connection.State != exported.TRYOPEN {
return sdkerrors.Wrapf(
types.ErrInvalidConnectionState,
"connection state is not TRYOPEN (got %s)", connection.State.String(),
)
}
prefix := k.GetCommitmentPrefix()
expectedCounterparty := types.NewCounterparty(connection.ClientID, connectionID, prefix)
expectedConnection := types.NewConnectionEnd(exported.OPEN, connection.Counterparty.ClientID, expectedCounterparty, connection.Versions)
// Check that connection on ChainA is open
if err := k.VerifyConnectionState(
ctx, connection, proofHeight, proofAck, connection.Counterparty.ConnectionID,
expectedConnection,
); err != nil {
return err
}
// Update ChainB's connection to Open
connection.State = exported.OPEN
k.SetConnection(ctx, connectionID, connection)
k.Logger(ctx).Info(fmt.Sprintf("connection %s state updated: TRYOPEN -> OPEN ", connectionID))
return nil
}

View File

@ -0,0 +1,286 @@
package keeper_test
import (
"fmt"
connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported"
ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types"
)
// TestConnOpenInit - Chain A (ID #1) initializes (INIT state) a connection with
// Chain B (ID #2) which is yet UNINITIALIZED
func (suite *KeeperTestSuite) TestConnOpenInit() {
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{"success", func() {
suite.chainA.CreateClient(suite.chainB)
}, true},
{"connection already exists", func() {
suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.INIT)
}, false},
{"couldn't add connection to client", func() {}, false},
}
counterparty := connection.NewCounterparty(testClientIDA, testConnectionIDB, suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix())
for i, tc := range testCases {
tc := tc
i := i
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
err := suite.chainA.App.IBCKeeper.ConnectionKeeper.ConnOpenInit(suite.chainA.GetContext(), testConnectionIDA, testClientIDB, counterparty)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg)
}
})
}
}
// TestConnOpenTry - Chain B (ID #2) calls ConnOpenTry to verify the state of
// connection on Chain A (ID #1) is INIT
func (suite *KeeperTestSuite) TestConnOpenTry() {
// counterparty for A on B
counterparty := connection.NewCounterparty(
testClientIDB, testConnectionIDA, suite.chainB.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix(),
)
testCases := []struct {
msg string
malleate func() uint64
expPass bool
}{
{"success", func() uint64 {
suite.chainB.CreateClient(suite.chainA)
suite.chainA.CreateClient(suite.chainB)
suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT)
suite.chainB.updateClient(suite.chainA)
suite.chainA.updateClient(suite.chainB)
suite.chainB.updateClient(suite.chainA)
suite.chainA.updateClient(suite.chainB)
return uint64(suite.chainB.Header.Height - 1)
}, true},
{"consensus height > latest height", func() uint64 {
return 0
}, false},
{"self consensus state not found", func() uint64 {
//suite.ctx = suite.ctx.WithBlockHeight(100)
return 100
}, false},
{"connection state verification invalid", func() uint64 {
suite.chainB.CreateClient(suite.chainA)
suite.chainA.CreateClient(suite.chainB)
suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.UNINITIALIZED)
suite.chainB.updateClient(suite.chainA)
return 0
}, false},
{"consensus state verification invalid", func() uint64 {
suite.chainB.CreateClient(suite.chainA)
suite.chainA.CreateClient(suite.chainB)
suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT)
suite.chainB.updateClient(suite.chainA)
suite.chainA.updateClient(suite.chainB)
return uint64(suite.chainB.Header.Height)
}, false},
{"invalid previous connection", func() uint64 {
suite.chainB.CreateClient(suite.chainA)
suite.chainA.CreateClient(suite.chainB)
suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.UNINITIALIZED)
suite.chainB.updateClient(suite.chainA)
suite.chainA.updateClient(suite.chainB)
return 0
}, false},
{"couldn't add connection to client", func() uint64 {
suite.chainB.CreateClient(suite.chainA)
suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, exported.UNINITIALIZED)
suite.chainB.updateClient(suite.chainA)
suite.chainA.updateClient(suite.chainB)
return 0
}, false},
}
for i, tc := range testCases {
tc := tc
i := i
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
consensusHeight := tc.malleate()
connectionKey := ibctypes.KeyConnection(testConnectionIDA)
proofInit, proofHeight := queryProof(suite.chainA, connectionKey)
consensusKey := ibctypes.KeyConsensusState(testClientIDB, consensusHeight)
proofConsensus, _ := queryProof(suite.chainA, consensusKey)
err := suite.chainB.App.IBCKeeper.ConnectionKeeper.ConnOpenTry(
suite.chainB.GetContext(), testConnectionIDB, counterparty, testClientIDA,
connection.GetCompatibleVersions(), proofInit, proofConsensus,
proofHeight+1, consensusHeight,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed with consensus height %d and proof height %d: %s", i, consensusHeight, proofHeight, tc.msg)
} else {
suite.Require().Error(err, "invalid test case %d passed with consensus height %d and proof height %d: %s", i, consensusHeight, proofHeight, tc.msg)
}
})
}
}
// TestConnOpenAck - Chain A (ID #1) calls TestConnOpenAck to acknowledge (ACK state)
// the initialization (TRYINIT) of the connection on Chain B (ID #2).
func (suite *KeeperTestSuite) TestConnOpenAck() {
version := connection.GetCompatibleVersions()[0]
testCases := []struct {
msg string
version string
malleate func() uint64
expPass bool
}{
{"success", version, func() uint64 {
suite.chainA.CreateClient(suite.chainB)
suite.chainB.CreateClient(suite.chainA)
suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.TRYOPEN)
suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT)
suite.chainB.updateClient(suite.chainA)
suite.chainA.updateClient(suite.chainB)
return uint64(suite.chainB.Header.Height)
}, true},
{"consensus height > latest height", version, func() uint64 {
return 10
}, false},
{"connection not found", version, func() uint64 {
return 2
}, false},
{"connection state is not INIT", version, func() uint64 {
suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.UNINITIALIZED)
suite.chainB.updateClient(suite.chainA)
return uint64(suite.chainB.Header.Height)
}, false},
{"incompatible IBC versions", "2.0", func() uint64 {
suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.INIT)
suite.chainB.updateClient(suite.chainA)
return uint64(suite.chainB.Header.Height)
}, false},
{"self consensus state not found", version, func() uint64 {
suite.chainB.CreateClient(suite.chainA)
suite.chainA.CreateClient(suite.chainB)
suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT)
suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.TRYOPEN)
suite.chainB.updateClient(suite.chainA)
return uint64(suite.chainB.Header.Height)
}, false},
{"connection state verification failed", version, func() uint64 {
suite.chainB.CreateClient(suite.chainA)
suite.chainA.CreateClient(suite.chainB)
suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT)
suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.UNINITIALIZED)
suite.chainB.updateClient(suite.chainA)
return uint64(suite.chainB.Header.Height)
}, false},
{"consensus state verification failed", version, func() uint64 {
suite.chainB.CreateClient(suite.chainA)
suite.chainA.CreateClient(suite.chainB)
suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT)
suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.UNINITIALIZED)
suite.chainB.updateClient(suite.chainA)
return uint64(suite.chainB.Header.Height)
}, false},
}
for i, tc := range testCases {
tc := tc
i := i
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
consensusHeight := tc.malleate()
connectionKey := ibctypes.KeyConnection(testConnectionIDB)
proofTry, proofHeight := queryProof(suite.chainB, connectionKey)
consensusKey := ibctypes.KeyConsensusState(testClientIDA, consensusHeight)
proofConsensus, _ := queryProof(suite.chainB, consensusKey)
err := suite.chainA.App.IBCKeeper.ConnectionKeeper.ConnOpenAck(
suite.chainA.GetContext(), testConnectionIDA, tc.version, proofTry, proofConsensus,
proofHeight+1, consensusHeight,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed with consensus height %d: %s", i, consensusHeight, tc.msg)
} else {
suite.Require().Error(err, "invalid test case %d passed with consensus height %d: %s", i, consensusHeight, tc.msg)
}
})
}
}
// TestConnOpenConfirm - Chain B (ID #2) calls ConnOpenConfirm to confirm that
// Chain A (ID #1) state is now OPEN.
func (suite *KeeperTestSuite) TestConnOpenConfirm() {
testCases := []testCase{
{"success", func() {
suite.chainB.CreateClient(suite.chainA)
suite.chainA.CreateClient(suite.chainB)
suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.OPEN)
suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.TRYOPEN)
suite.chainB.updateClient(suite.chainA)
}, true},
{"connection not found", func() {}, false},
{"chain B's connection state is not TRYOPEN", func() {
suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.UNINITIALIZED)
suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, exported.OPEN)
suite.chainA.updateClient(suite.chainB)
}, false},
{"connection state verification failed", func() {
suite.chainB.CreateClient(suite.chainA)
suite.chainA.CreateClient(suite.chainB)
suite.chainB.updateClient(suite.chainA)
suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.INIT)
suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, exported.TRYOPEN)
suite.chainA.updateClient(suite.chainA)
}, false},
}
for i, tc := range testCases {
tc := tc
i := i
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
connectionKey := ibctypes.KeyConnection(testConnectionIDA)
proofAck, proofHeight := queryProof(suite.chainA, connectionKey)
if tc.expPass {
err := suite.chainB.App.IBCKeeper.ConnectionKeeper.ConnOpenConfirm(
suite.chainB.GetContext(), testConnectionIDB, proofAck, proofHeight+1,
)
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg)
} else {
err := suite.chainB.App.IBCKeeper.ConnectionKeeper.ConnOpenConfirm(
suite.chainB.GetContext(), testConnectionIDB, proofAck, proofHeight+1,
)
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg)
}
})
}
}
type testCase = struct {
msg string
malleate func()
expPass bool
}

View File

@ -0,0 +1,156 @@
package keeper
import (
"fmt"
"github.com/tendermint/tendermint/libs/log"
"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/cosmos-sdk/x/ibc/02-client/types"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types"
)
// Keeper defines the IBC connection keeper
type Keeper struct {
storeKey sdk.StoreKey
cdc *codec.Codec
clientKeeper types.ClientKeeper
}
// NewKeeper creates a new IBC connection Keeper instance
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, ck types.ClientKeeper) Keeper {
return Keeper{
storeKey: key,
cdc: cdc,
clientKeeper: ck,
}
}
// Logger returns a module-specific logger.
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s/%s", ibctypes.ModuleName, types.SubModuleName))
}
// GetCommitmentPrefix returns the IBC connection store prefix as a commitment
// Prefix
func (k Keeper) GetCommitmentPrefix() commitmentexported.Prefix {
return commitmenttypes.NewMerklePrefix([]byte(k.storeKey.Name()))
}
// GetConnection returns a connection with a particular identifier
func (k Keeper) GetConnection(ctx sdk.Context, connectionID string) (types.ConnectionEnd, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(ibctypes.KeyConnection(connectionID))
if bz == nil {
return types.ConnectionEnd{}, false
}
var connection types.ConnectionEnd
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &connection)
return connection, true
}
// SetConnection sets a connection to the store
func (k Keeper) SetConnection(ctx sdk.Context, connectionID string, connection types.ConnectionEnd) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinaryLengthPrefixed(connection)
store.Set(ibctypes.KeyConnection(connectionID), bz)
}
// GetClientConnectionPaths returns all the connection paths stored under a
// particular client
func (k Keeper) GetClientConnectionPaths(ctx sdk.Context, clientID string) ([]string, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(ibctypes.KeyClientConnections(clientID))
if bz == nil {
return nil, false
}
var paths []string
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &paths)
return paths, true
}
// SetClientConnectionPaths sets the connections paths for client
func (k Keeper) SetClientConnectionPaths(ctx sdk.Context, clientID string, paths []string) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinaryLengthPrefixed(paths)
store.Set(ibctypes.KeyClientConnections(clientID), bz)
}
// IterateConnections provides an iterator over all ConnectionEnd objects.
// For each ConnectionEnd, cb will be called. If the cb returns true, the
// iterator will close and stop.
func (k Keeper) IterateConnections(ctx sdk.Context, cb func(types.IdentifiedConnectionEnd) bool) {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, ibctypes.KeyConnectionPrefix)
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
var connection types.ConnectionEnd
k.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &connection)
identifier := string(iterator.Key()[len(ibctypes.KeyConnectionPrefix)+1:])
conn := types.IdentifiedConnectionEnd{
Connection: connection,
Identifier: identifier,
}
if cb(conn) {
break
}
}
}
// GetAllConnections returns all stored ConnectionEnd objects.
func (k Keeper) GetAllConnections(ctx sdk.Context) (connections []types.IdentifiedConnectionEnd) {
k.IterateConnections(ctx, func(connection types.IdentifiedConnectionEnd) bool {
connections = append(connections, connection)
return false
})
return connections
}
// addConnectionToClient is used to add a connection identifier to the set of
// connections associated with a client.
func (k Keeper) addConnectionToClient(ctx sdk.Context, clientID, connectionID string) error {
_, found := k.clientKeeper.GetClientState(ctx, clientID)
if !found {
return clienttypes.ErrClientNotFound
}
conns, found := k.GetClientConnectionPaths(ctx, clientID)
if !found {
conns = []string{}
}
conns = append(conns, connectionID)
k.SetClientConnectionPaths(ctx, clientID, conns)
return nil
}
// removeConnectionFromClient is used to remove a connection identifier from the
// set of connections associated with a client.
//
// CONTRACT: client must already exist
// nolint: unused
func (k Keeper) removeConnectionFromClient(ctx sdk.Context, clientID, connectionID string) error {
conns, found := k.GetClientConnectionPaths(ctx, clientID)
if !found {
return sdkerrors.Wrap(types.ErrClientConnectionPathsNotFound, clientID)
}
conns, ok := host.RemovePath(conns, connectionID)
if !ok {
return sdkerrors.Wrap(types.ErrConnectionPath, clientID)
}
k.SetClientConnectionPaths(ctx, clientID, conns)
return nil
}

View File

@ -0,0 +1,318 @@
package keeper_test
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported"
channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types"
"github.com/cosmos/cosmos-sdk/x/staking"
)
const (
storeKey = ibctypes.StoreKey
testClientIDA = "testclientida" // chainid for chainA also chainB's clientID for A's liteclient
testConnectionIDA = "connectionidatob"
testClientIDB = "testclientidb" // chainid for chainB also chainA's clientID for B's liteclient
testConnectionIDB = "connectionidbtoa"
testClientID3 = "testclientidthree"
testConnectionID3 = "connectionidthree"
trustingPeriod time.Duration = time.Hour * 24 * 7 * 2
ubdPeriod time.Duration = time.Hour * 24 * 7 * 3
)
type KeeperTestSuite struct {
suite.Suite
cdc *codec.Codec
// ChainA testing fields
chainA *TestChain
// ChainB testing fields
chainB *TestChain
}
func (suite *KeeperTestSuite) SetupTest() {
suite.chainA = NewTestChain(testClientIDA)
suite.chainB = NewTestChain(testClientIDB)
suite.cdc = suite.chainA.App.Codec()
}
// nolint: unused
func queryProof(chain *TestChain, key []byte) (commitmenttypes.MerkleProof, uint64) {
res := chain.App.Query(abci.RequestQuery{
Path: fmt.Sprintf("store/%s/key", storeKey),
Height: chain.App.LastBlockHeight(),
Data: key,
Prove: true,
})
proof := commitmenttypes.MerkleProof{
Proof: res.Proof,
}
return proof, uint64(res.Height)
}
func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}
func (suite *KeeperTestSuite) TestSetAndGetConnection() {
_, existed := suite.chainA.App.IBCKeeper.ConnectionKeeper.GetConnection(suite.chainA.GetContext(), testConnectionIDA)
suite.Require().False(existed)
counterparty := types.NewCounterparty(testClientIDA, testConnectionIDA, suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix())
expConn := types.NewConnectionEnd(exported.INIT, testClientIDB, counterparty, types.GetCompatibleVersions())
suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(suite.chainA.GetContext(), testConnectionIDA, expConn)
conn, existed := suite.chainA.App.IBCKeeper.ConnectionKeeper.GetConnection(suite.chainA.GetContext(), testConnectionIDA)
suite.Require().True(existed)
suite.Require().EqualValues(expConn, conn)
}
func (suite *KeeperTestSuite) TestSetAndGetClientConnectionPaths() {
_, existed := suite.chainA.App.IBCKeeper.ConnectionKeeper.GetClientConnectionPaths(suite.chainA.GetContext(), testClientIDA)
suite.False(existed)
suite.chainA.App.IBCKeeper.ConnectionKeeper.SetClientConnectionPaths(suite.chainA.GetContext(), testClientIDB, types.GetCompatibleVersions())
paths, existed := suite.chainA.App.IBCKeeper.ConnectionKeeper.GetClientConnectionPaths(suite.chainA.GetContext(), testClientIDB)
suite.True(existed)
suite.EqualValues(types.GetCompatibleVersions(), paths)
}
func (suite KeeperTestSuite) TestGetAllConnections() {
// Connection (Counterparty): A(C) -> C(B) -> B(A)
counterparty1 := types.NewCounterparty(testClientIDA, testConnectionIDA, suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix())
counterparty2 := types.NewCounterparty(testClientIDB, testConnectionIDB, suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix())
counterparty3 := types.NewCounterparty(testClientID3, testConnectionID3, suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix())
conn1 := types.NewConnectionEnd(exported.INIT, testClientIDA, counterparty3, types.GetCompatibleVersions())
conn2 := types.NewConnectionEnd(exported.INIT, testClientIDB, counterparty1, types.GetCompatibleVersions())
conn3 := types.NewConnectionEnd(exported.UNINITIALIZED, testClientID3, counterparty2, types.GetCompatibleVersions())
expConnections := []types.IdentifiedConnectionEnd{
{Connection: conn1, Identifier: testConnectionIDA},
{Connection: conn2, Identifier: testConnectionIDB},
{Connection: conn3, Identifier: testConnectionID3},
}
suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(suite.chainA.GetContext(), testConnectionIDA, conn1)
suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(suite.chainA.GetContext(), testConnectionIDB, conn2)
suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(suite.chainA.GetContext(), testConnectionID3, conn3)
connections := suite.chainA.App.IBCKeeper.ConnectionKeeper.GetAllConnections(suite.chainA.GetContext())
suite.Require().Len(connections, len(expConnections))
suite.Require().ElementsMatch(expConnections, connections)
}
// TestChain is a testing struct that wraps a simapp with the latest Header, Vals and Signers
// It also contains a field called ClientID. This is the clientID that *other* chains use
// to refer to this TestChain. For simplicity's sake it is also the chainID on the TestChain Header
type TestChain struct {
ClientID string
App *simapp.SimApp
Header ibctmtypes.Header
Vals *tmtypes.ValidatorSet
Signers []tmtypes.PrivValidator
}
func NewTestChain(clientID string) *TestChain {
privVal := tmtypes.NewMockPV()
validator := tmtypes.NewValidator(privVal.GetPubKey(), 1)
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
signers := []tmtypes.PrivValidator{privVal}
now := time.Now()
header := ibctmtypes.CreateTestHeader(clientID, 1, now, valSet, signers)
return &TestChain{
ClientID: clientID,
App: simapp.Setup(false),
Header: header,
Vals: valSet,
Signers: signers,
}
}
// Creates simple context for testing purposes
func (chain *TestChain) GetContext() sdk.Context {
return chain.App.BaseApp.NewContext(false, abci.Header{ChainID: chain.Header.ChainID, Height: chain.Header.Height})
}
// createClient will create a client for clientChain on targetChain
func (chain *TestChain) CreateClient(client *TestChain) error {
client.Header = nextHeader(client)
// Commit and create a new block on appTarget to get a fresh CommitID
client.App.Commit()
commitID := client.App.LastCommitID()
client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}})
// Set HistoricalInfo on client chain after Commit
ctxClient := client.GetContext()
validator := staking.NewValidator(
sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{},
)
validator.Status = sdk.Bonded
validator.Tokens = sdk.NewInt(1000000) // get one voting power
validators := []staking.Validator{validator}
histInfo := staking.HistoricalInfo{
Header: abci.Header{
Time: client.Header.Time,
AppHash: commitID.Hash,
},
Valset: validators,
}
client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo)
// also set staking params
stakingParams := staking.DefaultParams()
stakingParams.HistoricalEntries = 10
client.App.StakingKeeper.SetParams(ctxClient, stakingParams)
// Create target ctx
ctxTarget := chain.GetContext()
// create client
clientState, err := ibctmtypes.Initialize(client.ClientID, trustingPeriod, ubdPeriod, client.Header)
if err != nil {
return err
}
_, err = chain.App.IBCKeeper.ClientKeeper.CreateClient(ctxTarget, clientState, client.Header.ConsensusState())
if err != nil {
return err
}
return nil
// _, _, err := simapp.SignCheckDeliver(
// suite.T(),
// suite.cdc,
// suite.app.BaseApp,
// suite.ctx.BlockHeader(),
// []sdk.Msg{clienttypes.NewMsgCreateClient(clientID, clientexported.ClientTypeTendermint, consState, accountAddress)},
// []uint64{baseAccount.GetAccountNumber()},
// []uint64{baseAccount.GetSequence()},
// true, true, accountPrivKey,
// )
}
func (chain *TestChain) updateClient(client *TestChain) {
// Create chain ctx
ctxTarget := chain.GetContext()
// if clientState does not already exist, return without updating
_, found := chain.App.IBCKeeper.ClientKeeper.GetClientState(
ctxTarget, client.ClientID,
)
if !found {
return
}
// always commit when updateClient and begin a new block
client.App.Commit()
commitID := client.App.LastCommitID()
client.Header = nextHeader(client)
/*
err := chain.App.IBCKeeper.ClientKeeper.UpdateClient(ctxTarget, client.ClientID, client.Header)
if err != nil {
panic(err)
}
*/
client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}})
// Set HistoricalInfo on client chain after Commit
ctxClient := client.GetContext()
validator := staking.NewValidator(
sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{},
)
validator.Status = sdk.Bonded
validator.Tokens = sdk.NewInt(1000000)
validators := []staking.Validator{validator}
histInfo := staking.HistoricalInfo{
Header: abci.Header{
Time: client.Header.Time,
AppHash: commitID.Hash,
},
Valset: validators,
}
client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo)
consensusState := ibctmtypes.ConsensusState{
Height: uint64(client.Header.Height),
Timestamp: client.Header.Time,
Root: commitmenttypes.NewMerkleRoot(commitID.Hash),
ValidatorSet: client.Vals,
}
chain.App.IBCKeeper.ClientKeeper.SetClientConsensusState(
ctxTarget, client.ClientID, uint64(client.Header.Height), consensusState,
)
chain.App.IBCKeeper.ClientKeeper.SetClientState(
ctxTarget, ibctmtypes.NewClientState(client.ClientID, trustingPeriod, ubdPeriod, client.Header),
)
// _, _, err := simapp.SignCheckDeliver(
// suite.T(),
// suite.cdc,
// suite.app.BaseApp,
// suite.ctx.BlockHeader(),
// []sdk.Msg{clienttypes.NewMsgUpdateClient(clientID, suite.header, accountAddress)},
// []uint64{baseAccount.GetAccountNumber()},
// []uint64{baseAccount.GetSequence()},
// true, true, accountPrivKey,
// )
// suite.Require().NoError(err)
}
func (chain *TestChain) createConnection(
connID, counterpartyConnID, clientID, counterpartyClientID string,
state exported.State,
) types.ConnectionEnd {
counterparty := types.NewCounterparty(counterpartyClientID, counterpartyConnID, chain.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix())
connection := types.ConnectionEnd{
State: state,
ClientID: clientID,
Counterparty: counterparty,
Versions: types.GetCompatibleVersions(),
}
ctx := chain.GetContext()
chain.App.IBCKeeper.ConnectionKeeper.SetConnection(ctx, connID, connection)
return connection
}
func (chain *TestChain) createChannel(
portID, channelID, counterpartyPortID, counterpartyChannelID string,
state channelexported.State, order channelexported.Order, connectionID string,
) channeltypes.Channel {
counterparty := channeltypes.NewCounterparty(counterpartyPortID, counterpartyChannelID)
channel := channeltypes.NewChannel(state, order, counterparty,
[]string{connectionID}, "1.0",
)
ctx := chain.GetContext()
chain.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, portID, channelID, channel)
return channel
}
func nextHeader(chain *TestChain) ibctmtypes.Header {
return ibctmtypes.CreateTestHeader(chain.Header.ChainID, chain.Header.Height+1,
time.Now(), chain.Vals, chain.Signers)
}

View File

@ -0,0 +1,57 @@
package keeper
import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
)
// QuerierConnections defines the sdk.Querier to query all the connections.
func QuerierConnections(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
var params types.QueryAllConnectionsParams
if err := k.cdc.UnmarshalJSON(req.Data, &params); err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
}
connections := k.GetAllConnections(ctx)
start, end := client.Paginate(len(connections), params.Page, params.Limit, 100)
if start < 0 || end < 0 {
connections = []types.IdentifiedConnectionEnd{}
} else {
connections = connections[start:end]
}
res, err := codec.MarshalJSONIndent(k.cdc, connections)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return res, nil
}
// QuerierClientConnections defines the sdk.Querier to query the client connections
func QuerierClientConnections(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
var params types.QueryClientConnectionsParams
if err := k.cdc.UnmarshalJSON(req.Data, &params); err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
}
clientConnectionPaths, found := k.GetClientConnectionPaths(ctx, params.ClientID)
if !found {
return nil, sdkerrors.Wrap(types.ErrClientConnectionPathsNotFound, params.ClientID)
}
bz, err := types.SubModuleCdc.MarshalJSON(clientConnectionPaths)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}

View File

@ -0,0 +1,236 @@
package keeper
import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported"
channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported"
commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported"
)
// VerifyClientConsensusState verifies a proof of the consensus state of the
// specified client stored on the target machine.
func (k Keeper) VerifyClientConsensusState(
ctx sdk.Context,
connection exported.ConnectionI,
height uint64,
consensusHeight uint64,
proof commitmentexported.Proof,
consensusState clientexported.ConsensusState,
) error {
clientID := connection.GetClientID()
clientState, found := k.clientKeeper.GetClientState(ctx, clientID)
if !found {
return sdkerrors.Wrap(clienttypes.ErrClientNotFound, clientID)
}
targetConsState, found := k.clientKeeper.GetClientConsensusState(ctx, clientID, height)
if !found {
return sdkerrors.Wrapf(clienttypes.ErrConsensusStateNotFound, "clientID: %s with height: %d", clientID, height)
}
return clientState.VerifyClientConsensusState(
k.cdc, targetConsState.GetRoot(), height, connection.GetCounterparty().GetClientID(), consensusHeight, connection.GetCounterparty().GetPrefix(), proof, consensusState,
)
}
// VerifyConnectionState verifies a proof of the connection state of the
// specified connection end stored on the target machine.
func (k Keeper) VerifyConnectionState(
ctx sdk.Context,
connection exported.ConnectionI,
height uint64,
proof commitmentexported.Proof,
connectionID string,
connectionEnd exported.ConnectionI, // opposite connection
) error {
clientState, found := k.clientKeeper.GetClientState(ctx, connection.GetClientID())
if !found {
return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID())
}
// TODO: move to specific clients; blocked by #5502
consensusState, found := k.clientKeeper.GetClientConsensusState(
ctx, connection.GetClientID(), height,
)
if !found {
return sdkerrors.Wrapf(
clienttypes.ErrConsensusStateNotFound,
"clientID (%s), height (%d)", connection.GetClientID(), height,
)
}
return clientState.VerifyConnectionState(
k.cdc, height, connection.GetCounterparty().GetPrefix(), proof, connectionID, connectionEnd, consensusState,
)
}
// VerifyChannelState verifies a proof of the channel state of the specified
// channel end, under the specified port, stored on the target machine.
func (k Keeper) VerifyChannelState(
ctx sdk.Context,
connection exported.ConnectionI,
height uint64,
proof commitmentexported.Proof,
portID,
channelID string,
channel channelexported.ChannelI,
) error {
clientState, found := k.clientKeeper.GetClientState(ctx, connection.GetClientID())
if !found {
return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID())
}
// TODO: move to specific clients; blocked by #5502
consensusState, found := k.clientKeeper.GetClientConsensusState(
ctx, connection.GetClientID(), height,
)
if !found {
return sdkerrors.Wrapf(
clienttypes.ErrConsensusStateNotFound,
"clientID (%s), height (%d)", connection.GetClientID(), height,
)
}
return clientState.VerifyChannelState(
k.cdc, height, connection.GetCounterparty().GetPrefix(), proof,
portID, channelID, channel, consensusState,
)
}
// VerifyPacketCommitment verifies a proof of an outgoing packet commitment at
// the specified port, specified channel, and specified sequence.
func (k Keeper) VerifyPacketCommitment(
ctx sdk.Context,
connection exported.ConnectionI,
height uint64,
proof commitmentexported.Proof,
portID,
channelID string,
sequence uint64,
commitmentBytes []byte,
) error {
clientState, found := k.clientKeeper.GetClientState(ctx, connection.GetClientID())
if !found {
return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID())
}
// TODO: move to specific clients; blocked by #5502
consensusState, found := k.clientKeeper.GetClientConsensusState(
ctx, connection.GetClientID(), height,
)
if !found {
return sdkerrors.Wrapf(
clienttypes.ErrConsensusStateNotFound,
"clientID (%s), height (%d)", connection.GetClientID(), height,
)
}
return clientState.VerifyPacketCommitment(
height, connection.GetCounterparty().GetPrefix(), proof, portID, channelID,
sequence, commitmentBytes, consensusState,
)
}
// VerifyPacketAcknowledgement verifies a proof of an incoming packet
// acknowledgement at the specified port, specified channel, and specified sequence.
func (k Keeper) VerifyPacketAcknowledgement(
ctx sdk.Context,
connection exported.ConnectionI,
height uint64,
proof commitmentexported.Proof,
portID,
channelID string,
sequence uint64,
acknowledgement []byte,
) error {
clientState, found := k.clientKeeper.GetClientState(ctx, connection.GetClientID())
if !found {
return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID())
}
// TODO: move to specific clients; blocked by #5502
consensusState, found := k.clientKeeper.GetClientConsensusState(
ctx, connection.GetClientID(), height,
)
if !found {
return sdkerrors.Wrapf(
clienttypes.ErrConsensusStateNotFound,
"clientID (%s), height (%d)", connection.GetClientID(), height,
)
}
return clientState.VerifyPacketAcknowledgement(
height, connection.GetCounterparty().GetPrefix(), proof, portID, channelID,
sequence, acknowledgement, consensusState,
)
}
// VerifyPacketAcknowledgementAbsence verifies a proof of the absence of an
// incoming packet acknowledgement at the specified port, specified channel, and
// specified sequence.
func (k Keeper) VerifyPacketAcknowledgementAbsence(
ctx sdk.Context,
connection exported.ConnectionI,
height uint64,
proof commitmentexported.Proof,
portID,
channelID string,
sequence uint64,
) error {
clientState, found := k.clientKeeper.GetClientState(ctx, connection.GetClientID())
if !found {
return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID())
}
// TODO: move to specific clients; blocked by #5502
consensusState, found := k.clientKeeper.GetClientConsensusState(
ctx, connection.GetClientID(), height,
)
if !found {
return sdkerrors.Wrapf(
clienttypes.ErrConsensusStateNotFound,
"clientID (%s), height (%d)", connection.GetClientID(), height,
)
}
return clientState.VerifyPacketAcknowledgementAbsence(
height, connection.GetCounterparty().GetPrefix(), proof, portID, channelID,
sequence, consensusState,
)
}
// VerifyNextSequenceRecv verifies a proof of the next sequence number to be
// received of the specified channel at the specified port.
func (k Keeper) VerifyNextSequenceRecv(
ctx sdk.Context,
connection exported.ConnectionI,
height uint64,
proof commitmentexported.Proof,
portID,
channelID string,
nextSequenceRecv uint64,
) error {
clientState, found := k.clientKeeper.GetClientState(ctx, connection.GetClientID())
if !found {
return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID())
}
// TODO: move to specific clients; blocked by #5502
consensusState, found := k.clientKeeper.GetClientConsensusState(
ctx, connection.GetClientID(), height,
)
if !found {
return sdkerrors.Wrapf(
clienttypes.ErrConsensusStateNotFound,
"clientID (%s), height (%d)", connection.GetClientID(), height,
)
}
return clientState.VerifyNextSequenceRecv(
height, connection.GetCounterparty().GetPrefix(), proof, portID, channelID,
nextSequenceRecv, consensusState,
)
}

View File

@ -0,0 +1,427 @@
package keeper_test
import (
"fmt"
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types"
)
const (
testPort1 = "firstport"
testPort2 = "secondport"
testChannel1 = "firstchannel"
testChannel2 = "secondchannel"
)
func (suite *KeeperTestSuite) TestVerifyClientConsensusState() {
// create connection on chainA to chainB
counterparty := types.NewCounterparty(
testClientIDA, testConnectionIDA,
suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix(),
)
connection1 := types.NewConnectionEnd(
exported.UNINITIALIZED, testClientIDB, counterparty,
types.GetCompatibleVersions(),
)
cases := []struct {
msg string
connection types.ConnectionEnd
malleate func() clientexported.ConsensusState
expPass bool
}{
{"verification success", connection1, func() clientexported.ConsensusState {
suite.chainA.CreateClient(suite.chainB)
suite.chainB.CreateClient(suite.chainA)
consState := suite.chainA.Header.ConsensusState()
return consState
}, true},
{"client state not found", connection1, func() clientexported.ConsensusState {
return suite.chainB.Header.ConsensusState()
}, false},
{"verification failed", connection1, func() clientexported.ConsensusState {
suite.chainA.CreateClient(suite.chainA)
return suite.chainA.Header.ConsensusState()
}, false},
}
// Create Client of chain B on Chain App
// Check that we can verify B's consensus state on chain A
for i, tc := range cases {
tc := tc
i := i
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
consState := tc.malleate()
// perform a couple updates of chain B on chain A
suite.chainA.updateClient(suite.chainB)
suite.chainA.updateClient(suite.chainB)
// TODO: is this the right consensus height
consensusHeight := uint64(suite.chainA.Header.Height)
consensusKey := ibctypes.KeyConsensusState(testClientIDA, consensusHeight)
// get proof that chainB stored chainA' consensus state
proof, proofHeight := queryProof(suite.chainB, consensusKey)
err := suite.chainA.App.IBCKeeper.ConnectionKeeper.VerifyClientConsensusState(
suite.chainA.GetContext(), tc.connection, proofHeight+1, consensusHeight, proof, consState,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg)
}
})
}
}
func (suite *KeeperTestSuite) TestVerifyConnectionState() {
connectionKey := ibctypes.KeyConnection(testConnectionIDA)
var invalidProofHeight uint64
cases := []struct {
msg string
malleate func()
expPass bool
}{
{"verification success", func() {
suite.chainA.CreateClient(suite.chainB)
suite.chainB.CreateClient(suite.chainA)
invalidProofHeight = 0 // don't use this
}, true},
{"client state not found", func() {}, false},
{"verification failed", func() {
suite.chainA.CreateClient(suite.chainB)
suite.chainB.CreateClient(suite.chainA)
invalidProofHeight = 10 // make proofHeight incorrect
}, false},
}
// Chains A and B create clients for each other
// A creates connectionEnd for chain B and stores it in state
// Check that B can verify connection is stored after some updates
for i, tc := range cases {
tc := tc
i := i
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
// create and store connection on chain A
expectedConnection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.OPEN)
// // create expected connection
// TODO: why is this commented
// expectedConnection := types.NewConnectionEnd(exported.INIT, testClientIDB, counterparty, []string{"1.0.0"})
// perform a couple updates of chain A on chain B
suite.chainB.updateClient(suite.chainA)
suite.chainB.updateClient(suite.chainA)
proof, proofHeight := queryProof(suite.chainA, connectionKey)
// if invalidProofHeight has been set, use that value instead
if invalidProofHeight != 0 {
proofHeight = invalidProofHeight
}
// Create B's connection to A
counterparty := types.NewCounterparty(testClientIDB, testConnectionIDA, commitmenttypes.NewMerklePrefix([]byte("ibc")))
connection := types.NewConnectionEnd(exported.UNINITIALIZED, testClientIDA, counterparty, []string{"1.0.0"})
// Ensure chain B can verify connection exists in chain A
err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyConnectionState(
suite.chainB.GetContext(), connection, proofHeight+1, proof, testConnectionIDA, expectedConnection,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg)
}
})
}
}
func (suite *KeeperTestSuite) TestVerifyChannelState() {
channelKey := ibctypes.KeyChannel(testPort1, testChannel1)
// create connection of chainB to pass into verify function
counterparty := types.NewCounterparty(
testClientIDB, testConnectionIDB,
suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix(),
)
connection := types.NewConnectionEnd(
exported.UNINITIALIZED, testClientIDA, counterparty,
types.GetCompatibleVersions(),
)
cases := []struct {
msg string
proofHeight uint64
malleate func()
expPass bool
}{
{"verification success", 0, func() {
suite.chainB.CreateClient(suite.chainA)
}, true},
{"client state not found", 0, func() {}, false},
{"consensus state not found", 100, func() {
suite.chainB.CreateClient(suite.chainA)
}, false},
{"verification failed", 7, func() {
suite.chainB.CreateClient(suite.chainB)
}, false},
}
// Chain A creates channel for chain B and stores in its state
// Check that chainB can verify channel is stored in chain A
for i, tc := range cases {
tc := tc
i := i
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
// Create and store channel on chain A
channel := suite.chainA.createChannel(
testPort1, testChannel1, testPort2, testChannel2,
channelexported.OPEN, channelexported.ORDERED, testConnectionIDA,
)
// Update chainA client on chainB
suite.chainB.updateClient(suite.chainA)
// Check that Chain B can verify channel is stored on chainA
proof, proofHeight := queryProof(suite.chainA, channelKey)
// if testcase proofHeight is not 0, replace proofHeight with this value
if tc.proofHeight != 0 {
proofHeight = tc.proofHeight
}
err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyChannelState(
suite.chainB.GetContext(), connection, proofHeight+1, proof, testPort1,
testChannel1, channel,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg)
}
})
}
}
func (suite *KeeperTestSuite) TestVerifyPacketCommitment() {
commitmentKey := ibctypes.KeyPacketCommitment(testPort1, testChannel1, 1)
commitmentBz := []byte("commitment")
cases := []struct {
msg string
proofHeight uint64
malleate func()
expPass bool
}{
{"verification success", 0, func() {
suite.chainB.CreateClient(suite.chainA)
}, true},
{"client state not found", 0, func() {}, false},
{"consensus state not found", 100, func() {
suite.chainB.CreateClient(suite.chainA)
}, false},
}
// ChainA sets packet commitment on channel with chainB in its state
// Check that ChainB can verify the PacketCommitment
for i, tc := range cases {
tc := tc
i := i
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
// Set PacketCommitment on chainA
connection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.OPEN)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainA.GetContext(), testPort1, testChannel1, 1, commitmentBz)
// Update ChainA client on chainB
suite.chainB.updateClient(suite.chainA)
// Check that ChainB can verify PacketCommitment stored in chainA
proof, proofHeight := queryProof(suite.chainA, commitmentKey)
// if testcase proofHeight is not 0, replace proofHeight with this value
if tc.proofHeight != 0 {
proofHeight = tc.proofHeight
}
err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyPacketCommitment(
suite.chainB.GetContext(), connection, proofHeight+1, proof, testPort1,
testChannel1, 1, commitmentBz,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg)
}
})
}
}
func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() {
packetAckKey := ibctypes.KeyPacketAcknowledgement(testPort1, testChannel1, 1)
ack := []byte("acknowledgement")
cases := []struct {
msg string
proofHeight uint64
malleate func()
expPass bool
}{
{"verification success", 0, func() {
suite.chainB.CreateClient(suite.chainA)
}, true},
{"client state not found", 0, func() {}, false},
{"consensus state not found", 100, func() {
suite.chainB.CreateClient(suite.chainA)
}, false},
}
for i, tc := range cases {
tc := tc
i := i
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
connection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.OPEN)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(suite.chainA.GetContext(), testPort1, testChannel1, 1, ack)
suite.chainB.updateClient(suite.chainA)
// TODO check this proof height
proof, proofHeight := queryProof(suite.chainA, packetAckKey)
// if testcase proofHeight is not 0, replace proofHeight with this value
if tc.proofHeight != 0 {
proofHeight = tc.proofHeight
}
err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyPacketAcknowledgement(
suite.chainB.GetContext(), connection, proofHeight+1, proof, testPort1,
testChannel1, 1, ack,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg)
}
})
}
}
func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgementAbsence() {
packetAckKey := ibctypes.KeyPacketAcknowledgement(testPort1, testChannel1, 1)
cases := []struct {
msg string
proofHeight uint64
malleate func()
expPass bool
}{
{"verification success", 0, func() {
suite.chainB.CreateClient(suite.chainA)
}, true},
{"client state not found", 0, func() {}, false},
{"consensus state not found", 100, func() {
suite.chainB.CreateClient(suite.chainA)
}, false},
}
for i, tc := range cases {
tc := tc
i := i
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
connection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.OPEN)
suite.chainB.updateClient(suite.chainA)
proof, proofHeight := queryProof(suite.chainA, packetAckKey)
// if testcase proofHeight is not 0, replace proofHeight with this value
if tc.proofHeight != 0 {
proofHeight = tc.proofHeight
}
err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyPacketAcknowledgementAbsence(
suite.chainB.GetContext(), connection, proofHeight+1, proof, testPort1,
testChannel1, 1,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg)
}
})
}
}
func (suite *KeeperTestSuite) TestVerifyNextSequenceRecv() {
nextSeqRcvKey := ibctypes.KeyNextSequenceRecv(testPort1, testChannel1)
cases := []struct {
msg string
proofHeight uint64
malleate func()
expPass bool
}{
{"verification success", uint64(0), func() {
suite.chainB.CreateClient(suite.chainA)
}, true},
{"client state not found", uint64(0), func() {}, false},
{"consensus state not found", uint64(100), func() {
suite.chainB.CreateClient(suite.chainA)
}, false},
}
for i, tc := range cases {
tc := tc
i := i
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
connection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.OPEN)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainA.GetContext(), testPort1, testChannel1, 1)
suite.chainB.updateClient(suite.chainA)
proof, proofHeight := queryProof(suite.chainA, nextSeqRcvKey)
// if testcase proofHeight is not 0, replace proofHeight with this value
if tc.proofHeight != 0 {
proofHeight = tc.proofHeight
}
err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyNextSequenceRecv(
suite.chainB.GetContext(), connection, proofHeight+1, proof, testPort1,
testChannel1, 1,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg)
}
})
}
}

View File

@ -0,0 +1,33 @@
package connection
import (
"fmt"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/client/cli"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/client/rest"
)
// Name returns the IBC connection ICS name
func Name() string {
return SubModuleName
}
// GetTxCmd returns the root tx command for the IBC connections.
func GetTxCmd(cdc *codec.Codec, storeKey string) *cobra.Command {
return cli.GetTxCmd(fmt.Sprintf("%s/%s", storeKey, SubModuleName), cdc)
}
// GetQueryCmd returns no root query command for the IBC connections.
func GetQueryCmd(cdc *codec.Codec, queryRoute string) *cobra.Command {
return cli.GetQueryCmd(fmt.Sprintf("%s/%s", queryRoute, SubModuleName), cdc)
}
// RegisterRESTRoutes registers the REST routes for the IBC connections.
func RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router, queryRoute string) {
rest.RegisterRoutes(ctx, rtr, fmt.Sprintf("%s/%s", queryRoute, SubModuleName))
}

View File

@ -0,0 +1,28 @@
package types
import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported"
)
// SubModuleCdc defines the IBC connection codec.
var SubModuleCdc *codec.Codec
// RegisterCodec registers the IBC connection types
func RegisterCodec(cdc *codec.Codec) {
cdc.RegisterInterface((*exported.ConnectionI)(nil), nil)
cdc.RegisterInterface((*exported.CounterpartyI)(nil), nil)
cdc.RegisterConcrete(ConnectionEnd{}, "ibc/connection/ConnectionEnd", nil)
cdc.RegisterConcrete(MsgConnectionOpenInit{}, "ibc/connection/MsgConnectionOpenInit", nil)
cdc.RegisterConcrete(MsgConnectionOpenTry{}, "ibc/connection/MsgConnectionOpenTry", nil)
cdc.RegisterConcrete(MsgConnectionOpenAck{}, "ibc/connection/MsgConnectionOpenAck", nil)
cdc.RegisterConcrete(MsgConnectionOpenConfirm{}, "ibc/connection/MsgConnectionOpenConfirm", nil)
SetSubModuleCodec(cdc)
}
// SetSubModuleCodec sets the ibc connection codec
func SetSubModuleCodec(cdc *codec.Codec) {
SubModuleCdc = cdc
}

View File

@ -0,0 +1,133 @@
package types
import (
"strings"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported"
commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types"
)
var _ exported.ConnectionI = ConnectionEnd{}
// ICS03 - Connection Data Structures as defined in https://github.com/cosmos/ics/tree/master/spec/ics-003-connection-semantics#data-structures
// ConnectionEnd defines a stateful object on a chain connected to another separate
// one.
// NOTE: there must only be 2 defined ConnectionEnds to establish a connection
// between two chains.
type ConnectionEnd struct {
State exported.State `json:"state" yaml:"state"`
ClientID string `json:"client_id" yaml:"client_id"`
// Counterparty chain associated with this connection.
Counterparty Counterparty `json:"counterparty" yaml:"counterparty"`
// Version is utilised to determine encodings or protocols for channels or
// packets utilising this connection.
Versions []string `json:"versions" yaml:"versions"`
}
// NewConnectionEnd creates a new ConnectionEnd instance.
func NewConnectionEnd(state exported.State, clientID string, counterparty Counterparty, versions []string) ConnectionEnd {
return ConnectionEnd{
State: state,
ClientID: clientID,
Counterparty: counterparty,
Versions: versions,
}
}
// GetState implements the Connection interface
func (c ConnectionEnd) GetState() exported.State {
return c.State
}
// GetClientID implements the Connection interface
func (c ConnectionEnd) GetClientID() string {
return c.ClientID
}
// GetCounterparty implements the Connection interface
func (c ConnectionEnd) GetCounterparty() exported.CounterpartyI {
return c.Counterparty
}
// GetVersions implements the Connection interface
func (c ConnectionEnd) GetVersions() []string {
return c.Versions
}
// ValidateBasic implements the Connection interface
func (c ConnectionEnd) ValidateBasic() error {
if err := host.DefaultClientIdentifierValidator(c.ClientID); err != nil {
return sdkerrors.Wrapf(err, "invalid client ID: %s", c.ClientID)
}
if len(c.Versions) == 0 {
return sdkerrors.Wrap(ibctypes.ErrInvalidVersion, "missing connection versions")
}
for _, version := range c.Versions {
if strings.TrimSpace(version) == "" {
return sdkerrors.Wrap(ibctypes.ErrInvalidVersion, "version can't be blank")
}
}
return c.Counterparty.ValidateBasic()
}
var _ exported.CounterpartyI = Counterparty{}
// Counterparty defines the counterparty chain associated with a connection end.
type Counterparty struct {
ClientID string `json:"client_id" yaml:"client_id"`
ConnectionID string `json:"connection_id" yaml:"connection_id"`
Prefix commitmentexported.Prefix `json:"prefix" yaml:"prefix"`
}
// NewCounterparty creates a new Counterparty instance.
func NewCounterparty(clientID, connectionID string, prefix commitmentexported.Prefix) Counterparty {
return Counterparty{
ClientID: clientID,
ConnectionID: connectionID,
Prefix: prefix,
}
}
// GetClientID implements the CounterpartyI interface
func (c Counterparty) GetClientID() string {
return c.ClientID
}
// GetConnectionID implements the CounterpartyI interface
func (c Counterparty) GetConnectionID() string {
return c.ConnectionID
}
// GetPrefix implements the CounterpartyI interface
func (c Counterparty) GetPrefix() commitmentexported.Prefix {
return c.Prefix
}
// ValidateBasic performs a basic validation check of the identifiers and prefix
func (c Counterparty) ValidateBasic() error {
if err := host.DefaultConnectionIdentifierValidator(c.ConnectionID); err != nil {
return sdkerrors.Wrap(err,
sdkerrors.Wrapf(
ErrInvalidCounterparty,
"invalid counterparty connection ID %s", c.ConnectionID,
).Error(),
)
}
if err := host.DefaultClientIdentifierValidator(c.ClientID); err != nil {
return sdkerrors.Wrap(err,
sdkerrors.Wrapf(
ErrInvalidCounterparty,
"invalid counterparty client ID %s", c.ClientID,
).Error(),
)
}
if c.Prefix == nil || len(c.Prefix.Bytes()) == 0 {
return sdkerrors.Wrap(ErrInvalidCounterparty, "invalid counterparty prefix")
}
return nil
}

View File

@ -0,0 +1,79 @@
package types
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
)
func TestConnectionValidateBasic(t *testing.T) {
testCases := []struct {
name string
connection ConnectionEnd
expPass bool
}{
{
"valid connection",
ConnectionEnd{exported.INIT, "clientidone", Counterparty{"clientidtwo", "connectionidone", commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []string{"1.0.0"}},
true,
},
{
"invalid client id",
ConnectionEnd{exported.INIT, "ClientIDTwo", Counterparty{"clientidtwo", "connectionidone", commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []string{"1.0.0"}},
false,
},
{
"empty versions",
ConnectionEnd{exported.INIT, "clientidone", Counterparty{"clientidtwo", "connectionidone", commitmenttypes.NewMerklePrefix([]byte("prefix"))}, nil},
false,
},
{
"invalid version",
ConnectionEnd{exported.INIT, "clientidone", Counterparty{"clientidtwo", "connectionidone", commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []string{""}},
false,
},
{
"invalid counterparty",
ConnectionEnd{exported.INIT, "clientidone", Counterparty{"clientidtwo", "connectionidone", nil}, []string{"1.0.0"}},
false,
},
}
for i, tc := range testCases {
tc := tc
err := tc.connection.ValidateBasic()
if tc.expPass {
require.NoError(t, err, "valid test case %d failed: %s", i, tc.name)
} else {
require.Error(t, err, "invalid test case %d passed: %s", i, tc.name)
}
}
}
func TestCounterpartyValidateBasic(t *testing.T) {
testCases := []struct {
name string
counterparty Counterparty
expPass bool
}{
{"valid counterparty", Counterparty{"clientidone", "connectionidone", commitmenttypes.NewMerklePrefix([]byte("prefix"))}, true},
{"invalid client id", Counterparty{"InvalidClient", "channelidone", commitmenttypes.NewMerklePrefix([]byte("prefix"))}, false},
{"invalid connection id", Counterparty{"clientidone", "InvalidConnection", commitmenttypes.NewMerklePrefix([]byte("prefix"))}, false},
{"invalid prefix", Counterparty{"clientidone", "connectionidone", nil}, false},
}
for i, tc := range testCases {
tc := tc
err := tc.counterparty.ValidateBasic()
if tc.expPass {
require.NoError(t, err, "valid test case %d failed: %s", i, tc.name)
} else {
require.Error(t, err, "invalid test case %d passed: %s", i, tc.name)
}
}
}

View File

@ -0,0 +1,16 @@
package types
import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// IBC connection sentinel errors
var (
ErrConnectionExists = sdkerrors.Register(SubModuleName, 1, "connection already exists")
ErrConnectionNotFound = sdkerrors.Register(SubModuleName, 2, "connection not found")
ErrClientConnectionPathsNotFound = sdkerrors.Register(SubModuleName, 3, "light client connection paths not found")
ErrConnectionPath = sdkerrors.Register(SubModuleName, 4, "connection path is not associated to the given light client")
ErrInvalidConnectionState = sdkerrors.Register(SubModuleName, 5, "invalid connection state")
ErrInvalidCounterparty = sdkerrors.Register(SubModuleName, 6, "invalid counterparty connection")
ErrInvalidConnection = sdkerrors.Register(SubModuleName, 7, "invalid connection")
)

View File

@ -0,0 +1,24 @@
package types
import (
"fmt"
ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types"
)
// IBC connection events
const (
AttributeKeyConnectionID = "connection_id"
AttributeKeyClientID = "client_id"
AttributeKeyCounterpartyClientID = "counterparty_client_id"
)
// IBC connection events vars
var (
EventTypeConnectionOpenInit = MsgConnectionOpenInit{}.Type()
EventTypeConnectionOpenTry = MsgConnectionOpenTry{}.Type()
EventTypeConnectionOpenAck = MsgConnectionOpenAck{}.Type()
EventTypeConnectionOpenConfirm = MsgConnectionOpenConfirm{}.Type()
AttributeValueCategory = fmt.Sprintf("%s_%s", ibctypes.ModuleName, SubModuleName)
)

View File

@ -0,0 +1,13 @@
package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
)
// ClientKeeper expected account IBC client keeper
type ClientKeeper interface {
GetClientState(ctx sdk.Context, clientID string) (clientexported.ClientState, bool)
GetClientConsensusState(ctx sdk.Context, clientID string, height uint64) (clientexported.ConsensusState, bool)
GetSelfConsensusState(ctx sdk.Context, height uint64) (clientexported.ConsensusState, bool)
}

View File

@ -0,0 +1,15 @@
package types
const (
// SubModuleName defines the IBC connection name
SubModuleName = "connection"
// StoreKey is the store key string for IBC connections
StoreKey = SubModuleName
// RouterKey is the message route for IBC connections
RouterKey = SubModuleName
// QuerierRoute is the querier route for IBC connections
QuerierRoute = SubModuleName
)

View File

@ -0,0 +1,310 @@
package types
import (
"strings"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types"
)
var _ sdk.Msg = MsgConnectionOpenInit{}
// MsgConnectionOpenInit defines the msg sent by an account on Chain A to
// initialize a connection with Chain B.
type MsgConnectionOpenInit struct {
ConnectionID string `json:"connection_id"`
ClientID string `json:"client_id"`
Counterparty Counterparty `json:"counterparty"`
Signer sdk.AccAddress `json:"signer"`
}
// NewMsgConnectionOpenInit creates a new MsgConnectionOpenInit instance
func NewMsgConnectionOpenInit(
connectionID, clientID, counterpartyConnectionID,
counterpartyClientID string, counterpartyPrefix commitmentexported.Prefix,
signer sdk.AccAddress,
) MsgConnectionOpenInit {
counterparty := NewCounterparty(counterpartyClientID, counterpartyConnectionID, counterpartyPrefix)
return MsgConnectionOpenInit{
ConnectionID: connectionID,
ClientID: clientID,
Counterparty: counterparty,
Signer: signer,
}
}
// Route implements sdk.Msg
func (msg MsgConnectionOpenInit) Route() string {
return ibctypes.RouterKey
}
// Type implements sdk.Msg
func (msg MsgConnectionOpenInit) Type() string {
return "connection_open_init"
}
// ValidateBasic implements sdk.Msg
func (msg MsgConnectionOpenInit) ValidateBasic() error {
if err := host.DefaultConnectionIdentifierValidator(msg.ConnectionID); err != nil {
return sdkerrors.Wrapf(err, "invalid connection ID: %s", msg.ConnectionID)
}
if err := host.DefaultClientIdentifierValidator(msg.ClientID); err != nil {
return sdkerrors.Wrapf(err, "invalid client ID: %s", msg.ClientID)
}
if msg.Signer.Empty() {
return sdkerrors.ErrInvalidAddress
}
return msg.Counterparty.ValidateBasic()
}
// GetSignBytes implements sdk.Msg
func (msg MsgConnectionOpenInit) GetSignBytes() []byte {
return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg))
}
// GetSigners implements sdk.Msg
func (msg MsgConnectionOpenInit) GetSigners() []sdk.AccAddress {
return []sdk.AccAddress{msg.Signer}
}
var _ sdk.Msg = MsgConnectionOpenTry{}
// MsgConnectionOpenTry defines a msg sent by a Relayer to try to open a connection
// on Chain B.
type MsgConnectionOpenTry struct {
ConnectionID string `json:"connection_id"`
ClientID string `json:"client_id"`
Counterparty Counterparty `json:"counterparty"`
CounterpartyVersions []string `json:"counterparty_versions"`
ProofInit commitmentexported.Proof `json:"proof_init"` // proof of the initialization the connection on Chain A: `none -> INIT`
ProofConsensus commitmentexported.Proof `json:"proof_consensus"` // proof of client consensus state
ProofHeight uint64 `json:"proof_height"`
ConsensusHeight uint64 `json:"consensus_height"`
Signer sdk.AccAddress `json:"signer"`
}
// NewMsgConnectionOpenTry creates a new MsgConnectionOpenTry instance
func NewMsgConnectionOpenTry(
connectionID, clientID, counterpartyConnectionID,
counterpartyClientID string, counterpartyPrefix commitmentexported.Prefix,
counterpartyVersions []string, proofInit, proofConsensus commitmentexported.Proof,
proofHeight, consensusHeight uint64, signer sdk.AccAddress,
) MsgConnectionOpenTry {
counterparty := NewCounterparty(counterpartyClientID, counterpartyConnectionID, counterpartyPrefix)
return MsgConnectionOpenTry{
ConnectionID: connectionID,
ClientID: clientID,
Counterparty: counterparty,
CounterpartyVersions: counterpartyVersions,
ProofInit: proofInit,
ProofConsensus: proofConsensus,
ProofHeight: proofHeight,
ConsensusHeight: consensusHeight,
Signer: signer,
}
}
// Route implements sdk.Msg
func (msg MsgConnectionOpenTry) Route() string {
return ibctypes.RouterKey
}
// Type implements sdk.Msg
func (msg MsgConnectionOpenTry) Type() string {
return "connection_open_try"
}
// ValidateBasic implements sdk.Msg
func (msg MsgConnectionOpenTry) ValidateBasic() error {
if err := host.DefaultConnectionIdentifierValidator(msg.ConnectionID); err != nil {
return sdkerrors.Wrapf(err, "invalid connection ID: %s", msg.ConnectionID)
}
if err := host.DefaultClientIdentifierValidator(msg.ClientID); err != nil {
return sdkerrors.Wrapf(err, "invalid client ID: %s", msg.ClientID)
}
if len(msg.CounterpartyVersions) == 0 {
return sdkerrors.Wrap(ibctypes.ErrInvalidVersion, "missing counterparty versions")
}
for _, version := range msg.CounterpartyVersions {
if strings.TrimSpace(version) == "" {
return sdkerrors.Wrap(ibctypes.ErrInvalidVersion, "version can't be blank")
}
}
if msg.ProofInit == nil || msg.ProofConsensus == nil {
return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof")
}
if err := msg.ProofInit.ValidateBasic(); err != nil {
return sdkerrors.Wrap(err, "proof init cannot be nil")
}
if err := msg.ProofConsensus.ValidateBasic(); err != nil {
return sdkerrors.Wrap(err, "proof consensus cannot be nil")
}
if msg.ProofHeight == 0 {
return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "proof height must be > 0")
}
if msg.ConsensusHeight == 0 {
return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "consensus height must be > 0")
}
if msg.Signer.Empty() {
return sdkerrors.ErrInvalidAddress
}
return msg.Counterparty.ValidateBasic()
}
// GetSignBytes implements sdk.Msg
func (msg MsgConnectionOpenTry) GetSignBytes() []byte {
return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg))
}
// GetSigners implements sdk.Msg
func (msg MsgConnectionOpenTry) GetSigners() []sdk.AccAddress {
return []sdk.AccAddress{msg.Signer}
}
var _ sdk.Msg = MsgConnectionOpenAck{}
// MsgConnectionOpenAck defines a msg sent by a Relayer to Chain A to acknowledge
// the change of connection state to TRYOPEN on Chain B.
type MsgConnectionOpenAck struct {
ConnectionID string `json:"connection_id"`
ProofTry commitmentexported.Proof `json:"proof_try"` // proof for the change of the connection state on Chain B: `none -> TRYOPEN`
ProofConsensus commitmentexported.Proof `json:"proof_consensus"` // proof of client consensus state
ProofHeight uint64 `json:"proof_height"`
ConsensusHeight uint64 `json:"consensus_height"`
Version string `json:"version"`
Signer sdk.AccAddress `json:"signer"`
}
// NewMsgConnectionOpenAck creates a new MsgConnectionOpenAck instance
func NewMsgConnectionOpenAck(
connectionID string, proofTry, proofConsensus commitmentexported.Proof,
proofHeight, consensusHeight uint64, version string,
signer sdk.AccAddress,
) MsgConnectionOpenAck {
return MsgConnectionOpenAck{
ConnectionID: connectionID,
ProofTry: proofTry,
ProofConsensus: proofConsensus,
ProofHeight: proofHeight,
ConsensusHeight: consensusHeight,
Version: version,
Signer: signer,
}
}
// Route implements sdk.Msg
func (msg MsgConnectionOpenAck) Route() string {
return ibctypes.RouterKey
}
// Type implements sdk.Msg
func (msg MsgConnectionOpenAck) Type() string {
return "connection_open_ack"
}
// ValidateBasic implements sdk.Msg
func (msg MsgConnectionOpenAck) ValidateBasic() error {
if err := host.DefaultConnectionIdentifierValidator(msg.ConnectionID); err != nil {
return sdkerrors.Wrap(err, "invalid connection ID")
}
if strings.TrimSpace(msg.Version) == "" {
return sdkerrors.Wrap(ibctypes.ErrInvalidVersion, "version can't be blank")
}
if msg.ProofTry == nil || msg.ProofConsensus == nil {
return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof")
}
if err := msg.ProofTry.ValidateBasic(); err != nil {
return sdkerrors.Wrap(err, "proof try cannot be nil")
}
if err := msg.ProofConsensus.ValidateBasic(); err != nil {
return sdkerrors.Wrap(err, "proof consensus cannot be nil")
}
if msg.ProofHeight == 0 {
return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "proof height must be > 0")
}
if msg.ConsensusHeight == 0 {
return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "consensus height must be > 0")
}
if msg.Signer.Empty() {
return sdkerrors.ErrInvalidAddress
}
return nil
}
// GetSignBytes implements sdk.Msg
func (msg MsgConnectionOpenAck) GetSignBytes() []byte {
return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg))
}
// GetSigners implements sdk.Msg
func (msg MsgConnectionOpenAck) GetSigners() []sdk.AccAddress {
return []sdk.AccAddress{msg.Signer}
}
var _ sdk.Msg = MsgConnectionOpenConfirm{}
// MsgConnectionOpenConfirm defines a msg sent by a Relayer to Chain B to acknowledge
// the change of connection state to OPEN on Chain A.
type MsgConnectionOpenConfirm struct {
ConnectionID string `json:"connection_id"`
ProofAck commitmentexported.Proof `json:"proof_ack"` // proof for the change of the connection state on Chain A: `INIT -> OPEN`
ProofHeight uint64 `json:"proof_height"`
Signer sdk.AccAddress `json:"signer"`
}
// NewMsgConnectionOpenConfirm creates a new MsgConnectionOpenConfirm instance
func NewMsgConnectionOpenConfirm(
connectionID string, proofAck commitmentexported.Proof, proofHeight uint64,
signer sdk.AccAddress,
) MsgConnectionOpenConfirm {
return MsgConnectionOpenConfirm{
ConnectionID: connectionID,
ProofAck: proofAck,
ProofHeight: proofHeight,
Signer: signer,
}
}
// Route implements sdk.Msg
func (msg MsgConnectionOpenConfirm) Route() string {
return ibctypes.RouterKey
}
// Type implements sdk.Msg
func (msg MsgConnectionOpenConfirm) Type() string {
return "connection_open_confirm"
}
// ValidateBasic implements sdk.Msg
func (msg MsgConnectionOpenConfirm) ValidateBasic() error {
if err := host.DefaultConnectionIdentifierValidator(msg.ConnectionID); err != nil {
return sdkerrors.Wrap(err, "invalid connection ID")
}
if msg.ProofAck == nil {
return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof")
}
if err := msg.ProofAck.ValidateBasic(); err != nil {
return sdkerrors.Wrap(err, "proof ack cannot be nil")
}
if msg.ProofHeight == 0 {
return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "proof height must be > 0")
}
if msg.Signer.Empty() {
return sdkerrors.ErrInvalidAddress
}
return nil
}
// GetSignBytes implements sdk.Msg
func (msg MsgConnectionOpenConfirm) GetSignBytes() []byte {
return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg))
}
// GetSigners implements sdk.Msg
func (msg MsgConnectionOpenConfirm) GetSigners() []sdk.AccAddress {
return []sdk.AccAddress{msg.Signer}
}

View File

@ -0,0 +1,215 @@
package types
import (
"fmt"
"testing"
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/store/iavl"
"github.com/cosmos/cosmos-sdk/store/rootmulti"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
)
type MsgTestSuite struct {
suite.Suite
proof commitmenttypes.MerkleProof
}
func (suite *MsgTestSuite) SetupTest() {
db := dbm.NewMemDB()
store := rootmulti.NewStore(db)
storeKey := storetypes.NewKVStoreKey("iavlStoreKey")
store.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, nil)
store.LoadVersion(0)
iavlStore := store.GetCommitStore(storeKey).(*iavl.Store)
iavlStore.Set([]byte("KEY"), []byte("VALUE"))
_ = store.Commit()
res := store.Query(abci.RequestQuery{
Path: fmt.Sprintf("/%s/key", storeKey.Name()), // required path to get key/value+proof
Data: []byte("KEY"),
Prove: true,
})
suite.proof = commitmenttypes.MerkleProof{Proof: res.Proof}
}
func TestMsgTestSuite(t *testing.T) {
suite.Run(t, new(MsgTestSuite))
}
func (suite *MsgTestSuite) TestNewMsgConnectionOpenInit() {
prefix := commitmenttypes.NewMerklePrefix([]byte("storePrefixKey"))
signer, _ := sdk.AccAddressFromBech32("cosmos1ckgw5d7jfj7wwxjzs9fdrdev9vc8dzcw3n2lht")
testMsgs := []MsgConnectionOpenInit{
NewMsgConnectionOpenInit("test/conn1", "clienttotesta", "connectiontotest", "clienttotest", prefix, signer),
NewMsgConnectionOpenInit("ibcconntest", "test/iris", "connectiontotest", "clienttotest", prefix, signer),
NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "test/conn1", "clienttotest", prefix, signer),
NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "connectiontotest", "test/conn1", prefix, signer),
NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "connectiontotest", "clienttotest", nil, signer),
NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "connectiontotest", "clienttotest", prefix, nil),
NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "connectiontotest", "clienttotest", prefix, signer),
}
var testCases = []struct {
msg MsgConnectionOpenInit
expPass bool
errMsg string
}{
{testMsgs[0], false, "invalid connection ID"},
{testMsgs[1], false, "invalid client ID"},
{testMsgs[2], false, "invalid counterparty client ID"},
{testMsgs[3], false, "invalid counterparty connection ID"},
{testMsgs[4], false, "empty counterparty prefix"},
{testMsgs[5], false, "empty singer"},
{testMsgs[6], true, "success"},
}
for i, tc := range testCases {
err := tc.msg.ValidateBasic()
if tc.expPass {
suite.Require().NoError(err, "Msg %d failed: %v", i, err)
} else {
suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg)
}
}
}
func (suite *MsgTestSuite) TestNewMsgConnectionOpenTry() {
prefix := commitmenttypes.NewMerklePrefix([]byte("storePrefixKey"))
signer, _ := sdk.AccAddressFromBech32("cosmos1ckgw5d7jfj7wwxjzs9fdrdev9vc8dzcw3n2lht")
testMsgs := []MsgConnectionOpenTry{
NewMsgConnectionOpenTry("test/conn1", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, suite.proof, suite.proof, 10, 10, signer),
NewMsgConnectionOpenTry("ibcconntest", "test/iris", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, suite.proof, suite.proof, 10, 10, signer),
NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "ibc/test", "clienttotest", prefix, []string{"1.0.0"}, suite.proof, suite.proof, 10, 10, signer),
NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "test/conn1", prefix, []string{"1.0.0"}, suite.proof, suite.proof, 10, 10, signer),
NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", nil, []string{"1.0.0"}, suite.proof, suite.proof, 10, 10, signer),
NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{}, suite.proof, suite.proof, 10, 10, signer),
NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, nil, suite.proof, 10, 10, signer),
NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, commitmenttypes.MerkleProof{Proof: nil}, suite.proof, 10, 10, signer),
NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, suite.proof, nil, 10, 10, signer),
NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, suite.proof, commitmenttypes.MerkleProof{Proof: nil}, 10, 10, signer),
NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, suite.proof, suite.proof, 0, 10, signer),
NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, suite.proof, suite.proof, 10, 0, signer),
NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, suite.proof, suite.proof, 10, 10, nil),
NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, suite.proof, suite.proof, 10, 10, signer),
}
var testCases = []struct {
msg MsgConnectionOpenTry
expPass bool
errMsg string
}{
{testMsgs[0], false, "invalid connection ID"},
{testMsgs[1], false, "invalid client ID"},
{testMsgs[2], false, "invalid counterparty connection ID"},
{testMsgs[3], false, "invalid counterparty client ID"},
{testMsgs[4], false, "empty counterparty prefix"},
{testMsgs[5], false, "empty counterpartyVersions"},
{testMsgs[6], false, "empty proofInit"},
{testMsgs[7], false, "empty proofInit"},
{testMsgs[8], false, "empty proofConsensus"},
{testMsgs[9], false, "empty proofConsensus"},
{testMsgs[10], false, "invalid proofHeight"},
{testMsgs[11], false, "invalid consensusHeight"},
{testMsgs[12], false, "empty singer"},
{testMsgs[13], true, "success"},
}
for i, tc := range testCases {
err := tc.msg.ValidateBasic()
if tc.expPass {
suite.Require().NoError(err, "Msg %d failed: %s", i, tc.errMsg)
} else {
suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg)
}
}
}
func (suite *MsgTestSuite) TestNewMsgConnectionOpenAck() {
signer, _ := sdk.AccAddressFromBech32("cosmos1ckgw5d7jfj7wwxjzs9fdrdev9vc8dzcw3n2lht")
testMsgs := []MsgConnectionOpenAck{
NewMsgConnectionOpenAck("test/conn1", suite.proof, suite.proof, 10, 10, "1.0.0", signer),
NewMsgConnectionOpenAck("ibcconntest", nil, suite.proof, 10, 10, "1.0.0", signer),
NewMsgConnectionOpenAck("ibcconntest", commitmenttypes.MerkleProof{Proof: nil}, suite.proof, 10, 10, "1.0.0", signer),
NewMsgConnectionOpenAck("ibcconntest", suite.proof, nil, 10, 10, "1.0.0", signer),
NewMsgConnectionOpenAck("ibcconntest", suite.proof, commitmenttypes.MerkleProof{Proof: nil}, 10, 10, "1.0.0", signer),
NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 0, 10, "1.0.0", signer),
NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 10, 0, "1.0.0", signer),
NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 10, 10, "", signer),
NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 10, 10, "1.0.0", nil),
NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 10, 10, "1.0.0", signer),
}
var testCases = []struct {
msg MsgConnectionOpenAck
expPass bool
errMsg string
}{
{testMsgs[0], false, "invalid connection ID"},
{testMsgs[1], false, "empty proofTry"},
{testMsgs[2], false, "empty proofTry"},
{testMsgs[3], false, "empty proofConsensus"},
{testMsgs[4], false, "empty proofConsensus"},
{testMsgs[5], false, "invalid proofHeight"},
{testMsgs[6], false, "invalid consensusHeight"},
{testMsgs[7], false, "invalid version"},
{testMsgs[8], false, "empty signer"},
{testMsgs[9], true, "success"},
}
for i, tc := range testCases {
err := tc.msg.ValidateBasic()
if tc.expPass {
suite.Require().NoError(err, "Msg %d failed: %s", i, tc.errMsg)
} else {
suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg)
}
}
}
func (suite *MsgTestSuite) TestNewMsgConnectionOpenConfirm() {
signer, _ := sdk.AccAddressFromBech32("cosmos1ckgw5d7jfj7wwxjzs9fdrdev9vc8dzcw3n2lht")
testMsgs := []MsgConnectionOpenConfirm{
NewMsgConnectionOpenConfirm("test/conn1", suite.proof, 10, signer),
NewMsgConnectionOpenConfirm("ibcconntest", nil, 10, signer),
NewMsgConnectionOpenConfirm("ibcconntest", commitmenttypes.MerkleProof{Proof: nil}, 10, signer),
NewMsgConnectionOpenConfirm("ibcconntest", suite.proof, 0, signer),
NewMsgConnectionOpenConfirm("ibcconntest", suite.proof, 10, nil),
NewMsgConnectionOpenConfirm("ibcconntest", suite.proof, 10, signer),
}
var testCases = []struct {
msg MsgConnectionOpenConfirm
expPass bool
errMsg string
}{
{testMsgs[0], false, "invalid connection ID"},
{testMsgs[1], false, "empty proofTry"},
{testMsgs[2], false, "empty proofTry"},
{testMsgs[3], false, "invalid proofHeight"},
{testMsgs[4], false, "empty signer"},
{testMsgs[5], true, "success"},
}
for i, tc := range testCases {
err := tc.msg.ValidateBasic()
if tc.expPass {
suite.Require().NoError(err, "Msg %d failed: %s", i, tc.errMsg)
} else {
suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg)
}
}
}

View File

@ -0,0 +1,93 @@
package types
import (
"strings"
"github.com/tendermint/tendermint/crypto/merkle"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types"
)
// query routes supported by the IBC connection Querier
const (
QueryAllConnections = "connections"
QueryClientConnections = "client_connections"
)
// IdentifiedConnectionEnd defines the union of a connection end & an identifier.
type IdentifiedConnectionEnd struct {
Connection ConnectionEnd `json:"connection_end" yaml:"connection_end"`
Identifier string `json:"identifier" yaml:"identifier"`
}
// ConnectionResponse defines the client query response for a connection which
// also includes a proof and the height from which the proof was retrieved.
type ConnectionResponse struct {
Connection IdentifiedConnectionEnd `json:"connection" yaml:"connection"`
Proof commitmenttypes.MerkleProof `json:"proof,omitempty" yaml:"proof,omitempty"`
ProofPath commitmenttypes.MerklePath `json:"proof_path,omitempty" yaml:"proof_path,omitempty"`
ProofHeight uint64 `json:"proof_height,omitempty" yaml:"proof_height,omitempty"`
}
// NewConnectionResponse creates a new ConnectionResponse instance
func NewConnectionResponse(
connectionID string, connection ConnectionEnd, proof *merkle.Proof, height int64,
) ConnectionResponse {
return ConnectionResponse{
Connection: IdentifiedConnectionEnd{connection, connectionID},
Proof: commitmenttypes.MerkleProof{Proof: proof},
ProofPath: commitmenttypes.NewMerklePath(strings.Split(ibctypes.ConnectionPath(connectionID), "/")),
ProofHeight: uint64(height),
}
}
// QueryAllConnectionsParams defines the parameters necessary for querying for all
// connections.
type QueryAllConnectionsParams struct {
Page int `json:"page" yaml:"page"`
Limit int `json:"limit" yaml:"limit"`
}
// NewQueryAllConnectionsParams creates a new QueryAllConnectionsParams instance.
func NewQueryAllConnectionsParams(page, limit int) QueryAllConnectionsParams {
return QueryAllConnectionsParams{
Page: page,
Limit: limit,
}
}
// ClientConnectionsResponse defines the client query response for a client
// connection paths which also includes a proof and the height from which the
// proof was retrieved.
type ClientConnectionsResponse struct {
ConnectionPaths []string `json:"connection_paths" yaml:"connection_paths"`
Proof commitmenttypes.MerkleProof `json:"proof,omitempty" yaml:"proof,omitempty"`
ProofPath commitmenttypes.MerklePath `json:"proof_path,omitempty" yaml:"proof_path,omitempty"`
ProofHeight uint64 `json:"proof_height,omitempty" yaml:"proof_height,omitempty"`
}
// NewClientConnectionsResponse creates a new ConnectionPaths instance
func NewClientConnectionsResponse(
clientID string, connectionPaths []string, proof *merkle.Proof, height int64,
) ClientConnectionsResponse {
return ClientConnectionsResponse{
ConnectionPaths: connectionPaths,
Proof: commitmenttypes.MerkleProof{Proof: proof},
ProofPath: commitmenttypes.NewMerklePath(strings.Split(ibctypes.ClientConnectionsPath(clientID), "/")),
ProofHeight: uint64(height),
}
}
// QueryClientConnectionsParams defines the params for the following queries:
// - 'custom/ibc/client/<clientID>/connections'
type QueryClientConnectionsParams struct {
ClientID string
}
// NewQueryClientConnectionsParams creates a new QueryClientConnectionsParams instance
func NewQueryClientConnectionsParams(clientID string) QueryClientConnectionsParams {
return QueryClientConnectionsParams{
ClientID: clientID,
}
}

View File

@ -0,0 +1,96 @@
package types
// GetCompatibleVersions returns an ordered set of compatible IBC versions for the
// caller chain's connection end.
func GetCompatibleVersions() []string {
return []string{"1.0.0"}
}
// LatestVersion gets the latest version of a connection protocol
//
// CONTRACT: version array MUST be already sorted.
func LatestVersion(versions []string) string {
if len(versions) == 0 {
return ""
}
return versions[len(versions)-1]
}
// PickVersion picks the counterparty latest version that is matches the list
// of compatible versions for the connection.
func PickVersion(counterpartyVersions, compatibleVersions []string) string {
n := len(counterpartyVersions)
m := len(compatibleVersions)
// aux hash maps to lookup already seen versions
counterpartyVerLookup := make(map[string]bool)
compatibleVerLookup := make(map[string]bool)
// versions suported
var supportedVersions []string
switch {
case n == 0 || m == 0:
return ""
case n == m:
for i := n - 1; i >= 0; i-- {
counterpartyVerLookup[counterpartyVersions[i]] = true
compatibleVerLookup[compatibleVersions[i]] = true
// check if we've seen any of the versions
if _, ok := compatibleVerLookup[counterpartyVersions[i]]; ok {
supportedVersions = append(supportedVersions, counterpartyVersions[i])
}
if _, ok := counterpartyVerLookup[compatibleVersions[i]]; ok {
// TODO: check if the version is already in the array
supportedVersions = append(supportedVersions, compatibleVersions[i])
}
}
case n > m:
for i := n - 1; i >= m; i-- {
counterpartyVerLookup[compatibleVersions[i]] = true
}
for i := m - 1; i >= 0; i-- {
counterpartyVerLookup[counterpartyVersions[i]] = true
compatibleVerLookup[compatibleVersions[i]] = true
// check if we've seen any of the versions
if _, ok := compatibleVerLookup[counterpartyVersions[i]]; ok {
supportedVersions = append(supportedVersions, counterpartyVersions[i])
}
if _, ok := counterpartyVerLookup[compatibleVersions[i]]; ok {
supportedVersions = append(supportedVersions, compatibleVersions[i])
}
}
case n < m:
for i := m - 1; i >= n; i-- {
compatibleVerLookup[compatibleVersions[i]] = true
}
for i := n - 1; i >= 0; i-- {
counterpartyVerLookup[counterpartyVersions[i]] = true
compatibleVerLookup[compatibleVersions[i]] = true
// check if we've seen any of the versions
if _, ok := compatibleVerLookup[counterpartyVersions[i]]; ok {
supportedVersions = append(supportedVersions, counterpartyVersions[i])
}
if _, ok := counterpartyVerLookup[compatibleVersions[i]]; ok {
supportedVersions = append(supportedVersions, compatibleVersions[i])
}
}
}
if len(supportedVersions) == 0 {
return ""
}
// TODO: compare latest version before appending
return supportedVersions[len(supportedVersions)-1]
}

85
x/ibc/04-channel/alias.go Normal file
View File

@ -0,0 +1,85 @@
package channel
// nolint
// autogenerated code using github.com/rigelrozanski/multitool
// aliases generated for the following subdirectories:
// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/04-channel/keeper
// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types
import (
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/keeper"
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
)
const (
SubModuleName = types.SubModuleName
StoreKey = types.StoreKey
RouterKey = types.RouterKey
QuerierRoute = types.QuerierRoute
QueryAllChannels = types.QueryAllChannels
QueryConnectionChannels = types.QueryConnectionChannels
QueryChannel = types.QueryChannel
)
var (
// functions aliases
NewKeeper = keeper.NewKeeper
QuerierChannels = keeper.QuerierChannels
QuerierConnectionChannels = keeper.QuerierConnectionChannels
NewChannel = types.NewChannel
NewCounterparty = types.NewCounterparty
RegisterCodec = types.RegisterCodec
ErrChannelExists = types.ErrChannelExists
ErrChannelNotFound = types.ErrChannelNotFound
ErrInvalidCounterparty = types.ErrInvalidCounterparty
ErrChannelCapabilityNotFound = types.ErrChannelCapabilityNotFound
ErrInvalidPacket = types.ErrInvalidPacket
ErrSequenceSendNotFound = types.ErrSequenceSendNotFound
ErrSequenceReceiveNotFound = types.ErrSequenceReceiveNotFound
ErrPacketTimeout = types.ErrPacketTimeout
ErrInvalidChannel = types.ErrInvalidChannel
ErrInvalidChannelState = types.ErrInvalidChannelState
ErrAcknowledgementTooLong = types.ErrAcknowledgementTooLong
NewMsgChannelOpenInit = types.NewMsgChannelOpenInit
NewMsgChannelOpenTry = types.NewMsgChannelOpenTry
NewMsgChannelOpenAck = types.NewMsgChannelOpenAck
NewMsgChannelOpenConfirm = types.NewMsgChannelOpenConfirm
NewMsgChannelCloseInit = types.NewMsgChannelCloseInit
NewMsgChannelCloseConfirm = types.NewMsgChannelCloseConfirm
NewMsgPacket = types.NewMsgPacket
NewMsgTimeout = types.NewMsgTimeout
NewMsgAcknowledgement = types.NewMsgAcknowledgement
NewPacket = types.NewPacket
NewChannelResponse = types.NewChannelResponse
// variable aliases
SubModuleCdc = types.SubModuleCdc
EventTypeChannelOpenInit = types.EventTypeChannelOpenInit
EventTypeChannelOpenTry = types.EventTypeChannelOpenTry
EventTypeChannelOpenAck = types.EventTypeChannelOpenAck
EventTypeChannelOpenConfirm = types.EventTypeChannelOpenConfirm
EventTypeChannelCloseInit = types.EventTypeChannelCloseInit
EventTypeChannelCloseConfirm = types.EventTypeChannelCloseConfirm
AttributeValueCategory = types.AttributeValueCategory
)
// nolint: golint
type (
Keeper = keeper.Keeper
Channel = types.Channel
Counterparty = types.Counterparty
ClientKeeper = types.ClientKeeper
ConnectionKeeper = types.ConnectionKeeper
PortKeeper = types.PortKeeper
MsgChannelOpenInit = types.MsgChannelOpenInit
MsgChannelOpenTry = types.MsgChannelOpenTry
MsgChannelOpenAck = types.MsgChannelOpenAck
MsgChannelOpenConfirm = types.MsgChannelOpenConfirm
MsgChannelCloseInit = types.MsgChannelCloseInit
MsgChannelCloseConfirm = types.MsgChannelCloseConfirm
MsgPacket = types.MsgPacket
MsgAcknowledgement = types.MsgAcknowledgement
MsgTimeout = types.MsgTimeout
Packet = types.Packet
ChannelResponse = types.ChannelResponse
)

View File

@ -0,0 +1,42 @@
package cli
import (
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
)
// GetQueryCmd returns the query commands for IBC channels
func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command {
ics04ChannelQueryCmd := &cobra.Command{
Use: "channel",
Short: "IBC channel query subcommands",
DisableFlagParsing: true,
}
ics04ChannelQueryCmd.AddCommand(flags.GetCommands(
GetCmdQueryChannel(storeKey, cdc),
)...)
return ics04ChannelQueryCmd
}
// GetTxCmd returns the transaction commands for IBC channels
func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command {
ics04ChannelTxCmd := &cobra.Command{
Use: "channel",
Short: "IBC channel transaction subcommands",
}
ics04ChannelTxCmd.AddCommand(flags.PostCommands(
GetMsgChannelOpenInitCmd(storeKey, cdc),
GetMsgChannelOpenTryCmd(storeKey, cdc),
GetMsgChannelOpenAckCmd(storeKey, cdc),
GetMsgChannelOpenConfirmCmd(storeKey, cdc),
GetMsgChannelCloseInitCmd(storeKey, cdc),
GetMsgChannelCloseConfirmCmd(storeKey, cdc),
)...)
return ics04ChannelTxCmd
}

View File

@ -0,0 +1,47 @@
package cli
import (
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/client/utils"
)
// GetCmdQueryChannel defines the command to query a channel end
func GetCmdQueryChannel(queryRoute string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "end [port-id] [channel-id]",
Short: "Query a channel end",
Long: strings.TrimSpace(fmt.Sprintf(`Query an IBC channel end
Example:
$ %s query ibc channel end [port-id] [channel-id]
`, version.ClientName),
),
Example: fmt.Sprintf("%s query ibc channel end [port-id] [channel-id]", version.ClientName),
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
portID := args[0]
channelID := args[1]
prove := viper.GetBool(flags.FlagProve)
channelRes, err := utils.QueryChannel(cliCtx, portID, channelID, prove)
if err != nil {
return err
}
return cliCtx.PrintOutput(channelRes)
},
}
cmd.Flags().Bool(flags.FlagProve, true, "show proofs for the query results")
return cmd
}

View File

@ -0,0 +1,251 @@
package cli
import (
"bufio"
"strconv"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
connectionutils "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/client/utils"
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
)
// IBC Channel flags
const (
FlagOrdered = "ordered"
FlagIBCVersion = "ibc-version"
)
// GetMsgChannelOpenInitCmd returns the command to create a MsgChannelOpenInit transaction
func GetMsgChannelOpenInitCmd(storeKey string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "open-init [port-id] [channel-id] [counterparty-port-id] [counterparty-channel-id] [connection-hops]",
Short: "Creates and sends a ChannelOpenInit message",
Args: cobra.ExactArgs(5),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
portID := args[0]
channelID := args[1]
counterpartyPortID := args[2]
counterpartyChannelID := args[3]
hops := strings.Split(args[4], "/")
order := channelOrder()
version := viper.GetString(FlagIBCVersion)
msg := types.NewMsgChannelOpenInit(
portID, channelID, version, order, hops,
counterpartyPortID, counterpartyChannelID, cliCtx.GetFromAddress(),
)
if err := msg.ValidateBasic(); err != nil {
return err
}
return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
cmd.Flags().Bool(FlagOrdered, true, "Pass flag for opening ordered channels")
cmd.Flags().String(FlagIBCVersion, "1.0.0", "supported IBC version")
return cmd
}
// GetMsgChannelOpenTryCmd returns the command to create a MsgChannelOpenTry transaction
func GetMsgChannelOpenTryCmd(storeKey string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "open-try [port-id] [channel-id] [counterparty-port-id] [counterparty-channel-id] [connection-hops] [/path/to/proof_init.json] [proof-height]",
Short: "Creates and sends a ChannelOpenTry message",
Args: cobra.ExactArgs(7),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
portID := args[0]
channelID := args[1]
counterpartyPortID := args[2]
counterpartyChannelID := args[3]
hops := strings.Split(args[4], "/")
order := channelOrder()
version := viper.GetString(FlagIBCVersion) // TODO: diferenciate between channel and counterparty versions
proofInit, err := connectionutils.ParseProof(cliCtx.Codec, args[5])
if err != nil {
return err
}
proofHeight, err := strconv.ParseInt(args[6], 10, 64)
if err != nil {
return err
}
msg := types.NewMsgChannelOpenTry(
portID, channelID, version, order, hops,
counterpartyPortID, counterpartyChannelID, version,
proofInit, uint64(proofHeight), cliCtx.GetFromAddress(),
)
if err := msg.ValidateBasic(); err != nil {
return err
}
return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
cmd.Flags().Bool(FlagOrdered, true, "Pass flag for opening ordered channels")
cmd.Flags().String(FlagIBCVersion, "1.0.0", "supported IBC version")
return cmd
}
// GetMsgChannelOpenAckCmd returns the command to create a MsgChannelOpenAck transaction
func GetMsgChannelOpenAckCmd(storeKey string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "open-ack [port-id] [channel-id] [/path/to/proof_try.json] [proof-height]",
Short: "Creates and sends a ChannelOpenAck message",
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
portID := args[0]
channelID := args[1]
version := viper.GetString(FlagIBCVersion) // TODO: diferenciate between channel and counterparty versions
proofTry, err := connectionutils.ParseProof(cliCtx.Codec, args[5])
if err != nil {
return err
}
proofHeight, err := strconv.ParseInt(args[3], 10, 64)
if err != nil {
return err
}
msg := types.NewMsgChannelOpenAck(
portID, channelID, version, proofTry, uint64(proofHeight), cliCtx.GetFromAddress(),
)
if err := msg.ValidateBasic(); err != nil {
return err
}
return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
cmd.Flags().String(FlagIBCVersion, "1.0.0", "supported IBC version")
return cmd
}
// GetMsgChannelOpenConfirmCmd returns the command to create a MsgChannelOpenConfirm transaction
func GetMsgChannelOpenConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "open-confirm [port-id] [channel-id] [/path/to/proof_ack.json] [proof-height]",
Short: "Creates and sends a ChannelOpenConfirm message",
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
portID := args[0]
channelID := args[1]
proofAck, err := connectionutils.ParseProof(cliCtx.Codec, args[5])
if err != nil {
return err
}
proofHeight, err := strconv.ParseInt(args[3], 10, 64)
if err != nil {
return err
}
msg := types.NewMsgChannelOpenConfirm(
portID, channelID, proofAck, uint64(proofHeight), cliCtx.GetFromAddress(),
)
if err := msg.ValidateBasic(); err != nil {
return err
}
return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
}
// GetMsgChannelCloseInitCmd returns the command to create a MsgChannelCloseInit transaction
func GetMsgChannelCloseInitCmd(storeKey string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "close-init [port-id] [channel-id]",
Short: "Creates and sends a ChannelCloseInit message",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
portID := args[0]
channelID := args[1]
msg := types.NewMsgChannelCloseInit(portID, channelID, cliCtx.GetFromAddress())
if err := msg.ValidateBasic(); err != nil {
return err
}
return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
}
// GetMsgChannelCloseConfirmCmd returns the command to create a MsgChannelCloseConfirm transaction
func GetMsgChannelCloseConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "close-confirm [port-id] [channel-id] [/path/to/proof_init.json] [proof-height]",
Short: "Creates and sends a ChannelCloseConfirm message",
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
portID := args[0]
channelID := args[1]
proofInit, err := connectionutils.ParseProof(cliCtx.Codec, args[5])
if err != nil {
return err
}
proofHeight, err := strconv.ParseInt(args[3], 10, 64)
if err != nil {
return err
}
msg := types.NewMsgChannelCloseConfirm(
portID, channelID, proofInit, uint64(proofHeight), cliCtx.GetFromAddress(),
)
if err := msg.ValidateBasic(); err != nil {
return err
}
return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
}
func channelOrder() exported.Order {
if viper.GetBool(FlagOrdered) {
return exported.ORDERED
}
return exported.UNORDERED
}

View File

@ -0,0 +1,52 @@
package rest
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/types/rest"
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/client/utils"
)
func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) {
r.HandleFunc(fmt.Sprintf("/ibc/ports/{%s}/channels/{%s}", RestPortID, RestChannelID), queryChannelHandlerFn(cliCtx, queryRoute)).Methods("GET")
}
// queryChannelHandlerFn implements a channel querying route
//
// @Summary Query channel
// @Tags IBC
// @Produce json
// @Param port-id path string true "Port ID"
// @Param channel-id path string true "Channel ID"
// @Param prove query boolean false "Proof of result"
// @Success 200 {object} QueryChannel "OK"
// @Failure 400 {object} rest.ErrorResponse "Invalid port id or channel id"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/ports/{port-id}/channels/{channel-id} [get]
func queryChannelHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
portID := vars[RestPortID]
channelID := vars[RestChannelID]
prove := rest.ParseQueryParamBool(r, flags.FlagProve)
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
channelRes, err := utils.QueryChannel(cliCtx, portID, channelID, prove)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
cliCtx = cliCtx.WithHeight(int64(channelRes.ProofHeight))
rest.PostProcessResponse(w, cliCtx, channelRes)
}
}

View File

@ -0,0 +1,84 @@
package rest
import (
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/types/rest"
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported"
)
const (
RestChannelID = "channel-id"
RestPortID = "port-id"
)
// RegisterRoutes - Central function to define routes that get registered by the main application
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) {
registerQueryRoutes(cliCtx, r, queryRoute)
registerTxRoutes(cliCtx, r)
}
// ChannelOpenInitReq defines the properties of a channel open init request's body.
type ChannelOpenInitReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
PortID string `json:"port_id" yaml:"port_id"`
ChannelID string `json:"channel_id" yaml:"channel_id"`
Version string `json:"version" yaml:"version"`
ChannelOrder exported.Order `json:"channel_order" yaml:"channel_order"`
ConnectionHops []string `json:"connection_hops" yaml:"connection_hops"`
CounterpartyPortID string `json:"counterparty_port_id" yaml:"counterparty_port_id"`
CounterpartyChannelID string `json:"counterparty_channel_id" yaml:"counterparty_channel_id"`
}
// ChannelOpenTryReq defines the properties of a channel open try request's body.
type ChannelOpenTryReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
PortID string `json:"port_id" yaml:"port_id"`
ChannelID string `json:"channel_id" yaml:"channel_id"`
Version string `json:"version" yaml:"version"`
ChannelOrder exported.Order `json:"channel_order" yaml:"channel_order"`
ConnectionHops []string `json:"connection_hops" yaml:"connection_hops"`
CounterpartyPortID string `json:"counterparty_port_id" yaml:"counterparty_port_id"`
CounterpartyChannelID string `json:"counterparty_channel_id" yaml:"counterparty_channel_id"`
CounterpartyVersion string `json:"counterparty_version" yaml:"counterparty_version"`
ProofInit commitmentexported.Proof `json:"proof_init" yaml:"proof_init"`
ProofHeight uint64 `json:"proof_height" yaml:"proof_height"`
}
// ChannelOpenAckReq defines the properties of a channel open ack request's body.
type ChannelOpenAckReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
CounterpartyVersion string `json:"counterparty_version" yaml:"counterparty_version"`
ProofTry commitmentexported.Proof `json:"proof_try" yaml:"proof_try"`
ProofHeight uint64 `json:"proof_height" yaml:"proof_height"`
}
// ChannelOpenConfirmReq defines the properties of a channel open confirm request's body.
type ChannelOpenConfirmReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
ProofAck commitmentexported.Proof `json:"proof_ack" yaml:"proof_ack"`
ProofHeight uint64 `json:"proof_height" yaml:"proof_height"`
}
// ConnectionOpenInitReq defines the properties of a channel close init request's body.
type ChannelCloseInitReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
}
// ChannelCloseConfirmReq defines the properties of a channel close confirm request's body.
type ChannelCloseConfirmReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
ProofInit commitmentexported.Proof `json:"proof_init" yaml:"proof_init"`
ProofHeight uint64 `json:"proof_height" yaml:"proof_height"`
}
// RecvPacketReq defines the properties of a receive packet request's body.
type RecvPacketReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
Packet types.Packet `json:"packet" yaml:"packet"`
Proofs commitmentexported.Proof `json:"proofs" yaml:"proofs"`
Height uint64 `json:"height" yaml:"height"`
}

View File

@ -0,0 +1,382 @@
package rest
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/rest"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
)
// RegisterRoutes - Central function to define routes that get registered by the main application
func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) {
r.HandleFunc("/ibc/channels/open-init", channelOpenInitHandlerFn(cliCtx)).Methods("POST")
r.HandleFunc("/ibc/channels/open-try", channelOpenTryHandlerFn(cliCtx)).Methods("POST")
r.HandleFunc(fmt.Sprintf("/ibc/ports/{%s}/channels/{%s}/open-ack", RestPortID, RestChannelID), channelOpenAckHandlerFn(cliCtx)).Methods("POST")
r.HandleFunc(fmt.Sprintf("/ibc/ports/{%s}/channels/{%s}/open-confirm", RestPortID, RestChannelID), channelOpenConfirmHandlerFn(cliCtx)).Methods("POST")
r.HandleFunc(fmt.Sprintf("/ibc/ports/{%s}/channels/{%s}/close-init", RestPortID, RestChannelID), channelCloseInitHandlerFn(cliCtx)).Methods("POST")
r.HandleFunc(fmt.Sprintf("/ibc/ports/{%s}/channels/{%s}/close-confirm", RestPortID, RestChannelID), channelCloseConfirmHandlerFn(cliCtx)).Methods("POST")
r.HandleFunc(fmt.Sprintf("/ibc/packets/receive"), recvPacketHandlerFn(cliCtx)).Methods("POST")
}
// channelOpenInitHandlerFn implements a channel open init handler
//
// @Summary Channel open-init
// @Tags IBC
// @Accept json
// @Produce json
// @Param body body rest.ChannelOpenInitReq true "Channel open-init request body"
// @Success 200 {object} PostChannelOpenInit "OK"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/channels/open-init [post]
func channelOpenInitHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req ChannelOpenInitReq
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
return
}
req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
return
}
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
// create the message
msg := types.NewMsgChannelOpenInit(
req.PortID,
req.ChannelID,
req.Version,
req.ChannelOrder,
req.ConnectionHops,
req.CounterpartyPortID,
req.CounterpartyChannelID,
fromAddr,
)
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg})
}
}
// channelOpenTryHandlerFn implements a channel open try handler
//
// @Summary Channel open-try
// @Tags IBC
// @Accept json
// @Produce json
// @Param body body rest.ChannelOpenTryReq true "Channel open-try request body"
// @Success 200 {object} PostChannelOpenTry "OK"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/channels/open-try [post]
func channelOpenTryHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req ChannelOpenTryReq
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
return
}
req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
return
}
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
// create the message
msg := types.NewMsgChannelOpenTry(
req.PortID,
req.ChannelID,
req.Version,
req.ChannelOrder,
req.ConnectionHops,
req.CounterpartyPortID,
req.CounterpartyChannelID,
req.CounterpartyVersion,
req.ProofInit,
req.ProofHeight,
fromAddr,
)
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg})
}
}
// channelOpenAckHandlerFn implements a channel open ack handler
//
// @Summary Channel open-ack
// @Tags IBC
// @Accept json
// @Produce json
// @Param port-id path string true "Port ID"
// @Param channel-id path string true "Channel ID"
// @Param body body rest.ChannelOpenAckReq true "Channel open-ack request body"
// @Success 200 {object} PostChannelOpenAck "OK"
// @Failure 400 {object} rest.ErrorResponse "Invalid port id or channel id"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/ports/{port-id}/channels/{channel-id}/open-ack [post]
func channelOpenAckHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
portID := vars[RestPortID]
channelID := vars[RestChannelID]
var req ChannelOpenAckReq
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
return
}
req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
return
}
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
// create the message
msg := types.NewMsgChannelOpenAck(
portID,
channelID,
req.CounterpartyVersion,
req.ProofTry,
req.ProofHeight,
fromAddr,
)
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg})
}
}
// channelOpenConfirmHandlerFn implements a channel open confirm handler
//
// @Summary Channel open-confirm
// @Tags IBC
// @Accept json
// @Produce json
// @Param port-id path string true "Port ID"
// @Param channel-id path string true "Channel ID"
// @Param body body rest.ChannelOpenConfirmReq true "Channel open-confirm request body"
// @Success 200 {object} PostChannelOpenConfirm "OK"
// @Failure 400 {object} rest.ErrorResponse "Invalid port id or channel id"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/ports/{port-id}/channels/{channel-id}/open-confirm [post]
func channelOpenConfirmHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
portID := vars[RestPortID]
channelID := vars[RestChannelID]
var req ChannelOpenConfirmReq
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
return
}
req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
return
}
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
// create the message
msg := types.NewMsgChannelOpenConfirm(
portID,
channelID,
req.ProofAck,
req.ProofHeight,
fromAddr,
)
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg})
}
}
// channelCloseInitHandlerFn implements a channel close init handler
//
// @Summary Channel close-init
// @Tags IBC
// @Accept json
// @Produce json
// @Param port-id path string true "Port ID"
// @Param channel-id path string true "Channel ID"
// @Param body body rest.ChannelCloseInitReq true "Channel close-init request body"
// @Success 200 {object} PostChannelCloseInit "OK"
// @Failure 400 {object} rest.ErrorResponse "Invalid port id or channel id"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/ports/{port-id}/channels/{channel-id}/close-init [post]
func channelCloseInitHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
portID := vars[RestPortID]
channelID := vars[RestChannelID]
var req ChannelCloseInitReq
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
return
}
req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
return
}
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
// create the message
msg := types.NewMsgChannelCloseInit(
portID,
channelID,
fromAddr,
)
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg})
}
}
// channelCloseConfirmHandlerFn implements a channel close confirm handler
//
// @Summary Channel close-confirm
// @Tags IBC
// @Accept json
// @Produce json
// @Param port-id path string true "Port ID"
// @Param channel-id path string true "Channel ID"
// @Param body body rest.ChannelCloseConfirmReq true "Channel close-confirm request body"
// @Success 200 {object} PostChannelCloseConfirm "OK"
// @Failure 400 {object} rest.ErrorResponse "Invalid port id or channel id"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/ports/{port-id}/channels/{channel-id}/close-confirm [post]
func channelCloseConfirmHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
portID := vars[RestPortID]
channelID := vars[RestChannelID]
var req ChannelCloseConfirmReq
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
return
}
req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
return
}
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
// create the message
msg := types.NewMsgChannelCloseConfirm(
portID,
channelID,
req.ProofInit,
req.ProofHeight,
fromAddr,
)
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg})
}
}
// recvPacketHandlerFn implements a receive packet handler
//
// @Summary Receive packet
// @Tags IBC
// @Accept json
// @Produce json
// @Param body body rest.RecvPacketReq true "Receive packet request body"
// @Success 200 {object} PostRecvPacket "OK"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/packets/receive [post]
func recvPacketHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req RecvPacketReq
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
return
}
req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
return
}
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
// create the message
msg := types.NewMsgPacket(
req.Packet,
req.Proofs,
req.Height,
fromAddr,
)
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg})
}
}

View File

@ -0,0 +1,69 @@
package utils
import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types"
)
// QueryPacket returns a packet from the store
func QueryPacket(
ctx context.CLIContext, portID, channelID string,
sequence, timeout uint64, prove bool,
) (types.PacketResponse, error) {
req := abci.RequestQuery{
Path: "store/ibc/key",
Data: ibctypes.KeyPacketCommitment(portID, channelID, sequence),
Prove: prove,
}
res, err := ctx.QueryABCI(req)
if err != nil {
return types.PacketResponse{}, err
}
channelRes, err := QueryChannel(ctx, portID, channelID, prove)
if err != nil {
return types.PacketResponse{}, err
}
destPortID := channelRes.Channel.Channel.Counterparty.PortID
destChannelID := channelRes.Channel.Channel.Counterparty.ChannelID
packet := types.NewPacket(
res.Value,
sequence,
portID,
channelID,
destPortID,
destChannelID,
timeout,
)
// FIXME: res.Height+1 is hack, fix later
return types.NewPacketResponse(portID, channelID, sequence, packet, res.Proof, res.Height+1), nil
}
// QueryChannel queries the store to get a channel and a merkle proof.
func QueryChannel(
ctx context.CLIContext, portID, channelID string, prove bool,
) (types.ChannelResponse, error) {
req := abci.RequestQuery{
Path: "store/ibc/key",
Data: ibctypes.KeyChannel(portID, channelID),
Prove: prove,
}
res, err := ctx.QueryABCI(req)
if res.Value == nil || err != nil {
return types.ChannelResponse{}, err
}
var channel types.Channel
if err := ctx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &channel); err != nil {
return types.ChannelResponse{}, err
}
return types.NewChannelResponse(portID, channelID, channel, res.Proof, res.Height), nil
}

View File

@ -0,0 +1,170 @@
package exported
import (
"encoding/json"
"fmt"
)
// ChannelI defines the standard interface for a channel end.
type ChannelI interface {
GetState() State
GetOrdering() Order
GetCounterparty() CounterpartyI
GetConnectionHops() []string
GetVersion() string
ValidateBasic() error
}
// CounterpartyI defines the standard interface for a channel end's
// counterparty.
type CounterpartyI interface {
GetPortID() string
GetChannelID() string
ValidateBasic() error
}
// PacketI defines the standard interface for IBC packets
type PacketI interface {
GetSequence() uint64
GetTimeoutHeight() uint64
GetSourcePort() string
GetSourceChannel() string
GetDestPort() string
GetDestChannel() string
GetData() []byte
ValidateBasic() error
}
// Order defines if a channel is ORDERED or UNORDERED
type Order byte
// string representation of the channel ordering
const (
NONE Order = iota // zero-value for channel ordering
UNORDERED // packets can be delivered in any order, which may differ from the order in which they were sent.
ORDERED // packets are delivered exactly in the order which they were sent
)
// channel order types
const (
OrderNone string = ""
OrderUnordered string = "UNORDERED"
OrderOrdered string = "ORDERED"
)
// String implements the Stringer interface
func (o Order) String() string {
switch o {
case UNORDERED:
return OrderUnordered
case ORDERED:
return OrderOrdered
default:
return OrderNone
}
}
// MarshalJSON marshal to JSON using string.
func (o Order) MarshalJSON() ([]byte, error) {
return json.Marshal(o.String())
}
// UnmarshalJSON decodes from JSON.
func (o *Order) UnmarshalJSON(data []byte) error {
var s string
err := json.Unmarshal(data, &s)
if err != nil {
return err
}
order := OrderFromString(s)
if order == 0 {
return fmt.Errorf("invalid order '%s'", s)
}
*o = order
return nil
}
// OrderFromString parses a string into a channel order byte
func OrderFromString(order string) Order {
switch order {
case OrderUnordered:
return UNORDERED
case OrderOrdered:
return ORDERED
default:
return NONE
}
}
// State defines if a channel is in one of the following states:
// CLOSED, INIT, OPENTRY or OPEN
type State byte
// channel state types
const (
UNINITIALIZED State = iota // Default State
INIT // A channel end has just started the opening handshake.
TRYOPEN // A channel end has acknowledged the handshake step on the counterparty chain.
OPEN // A channel end has completed the handshake and is ready to send and receive packets.
CLOSED // A channel end has been closed and can no longer be used to send or receive packets.
)
// string representation of the channel states
const (
StateUninitialized string = "UNINITIALIZED"
StateInit string = "INIT"
StateTryOpen string = "TRYOPEN"
StateOpen string = "OPEN"
StateClosed string = "CLOSED"
)
// String implements the Stringer interface
func (s State) String() string {
switch s {
case INIT:
return StateInit
case TRYOPEN:
return StateTryOpen
case OPEN:
return StateOpen
case CLOSED:
return StateClosed
default:
return StateUninitialized
}
}
// MarshalJSON marshal to JSON using string.
func (s State) MarshalJSON() ([]byte, error) {
return json.Marshal(s.String())
}
// UnmarshalJSON decodes from JSON.
func (s *State) UnmarshalJSON(data []byte) error {
var stateStr string
err := json.Unmarshal(data, &stateStr)
if err != nil {
return err
}
*s = StateFromString(stateStr)
return nil
}
// StateFromString parses a string into a channel state byte
func StateFromString(state string) State {
switch state {
case StateClosed:
return CLOSED
case StateInit:
return INIT
case StateTryOpen:
return TRYOPEN
case StateOpen:
return OPEN
default:
return UNINITIALIZED
}
}

View File

@ -0,0 +1,91 @@
package exported
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestChannelStateString(t *testing.T) {
cases := []struct {
name string
state State
}{
{StateUninitialized, UNINITIALIZED},
{StateInit, INIT},
{StateTryOpen, TRYOPEN},
{StateOpen, OPEN},
{StateClosed, CLOSED},
}
for _, tt := range cases {
tt := tt
require.Equal(t, tt.state, StateFromString(tt.name))
require.Equal(t, tt.name, tt.state.String())
}
}
func TestChannelStateMarshalJSON(t *testing.T) {
cases := []struct {
name string
state State
}{
{StateUninitialized, UNINITIALIZED},
{StateInit, INIT},
{StateTryOpen, TRYOPEN},
{StateOpen, OPEN},
{StateClosed, CLOSED},
}
for _, tt := range cases {
tt := tt
bz, err := tt.state.MarshalJSON()
require.NoError(t, err)
var state State
require.NoError(t, state.UnmarshalJSON(bz))
require.Equal(t, tt.name, state.String())
}
}
func TestOrderString(t *testing.T) {
cases := []struct {
name string
order Order
}{
{OrderNone, NONE},
{OrderUnordered, UNORDERED},
{OrderOrdered, ORDERED},
}
for _, tt := range cases {
tt := tt
require.Equal(t, tt.order, OrderFromString(tt.name))
require.Equal(t, tt.name, tt.order.String())
}
}
func TestOrderMarshalJSON(t *testing.T) {
cases := []struct {
msg string
name string
order Order
expectPass bool
}{
{"none ordering should have failed", OrderNone, NONE, false},
{"unordered should have passed", OrderUnordered, UNORDERED, true},
{"ordered should have passed", OrderOrdered, ORDERED, true},
}
for _, tt := range cases {
tt := tt
bz, err := tt.order.MarshalJSON()
require.NoError(t, err)
var order Order
if tt.expectPass {
require.NoError(t, order.UnmarshalJSON(bz), tt.msg)
require.Equal(t, tt.name, order.String(), tt.msg)
} else {
require.Error(t, order.UnmarshalJSON(bz), tt.msg)
}
}
}

171
x/ibc/04-channel/handler.go Normal file
View File

@ -0,0 +1,171 @@
package channel
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/capability"
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/keeper"
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
)
// HandleMsgChannelOpenInit defines the sdk.Handler for MsgChannelOpenInit
func HandleMsgChannelOpenInit(ctx sdk.Context, k keeper.Keeper, portCap *capability.Capability, msg types.MsgChannelOpenInit) (*sdk.Result, *capability.Capability, error) {
capKey, err := k.ChanOpenInit(
ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID,
portCap, msg.Channel.Counterparty, msg.Channel.Version,
)
if err != nil {
return nil, nil, err
}
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeChannelOpenInit,
sdk.NewAttribute(types.AttributeKeyPortID, msg.PortID),
sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID),
sdk.NewAttribute(types.AttributeCounterpartyPortID, msg.Channel.Counterparty.PortID),
sdk.NewAttribute(types.AttributeCounterpartyChannelID, msg.Channel.Counterparty.ChannelID),
sdk.NewAttribute(types.AttributeKeyConnectionID, msg.Channel.ConnectionHops[0]), // TODO: iterate
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()),
),
})
return &sdk.Result{
Events: ctx.EventManager().Events().ToABCIEvents(),
}, capKey, nil
}
// HandleMsgChannelOpenTry defines the sdk.Handler for MsgChannelOpenTry
func HandleMsgChannelOpenTry(ctx sdk.Context, k keeper.Keeper, portCap *capability.Capability, msg types.MsgChannelOpenTry) (*sdk.Result, *capability.Capability, error) {
capKey, err := k.ChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID,
portCap, msg.Channel.Counterparty, msg.Channel.Version, msg.CounterpartyVersion, msg.ProofInit, msg.ProofHeight,
)
if err != nil {
return nil, nil, err
}
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeChannelOpenTry,
sdk.NewAttribute(types.AttributeKeyPortID, msg.PortID),
sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID),
sdk.NewAttribute(types.AttributeCounterpartyPortID, msg.Channel.Counterparty.PortID),
sdk.NewAttribute(types.AttributeCounterpartyChannelID, msg.Channel.Counterparty.ChannelID),
sdk.NewAttribute(types.AttributeKeyConnectionID, msg.Channel.ConnectionHops[0]), // TODO: iterate
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()),
),
})
return &sdk.Result{
Events: ctx.EventManager().Events().ToABCIEvents(),
}, capKey, nil
}
// HandleMsgChannelOpenAck defines the sdk.Handler for MsgChannelOpenAck
func HandleMsgChannelOpenAck(ctx sdk.Context, k keeper.Keeper, channelCap *capability.Capability, msg types.MsgChannelOpenAck) (*sdk.Result, error) {
err := k.ChanOpenAck(
ctx, msg.PortID, msg.ChannelID, channelCap, msg.CounterpartyVersion, msg.ProofTry, msg.ProofHeight,
)
if err != nil {
return nil, err
}
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeChannelOpenAck,
sdk.NewAttribute(types.AttributeKeyPortID, msg.PortID),
sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()),
),
})
return &sdk.Result{
Events: ctx.EventManager().Events().ToABCIEvents(),
}, nil
}
// HandleMsgChannelOpenConfirm defines the sdk.Handler for MsgChannelOpenConfirm
func HandleMsgChannelOpenConfirm(ctx sdk.Context, k keeper.Keeper, channelCap *capability.Capability, msg types.MsgChannelOpenConfirm) (*sdk.Result, error) {
err := k.ChanOpenConfirm(ctx, msg.PortID, msg.ChannelID, channelCap, msg.ProofAck, msg.ProofHeight)
if err != nil {
return nil, err
}
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeChannelOpenConfirm,
sdk.NewAttribute(types.AttributeKeyPortID, msg.PortID),
sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()),
),
})
return &sdk.Result{
Events: ctx.EventManager().Events().ToABCIEvents(),
}, nil
}
// HandleMsgChannelCloseInit defines the sdk.Handler for MsgChannelCloseInit
func HandleMsgChannelCloseInit(ctx sdk.Context, k keeper.Keeper, channelCap *capability.Capability, msg types.MsgChannelCloseInit) (*sdk.Result, error) {
err := k.ChanCloseInit(ctx, msg.PortID, msg.ChannelID, channelCap)
if err != nil {
return nil, err
}
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeChannelCloseInit,
sdk.NewAttribute(types.AttributeKeyPortID, msg.PortID),
sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()),
),
})
return &sdk.Result{
Events: ctx.EventManager().Events().ToABCIEvents(),
}, nil
}
// HandleMsgChannelCloseConfirm defines the sdk.Handler for MsgChannelCloseConfirm
func HandleMsgChannelCloseConfirm(ctx sdk.Context, k keeper.Keeper, channelCap *capability.Capability, msg types.MsgChannelCloseConfirm) (*sdk.Result, error) {
err := k.ChanCloseConfirm(ctx, msg.PortID, msg.ChannelID, channelCap, msg.ProofInit, msg.ProofHeight)
if err != nil {
return nil, err
}
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeChannelCloseConfirm,
sdk.NewAttribute(types.AttributeKeyPortID, msg.PortID),
sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()),
),
})
return &sdk.Result{
Events: ctx.EventManager().Events().ToABCIEvents(),
}, nil
}

View File

@ -0,0 +1,393 @@
package keeper
import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/capability"
connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection"
connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
porttypes "github.com/cosmos/cosmos-sdk/x/ibc/05-port/types"
commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported"
ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types"
)
// CounterpartyHops returns the connection hops of the counterparty channel.
// The counterparty hops are stored in the inverse order as the channel's.
func (k Keeper) CounterpartyHops(ctx sdk.Context, ch types.Channel) ([]string, bool) {
counterPartyHops := make([]string, len(ch.ConnectionHops))
for i, hop := range ch.ConnectionHops {
connection, found := k.connectionKeeper.GetConnection(ctx, hop)
if !found {
return []string{}, false
}
counterPartyHops[len(counterPartyHops)-1-i] = connection.GetCounterparty().GetConnectionID()
}
return counterPartyHops, true
}
// ChanOpenInit is called by a module to initiate a channel opening handshake with
// a module on another chain.
func (k Keeper) ChanOpenInit(
ctx sdk.Context,
order exported.Order,
connectionHops []string,
portID,
channelID string,
portCap *capability.Capability,
counterparty types.Counterparty,
version string,
) (*capability.Capability, error) {
// channel identifier and connection hop length checked on msg.ValidateBasic()
_, found := k.GetChannel(ctx, portID, channelID)
if found {
return nil, sdkerrors.Wrap(types.ErrChannelExists, channelID)
}
connectionEnd, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0])
if !found {
return nil, sdkerrors.Wrap(connection.ErrConnectionNotFound, connectionHops[0])
}
if connectionEnd.GetState() == connectionexported.UNINITIALIZED {
return nil, sdkerrors.Wrap(
connection.ErrInvalidConnectionState,
"connection state cannot be UNINITIALIZED",
)
}
if !k.portKeeper.Authenticate(ctx, portCap, portID) {
return nil, sdkerrors.Wrap(porttypes.ErrInvalidPort, "caller does not own port capability")
}
channel := types.NewChannel(exported.INIT, order, counterparty, connectionHops, version)
k.SetChannel(ctx, portID, channelID, channel)
capKey, err := k.scopedKeeper.NewCapability(ctx, ibctypes.ChannelCapabilityPath(portID, channelID))
if err != nil {
return nil, sdkerrors.Wrap(types.ErrInvalidChannelCapability, err.Error())
}
k.SetNextSequenceSend(ctx, portID, channelID, 1)
k.SetNextSequenceRecv(ctx, portID, channelID, 1)
return capKey, nil
}
// ChanOpenTry is called by a module to accept the first step of a channel opening
// handshake initiated by a module on another chain.
func (k Keeper) ChanOpenTry(
ctx sdk.Context,
order exported.Order,
connectionHops []string,
portID,
channelID string,
portCap *capability.Capability,
counterparty types.Counterparty,
version,
counterpartyVersion string,
proofInit commitmentexported.Proof,
proofHeight uint64,
) (*capability.Capability, error) {
// channel identifier and connection hop length checked on msg.ValidateBasic()
previousChannel, found := k.GetChannel(ctx, portID, channelID)
if found && !(previousChannel.State == exported.INIT &&
previousChannel.Ordering == order &&
previousChannel.Counterparty.PortID == counterparty.PortID &&
previousChannel.Counterparty.ChannelID == counterparty.ChannelID &&
previousChannel.ConnectionHops[0] == connectionHops[0] &&
previousChannel.Version == version) {
sdkerrors.Wrap(types.ErrInvalidChannel, "cannot relay connection attempt")
}
if !k.portKeeper.Authenticate(ctx, portCap, portID) {
return nil, sdkerrors.Wrap(porttypes.ErrInvalidPort, "caller does not own port capability")
}
connectionEnd, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0])
if !found {
return nil, sdkerrors.Wrap(connection.ErrConnectionNotFound, connectionHops[0])
}
if connectionEnd.GetState() != connectionexported.OPEN {
return nil, sdkerrors.Wrapf(
connection.ErrInvalidConnectionState,
"connection state is not OPEN (got %s)", connectionEnd.GetState().String(),
)
}
// NOTE: this step has been switched with the one below to reverse the connection
// hops
channel := types.NewChannel(exported.TRYOPEN, order, counterparty, connectionHops, version)
counterpartyHops, found := k.CounterpartyHops(ctx, channel)
if !found {
// should not reach here, connectionEnd was able to be retrieved above
panic("cannot find connection")
}
// expectedCounterpaty is the counterparty of the counterparty's channel end
// (i.e self)
expectedCounterparty := types.NewCounterparty(portID, channelID)
expectedChannel := types.NewChannel(
exported.INIT, channel.Ordering, expectedCounterparty,
counterpartyHops, channel.Version,
)
if err := k.connectionKeeper.VerifyChannelState(
ctx, connectionEnd, proofHeight, proofInit,
counterparty.PortID, counterparty.ChannelID, expectedChannel,
); err != nil {
return nil, err
}
k.SetChannel(ctx, portID, channelID, channel)
capKey, err := k.scopedKeeper.NewCapability(ctx, ibctypes.ChannelCapabilityPath(portID, channelID))
if err != nil {
return nil, sdkerrors.Wrap(types.ErrInvalidChannelCapability, err.Error())
}
k.SetNextSequenceSend(ctx, portID, channelID, 1)
k.SetNextSequenceRecv(ctx, portID, channelID, 1)
return capKey, nil
}
// ChanOpenAck is called by the handshake-originating module to acknowledge the
// acceptance of the initial request by the counterparty module on the other chain.
func (k Keeper) ChanOpenAck(
ctx sdk.Context,
portID,
channelID string,
chanCap *capability.Capability,
counterpartyVersion string,
proofTry commitmentexported.Proof,
proofHeight uint64,
) error {
channel, found := k.GetChannel(ctx, portID, channelID)
if !found {
return sdkerrors.Wrap(types.ErrChannelNotFound, channelID)
}
if !(channel.State == exported.INIT || channel.State == exported.TRYOPEN) {
return sdkerrors.Wrapf(
types.ErrInvalidChannelState,
"channel state should be INIT or TRYOPEN (got %s)", channel.State.String(),
)
}
if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, ibctypes.ChannelCapabilityPath(portID, channelID)) {
return sdkerrors.Wrap(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel")
}
connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0])
if !found {
return sdkerrors.Wrap(connection.ErrConnectionNotFound, channel.ConnectionHops[0])
}
if connectionEnd.GetState() != connectionexported.OPEN {
return sdkerrors.Wrapf(
connection.ErrInvalidConnectionState,
"connection state is not OPEN (got %s)", connectionEnd.GetState().String(),
)
}
counterpartyHops, found := k.CounterpartyHops(ctx, channel)
if !found {
// should not reach here, connectionEnd was able to be retrieved above
panic("cannot find connection")
}
// counterparty of the counterparty channel end (i.e self)
counterparty := types.NewCounterparty(portID, channelID)
expectedChannel := types.NewChannel(
exported.TRYOPEN, channel.Ordering, counterparty,
counterpartyHops, channel.Version,
)
if err := k.connectionKeeper.VerifyChannelState(
ctx, connectionEnd, proofHeight, proofTry,
channel.Counterparty.PortID, channel.Counterparty.ChannelID,
expectedChannel,
); err != nil {
return err
}
channel.State = exported.OPEN
channel.Version = counterpartyVersion
k.SetChannel(ctx, portID, channelID, channel)
return nil
}
// ChanOpenConfirm is called by the counterparty module to close their end of the
// channel, since the other end has been closed.
func (k Keeper) ChanOpenConfirm(
ctx sdk.Context,
portID,
channelID string,
chanCap *capability.Capability,
proofAck commitmentexported.Proof,
proofHeight uint64,
) error {
channel, found := k.GetChannel(ctx, portID, channelID)
if !found {
return sdkerrors.Wrap(types.ErrChannelNotFound, channelID)
}
if channel.State != exported.TRYOPEN {
return sdkerrors.Wrapf(
types.ErrInvalidChannelState,
"channel state is not TRYOPEN (got %s)", channel.State.String(),
)
}
if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, ibctypes.ChannelCapabilityPath(portID, channelID)) {
return sdkerrors.Wrap(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel")
}
connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0])
if !found {
return sdkerrors.Wrap(connection.ErrConnectionNotFound, channel.ConnectionHops[0])
}
if connectionEnd.GetState() != connectionexported.OPEN {
return sdkerrors.Wrapf(
connection.ErrInvalidConnectionState,
"connection state is not OPEN (got %s)", connectionEnd.GetState().String(),
)
}
counterpartyHops, found := k.CounterpartyHops(ctx, channel)
if !found {
// Should not reach here, connectionEnd was able to be retrieved above
panic("cannot find connection")
}
counterparty := types.NewCounterparty(portID, channelID)
expectedChannel := types.NewChannel(
exported.OPEN, channel.Ordering, counterparty,
counterpartyHops, channel.Version,
)
if err := k.connectionKeeper.VerifyChannelState(
ctx, connectionEnd, proofHeight, proofAck,
channel.Counterparty.PortID, channel.Counterparty.ChannelID,
expectedChannel,
); err != nil {
return err
}
channel.State = exported.OPEN
k.SetChannel(ctx, portID, channelID, channel)
return nil
}
// Closing Handshake
//
// This section defines the set of functions required to close a channel handshake
// as defined in https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#closing-handshake
// ChanCloseInit is called by either module to close their end of the channel. Once
// closed, channels cannot be reopened.
func (k Keeper) ChanCloseInit(
ctx sdk.Context,
portID,
channelID string,
chanCap *capability.Capability,
) error {
if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, ibctypes.ChannelCapabilityPath(portID, channelID)) {
return sdkerrors.Wrap(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel")
}
channel, found := k.GetChannel(ctx, portID, channelID)
if !found {
return sdkerrors.Wrap(types.ErrChannelNotFound, channelID)
}
if channel.State == exported.CLOSED {
return sdkerrors.Wrap(types.ErrInvalidChannelState, "channel is already CLOSED")
}
connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0])
if !found {
return sdkerrors.Wrap(connection.ErrConnectionNotFound, channel.ConnectionHops[0])
}
if connectionEnd.GetState() != connectionexported.OPEN {
return sdkerrors.Wrapf(
connection.ErrInvalidConnectionState,
"connection state is not OPEN (got %s)", connectionEnd.GetState().String(),
)
}
channel.State = exported.CLOSED
k.SetChannel(ctx, portID, channelID, channel)
k.Logger(ctx).Info("channel close initialized: portID (%s), channelID (%s)", portID, channelID)
return nil
}
// ChanCloseConfirm is called by the counterparty module to close their end of the
// channel, since the other end has been closed.
func (k Keeper) ChanCloseConfirm(
ctx sdk.Context,
portID,
channelID string,
chanCap *capability.Capability,
proofInit commitmentexported.Proof,
proofHeight uint64,
) error {
if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, ibctypes.ChannelCapabilityPath(portID, channelID)) {
return sdkerrors.Wrap(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel")
}
channel, found := k.GetChannel(ctx, portID, channelID)
if !found {
return sdkerrors.Wrap(types.ErrChannelNotFound, channelID)
}
if channel.State == exported.CLOSED {
return sdkerrors.Wrap(types.ErrInvalidChannelState, "channel is already CLOSED")
}
connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0])
if !found {
return sdkerrors.Wrap(connection.ErrConnectionNotFound, channel.ConnectionHops[0])
}
if connectionEnd.GetState() != connectionexported.OPEN {
return sdkerrors.Wrapf(
connection.ErrInvalidConnectionState,
"connection state is not OPEN (got %s)", connectionEnd.GetState().String(),
)
}
counterpartyHops, found := k.CounterpartyHops(ctx, channel)
if !found {
// Should not reach here, connectionEnd was able to be retrieved above
panic("cannot find connection")
}
counterparty := types.NewCounterparty(portID, channelID)
expectedChannel := types.NewChannel(
exported.CLOSED, channel.Ordering, counterparty,
counterpartyHops, channel.Version,
)
if err := k.connectionKeeper.VerifyChannelState(
ctx, connectionEnd, proofHeight, proofInit,
channel.Counterparty.PortID, channel.Counterparty.ChannelID,
expectedChannel,
); err != nil {
return err
}
channel.State = exported.CLOSED
k.SetChannel(ctx, portID, channelID, channel)
return nil
}

Some files were not shown because too many files have changed in this diff Show More