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:
parent
8eb4808b0e
commit
b5a6587291
16
CHANGELOG.md
16
CHANGELOG.md
@ -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
|
||||
|
||||
|
||||
@ -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
1199
client/lcd/swagger-ui/swagger.yaml
vendored
1199
client/lcd/swagger-ui/swagger.yaml
vendored
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
2
docs/package-lock.json
generated
2
docs/package-lock.json
generated
@ -10661,4 +10661,4 @@
|
||||
"integrity": "sha1-4Se9nmb9hGvl6rSME5SIL3wOT5g="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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.
|
||||
120
simapp/app.go
120
simapp/app.go
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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:]]*`
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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"
|
||||
|
||||
|
||||
@ -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)))
|
||||
}
|
||||
|
||||
@ -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
|
||||
)
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
42
x/capability/alias.go
Normal 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
|
||||
)
|
||||
89
x/capability/docs/README.md
Normal file
89
x/capability/docs/README.md
Normal 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.
|
||||
325
x/capability/keeper/keeper.go
Normal file
325
x/capability/keeper/keeper.go
Normal 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))
|
||||
}
|
||||
245
x/capability/keeper/keeper_test.go
Normal file
245
x/capability/keeper/keeper_test.go
Normal 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
117
x/capability/module.go
Normal 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{}
|
||||
}
|
||||
30
x/capability/types/codec.go
Normal file
30
x/capability/types/codec.go
Normal 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()
|
||||
}
|
||||
14
x/capability/types/errors.go
Normal file
14
x/capability/types/errors.go
Normal 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")
|
||||
)
|
||||
51
x/capability/types/keys.go
Normal file
51
x/capability/types/keys.go
Normal 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)
|
||||
}
|
||||
29
x/capability/types/keys_test.go
Normal file
29
x/capability/types/keys_test.go
Normal 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}))
|
||||
}
|
||||
56
x/capability/types/store.go
Normal file
56
x/capability/types/store.go
Normal 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))
|
||||
}
|
||||
87
x/capability/types/types.go
Normal file
87
x/capability/types/types.go
Normal 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
|
||||
}
|
||||
710
x/capability/types/types.pb.go
Normal file
710
x/capability/types/types.pb.go
Normal 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")
|
||||
)
|
||||
33
x/capability/types/types.proto
Normal file
33
x/capability/types/types.proto
Normal 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
|
||||
];
|
||||
}
|
||||
69
x/capability/types/types_test.go
Normal file
69
x/capability/types/types_test.go
Normal 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)
|
||||
}
|
||||
@ -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,
|
||||
|
||||
@ -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
51
x/ibc/02-client/alias.go
Normal 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
|
||||
)
|
||||
28
x/ibc/02-client/client/cli/cli.go
Normal file
28
x/ibc/02-client/client/cli/cli.go
Normal 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
|
||||
}
|
||||
180
x/ibc/02-client/client/cli/query.go
Normal file
180
x/ibc/02-client/client/cli/query.go
Normal 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)
|
||||
},
|
||||
}
|
||||
}
|
||||
172
x/ibc/02-client/client/rest/query.go
Normal file
172
x/ibc/02-client/client/rest/query.go
Normal 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)
|
||||
}
|
||||
}
|
||||
18
x/ibc/02-client/client/rest/rest.go
Normal file
18
x/ibc/02-client/client/rest/rest.go
Normal 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)
|
||||
}
|
||||
157
x/ibc/02-client/client/utils/utils.go
Normal file
157
x/ibc/02-client/client/utils/utils.go
Normal 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
10
x/ibc/02-client/doc.go
Normal 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
|
||||
193
x/ibc/02-client/exported/exported.go
Normal file
193
x/ibc/02-client/exported/exported.go
Normal 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
|
||||
}
|
||||
}
|
||||
49
x/ibc/02-client/exported/exported_test.go
Normal file
49
x/ibc/02-client/exported/exported_test.go
Normal 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
104
x/ibc/02-client/handler.go
Normal 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)
|
||||
}
|
||||
}
|
||||
153
x/ibc/02-client/keeper/client.go
Normal file
153
x/ibc/02-client/keeper/client.go
Normal 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
|
||||
}
|
||||
316
x/ibc/02-client/keeper/client_test.go
Normal file
316
x/ibc/02-client/keeper/client_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
171
x/ibc/02-client/keeper/keeper.go
Normal file
171
x/ibc/02-client/keeper/keeper.go
Normal 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
|
||||
}
|
||||
188
x/ibc/02-client/keeper/keeper_test.go
Normal file
188
x/ibc/02-client/keeper/keeper_test.go
Normal 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)
|
||||
}
|
||||
37
x/ibc/02-client/keeper/querier.go
Normal file
37
x/ibc/02-client/keeper/querier.go
Normal 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, ¶ms); 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
28
x/ibc/02-client/module.go
Normal 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)
|
||||
}
|
||||
25
x/ibc/02-client/types/codec.go
Normal file
25
x/ibc/02-client/types/codec.go
Normal 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
|
||||
}
|
||||
27
x/ibc/02-client/types/errors.go
Normal file
27
x/ibc/02-client/types/errors.go
Normal 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")
|
||||
)
|
||||
22
x/ibc/02-client/types/events.go
Normal file
22
x/ibc/02-client/types/events.go
Normal 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)
|
||||
)
|
||||
14
x/ibc/02-client/types/expected_keepers.go
Normal file
14
x/ibc/02-client/types/expected_keepers.go
Normal 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
|
||||
}
|
||||
12
x/ibc/02-client/types/keys.go
Normal file
12
x/ibc/02-client/types/keys.go
Normal 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
|
||||
)
|
||||
75
x/ibc/02-client/types/querier.go
Normal file
75
x/ibc/02-client/types/querier.go
Normal 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),
|
||||
}
|
||||
}
|
||||
72
x/ibc/03-connection/alias.go
Normal file
72
x/ibc/03-connection/alias.go
Normal 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
|
||||
)
|
||||
41
x/ibc/03-connection/client/cli/cli.go
Normal file
41
x/ibc/03-connection/client/cli/cli.go
Normal 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
|
||||
}
|
||||
107
x/ibc/03-connection/client/cli/query.go
Normal file
107
x/ibc/03-connection/client/cli/query.go
Normal 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)
|
||||
},
|
||||
}
|
||||
}
|
||||
251
x/ibc/03-connection/client/cli/tx.go
Normal file
251
x/ibc/03-connection/client/cli/tx.go
Normal 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
|
||||
}
|
||||
84
x/ibc/03-connection/client/rest/query.go
Normal file
84
x/ibc/03-connection/client/rest/query.go
Normal 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)
|
||||
}
|
||||
}
|
||||
62
x/ibc/03-connection/client/rest/rest.go
Normal file
62
x/ibc/03-connection/client/rest/rest.go
Normal 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"`
|
||||
}
|
||||
204
x/ibc/03-connection/client/rest/tx.go
Normal file
204
x/ibc/03-connection/client/rest/tx.go
Normal 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})
|
||||
}
|
||||
}
|
||||
124
x/ibc/03-connection/client/utils/utils.go
Normal file
124
x/ibc/03-connection/client/utils/utils.go
Normal 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
|
||||
}
|
||||
89
x/ibc/03-connection/exported/exported.go
Normal file
89
x/ibc/03-connection/exported/exported.go
Normal 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
|
||||
}
|
||||
46
x/ibc/03-connection/exported/exported_test.go
Normal file
46
x/ibc/03-connection/exported/exported_test.go
Normal 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())
|
||||
}
|
||||
}
|
||||
113
x/ibc/03-connection/handler.go
Normal file
113
x/ibc/03-connection/handler.go
Normal 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
|
||||
}
|
||||
234
x/ibc/03-connection/keeper/handshake.go
Normal file
234
x/ibc/03-connection/keeper/handshake.go
Normal 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
|
||||
}
|
||||
286
x/ibc/03-connection/keeper/handshake_test.go
Normal file
286
x/ibc/03-connection/keeper/handshake_test.go
Normal 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
|
||||
}
|
||||
156
x/ibc/03-connection/keeper/keeper.go
Normal file
156
x/ibc/03-connection/keeper/keeper.go
Normal 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
|
||||
}
|
||||
318
x/ibc/03-connection/keeper/keeper_test.go
Normal file
318
x/ibc/03-connection/keeper/keeper_test.go
Normal 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)
|
||||
}
|
||||
57
x/ibc/03-connection/keeper/querier.go
Normal file
57
x/ibc/03-connection/keeper/querier.go
Normal 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, ¶ms); 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, ¶ms); 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
|
||||
}
|
||||
236
x/ibc/03-connection/keeper/verify.go
Normal file
236
x/ibc/03-connection/keeper/verify.go
Normal 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,
|
||||
)
|
||||
}
|
||||
427
x/ibc/03-connection/keeper/verify_test.go
Normal file
427
x/ibc/03-connection/keeper/verify_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
33
x/ibc/03-connection/module.go
Normal file
33
x/ibc/03-connection/module.go
Normal 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))
|
||||
}
|
||||
28
x/ibc/03-connection/types/codec.go
Normal file
28
x/ibc/03-connection/types/codec.go
Normal 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
|
||||
}
|
||||
133
x/ibc/03-connection/types/connection.go
Normal file
133
x/ibc/03-connection/types/connection.go
Normal 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
|
||||
}
|
||||
79
x/ibc/03-connection/types/connection_test.go
Normal file
79
x/ibc/03-connection/types/connection_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
16
x/ibc/03-connection/types/errors.go
Normal file
16
x/ibc/03-connection/types/errors.go
Normal 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")
|
||||
)
|
||||
24
x/ibc/03-connection/types/events.go
Normal file
24
x/ibc/03-connection/types/events.go
Normal 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)
|
||||
)
|
||||
13
x/ibc/03-connection/types/expected_keepers.go
Normal file
13
x/ibc/03-connection/types/expected_keepers.go
Normal 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)
|
||||
}
|
||||
15
x/ibc/03-connection/types/keys.go
Normal file
15
x/ibc/03-connection/types/keys.go
Normal 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
|
||||
)
|
||||
310
x/ibc/03-connection/types/msgs.go
Normal file
310
x/ibc/03-connection/types/msgs.go
Normal 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}
|
||||
}
|
||||
215
x/ibc/03-connection/types/msgs_test.go
Normal file
215
x/ibc/03-connection/types/msgs_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
93
x/ibc/03-connection/types/querier.go
Normal file
93
x/ibc/03-connection/types/querier.go
Normal 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,
|
||||
}
|
||||
}
|
||||
96
x/ibc/03-connection/types/version.go
Normal file
96
x/ibc/03-connection/types/version.go
Normal 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
85
x/ibc/04-channel/alias.go
Normal 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
|
||||
)
|
||||
42
x/ibc/04-channel/client/cli/cli.go
Normal file
42
x/ibc/04-channel/client/cli/cli.go
Normal 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
|
||||
}
|
||||
47
x/ibc/04-channel/client/cli/query.go
Normal file
47
x/ibc/04-channel/client/cli/query.go
Normal 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
|
||||
}
|
||||
251
x/ibc/04-channel/client/cli/tx.go
Normal file
251
x/ibc/04-channel/client/cli/tx.go
Normal 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
|
||||
}
|
||||
52
x/ibc/04-channel/client/rest/query.go
Normal file
52
x/ibc/04-channel/client/rest/query.go
Normal 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)
|
||||
}
|
||||
}
|
||||
84
x/ibc/04-channel/client/rest/rest.go
Normal file
84
x/ibc/04-channel/client/rest/rest.go
Normal 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"`
|
||||
}
|
||||
382
x/ibc/04-channel/client/rest/tx.go
Normal file
382
x/ibc/04-channel/client/rest/tx.go
Normal 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})
|
||||
}
|
||||
}
|
||||
69
x/ibc/04-channel/client/utils/utils.go
Normal file
69
x/ibc/04-channel/client/utils/utils.go
Normal 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
|
||||
}
|
||||
170
x/ibc/04-channel/exported/exported.go
Normal file
170
x/ibc/04-channel/exported/exported.go
Normal 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
|
||||
}
|
||||
}
|
||||
91
x/ibc/04-channel/exported/exported_test.go
Normal file
91
x/ibc/04-channel/exported/exported_test.go
Normal 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
171
x/ibc/04-channel/handler.go
Normal 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
|
||||
}
|
||||
393
x/ibc/04-channel/keeper/handshake.go
Normal file
393
x/ibc/04-channel/keeper/handshake.go
Normal 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
Loading…
Reference in New Issue
Block a user